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