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) \
23extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam);
24#include "CamInternalSensors.h"
25#undef B_WEBCAM_DECLARE_SENSOR
26typedef CamSensor *(*SensorInstFunc)(CamDevice *cam);
27struct { 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
36CamDevice::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
74CamDevice::~CamDevice()
75{
76	close(fDumpFD);
77	free(fBuffer);
78	if (fDeframer)
79		delete fDeframer;
80}
81
82
83status_t
84CamDevice::InitCheck()
85{
86	return fInitStatus;
87}
88
89
90bool
91CamDevice::Matches(BUSBDevice* _device)
92{
93	return _device == fDevice;
94}
95
96
97BUSBDevice*
98CamDevice::GetDevice()
99{
100	return fDevice;
101}
102
103
104void
105CamDevice::Unplugged()
106{
107	fDevice = NULL;
108	fBulkIn = NULL;
109	fIsoIn = NULL;
110}
111
112
113bool
114CamDevice::IsPlugged()
115{
116	return (fDevice != NULL);
117}
118
119
120const char *
121CamDevice::BrandName()
122{
123	if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1))
124		return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor;
125	return "<unknown>";
126}
127
128
129const char *
130CamDevice::ModelName()
131{
132	if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1))
133		return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product;
134	return "<unknown>";
135}
136
137
138bool
139CamDevice::SupportsBulk()
140{
141	return false;
142}
143
144
145bool
146CamDevice::SupportsIsochronous()
147{
148	return false;
149}
150
151
152status_t
153CamDevice::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
174status_t
175CamDevice::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
196status_t
197CamDevice::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
208status_t
209CamDevice::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
221status_t
222CamDevice::SetVideoFrame(BRect frame)
223{
224	fVideoFrame = frame;
225	return B_OK;
226}
227
228
229status_t
230CamDevice::SetScale(float scale)
231{
232	return B_OK;
233}
234
235
236status_t
237CamDevice::SetVideoParams(float brightness, float contrast, float hue,
238	float red, float green, float blue)
239{
240	return B_OK;
241}
242
243
244void
245CamDevice::AddParameters(BParameterGroup *group, int32 &index)
246{
247	fFirstParameterID = index;
248}
249
250
251status_t
252CamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value,
253	size_t *size)
254{
255	return B_BAD_VALUE;
256}
257
258
259status_t
260CamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value,
261	size_t size)
262{
263	return B_BAD_VALUE;
264}
265
266
267size_t
268CamDevice::MinRawFrameSize()
269{
270	return 0;
271}
272
273
274size_t
275CamDevice::MaxRawFrameSize()
276{
277	return 0;
278}
279
280
281bool
282CamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
283{
284	return true;
285}
286
287
288bool
289CamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen,
290	size_t datalen)
291{
292	return true;
293}
294
295
296status_t
297CamDevice::WaitFrame(bigtime_t timeout)
298{
299	if (fDeframer)
300		return WaitFrame(timeout);
301	return EINVAL;
302}
303
304
305status_t
306CamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp)
307{
308	return EINVAL;
309}
310
311
312status_t
313CamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
314{
315	return EINVAL;
316}
317
318
319bool
320CamDevice::Lock()
321{
322	return fLocker.Lock();
323}
324
325
326status_t
327CamDevice::PowerOnSensor(bool on)
328{
329	return B_OK;
330}
331
332
333ssize_t
334CamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
335{
336	return ENOSYS;
337}
338
339
340ssize_t
341CamDevice::WriteReg8(uint16 address, uint8 data)
342{
343	return WriteReg(address, &data, sizeof(uint8));
344}
345
346
347ssize_t
348CamDevice::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
358ssize_t
359CamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
360{
361	return ENOSYS;
362}
363
364
365ssize_t
366CamDevice::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
377ssize_t
378CamDevice::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/*
389status_t
390CamDevice::GetStatusIIC()
391{
392	return ENOSYS;
393}
394*/
395
396/*status_t
397CamDevice::WaitReadyIIC()
398{
399	return ENOSYS;
400}
401*/
402
403ssize_t
404CamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
405{
406	return ENOSYS;
407}
408
409
410ssize_t
411CamDevice::WriteIIC8(uint8 address, uint8 data)
412{
413	return WriteIIC(address, &data, 1);
414}
415
416
417ssize_t
418CamDevice::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
428ssize_t
429CamDevice::ReadIIC(uint8 address, uint8 *data)
430{
431	//TODO: make it mode generic
432	return ENOSYS;
433}
434
435
436ssize_t
437CamDevice::ReadIIC8(uint8 address, uint8 *data)
438{
439	return ReadIIC(address, data);
440}
441
442
443ssize_t
444CamDevice::ReadIIC16(uint8 address, uint16 *data)
445{
446	return ENOSYS;
447}
448
449
450status_t
451CamDevice::SetIICBitsMode(size_t bits)
452{
453	return ENOSYS;
454}
455
456
457status_t
458CamDevice::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
508CamSensor *
509CamDevice::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
520void
521CamDevice::SetDataInput(BDataIO *input)
522{
523	fDataInput = input;
524}
525
526
527status_t
528CamDevice::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
629int32
630CamDevice::_DataPumpThread(void *_this)
631{
632	CamDevice *dev = (CamDevice *)_this;
633	return dev->DataPumpThread();
634}
635
636
637void
638CamDevice::DumpRegs()
639{
640}
641
642
643status_t
644CamDevice::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
659CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn* webcam)
660	: fWebCamAddOn(webcam),
661	  fSupportedDevices(NULL)
662{
663}
664
665
666CamDeviceAddon::~CamDeviceAddon()
667{
668}
669
670
671const char *
672CamDeviceAddon::BrandName()
673{
674	return "<unknown>";
675}
676
677
678status_t
679CamDeviceAddon::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
733CamDevice *
734CamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
735{
736	return NULL;
737}
738
739
740void
741CamDeviceAddon::SetSupportedDevices(const usb_webcam_support_descriptor *devs)
742{
743	fSupportedDevices = devs;
744}
745