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