#include "CamDevice.h" #include "CamSensor.h" #include "CamDeframer.h" #include "CamDebug.h" #include "AddOn.h" #include #include //#define DEBUG_WRITE_DUMP //#define DEBUG_DISCARD_DATA //#define DEBUG_READ_DUMP //#define DEBUG_DISCARD_INPUT #undef B_WEBCAM_DECLARE_SENSOR #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \ extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam); #include "CamInternalSensors.h" #undef B_WEBCAM_DECLARE_SENSOR typedef CamSensor *(*SensorInstFunc)(CamDevice *cam); struct { const char *name; SensorInstFunc instfunc; } kSensorTable[] = { #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \ { #sensorname, &Instantiate##sensorclass }, #include "CamInternalSensors.h" { NULL, NULL }, }; #undef B_WEBCAM_DECLARE_SENSOR CamDevice::CamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) : fInitStatus(B_NO_INIT), fSensor(NULL), fLastParameterChanges(0), fCamDeviceAddon(_addon), fDevice(_device), fSupportedDeviceIndex(-1), fChipIsBigEndian(false), fTransferEnabled(false), fLocker("WebcamDeviceLock") { // fill in the generic flavor memset(&fFlavorInfo, 0, sizeof(fFlavorInfo)); _addon.WebCamAddOn()->FillDefaultFlavorInfo(&fFlavorInfo); // if we use id matching, cache the index to the list if (fCamDeviceAddon.SupportedDevices()) { fSupportedDeviceIndex = fCamDeviceAddon.Sniff(_device); fFlavorInfoNameStr = ""; fFlavorInfoNameStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor << " USB Webcam"; fFlavorInfoInfoStr = ""; fFlavorInfoInfoStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor; fFlavorInfoInfoStr << " (" << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product << ") USB Webcam"; fFlavorInfo.name = (char *)fFlavorInfoNameStr.String(); fFlavorInfo.info = (char *)fFlavorInfoInfoStr.String(); } #ifdef DEBUG_WRITE_DUMP fDumpFD = open("/boot/home/webcam.out", O_CREAT|O_RDWR, 0644); #endif #ifdef DEBUG_READ_DUMP fDumpFD = open("/boot/home/webcam.out", O_RDONLY, 0644); #endif fBufferLen = 1*B_PAGE_SIZE; fBuffer = (uint8 *)malloc(fBufferLen); } CamDevice::~CamDevice() { close(fDumpFD); free(fBuffer); if (fDeframer) delete fDeframer; } status_t CamDevice::InitCheck() { return fInitStatus; } bool CamDevice::Matches(BUSBDevice* _device) { return (_device) == (fDevice); } BUSBDevice* CamDevice::GetDevice() { return fDevice; } void CamDevice::Unplugged() { fDevice = NULL; fBulkIn = NULL; } bool CamDevice::IsPlugged() { return (fDevice != NULL); } const char * CamDevice::BrandName() { if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1)) return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor; return ""; } const char * CamDevice::ModelName() { if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1)) return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product; return ""; } bool CamDevice::SupportsBulk() { return false; } bool CamDevice::SupportsIsochronous() { return false; } status_t CamDevice::StartTransfer() { status_t err = B_OK; PRINT((CH "()" CT)); if (fTransferEnabled) return EALREADY; fPumpThread = spawn_thread(_DataPumpThread, "USB Webcam Data Pump", 50, this); if (fPumpThread < B_OK) return fPumpThread; if (fSensor) err = fSensor->StartTransfer(); if (err < B_OK) return err; fTransferEnabled = true; resume_thread(fPumpThread); PRINT((CH ": transfer enabled" CT)); return B_OK; } status_t CamDevice::StopTransfer() { status_t err = B_OK; PRINT((CH "()" CT)); if (!fTransferEnabled) return EALREADY; if (fSensor) err = fSensor->StopTransfer(); if (err < B_OK) return err; fTransferEnabled = false; // the thread itself might Lock() fLocker.Unlock(); wait_for_thread(fPumpThread, &err); fLocker.Lock(); return B_OK; } status_t CamDevice::AcceptVideoFrame(uint32 &width, uint32 &height) { status_t err = ENOSYS; if (Sensor()) err = Sensor()->AcceptVideoFrame(width, height); if (err < B_OK) return err; fVideoFrame = BRect(0, 0, width - 1, height - 1); return B_OK; } status_t CamDevice::SetVideoFrame(BRect frame) { fVideoFrame = frame; return B_OK; } status_t CamDevice::SetScale(float scale) { return B_OK; } status_t CamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue) { return B_OK; } void CamDevice::AddParameters(BParameterGroup *group, int32 &index) { fFirstParameterID = index; } status_t CamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size) { return B_BAD_VALUE; } status_t CamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size) { return B_BAD_VALUE; } size_t CamDevice::MinRawFrameSize() { return 0; } size_t CamDevice::MaxRawFrameSize() { return 0; } bool CamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen) { return true; } bool CamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen) { return true; } status_t CamDevice::WaitFrame(bigtime_t timeout) { if (fDeframer) return WaitFrame(timeout); return EINVAL; } status_t CamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp) { return EINVAL; } status_t CamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp) { return EINVAL; } bool CamDevice::Lock() { return fLocker.Lock(); } ssize_t CamDevice::WriteReg(uint16 address, uint8 *data, size_t count) { return ENOSYS; } ssize_t CamDevice::WriteReg8(uint16 address, uint8 data) { return WriteReg(address, &data, sizeof(uint8)); } ssize_t CamDevice::WriteReg16(uint16 address, uint16 data) { if (fChipIsBigEndian) data = B_HOST_TO_BENDIAN_INT16(data); else data = B_HOST_TO_LENDIAN_INT16(data); return WriteReg(address, (uint8 *)&data, sizeof(uint16)); } ssize_t CamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached) { return ENOSYS; } /* status_t CamDevice::GetStatusIIC() { return ENOSYS; } */ /*status_t CamDevice::WaitReadyIIC() { return ENOSYS; } */ ssize_t CamDevice::WriteIIC(uint8 address, uint8 *data, size_t count) { return ENOSYS; } ssize_t CamDevice::WriteIIC8(uint8 address, uint8 data) { return WriteIIC(address, &data, 1); } ssize_t CamDevice::WriteIIC16(uint8 address, uint16 data) { if (Sensor() && Sensor()->IsBigEndian()) data = B_HOST_TO_BENDIAN_INT16(data); else data = B_HOST_TO_LENDIAN_INT16(data); return WriteIIC(address, (uint8 *)&data, 2); } ssize_t CamDevice::ReadIIC(uint8 address, uint8 *data) { //TODO: make it mode generic return ENOSYS; } ssize_t CamDevice::ReadIIC8(uint8 address, uint8 *data) { return ReadIIC(address, data); } ssize_t CamDevice::ReadIIC16(uint8 address, uint16 *data) { return ENOSYS; } status_t CamDevice::SetIICBitsMode(size_t bits) { return ENOSYS; } status_t CamDevice::ProbeSensor() { const usb_webcam_support_descriptor *devs; const usb_webcam_support_descriptor *dev = NULL; status_t err; int32 i; PRINT((CH ": probing sensors..." CT)); if (fCamDeviceAddon.SupportedDevices() == NULL) return B_ERROR; devs = fCamDeviceAddon.SupportedDevices(); for (i = 0; devs[i].vendor; i++) { if (GetDevice()->VendorID() != devs[i].desc.vendor) continue; if (GetDevice()->ProductID() != devs[i].desc.product) continue; dev = &devs[i]; break; } if (!dev) return ENODEV; if (!dev->sensors) // no usable sensor return ENOENT; BString sensors(dev->sensors); for (i = 0; i > -1 && i < sensors.Length(); ) { BString name; sensors.CopyInto(name, i, sensors.FindFirst(',', i) - i); PRINT((CH ": probing sensor '%s'..." CT, name.String())); fSensor = CreateSensor(name.String()); if (fSensor) { err = fSensor->Probe(); if (err >= B_OK) return B_OK; PRINT((CH ": sensor '%s' Probe: %s" CT, name.String(), strerror(err))); delete fSensor; fSensor = NULL; } i = sensors.FindFirst(',', i+1); if (i > - 1) i++; } return ENOENT; } CamSensor * CamDevice::CreateSensor(const char *name) { int i; for (i = 0; kSensorTable[i].name; i++) { if (!strcmp(kSensorTable[i].name, name)) return kSensorTable[i].instfunc(this); } PRINT((CH ": sensor '%s' not found" CT, name)); return NULL; } void CamDevice::SetDataInput(BDataIO *input) { fDataInput = input; } status_t CamDevice::DataPumpThread() { if (SupportsBulk()) { PRINT((CH ": using Bulk" CT)); while (fTransferEnabled) { ssize_t len = -1; BAutolock lock(fLocker); if (!lock.IsLocked()) break; if (!fBulkIn) break; #ifndef DEBUG_DISCARD_INPUT len = fBulkIn->BulkTransfer(fBuffer, fBufferLen); #endif //PRINT((CH ": got %d bytes" CT, len)); #ifdef DEBUG_WRITE_DUMP write(fDumpFD, fBuffer, len); #endif #ifdef DEBUG_READ_DUMP if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen) lseek(fDumpFD, 0LL, SEEK_SET); #endif if (len <= 0) { PRINT((CH ": BulkIn: %s" CT, strerror(len))); break; } #ifndef DEBUG_DISCARD_DATA if (fDataInput) { fDataInput->Write(fBuffer, len); // else drop } #endif //snooze(2000); } } #ifdef SUPPORT_ISO else if (SupportsIsochronous()) { int numPacketDescriptors = 20; usb_iso_packet_descriptor packetDescriptors[numPacketDescriptors]; while (fTransferEnabled) { ssize_t len = -1; BAutolock lock(fLocker); if (!lock.IsLocked()) break; if (!fIsoIn) break; #ifndef DEBUG_DISCARD_INPUT len = fIsoIn->IsochronousTransfer(fBuffer, fBufferLen, packetDescriptors, numPacketDescriptors); #endif //PRINT((CH ": got %d bytes" CT, len)); #ifdef DEBUG_WRITE_DUMP write(fDumpFD, fBuffer, len); #endif #ifdef DEBUG_READ_DUMP if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen) lseek(fDumpFD, 0LL, SEEK_SET); #endif if (len <= 0) { PRINT((CH ": BulkIn: %s" CT, strerror(len))); break; } #ifndef DEBUG_DISCARD_DATA if (fDataInput) { fDataInput->Write(fBuffer, len); // else drop } #endif //snooze(2000); } } #endif else { PRINT((CH ": No supported transport." CT)); return B_UNSUPPORTED; } return B_OK; } int32 CamDevice::_DataPumpThread(void *_this) { CamDevice *dev = (CamDevice *)_this; return dev->DataPumpThread(); } void CamDevice::DumpRegs() { } status_t CamDevice::SendCommand(uint8 dir, uint8 request, uint16 value, uint16 index, uint16 length, void* data) { size_t ret; if (!GetDevice()) return ENODEV; if (length > GetDevice()->MaxEndpoint0PacketSize()) return EINVAL; ret = GetDevice()->ControlTransfer( USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir, request, value, index, length, data); return ret; } CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn* webcam) : fWebCamAddOn(webcam), fSupportedDevices(NULL) { } CamDeviceAddon::~CamDeviceAddon() { } const char * CamDeviceAddon::BrandName() { return ""; } status_t CamDeviceAddon::Sniff(BUSBDevice *device) { PRINT((CH ": Sniffing for %s" CT, BrandName())); if (!fSupportedDevices) return ENODEV; if (!device) return EINVAL; for (uint32 i = 0; fSupportedDevices[i].vendor; i++) { /* PRINT((CH "{%u,%u,%u,0x%x,0x%x} <> {%u,%u,%u,0x%x,0x%x}" CT, device.Class(), device.Subclass(), device.Protocol(), device.VendorID(), device.ProductID(), fSupportedDevices[i].desc.dev_class, fSupportedDevices[i].desc.dev_subclass, fSupportedDevices[i].desc.dev_protocol, fSupportedDevices[i].desc.vendor, fSupportedDevices[i].desc.product));*/ /* if (device.Class() != fSupportedDevices[i].desc.dev_class) continue; if (device.Subclass() != fSupportedDevices[i].desc.dev_subclass) continue; if (device.Protocol() != fSupportedDevices[i].desc.dev_protocol) continue;*/ if (device->VendorID() != fSupportedDevices[i].desc.vendor) continue; if (device->ProductID() != fSupportedDevices[i].desc.product) continue; return i; } return ENODEV; } CamDevice * CamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) { return NULL; } void CamDeviceAddon::SetSupportedDevices(const usb_webcam_support_descriptor *devs) { fSupportedDevices = devs; }