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