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// TODO: Complete implementation!
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	SetScale(1);
93	if (Sensor())
94		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
95
96	//SetVideoFrame(BRect(0, 0, 320-1, 240-1));
97
98DumpRegs();
99#if 0
100	status_t err;
101	uint8 r;
102
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	DumpRegs();
120	err = CamDevice::StopTransfer();
121#if 0
122	uint8 r;
123
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, %" B_PRIuSIZE ")" 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, %" 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
156status_t
157NW80xCamDevice::GetStatusIIC()
158{
159	status_t err = B_ERROR;
160	uint8 status = 0;
161	// TODO: 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
169status_t
170NW80xCamDevice::WaitReadyIIC()
171{
172	// TODO: WRITEME
173	return EBUSY;
174}
175
176
177ssize_t
178NW80xCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
179{
180	size_t i;
181	uint8 buffer[0x23];
182	if (count > 16)
183		return EINVAL;
184	memset(buffer, 0, sizeof(buffer));
185	buffer[0x20] = Sensor() ? Sensor()->IICWriteAddress() : 0;
186	buffer[0x21] = count - 1;
187	buffer[0x22] = 0x01;
188	for (i = 0; i < count; i++) {
189		buffer[i] = address + i;
190		buffer[i+16] = data[i];
191	}
192	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
193}
194
195
196ssize_t
197NW80xCamDevice::ReadIIC(uint8 address, uint8 *data)
198{
199	return ReadIIC(address, data);
200}
201
202
203ssize_t
204NW80xCamDevice::ReadIIC8(uint8 address, uint8 *data)
205{
206	status_t err;
207	uint8 buffer[0x23];
208	memset(buffer, 0, sizeof(buffer));
209	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
210	buffer[0x21] = 1 - 1;
211	buffer[0x22] = 0x03;
212	buffer[0] = address;
213	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
214	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
215	if (err < B_OK)
216		return err;
217
218	buffer[0] = 0xaa;
219	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
220	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
221	if (err < B_OK)
222		return err;
223
224	*data = buffer[0];
225	PRINT((CH ": 0x%02x" CT, *data));
226	return 1;
227}
228
229
230ssize_t
231NW80xCamDevice::ReadIIC16(uint8 address, uint16 *data)
232{
233	status_t err;
234	uint8 buffer[0x23];
235	memset(buffer, 0, sizeof(buffer));
236	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
237	buffer[0x21] = 1 - 1;
238	buffer[0x22] = 0x03;
239	buffer[0] = address;
240	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
241	if (err < B_OK)
242		return err;
243
244	buffer[0] = 0xaa;
245	buffer[1] = 0xaa;
246	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
247	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
248	if (err < B_OK)
249		return err;
250
251	if (fChipIsBigEndian)
252		*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
253	else
254		*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
255	PRINT((CH ": 0x%04x" CT, *data));
256	return 2;
257}
258
259
260status_t
261NW80xCamDevice::SetIICBitsMode(size_t bits)
262{
263	switch (bits) {
264		case 8:
265			WriteReg8(STV_REG23, 0);
266			break;
267		case 16:
268			WriteReg8(STV_REG23, 1);
269			break;
270		default:
271			return EINVAL;
272	}
273	return B_OK;
274}
275
276
277status_t
278NW80xCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
279							uint16 index, uint16 length, void* data)
280{
281	size_t ret;
282	if (!GetDevice())
283		return ENODEV;
284	if (length > GetDevice()->MaxEndpoint0PacketSize())
285		return EINVAL;
286	ret = GetDevice()->ControlTransfer(
287				USB_REQTYPE_VENDOR | dir,
288				request, value, index, length, data);
289	return ret;
290}
291
292
293NW80xCamDeviceAddon::NW80xCamDeviceAddon(WebCamMediaAddOn* webcam)
294	: CamDeviceAddon(webcam)
295{
296	SetSupportedDevices(kSupportedDevices);
297}
298
299
300NW80xCamDeviceAddon::~NW80xCamDeviceAddon()
301{
302}
303
304
305const char *
306NW80xCamDeviceAddon::BrandName()
307{
308	return "NW80x-based";
309}
310
311
312NW80xCamDevice *
313NW80xCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
314{
315	return new NW80xCamDevice(*this, from);
316}
317
318
319extern "C" status_t
320B_WEBCAM_MKINTFUNC(nw80xcam)
321(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
322{
323	*addon = new NW80xCamDeviceAddon(webcam);
324	return B_OK;
325}
326