xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp (revision b46615c55ad2c8fe6de54412055a0713da3d610a)
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 = 20;
569 		usb_iso_packet_descriptor packetDescriptors[numPacketDescriptors];
570 		while (fTransferEnabled) {
571 			ssize_t len = -1;
572 			BAutolock lock(fLocker);
573 			if (!lock.IsLocked())
574 				break;
575 			if (!fIsoIn)
576 				break;
577 #ifndef DEBUG_DISCARD_INPUT
578 			len = fIsoIn->IsochronousTransfer(fBuffer, fBufferLen, packetDescriptors, numPacketDescriptors);
579 #endif
580 
581 			//PRINT((CH ": got %d bytes" CT, len));
582 #ifdef DEBUG_WRITE_DUMP
583 			write(fDumpFD, fBuffer, len);
584 #endif
585 #ifdef DEBUG_READ_DUMP
586 			if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen)
587 				lseek(fDumpFD, 0LL, SEEK_SET);
588 #endif
589 
590 			if (len <= 0) {
591 				PRINT((CH ": IsoIn: %s" CT, strerror(len)));
592 				continue;
593 			}
594 
595 #ifndef DEBUG_DISCARD_DATA
596 			if (fDataInput) {
597 				fDataInput->Write(fBuffer, len);
598 				// else drop
599 			}
600 #endif
601 			//snooze(2000);
602 		}
603 	}
604 #endif
605 	else {
606 		PRINT((CH ": No supported transport." CT));
607 		return B_UNSUPPORTED;
608 	}
609 	return B_OK;
610 }
611 
612 
613 int32
614 CamDevice::_DataPumpThread(void *_this)
615 {
616 	CamDevice *dev = (CamDevice *)_this;
617 	return dev->DataPumpThread();
618 }
619 
620 
621 void
622 CamDevice::DumpRegs()
623 {
624 }
625 
626 
627 status_t
628 CamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
629 	uint16 index, uint16 length, void* data)
630 {
631 	ssize_t ret;
632 	if (!GetDevice())
633 		return ENODEV;
634 	if (length > GetDevice()->MaxEndpoint0PacketSize())
635 		return EINVAL;
636 	ret = GetDevice()->ControlTransfer(
637 		USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
638 		request, value, index, length, data);
639 	return ret;
640 }
641 
642 
643 CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn* webcam)
644 	: fWebCamAddOn(webcam),
645 	  fSupportedDevices(NULL)
646 {
647 }
648 
649 
650 CamDeviceAddon::~CamDeviceAddon()
651 {
652 }
653 
654 
655 const char *
656 CamDeviceAddon::BrandName()
657 {
658 	return "<unknown>";
659 }
660 
661 
662 status_t
663 CamDeviceAddon::Sniff(BUSBDevice *device)
664 {
665 	PRINT((CH ": Sniffing for %s" CT, BrandName()));
666 	if (!fSupportedDevices)
667 		return ENODEV;
668 	if (!device)
669 		return EINVAL;
670 
671 	bool supported = false;
672 	for (uint32 i = 0; !supported && fSupportedDevices[i].vendor; i++) {
673 		if ((fSupportedDevices[i].desc.vendor != 0
674 			&& device->VendorID() != fSupportedDevices[i].desc.vendor)
675 			|| (fSupportedDevices[i].desc.product != 0
676 			&& device->ProductID() != fSupportedDevices[i].desc.product))
677 			continue;
678 
679 		if ((fSupportedDevices[i].desc.dev_class == 0
680 			|| device->Class() == fSupportedDevices[i].desc.dev_class)
681 			&& (fSupportedDevices[i].desc.dev_subclass == 0
682 			|| device->Subclass() == fSupportedDevices[i].desc.dev_subclass)
683 			&& (fSupportedDevices[i].desc.dev_protocol == 0
684 			|| device->Protocol() == fSupportedDevices[i].desc.dev_protocol)) {
685 			supported = true;
686 		}
687 
688 #ifdef __HAIKU__
689 		// we have to check all interfaces for matching class/subclass/protocol
690 		for (uint32 j = 0; !supported && j < device->CountConfigurations(); j++) {
691 			const BUSBConfiguration* cfg = device->ConfigurationAt(j);
692 			for (uint32 k = 0; !supported && k < cfg->CountInterfaces(); k++) {
693 				const BUSBInterface* intf = cfg->InterfaceAt(k);
694 				for (uint32 l = 0; !supported && l < intf->CountAlternates(); l++) {
695 					const BUSBInterface* alt = intf->AlternateAt(l);
696 					if ((fSupportedDevices[i].desc.dev_class == 0
697 						|| alt->Class() == fSupportedDevices[i].desc.dev_class)
698 						&& (fSupportedDevices[i].desc.dev_subclass == 0
699 						|| alt->Subclass() == fSupportedDevices[i].desc.dev_subclass)
700 						&& (fSupportedDevices[i].desc.dev_protocol == 0
701 						|| alt->Protocol() == fSupportedDevices[i].desc.dev_protocol)) {
702 						supported = true;
703 					}
704 				}
705 			}
706 		}
707 #endif
708 
709 		if (supported)
710 			return i;
711 	}
712 
713 	return ENODEV;
714 }
715 
716 
717 CamDevice *
718 CamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
719 {
720 	return NULL;
721 }
722 
723 
724 void
725 CamDeviceAddon::SetSupportedDevices(const usb_webcam_support_descriptor *devs)
726 {
727 	fSupportedDevices = devs;
728 }
729