1/* 2 * Copyright 2004-2008, Fran��ois Revol, <revol@free.fr>. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#include "QuickCamDevice.h" 7#include "CamDebug.h" 8#include "CamSensor.h" 9 10 11const usb_webcam_support_descriptor kSupportedDevices[] = { 12{{ 0, 0, 0, 0x046d, 0x0840 }, "Logitech", "QuickCam Express", NULL }, 13{{ 0, 0, 0, 0x046d, 0x0850 }, "Logitech", "QuickCam Express LEGO", NULL }, 14{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL } 15}; 16 17 18 19QuickCamDevice::QuickCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) 20 :CamDevice(_addon, _device) 21{ 22 status_t err; 23 24 // linux seems to infer this sets I2C controller to 8 or 16 bit mode... 25 // sensors will set to the mode they want when probing 26 SetIICBitsMode(8); 27 err = ProbeSensor(); 28 if (err < B_OK) { 29 // reset I2C mode to 8 bit as linux driver does 30 SetIICBitsMode(8); 31 // not much we can do anyway 32 } 33 34 fInitStatus = B_OK; 35} 36 37 38QuickCamDevice::~QuickCamDevice() 39{ 40 41} 42 43 44bool 45QuickCamDevice::SupportsBulk() 46{ 47 return true; 48} 49 50 51bool 52QuickCamDevice::SupportsIsochronous() 53{ 54 return true; 55} 56 57 58status_t 59QuickCamDevice::StartTransfer() 60{ 61 SetScale(1); 62 if (Sensor()) 63 SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1)); 64 65 //SetVideoFrame(BRect(0, 0, 320-1, 240-1)); 66 67DumpRegs(); 68#if 0 69 err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true); 70 if (err < 0) 71 return err; 72 r |= 0x04; 73 err = WriteReg8(SN9C102_CHIP_CTRL, r); 74 if (err < 0) 75 return err; 76#endif 77 return CamDevice::StartTransfer(); 78} 79 80 81status_t 82QuickCamDevice::StopTransfer() 83{ 84 status_t err; 85 86DumpRegs(); 87 err = CamDevice::StopTransfer(); 88#if 0 89// if (err < 0) 90// return err; 91 err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true); 92 if (err < 0) 93 return err; 94 r &= ~0x04; 95 err = WriteReg8(SN9C102_CHIP_CTRL, r); 96 if (err < 0) 97 return err; 98#endif 99 return err; 100} 101 102 103ssize_t 104QuickCamDevice::WriteReg(uint16 address, uint8 *data, size_t count) 105{ 106 PRINT((CH "(%u, @%p, %" B_PRIuSIZE ")" CT, address, data, count)); 107 return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, address, 0, count, data); 108} 109 110 111ssize_t 112QuickCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached) 113{ 114 PRINT((CH "(%u, @%p, %" B_PRIuSIZE ", %d)" CT, address, data, count, 115 cached)); 116 memset(data, 0xaa, count); // linux drivers do that without explaining why !? 117 return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data); 118} 119 120 121status_t 122QuickCamDevice::GetStatusIIC() 123{ 124 status_t err = B_ERROR; 125 uint8 status = 0; 126 // TODO: WRITEME 127 //dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status); 128 if (err < 0) 129 return err; 130 return (status&0x08)?EIO:0; 131} 132 133 134status_t 135QuickCamDevice::WaitReadyIIC() 136{ 137 // TODO: WRITEME 138 return EBUSY; 139} 140 141 142ssize_t 143QuickCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count) 144{ 145 size_t i; 146 uint8 buffer[0x23]; 147 if (count > 16) 148 return EINVAL; 149 memset(buffer, 0, sizeof(buffer)); 150 buffer[0x20] = Sensor() ? Sensor()->IICWriteAddress() : 0; 151 buffer[0x21] = count - 1; 152 buffer[0x22] = 0x01; 153 for (i = 0; i < count; i++) { 154 buffer[i] = address + i; 155 buffer[i+16] = data[i]; 156 } 157 return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer); 158} 159 160 161ssize_t 162QuickCamDevice::ReadIIC(uint8 address, uint8 *data) 163{ 164 return ReadIIC(address, data); 165} 166 167 168ssize_t 169QuickCamDevice::ReadIIC8(uint8 address, uint8 *data) 170{ 171 status_t err; 172 uint8 buffer[0x23]; 173 memset(buffer, 0, sizeof(buffer)); 174 buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0; 175 buffer[0x21] = 1 - 1; 176 buffer[0x22] = 0x03; 177 buffer[0] = address; 178 err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer); 179 PRINT((CH ": SendCommand: %s" CT, strerror(err))); 180 if (err < B_OK) 181 return err; 182 183 buffer[0] = 0xaa; 184 err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer); 185 PRINT((CH ": SendCommand: %s" CT, strerror(err))); 186 if (err < B_OK) 187 return err; 188 189 *data = buffer[0]; 190 PRINT((CH ": 0x%02x" CT, *data)); 191 return 1; 192} 193 194 195ssize_t 196QuickCamDevice::ReadIIC16(uint8 address, uint16 *data) 197{ 198 status_t err; 199 uint8 buffer[0x23]; 200 memset(buffer, 0, sizeof(buffer)); 201 buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0; 202 buffer[0x21] = 1 - 1; 203 buffer[0x22] = 0x03; 204 buffer[0] = address; 205 err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer); 206 if (err < B_OK) 207 return err; 208 209 buffer[0] = 0xaa; 210 buffer[1] = 0xaa; 211 err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer); 212 PRINT((CH ": SendCommand: %s" CT, strerror(err))); 213 if (err < B_OK) 214 return err; 215 216 if (fChipIsBigEndian) 217 *data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0])); 218 else 219 *data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0])); 220 PRINT((CH ": 0x%04x" CT, *data)); 221 return 2; 222} 223 224 225status_t 226QuickCamDevice::SetIICBitsMode(size_t bits) 227{ 228 switch (bits) { 229 case 8: 230 WriteReg8(STV_REG23, 0); 231 break; 232 case 16: 233 WriteReg8(STV_REG23, 1); 234 break; 235 default: 236 return EINVAL; 237 } 238 return B_OK; 239} 240 241 242status_t 243QuickCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value, 244 uint16 index, uint16 length, void* data) 245{ 246 size_t ret; 247 if (!GetDevice()) 248 return ENODEV; 249 if (length > GetDevice()->MaxEndpoint0PacketSize()) 250 return EINVAL; 251 ret = GetDevice()->ControlTransfer( 252 USB_REQTYPE_VENDOR | dir, 253 request, value, index, length, data); 254 return ret; 255} 256 257 258QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam) 259 : CamDeviceAddon(webcam) 260{ 261 SetSupportedDevices(kSupportedDevices); 262} 263 264 265QuickCamDeviceAddon::~QuickCamDeviceAddon() 266{ 267} 268 269 270const char * 271QuickCamDeviceAddon::BrandName() 272{ 273 return "QuickCam"; 274} 275 276 277QuickCamDevice * 278QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) 279{ 280 return new QuickCamDevice(*this, from); 281} 282 283 284extern "C" status_t 285B_WEBCAM_MKINTFUNC(quickcam) 286(WebCamMediaAddOn* webcam, CamDeviceAddon **addon) 287{ 288 *addon = new QuickCamDeviceAddon(webcam); 289 return B_OK; 290} 291