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
19const 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
50NW80xCamDevice::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
69NW80xCamDevice::~NW80xCamDevice()
70{
71
72}
73
74
75bool
76NW80xCamDevice::SupportsBulk()
77{
78	return true;
79}
80
81
82bool
83NW80xCamDevice::SupportsIsochronous()
84{
85	return true;
86}
87
88
89status_t
90NW80xCamDevice::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
101DumpRegs();
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
115status_t
116NW80xCamDevice::StopTransfer()
117{
118	status_t err;
119	uint8 r;
120
121DumpRegs();
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
138ssize_t
139NW80xCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
140{
141	PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
142	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, address, 0, count, data);
143}
144
145
146ssize_t
147NW80xCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
148{
149	PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
150	memset(data, 0xaa, count); // linux drivers do that without explaining why !?
151	return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data);
152}
153
154
155status_t
156NW80xCamDevice::GetStatusIIC()
157{
158	status_t err = B_ERROR;
159	uint8 status = 0;
160#warning WRITEME
161	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
162	if (err < 0)
163		return err;
164	return (status&0x08)?EIO:0;
165}
166
167
168status_t
169NW80xCamDevice::WaitReadyIIC()
170{
171	status_t err;
172#warning WRITEME
173	return EBUSY;
174}
175
176
177ssize_t
178NW80xCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
179{
180	status_t err;
181	int i;
182	uint8 buffer[0x23];
183	if (count > 16)
184		return EINVAL;
185	memset(buffer, 0, sizeof(buffer));
186	buffer[0x20] = Sensor() ? Sensor()->IICWriteAddress() : 0;
187	buffer[0x21] = count - 1;
188	buffer[0x22] = 0x01;
189	for (i = 0; i < count; i++) {
190		buffer[i] = address + i;
191		buffer[i+16] = data[i];
192	}
193	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
194}
195
196
197ssize_t
198NW80xCamDevice::ReadIIC(uint8 address, uint8 *data)
199{
200	return ReadIIC(address, data);
201}
202
203
204ssize_t
205NW80xCamDevice::ReadIIC8(uint8 address, uint8 *data)
206{
207	status_t err;
208	int i;
209	uint8 buffer[0x23];
210	memset(buffer, 0, sizeof(buffer));
211	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
212	buffer[0x21] = 1 - 1;
213	buffer[0x22] = 0x03;
214	buffer[0] = address;
215	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
216	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
217	if (err < B_OK)
218		return err;
219
220	buffer[0] = 0xaa;
221	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
222	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
223	if (err < B_OK)
224		return err;
225
226	*data = buffer[0];
227	PRINT((CH ": 0x%02x" CT, *data));
228	return 1;
229}
230
231
232ssize_t
233NW80xCamDevice::ReadIIC16(uint8 address, uint16 *data)
234{
235	status_t err;
236	int i;
237	uint8 buffer[0x23];
238	memset(buffer, 0, sizeof(buffer));
239	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
240	buffer[0x21] = 1 - 1;
241	buffer[0x22] = 0x03;
242	buffer[0] = address;
243	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
244	if (err < B_OK)
245		return err;
246
247	buffer[0] = 0xaa;
248	buffer[1] = 0xaa;
249	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
250	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
251	if (err < B_OK)
252		return err;
253
254	if (fChipIsBigEndian)
255		*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
256	else
257		*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
258	PRINT((CH ": 0x%04x" CT, *data));
259	return 2;
260}
261
262
263status_t
264NW80xCamDevice::SetIICBitsMode(size_t bits)
265{
266	switch (bits) {
267		case 8:
268			WriteReg8(STV_REG23, 0);
269			break;
270		case 16:
271			WriteReg8(STV_REG23, 1);
272			break;
273		default:
274			return EINVAL;
275	}
276	return B_OK;
277}
278
279
280status_t
281NW80xCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
282							uint16 index, uint16 length, void* data)
283{
284	size_t ret;
285	if (!GetDevice())
286		return ENODEV;
287	if (length > GetDevice()->MaxEndpoint0PacketSize())
288		return EINVAL;
289	ret = GetDevice()->ControlTransfer(
290				USB_REQTYPE_VENDOR | dir,
291				request, value, index, length, data);
292	return ret;
293}
294
295
296NW80xCamDeviceAddon::NW80xCamDeviceAddon(WebCamMediaAddOn* webcam)
297	: CamDeviceAddon(webcam)
298{
299	SetSupportedDevices(kSupportedDevices);
300}
301
302
303NW80xCamDeviceAddon::~NW80xCamDeviceAddon()
304{
305}
306
307
308const char *
309NW80xCamDeviceAddon::BrandName()
310{
311	return "NW80x-based";
312}
313
314
315NW80xCamDevice *
316NW80xCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
317{
318	return new NW80xCamDevice(*this, from);
319}
320
321
322extern "C" status_t
323B_WEBCAM_MKINTFUNC(nw80xcam)
324(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
325{
326	*addon = new NW80xCamDeviceAddon(webcam);
327	return B_OK;
328}
329