xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 
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 
38 QuickCamDevice::~QuickCamDevice()
39 {
40 
41 }
42 
43 
44 bool
45 QuickCamDevice::SupportsBulk()
46 {
47 	return true;
48 }
49 
50 
51 bool
52 QuickCamDevice::SupportsIsochronous()
53 {
54 	return true;
55 }
56 
57 
58 status_t
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
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
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
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
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
135 QuickCamDevice::WaitReadyIIC()
136 {
137 	// TODO: WRITEME
138 	return EBUSY;
139 }
140 
141 
142 ssize_t
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
162 QuickCamDevice::ReadIIC(uint8 address, uint8 *data)
163 {
164 	return ReadIIC(address, data);
165 }
166 
167 
168 ssize_t
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
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
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
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 
258 QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam)
259 	: CamDeviceAddon(webcam)
260 {
261 	SetSupportedDevices(kSupportedDevices);
262 }
263 
264 
265 QuickCamDeviceAddon::~QuickCamDeviceAddon()
266 {
267 }
268 
269 
270 const char *
271 QuickCamDeviceAddon::BrandName()
272 {
273 	return "QuickCam";
274 }
275 
276 
277 QuickCamDevice *
278 QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
279 {
280 	return new QuickCamDevice(*this, from);
281 }
282 
283 
284 extern "C" status_t
285 B_WEBCAM_MKINTFUNC(quickcam)
286 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
287 {
288 	*addon = new QuickCamDeviceAddon(webcam);
289 	return B_OK;
290 }
291