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