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