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
11const 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
19QuickCamDevice::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
38QuickCamDevice::~QuickCamDevice()
39{
40
41}
42
43
44bool
45QuickCamDevice::SupportsBulk()
46{
47	return true;
48}
49
50
51bool
52QuickCamDevice::SupportsIsochronous()
53{
54	return true;
55}
56
57
58status_t
59QuickCamDevice::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
67DumpRegs();
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
81status_t
82QuickCamDevice::StopTransfer()
83{
84	status_t err;
85
86DumpRegs();
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
103ssize_t
104QuickCamDevice::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
111ssize_t
112QuickCamDevice::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
121status_t
122QuickCamDevice::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
134status_t
135QuickCamDevice::WaitReadyIIC()
136{
137	// TODO: WRITEME
138	return EBUSY;
139}
140
141
142ssize_t
143QuickCamDevice::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
161ssize_t
162QuickCamDevice::ReadIIC(uint8 address, uint8 *data)
163{
164	return ReadIIC(address, data);
165}
166
167
168ssize_t
169QuickCamDevice::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
195ssize_t
196QuickCamDevice::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
225status_t
226QuickCamDevice::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
242status_t
243QuickCamDevice::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
258QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam)
259	: CamDeviceAddon(webcam)
260{
261	SetSupportedDevices(kSupportedDevices);
262}
263
264
265QuickCamDeviceAddon::~QuickCamDeviceAddon()
266{
267}
268
269
270const char *
271QuickCamDeviceAddon::BrandName()
272{
273	return "QuickCam";
274}
275
276
277QuickCamDevice *
278QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
279{
280	return new QuickCamDevice(*this, from);
281}
282
283
284extern "C" status_t
285B_WEBCAM_MKINTFUNC(quickcam)
286(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
287{
288	*addon = new QuickCamDeviceAddon(webcam);
289	return B_OK;
290}
291