xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/NW80xCamDevice.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
1 /*
2  * Copyright 2004-2008, François Revol, <revol@free.fr>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "NW80xCamDevice.h"
7 #include "CamDebug.h"
8 #include "CamSensor.h"
9 
10 // reference drivers:
11 // http://nw802.cvs.sourceforge.net
12 // http://nw802.cvs.sourceforge.net/nw802/nw802-2.4/
13 // http://www.medias.ne.jp/~takam/bsd/NetBSD.html#nw802
14 // https://dev.openwrt.org/attachment/ticket/2319/nw802-patch.txt
15 // win binary driver template, readme has interesting info:
16 // http://www.bulgar-bg.com/Downloads/drivers/PCAMDriver/
17 // http://www.bulgar-bg.com/Downloads/drivers/PCAMDriver/Readme.txt
18 
19 const usb_webcam_support_descriptor kSupportedDevices[] = {
20 {{ 0, 0, 0, 0x046d, 0xd001 }, "Logitech", "QuickCam Pro", "??" }, // Alan's
21 // other IDs according to nw802 linux driver:
22 {{ 0, 0, 0, 0x052b, 0xd001 }, "Ezonics", "EZCam Pro", "??" },
23 {{ 0, 0, 0, 0x055f, 0xd001 }, "Mustek"/*"PCLine"*/, "WCam 300"/*"PCL-W300"*/, "??" },
24 {{ 0, 0, 0, 0x06a5, 0xd001 }, "Divio", "NW802", "??" },
25 {{ 0, 0, 0, 0x06a5, 0x0000 }, "Divio", "NW800", "??" },
26 {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
27 };
28 
29 
30 #warning TODO!
31 
32 // datasheets: (scarce)
33 // http://www.digchip.com/datasheets/parts/datasheet/132/NW800.php
34 // http://www.digchip.com/datasheets/parts/datasheet/132/NW802.php
35 // http://web.archive.org/web/*/divio.com/*
36 // http://web.archive.org/web/20020217173519/divio.com/NW802.html
37 //
38 // supported sensors:
39 // Sensor        Model # Data Width Voltage Timing
40 // Conexant     CN0352     10 bits   3.3 V  Master
41 // Elecvision   EVS110K     8 bits   3.3 V  Slave
42 // HP (Agilent) HDC1000    10 bits   3.3 V  Master
43 // Hyundai      HB7121B     8 bits   3.3 V  Master
44 // Pixart       PAS006AC    9 bits   3.3 V  Master
45 // TASC         TAS5110A    9 bits   3.8 V  Slave
46 //
47 // http://www.wifi.com.ar/english/doc/webcam/ov511cameras.html says:
48 // 06a5 (Divio)  	d800   Etoms ET31X110 (A.K.A Divio NW800)
49 
50 NW80xCamDevice::NW80xCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
51           :CamDevice(_addon, _device)
52 {
53 	status_t err;
54 
55 	// linux seems to infer this sets I2C controller to 8 or 16 bit mode...
56 	// sensors will set to the mode they want when probing
57 	SetIICBitsMode(8);
58 	err = ProbeSensor();
59 	if (err < B_OK) {
60 		// reset I2C mode to 8 bit as linux driver does
61 		SetIICBitsMode(8);
62 		// not much we can do anyway
63 	}
64 
65 	fInitStatus = B_OK;
66 }
67 
68 
69 NW80xCamDevice::~NW80xCamDevice()
70 {
71 
72 }
73 
74 
75 bool
76 NW80xCamDevice::SupportsBulk()
77 {
78 	return true;
79 }
80 
81 
82 bool
83 NW80xCamDevice::SupportsIsochronous()
84 {
85 	return true;
86 }
87 
88 
89 status_t
90 NW80xCamDevice::StartTransfer()
91 {
92 	status_t err;
93 	uint8 r;
94 
95 	SetScale(1);
96 	if (Sensor())
97 		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
98 
99 	//SetVideoFrame(BRect(0, 0, 320-1, 240-1));
100 
101 DumpRegs();
102 #if 0
103 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
104 	if (err < 0)
105 		return err;
106 	r |= 0x04;
107 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
108 	if (err < 0)
109 		return err;
110 #endif
111 	return CamDevice::StartTransfer();
112 }
113 
114 
115 status_t
116 NW80xCamDevice::StopTransfer()
117 {
118 	status_t err;
119 	uint8 r;
120 
121 DumpRegs();
122 	err = CamDevice::StopTransfer();
123 #if 0
124 //	if (err < 0)
125 //		return err;
126 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
127 	if (err < 0)
128 		return err;
129 	r &= ~0x04;
130 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
131 	if (err < 0)
132 		return err;
133 #endif
134 	return err;
135 }
136 
137 
138 ssize_t
139 NW80xCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
140 {
141 	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ")" CT, address, data, count));
142 	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, address, 0, count, data);
143 }
144 
145 
146 ssize_t
147 NW80xCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
148 {
149 	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ", %d)" CT, address, data, count,
150 		cached));
151 	memset(data, 0xaa, count); // linux drivers do that without explaining why !?
152 	return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data);
153 }
154 
155 
156 status_t
157 NW80xCamDevice::GetStatusIIC()
158 {
159 	status_t err = B_ERROR;
160 	uint8 status = 0;
161 #warning WRITEME
162 	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
163 	if (err < 0)
164 		return err;
165 	return (status&0x08)?EIO:0;
166 }
167 
168 
169 status_t
170 NW80xCamDevice::WaitReadyIIC()
171 {
172 	status_t err;
173 #warning WRITEME
174 	return EBUSY;
175 }
176 
177 
178 ssize_t
179 NW80xCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
180 {
181 	status_t err;
182 	int i;
183 	uint8 buffer[0x23];
184 	if (count > 16)
185 		return EINVAL;
186 	memset(buffer, 0, sizeof(buffer));
187 	buffer[0x20] = Sensor() ? Sensor()->IICWriteAddress() : 0;
188 	buffer[0x21] = count - 1;
189 	buffer[0x22] = 0x01;
190 	for (i = 0; i < count; i++) {
191 		buffer[i] = address + i;
192 		buffer[i+16] = data[i];
193 	}
194 	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
195 }
196 
197 
198 ssize_t
199 NW80xCamDevice::ReadIIC(uint8 address, uint8 *data)
200 {
201 	return ReadIIC(address, data);
202 }
203 
204 
205 ssize_t
206 NW80xCamDevice::ReadIIC8(uint8 address, uint8 *data)
207 {
208 	status_t err;
209 	int i;
210 	uint8 buffer[0x23];
211 	memset(buffer, 0, sizeof(buffer));
212 	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
213 	buffer[0x21] = 1 - 1;
214 	buffer[0x22] = 0x03;
215 	buffer[0] = address;
216 	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
217 	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
218 	if (err < B_OK)
219 		return err;
220 
221 	buffer[0] = 0xaa;
222 	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
223 	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
224 	if (err < B_OK)
225 		return err;
226 
227 	*data = buffer[0];
228 	PRINT((CH ": 0x%02x" CT, *data));
229 	return 1;
230 }
231 
232 
233 ssize_t
234 NW80xCamDevice::ReadIIC16(uint8 address, uint16 *data)
235 {
236 	status_t err;
237 	int i;
238 	uint8 buffer[0x23];
239 	memset(buffer, 0, sizeof(buffer));
240 	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
241 	buffer[0x21] = 1 - 1;
242 	buffer[0x22] = 0x03;
243 	buffer[0] = address;
244 	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
245 	if (err < B_OK)
246 		return err;
247 
248 	buffer[0] = 0xaa;
249 	buffer[1] = 0xaa;
250 	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
251 	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
252 	if (err < B_OK)
253 		return err;
254 
255 	if (fChipIsBigEndian)
256 		*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
257 	else
258 		*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
259 	PRINT((CH ": 0x%04x" CT, *data));
260 	return 2;
261 }
262 
263 
264 status_t
265 NW80xCamDevice::SetIICBitsMode(size_t bits)
266 {
267 	switch (bits) {
268 		case 8:
269 			WriteReg8(STV_REG23, 0);
270 			break;
271 		case 16:
272 			WriteReg8(STV_REG23, 1);
273 			break;
274 		default:
275 			return EINVAL;
276 	}
277 	return B_OK;
278 }
279 
280 
281 status_t
282 NW80xCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
283 							uint16 index, uint16 length, void* data)
284 {
285 	size_t ret;
286 	if (!GetDevice())
287 		return ENODEV;
288 	if (length > GetDevice()->MaxEndpoint0PacketSize())
289 		return EINVAL;
290 	ret = GetDevice()->ControlTransfer(
291 				USB_REQTYPE_VENDOR | dir,
292 				request, value, index, length, data);
293 	return ret;
294 }
295 
296 
297 NW80xCamDeviceAddon::NW80xCamDeviceAddon(WebCamMediaAddOn* webcam)
298 	: CamDeviceAddon(webcam)
299 {
300 	SetSupportedDevices(kSupportedDevices);
301 }
302 
303 
304 NW80xCamDeviceAddon::~NW80xCamDeviceAddon()
305 {
306 }
307 
308 
309 const char *
310 NW80xCamDeviceAddon::BrandName()
311 {
312 	return "NW80x-based";
313 }
314 
315 
316 NW80xCamDevice *
317 NW80xCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
318 {
319 	return new NW80xCamDevice(*this, from);
320 }
321 
322 
323 extern "C" status_t
324 B_WEBCAM_MKINTFUNC(nw80xcam)
325 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
326 {
327 	*addon = new NW80xCamDeviceAddon(webcam);
328 	return B_OK;
329 }
330