xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp (revision 610f99c838cb661ff85377789ffd3ad4ff672a08)
1 /*
2  * Copyright 2004-2008, François Revol, <revol@free.fr>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "CamDevice.h"
8 #include "CamSensor.h"
9 #include "CamDeframer.h"
10 #include "CamDebug.h"
11 #include "AddOn.h"
12 
13 #include <OS.h>
14 #include <Autolock.h>
15 
16 //#define DEBUG_WRITE_DUMP
17 //#define DEBUG_DISCARD_DATA
18 //#define DEBUG_READ_DUMP
19 //#define DEBUG_DISCARD_INPUT
20 
21 #undef B_WEBCAM_DECLARE_SENSOR
22 #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \
23 extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam);
24 #include "CamInternalSensors.h"
25 #undef B_WEBCAM_DECLARE_SENSOR
26 typedef CamSensor *(*SensorInstFunc)(CamDevice *cam);
27 struct { const char *name; SensorInstFunc instfunc; } kSensorTable[] = {
28 #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \
29 { #sensorname, &Instantiate##sensorclass },
30 #include "CamInternalSensors.h"
31 { NULL, NULL },
32 };
33 #undef B_WEBCAM_DECLARE_SENSOR
34 
35 
36 CamDevice::CamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
37 	: fInitStatus(B_NO_INIT),
38 	  fSensor(NULL),
39 	  fBulkIn(NULL),
40 	  fIsoIn(NULL),
41 	  fLastParameterChanges(0),
42 	  fCamDeviceAddon(_addon),
43 	  fDevice(_device),
44 	  fSupportedDeviceIndex(-1),
45 	  fChipIsBigEndian(false),
46 	  fTransferEnabled(false),
47 	  fLocker("WebcamDeviceLock")
48 {
49 	// fill in the generic flavor
50 	_addon.WebCamAddOn()->FillDefaultFlavorInfo(&fFlavorInfo);
51 	// if we use id matching, cache the index to the list
52 	if (fCamDeviceAddon.SupportedDevices()) {
53 		fSupportedDeviceIndex = fCamDeviceAddon.Sniff(_device);
54 		fFlavorInfoNameStr = "";
55 		fFlavorInfoNameStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor << " USB Webcam";
56 		fFlavorInfoInfoStr = "";
57 		fFlavorInfoInfoStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor;
58 		fFlavorInfoInfoStr << " (" << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product << ") USB Webcam";
59 		fFlavorInfo.name = fFlavorInfoNameStr.String();
60 		fFlavorInfo.info = fFlavorInfoInfoStr.String();
61 	}
62 #ifdef DEBUG_WRITE_DUMP
63 	fDumpFD = open("/boot/home/webcam.out", O_CREAT|O_RDWR, 0644);
64 #endif
65 #ifdef DEBUG_READ_DUMP
66 	fDumpFD = open("/boot/home/webcam.out", O_RDONLY, 0644);
67 #endif
68 	fBufferLen = 1*B_PAGE_SIZE;
69 	fBuffer = (uint8 *)malloc(fBufferLen);
70 }
71 
72 
73 CamDevice::~CamDevice()
74 {
75 	close(fDumpFD);
76 	free(fBuffer);
77 	if (fDeframer)
78 		delete fDeframer;
79 }
80 
81 
82 status_t
83 CamDevice::InitCheck()
84 {
85 	return fInitStatus;
86 }
87 
88 
89 bool
90 CamDevice::Matches(BUSBDevice* _device)
91 {
92 	return _device == fDevice;
93 }
94 
95 
96 BUSBDevice*
97 CamDevice::GetDevice()
98 {
99 	return fDevice;
100 }
101 
102 
103 void
104 CamDevice::Unplugged()
105 {
106 	fDevice = NULL;
107 	fBulkIn = NULL;
108 	fIsoIn = NULL;
109 }
110 
111 
112 bool
113 CamDevice::IsPlugged()
114 {
115 	return (fDevice != NULL);
116 }
117 
118 
119 const char *
120 CamDevice::BrandName()
121 {
122 	if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1))
123 		return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor;
124 	return "<unknown>";
125 }
126 
127 
128 const char *
129 CamDevice::ModelName()
130 {
131 	if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1))
132 		return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product;
133 	return "<unknown>";
134 }
135 
136 
137 bool
138 CamDevice::SupportsBulk()
139 {
140 	return false;
141 }
142 
143 
144 bool
145 CamDevice::SupportsIsochronous()
146 {
147 	return false;
148 }
149 
150 
151 status_t
152 CamDevice::StartTransfer()
153 {
154 	status_t err = B_OK;
155 	PRINT((CH "()" CT));
156 	if (fTransferEnabled)
157 		return EALREADY;
158 	fPumpThread = spawn_thread(_DataPumpThread, "USB Webcam Data Pump", 50,
159 		this);
160 	if (fPumpThread < B_OK)
161 		return fPumpThread;
162 	if (fSensor)
163 		err = fSensor->StartTransfer();
164 	if (err < B_OK)
165 		return err;
166 	fTransferEnabled = true;
167 	resume_thread(fPumpThread);
168 	PRINT((CH ": transfer enabled" CT));
169 	return B_OK;
170 }
171 
172 
173 status_t
174 CamDevice::StopTransfer()
175 {
176 	status_t err = B_OK;
177 	PRINT((CH "()" CT));
178 	if (!fTransferEnabled)
179 		return EALREADY;
180 	if (fSensor)
181 		err = fSensor->StopTransfer();
182 	if (err < B_OK)
183 		return err;
184 	fTransferEnabled = false;
185 
186 	// the thread itself might Lock()
187 	fLocker.Unlock();
188 	wait_for_thread(fPumpThread, &err);
189 	fLocker.Lock();
190 
191 	return B_OK;
192 }
193 
194 
195 status_t
196 CamDevice::SuggestVideoFrame(uint32 &width, uint32 &height)
197 {
198 	if (Sensor()) {
199 		width = Sensor()->MaxWidth();
200 		height = Sensor()->MaxHeight();
201 		return B_OK;
202 	}
203 	return B_NO_INIT;
204 }
205 
206 
207 status_t
208 CamDevice::AcceptVideoFrame(uint32 &width, uint32 &height)
209 {
210 	status_t err = ENOSYS;
211 	if (Sensor())
212 		err = Sensor()->AcceptVideoFrame(width, height);
213 	if (err < B_OK)
214 		return err;
215 	SetVideoFrame(BRect(0, 0, width - 1, height - 1));
216 	return B_OK;
217 }
218 
219 
220 status_t
221 CamDevice::SetVideoFrame(BRect frame)
222 {
223 	fVideoFrame = frame;
224 	return B_OK;
225 }
226 
227 
228 status_t
229 CamDevice::SetScale(float scale)
230 {
231 	return B_OK;
232 }
233 
234 
235 status_t
236 CamDevice::SetVideoParams(float brightness, float contrast, float hue,
237 	float red, float green, float blue)
238 {
239 	return B_OK;
240 }
241 
242 
243 void
244 CamDevice::AddParameters(BParameterGroup *group, int32 &index)
245 {
246 	fFirstParameterID = index;
247 }
248 
249 
250 status_t
251 CamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value,
252 	size_t *size)
253 {
254 	return B_BAD_VALUE;
255 }
256 
257 
258 status_t
259 CamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value,
260 	size_t size)
261 {
262 	return B_BAD_VALUE;
263 }
264 
265 
266 size_t
267 CamDevice::MinRawFrameSize()
268 {
269 	return 0;
270 }
271 
272 
273 size_t
274 CamDevice::MaxRawFrameSize()
275 {
276 	return 0;
277 }
278 
279 
280 bool
281 CamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
282 {
283 	return true;
284 }
285 
286 
287 bool
288 CamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen,
289 	size_t datalen)
290 {
291 	return true;
292 }
293 
294 
295 status_t
296 CamDevice::WaitFrame(bigtime_t timeout)
297 {
298 	if (fDeframer)
299 		return WaitFrame(timeout);
300 	return EINVAL;
301 }
302 
303 
304 status_t
305 CamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp)
306 {
307 	return EINVAL;
308 }
309 
310 
311 status_t
312 CamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
313 {
314 	return EINVAL;
315 }
316 
317 
318 bool
319 CamDevice::Lock()
320 {
321 	return fLocker.Lock();
322 }
323 
324 
325 status_t
326 CamDevice::PowerOnSensor(bool on)
327 {
328 	return B_OK;
329 }
330 
331 
332 ssize_t
333 CamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
334 {
335 	return ENOSYS;
336 }
337 
338 
339 ssize_t
340 CamDevice::WriteReg8(uint16 address, uint8 data)
341 {
342 	return WriteReg(address, &data, sizeof(uint8));
343 }
344 
345 
346 ssize_t
347 CamDevice::WriteReg16(uint16 address, uint16 data)
348 {
349 	if (fChipIsBigEndian)
350 		data = B_HOST_TO_BENDIAN_INT16(data);
351 	else
352 		data = B_HOST_TO_LENDIAN_INT16(data);
353 	return WriteReg(address, (uint8 *)&data, sizeof(uint16));
354 }
355 
356 
357 ssize_t
358 CamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
359 {
360 	return ENOSYS;
361 }
362 
363 
364 ssize_t
365 CamDevice::OrReg8(uint16 address, uint8 data, uint8 mask)
366 {
367 	uint8 value;
368 	if (ReadReg(address, &value, 1, true) < 1)
369 		return EIO;
370 	value &= mask;
371 	value |= data;
372 	return WriteReg8(address, value);
373 }
374 
375 
376 ssize_t
377 CamDevice::AndReg8(uint16 address, uint8 data)
378 {
379 	uint8 value;
380 	if (ReadReg(address, &value, 1, true) < 1)
381 		return EIO;
382 	value &= data;
383 	return WriteReg8(address, value);
384 }
385 
386 
387 /*
388 status_t
389 CamDevice::GetStatusIIC()
390 {
391 	return ENOSYS;
392 }
393 */
394 
395 /*status_t
396 CamDevice::WaitReadyIIC()
397 {
398 	return ENOSYS;
399 }
400 */
401 
402 ssize_t
403 CamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
404 {
405 	return ENOSYS;
406 }
407 
408 
409 ssize_t
410 CamDevice::WriteIIC8(uint8 address, uint8 data)
411 {
412 	return WriteIIC(address, &data, 1);
413 }
414 
415 
416 ssize_t
417 CamDevice::WriteIIC16(uint8 address, uint16 data)
418 {
419 	if (Sensor() && Sensor()->IsBigEndian())
420 		data = B_HOST_TO_BENDIAN_INT16(data);
421 	else
422 		data = B_HOST_TO_LENDIAN_INT16(data);
423 	return WriteIIC(address, (uint8 *)&data, 2);
424 }
425 
426 
427 ssize_t
428 CamDevice::ReadIIC(uint8 address, uint8 *data)
429 {
430 	//TODO: make it mode generic
431 	return ENOSYS;
432 }
433 
434 
435 ssize_t
436 CamDevice::ReadIIC8(uint8 address, uint8 *data)
437 {
438 	return ReadIIC(address, data);
439 }
440 
441 
442 ssize_t
443 CamDevice::ReadIIC16(uint8 address, uint16 *data)
444 {
445 	return ENOSYS;
446 }
447 
448 
449 status_t
450 CamDevice::SetIICBitsMode(size_t bits)
451 {
452 	return ENOSYS;
453 }
454 
455 
456 status_t
457 CamDevice::ProbeSensor()
458 {
459 	const usb_webcam_support_descriptor *devs;
460 	const usb_webcam_support_descriptor *dev = NULL;
461 	status_t err;
462 	int32 i;
463 
464 	PRINT((CH ": probing sensors..." CT));
465 	if (fCamDeviceAddon.SupportedDevices() == NULL)
466 		return B_ERROR;
467 	devs = fCamDeviceAddon.SupportedDevices();
468 	for (i = 0; devs[i].vendor; i++) {
469 		if (GetDevice()->VendorID() != devs[i].desc.vendor)
470 			continue;
471 		if (GetDevice()->ProductID() != devs[i].desc.product)
472 			continue;
473 		dev = &devs[i];
474 		break;
475 	}
476 	if (!dev)
477 		return ENODEV;
478 	if (!dev->sensors) // no usable sensor
479 		return ENOENT;
480 	BString sensors(dev->sensors);
481 	for (i = 0; i > -1 && i < sensors.Length(); ) {
482 		BString name;
483 		sensors.CopyInto(name, i, sensors.FindFirst(',', i) - i);
484 		PRINT((CH ": probing sensor '%s'..." CT, name.String()));
485 
486 		fSensor = CreateSensor(name.String());
487 		if (fSensor) {
488 			err = fSensor->Probe();
489 			if (err >= B_OK)
490 				return B_OK;
491 
492 			PRINT((CH ": sensor '%s' Probe: %s" CT, name.String(),
493 				strerror(err)));
494 
495 			delete fSensor;
496 			fSensor = NULL;
497 		}
498 
499 		i = sensors.FindFirst(',', i+1);
500 		if (i > - 1)
501 			i++;
502 	}
503 	return ENOENT;
504 }
505 
506 
507 CamSensor *
508 CamDevice::CreateSensor(const char *name)
509 {
510 	for (int32 i = 0; kSensorTable[i].name; i++) {
511 		if (!strcmp(kSensorTable[i].name, name))
512 			return kSensorTable[i].instfunc(this);
513 	}
514 	PRINT((CH ": sensor '%s' not found" CT, name));
515 	return NULL;
516 }
517 
518 
519 void
520 CamDevice::SetDataInput(BDataIO *input)
521 {
522 	fDataInput = input;
523 }
524 
525 
526 status_t
527 CamDevice::DataPumpThread()
528 {
529 	if (SupportsBulk()) {
530 		PRINT((CH ": using Bulk" CT));
531 		while (fTransferEnabled) {
532 			ssize_t len = -1;
533 			BAutolock lock(fLocker);
534 			if (!lock.IsLocked())
535 				break;
536 			if (!fBulkIn)
537 				break;
538 #ifndef DEBUG_DISCARD_INPUT
539 			len = fBulkIn->BulkTransfer(fBuffer, fBufferLen);
540 #endif
541 
542 			//PRINT((CH ": got %ld bytes" CT, len));
543 #ifdef DEBUG_WRITE_DUMP
544 			write(fDumpFD, fBuffer, len);
545 #endif
546 #ifdef DEBUG_READ_DUMP
547 			if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen)
548 				lseek(fDumpFD, 0LL, SEEK_SET);
549 #endif
550 
551 			if (len <= 0) {
552 				PRINT((CH ": BulkIn: %s" CT, strerror(len)));
553 				break;
554 			}
555 
556 #ifndef DEBUG_DISCARD_DATA
557 			if (fDataInput) {
558 				fDataInput->Write(fBuffer, len);
559 				// else drop
560 			}
561 #endif
562 			//snooze(2000);
563 		}
564 	}
565 #ifdef SUPPORT_ISO
566 	else if (SupportsIsochronous()) {
567 		int numPacketDescriptors = 16;
568 		usb_iso_packet_descriptor packetDescriptors[numPacketDescriptors];
569 
570 		// Initialize packetDescriptor request lengths
571 		for (int i = 0; i<numPacketDescriptors; i++)
572 			packetDescriptors[i].request_length = 256;
573 
574 		int fullPackets = 0;
575 		int totalPackets = 0;
576 		while (fTransferEnabled) {
577 			ssize_t len = -1;
578 			BAutolock lock(fLocker);
579 			if (!lock.IsLocked())
580 				break;
581 			if (!fIsoIn)
582 				break;
583 #ifndef DEBUG_DISCARD_INPUT
584 			len = fIsoIn->IsochronousTransfer(fBuffer, fBufferLen, packetDescriptors,
585 				numPacketDescriptors);
586 #endif
587 
588 			//PRINT((CH ": got %d bytes" CT, len));
589 #ifdef DEBUG_WRITE_DUMP
590 			write(fDumpFD, fBuffer, len);
591 #endif
592 #ifdef DEBUG_READ_DUMP
593 			if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen)
594 				lseek(fDumpFD, 0LL, SEEK_SET);
595 #endif
596 
597 			if (len <= 0) {
598 				PRINT((CH ": IsoIn: %s" CT, strerror(len)));
599 				continue;
600 			}
601 
602 #ifndef DEBUG_DISCARD_DATA
603 			if (fDataInput) {
604 				int fBufferIndex = 0;
605 				for (int i = 0; i < numPacketDescriptors; i++) {
606 					int actual_length = ((usb_iso_packet_descriptor)
607 						packetDescriptors[i]).actual_length;
608 					if (actual_length > 0) {
609 						fDataInput->Write(&fBuffer[fBufferIndex],
610 							actual_length);
611 					}
612 					fBufferIndex += actual_length;
613 				}
614 			}
615 #endif
616 			//snooze(2000);
617 		}
618 	}
619 #endif
620 	else {
621 		PRINT((CH ": No supported transport." CT));
622 		return B_UNSUPPORTED;
623 	}
624 	return B_OK;
625 }
626 
627 
628 int32
629 CamDevice::_DataPumpThread(void *_this)
630 {
631 	CamDevice *dev = (CamDevice *)_this;
632 	return dev->DataPumpThread();
633 }
634 
635 
636 void
637 CamDevice::DumpRegs()
638 {
639 }
640 
641 
642 status_t
643 CamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
644 	uint16 index, uint16 length, void* data)
645 {
646 	ssize_t ret;
647 	if (!GetDevice())
648 		return ENODEV;
649 	if (length > GetDevice()->MaxEndpoint0PacketSize())
650 		return EINVAL;
651 	ret = GetDevice()->ControlTransfer(
652 		USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
653 		request, value, index, length, data);
654 	return ret;
655 }
656 
657 
658 CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn* webcam)
659 	: fWebCamAddOn(webcam),
660 	  fSupportedDevices(NULL)
661 {
662 }
663 
664 
665 CamDeviceAddon::~CamDeviceAddon()
666 {
667 }
668 
669 
670 const char *
671 CamDeviceAddon::BrandName()
672 {
673 	return "<unknown>";
674 }
675 
676 
677 status_t
678 CamDeviceAddon::Sniff(BUSBDevice *device)
679 {
680 	PRINT((CH ": Sniffing for %s" CT, BrandName()));
681 	if (!fSupportedDevices)
682 		return ENODEV;
683 	if (!device)
684 		return EINVAL;
685 
686 	bool supported = false;
687 	for (uint32 i = 0; !supported && fSupportedDevices[i].vendor; i++) {
688 		if ((fSupportedDevices[i].desc.vendor != 0
689 			&& device->VendorID() != fSupportedDevices[i].desc.vendor)
690 			|| (fSupportedDevices[i].desc.product != 0
691 			&& device->ProductID() != fSupportedDevices[i].desc.product))
692 			continue;
693 
694 		if ((fSupportedDevices[i].desc.dev_class == 0
695 			|| device->Class() == fSupportedDevices[i].desc.dev_class)
696 			&& (fSupportedDevices[i].desc.dev_subclass == 0
697 			|| device->Subclass() == fSupportedDevices[i].desc.dev_subclass)
698 			&& (fSupportedDevices[i].desc.dev_protocol == 0
699 			|| device->Protocol() == fSupportedDevices[i].desc.dev_protocol)) {
700 			supported = true;
701 		}
702 
703 #ifdef __HAIKU__
704 		// we have to check all interfaces for matching class/subclass/protocol
705 		for (uint32 j = 0; !supported && j < device->CountConfigurations(); j++) {
706 			const BUSBConfiguration* cfg = device->ConfigurationAt(j);
707 			for (uint32 k = 0; !supported && k < cfg->CountInterfaces(); k++) {
708 				const BUSBInterface* intf = cfg->InterfaceAt(k);
709 				for (uint32 l = 0; !supported && l < intf->CountAlternates(); l++) {
710 					const BUSBInterface* alt = intf->AlternateAt(l);
711 					if ((fSupportedDevices[i].desc.dev_class == 0
712 						|| alt->Class() == fSupportedDevices[i].desc.dev_class)
713 						&& (fSupportedDevices[i].desc.dev_subclass == 0
714 						|| alt->Subclass() == fSupportedDevices[i].desc.dev_subclass)
715 						&& (fSupportedDevices[i].desc.dev_protocol == 0
716 						|| alt->Protocol() == fSupportedDevices[i].desc.dev_protocol)) {
717 						supported = true;
718 					}
719 				}
720 			}
721 		}
722 #endif
723 
724 		if (supported)
725 			return i;
726 	}
727 
728 	return ENODEV;
729 }
730 
731 
732 CamDevice *
733 CamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
734 {
735 	return NULL;
736 }
737 
738 
739 void
740 CamDeviceAddon::SetSupportedDevices(const usb_webcam_support_descriptor *devs)
741 {
742 	fSupportedDevices = devs;
743 }
744