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
11 const 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
QuickCamDevice(CamDeviceAddon & _addon,BUSBDevice * _device)19 QuickCamDevice::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
~QuickCamDevice()38 QuickCamDevice::~QuickCamDevice()
39 {
40
41 }
42
43
44 bool
SupportsBulk()45 QuickCamDevice::SupportsBulk()
46 {
47 return true;
48 }
49
50
51 bool
SupportsIsochronous()52 QuickCamDevice::SupportsIsochronous()
53 {
54 return true;
55 }
56
57
58 status_t
StartTransfer()59 QuickCamDevice::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
67 DumpRegs();
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
81 status_t
StopTransfer()82 QuickCamDevice::StopTransfer()
83 {
84 status_t err;
85
86 DumpRegs();
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
103 ssize_t
WriteReg(uint16 address,uint8 * data,size_t count)104 QuickCamDevice::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
111 ssize_t
ReadReg(uint16 address,uint8 * data,size_t count,bool cached)112 QuickCamDevice::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
121 status_t
GetStatusIIC()122 QuickCamDevice::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
134 status_t
WaitReadyIIC()135 QuickCamDevice::WaitReadyIIC()
136 {
137 // TODO: WRITEME
138 return EBUSY;
139 }
140
141
142 ssize_t
WriteIIC(uint8 address,uint8 * data,size_t count)143 QuickCamDevice::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
161 ssize_t
ReadIIC(uint8 address,uint8 * data)162 QuickCamDevice::ReadIIC(uint8 address, uint8 *data)
163 {
164 return ReadIIC(address, data);
165 }
166
167
168 ssize_t
ReadIIC8(uint8 address,uint8 * data)169 QuickCamDevice::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
195 ssize_t
ReadIIC16(uint8 address,uint16 * data)196 QuickCamDevice::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
225 status_t
SetIICBitsMode(size_t bits)226 QuickCamDevice::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
242 status_t
SendCommand(uint8 dir,uint8 request,uint16 value,uint16 index,uint16 length,void * data)243 QuickCamDevice::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
QuickCamDeviceAddon(WebCamMediaAddOn * webcam)258 QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam)
259 : CamDeviceAddon(webcam)
260 {
261 SetSupportedDevices(kSupportedDevices);
262 }
263
264
~QuickCamDeviceAddon()265 QuickCamDeviceAddon::~QuickCamDeviceAddon()
266 {
267 }
268
269
270 const char *
BrandName()271 QuickCamDeviceAddon::BrandName()
272 {
273 return "QuickCam";
274 }
275
276
277 QuickCamDevice *
Instantiate(CamRoster & roster,BUSBDevice * from)278 QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
279 {
280 return new QuickCamDevice(*this, from);
281 }
282
283
284 extern "C" status_t
B_WEBCAM_MKINTFUNC(quickcam)285 B_WEBCAM_MKINTFUNC(quickcam)
286 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
287 {
288 *addon = new QuickCamDeviceAddon(webcam);
289 return B_OK;
290 }
291