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