2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
9 #include "CamDeframer.h"
16 //#define DEBUG_WRITE_DUMP
17 //#define DEBUG_DISCARD_DATA
18 //#define DEBUG_READ_DUMP
19 //#define DEBUG_DISCARD_INPUT
21 #undef B_WEBCAM_DECLARE_SENSOR
22 #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \
23 extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam);
24 #include "CamInternalSensors.h"
25 #undef B_WEBCAM_DECLARE_SENSOR
26 typedef CamSensor
*(*SensorInstFunc
)(CamDevice
*cam
);
27 struct { const char *name
; SensorInstFunc instfunc
; } kSensorTable
[] = {
28 #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \
29 { #sensorname, &Instantiate##sensorclass },
30 #include "CamInternalSensors.h"
33 #undef B_WEBCAM_DECLARE_SENSOR
36 CamDevice::CamDevice(CamDeviceAddon
&_addon
, BUSBDevice
* _device
)
37 : fInitStatus(B_NO_INIT
),
41 fLastParameterChanges(0),
42 fCamDeviceAddon(_addon
),
44 fSupportedDeviceIndex(-1),
45 fChipIsBigEndian(false),
46 fTransferEnabled(false),
47 fLocker("WebcamDeviceLock")
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();
63 #ifdef DEBUG_WRITE_DUMP
64 fDumpFD
= open("/boot/home/webcam.out", O_CREAT
|O_RDWR
, 0644);
66 #ifdef DEBUG_READ_DUMP
67 fDumpFD
= open("/boot/home/webcam.out", O_RDONLY
, 0644);
69 fBufferLen
= 1*B_PAGE_SIZE
;
70 fBuffer
= (uint8
*)malloc(fBufferLen
);
74 CamDevice::~CamDevice()
84 CamDevice::InitCheck()
91 CamDevice::Matches(BUSBDevice
* _device
)
93 return _device
== fDevice
;
98 CamDevice::GetDevice()
105 CamDevice::Unplugged()
114 CamDevice::IsPlugged()
116 return (fDevice
!= NULL
);
121 CamDevice::BrandName()
123 if (fCamDeviceAddon
.SupportedDevices() && (fSupportedDeviceIndex
> -1))
124 return fCamDeviceAddon
.SupportedDevices()[fSupportedDeviceIndex
].vendor
;
130 CamDevice::ModelName()
132 if (fCamDeviceAddon
.SupportedDevices() && (fSupportedDeviceIndex
> -1))
133 return fCamDeviceAddon
.SupportedDevices()[fSupportedDeviceIndex
].product
;
139 CamDevice::SupportsBulk()
146 CamDevice::SupportsIsochronous()
153 CamDevice::StartTransfer()
157 if (fTransferEnabled
)
159 fPumpThread
= spawn_thread(_DataPumpThread
, "USB Webcam Data Pump", 50,
161 if (fPumpThread
< B_OK
)
164 err
= fSensor
->StartTransfer();
167 fTransferEnabled
= true;
168 resume_thread(fPumpThread
);
169 PRINT((CH
": transfer enabled" CT
));
175 CamDevice::StopTransfer()
179 if (!fTransferEnabled
)
182 err
= fSensor
->StopTransfer();
185 fTransferEnabled
= false;
187 // the thread itself might Lock()
189 wait_for_thread(fPumpThread
, &err
);
197 CamDevice::SuggestVideoFrame(uint32
&width
, uint32
&height
)
200 width
= Sensor()->MaxWidth();
201 height
= Sensor()->MaxHeight();
209 CamDevice::AcceptVideoFrame(uint32
&width
, uint32
&height
)
211 status_t err
= ENOSYS
;
213 err
= Sensor()->AcceptVideoFrame(width
, height
);
216 SetVideoFrame(BRect(0, 0, width
- 1, height
- 1));
222 CamDevice::SetVideoFrame(BRect frame
)
230 CamDevice::SetScale(float scale
)
237 CamDevice::SetVideoParams(float brightness
, float contrast
, float hue
,
238 float red
, float green
, float blue
)
245 CamDevice::AddParameters(BParameterGroup
*group
, int32
&index
)
247 fFirstParameterID
= index
;
252 CamDevice::GetParameterValue(int32 id
, bigtime_t
*last_change
, void *value
,
260 CamDevice::SetParameterValue(int32 id
, bigtime_t when
, const void *value
,
268 CamDevice::MinRawFrameSize()
275 CamDevice::MaxRawFrameSize()
282 CamDevice::ValidateStartOfFrameTag(const uint8
*tag
, size_t taglen
)
289 CamDevice::ValidateEndOfFrameTag(const uint8
*tag
, size_t taglen
,
297 CamDevice::WaitFrame(bigtime_t timeout
)
300 return WaitFrame(timeout
);
306 CamDevice::GetFrameBitmap(BBitmap
**bm
, bigtime_t
*stamp
)
313 CamDevice::FillFrameBuffer(BBuffer
*buffer
, bigtime_t
*stamp
)
322 return fLocker
.Lock();
327 CamDevice::PowerOnSensor(bool on
)
334 CamDevice::WriteReg(uint16 address
, uint8
*data
, size_t count
)
341 CamDevice::WriteReg8(uint16 address
, uint8 data
)
343 return WriteReg(address
, &data
, sizeof(uint8
));
348 CamDevice::WriteReg16(uint16 address
, uint16 data
)
350 if (fChipIsBigEndian
)
351 data
= B_HOST_TO_BENDIAN_INT16(data
);
353 data
= B_HOST_TO_LENDIAN_INT16(data
);
354 return WriteReg(address
, (uint8
*)&data
, sizeof(uint16
));
359 CamDevice::ReadReg(uint16 address
, uint8
*data
, size_t count
, bool cached
)
366 CamDevice::OrReg8(uint16 address
, uint8 data
, uint8 mask
)
369 if (ReadReg(address
, &value
, 1, true) < 1)
373 return WriteReg8(address
, value
);
378 CamDevice::AndReg8(uint16 address
, uint8 data
)
381 if (ReadReg(address
, &value
, 1, true) < 1)
384 return WriteReg8(address
, value
);
390 CamDevice::GetStatusIIC()
397 CamDevice::WaitReadyIIC()
404 CamDevice::WriteIIC(uint8 address
, uint8
*data
, size_t count
)
411 CamDevice::WriteIIC8(uint8 address
, uint8 data
)
413 return WriteIIC(address
, &data
, 1);
418 CamDevice::WriteIIC16(uint8 address
, uint16 data
)
420 if (Sensor() && Sensor()->IsBigEndian())
421 data
= B_HOST_TO_BENDIAN_INT16(data
);
423 data
= B_HOST_TO_LENDIAN_INT16(data
);
424 return WriteIIC(address
, (uint8
*)&data
, 2);
429 CamDevice::ReadIIC(uint8 address
, uint8
*data
)
431 //TODO: make it mode generic
437 CamDevice::ReadIIC8(uint8 address
, uint8
*data
)
439 return ReadIIC(address
, data
);
444 CamDevice::ReadIIC16(uint8 address
, uint16
*data
)
451 CamDevice::SetIICBitsMode(size_t bits
)
458 CamDevice::ProbeSensor()
460 const usb_webcam_support_descriptor
*devs
;
461 const usb_webcam_support_descriptor
*dev
= NULL
;
465 PRINT((CH
": probing sensors..." CT
));
466 if (fCamDeviceAddon
.SupportedDevices() == NULL
)
468 devs
= fCamDeviceAddon
.SupportedDevices();
469 for (i
= 0; devs
[i
].vendor
; i
++) {
470 if (GetDevice()->VendorID() != devs
[i
].desc
.vendor
)
472 if (GetDevice()->ProductID() != devs
[i
].desc
.product
)
479 if (!dev
->sensors
) // no usable sensor
481 BString
sensors(dev
->sensors
);
482 for (i
= 0; i
> -1 && i
< sensors
.Length(); ) {
484 sensors
.CopyInto(name
, i
, sensors
.FindFirst(',', i
) - i
);
485 PRINT((CH
": probing sensor '%s'..." CT
, name
.String()));
487 fSensor
= CreateSensor(name
.String());
489 err
= fSensor
->Probe();
493 PRINT((CH
": sensor '%s' Probe: %s" CT
, name
.String(),
500 i
= sensors
.FindFirst(',', i
+1);
509 CamDevice::CreateSensor(const char *name
)
511 for (int32 i
= 0; kSensorTable
[i
].name
; i
++) {
512 if (!strcmp(kSensorTable
[i
].name
, name
))
513 return kSensorTable
[i
].instfunc(this);
515 PRINT((CH
": sensor '%s' not found" CT
, name
));
521 CamDevice::SetDataInput(BDataIO
*input
)
528 CamDevice::DataPumpThread()
530 if (SupportsBulk()) {
531 PRINT((CH
": using Bulk" CT
));
532 while (fTransferEnabled
) {
534 BAutolock
lock(fLocker
);
535 if (!lock
.IsLocked())
539 #ifndef DEBUG_DISCARD_INPUT
540 len
= fBulkIn
->BulkTransfer(fBuffer
, fBufferLen
);
543 //PRINT((CH ": got %ld bytes" CT, len));
544 #ifdef DEBUG_WRITE_DUMP
545 write(fDumpFD
, fBuffer
, len
);
547 #ifdef DEBUG_READ_DUMP
548 if ((len
= read(fDumpFD
, fBuffer
, fBufferLen
)) < fBufferLen
)
549 lseek(fDumpFD
, 0LL, SEEK_SET
);
553 PRINT((CH
": BulkIn: %s" CT
, strerror(len
)));
557 #ifndef DEBUG_DISCARD_DATA
559 fDataInput
->Write(fBuffer
, len
);
567 else if (SupportsIsochronous()) {
568 int numPacketDescriptors
= 16;
569 usb_iso_packet_descriptor packetDescriptors
[numPacketDescriptors
];
571 // Initialize packetDescriptor request lengths
572 for (int i
= 0; i
<numPacketDescriptors
; i
++)
573 packetDescriptors
[i
].request_length
= 256;
576 int totalPackets
= 0;
577 while (fTransferEnabled
) {
579 BAutolock
lock(fLocker
);
580 if (!lock
.IsLocked())
584 #ifndef DEBUG_DISCARD_INPUT
585 len
= fIsoIn
->IsochronousTransfer(fBuffer
, fBufferLen
, packetDescriptors
,
586 numPacketDescriptors
);
589 //PRINT((CH ": got %d bytes" CT, len));
590 #ifdef DEBUG_WRITE_DUMP
591 write(fDumpFD
, fBuffer
, len
);
593 #ifdef DEBUG_READ_DUMP
594 if ((len
= read(fDumpFD
, fBuffer
, fBufferLen
)) < fBufferLen
)
595 lseek(fDumpFD
, 0LL, SEEK_SET
);
599 PRINT((CH
": IsoIn: %s" CT
, strerror(len
)));
603 #ifndef DEBUG_DISCARD_DATA
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
],
613 fBufferIndex
+= actual_length
;
622 PRINT((CH
": No supported transport." CT
));
623 return B_UNSUPPORTED
;
630 CamDevice::_DataPumpThread(void *_this
)
632 CamDevice
*dev
= (CamDevice
*)_this
;
633 return dev
->DataPumpThread();
638 CamDevice::DumpRegs()
644 CamDevice::SendCommand(uint8 dir
, uint8 request
, uint16 value
,
645 uint16 index
, uint16 length
, void* data
)
650 if (length
> GetDevice()->MaxEndpoint0PacketSize())
652 ret
= GetDevice()->ControlTransfer(
653 USB_REQTYPE_VENDOR
| USB_REQTYPE_INTERFACE_OUT
| dir
,
654 request
, value
, index
, length
, data
);
659 CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn
* webcam
)
660 : fWebCamAddOn(webcam
),
661 fSupportedDevices(NULL
)
666 CamDeviceAddon::~CamDeviceAddon()
672 CamDeviceAddon::BrandName()
679 CamDeviceAddon::Sniff(BUSBDevice
*device
)
681 PRINT((CH
": Sniffing for %s" CT
, BrandName()));
682 if (!fSupportedDevices
)
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
))
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
)) {
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
)) {
734 CamDeviceAddon::Instantiate(CamRoster
&roster
, BUSBDevice
*from
)
741 CamDeviceAddon::SetSupportedDevices(const usb_webcam_support_descriptor
*devs
)
743 fSupportedDevices
= devs
;