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, %u)" 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, %u, %d)" CT, address, data, count, cached));
115	memset(data, 0xaa, count); // linux drivers do that without explaining why !?
116	return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data);
117}
118
119
120status_t
121QuickCamDevice::GetStatusIIC()
122{
123	status_t err = B_ERROR;
124	uint8 status = 0;
125#warning WRITEME
126	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
127	if (err < 0)
128		return err;
129	return (status&0x08)?EIO:0;
130}
131
132
133status_t
134QuickCamDevice::WaitReadyIIC()
135{
136#warning WRITEME
137	return EBUSY;
138}
139
140
141ssize_t
142QuickCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
143{
144	int i;
145	uint8 buffer[0x23];
146	if (count > 16)
147		return EINVAL;
148	memset(buffer, 0, sizeof(buffer));
149	buffer[0x20] = Sensor() ? Sensor()->IICWriteAddress() : 0;
150	buffer[0x21] = count - 1;
151	buffer[0x22] = 0x01;
152	for (i = 0; i < count; i++) {
153		buffer[i] = address + i;
154		buffer[i+16] = data[i];
155	}
156	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
157}
158
159
160ssize_t
161QuickCamDevice::ReadIIC(uint8 address, uint8 *data)
162{
163	return ReadIIC(address, data);
164}
165
166
167ssize_t
168QuickCamDevice::ReadIIC8(uint8 address, uint8 *data)
169{
170	status_t err;
171	uint8 buffer[0x23];
172	memset(buffer, 0, sizeof(buffer));
173	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
174	buffer[0x21] = 1 - 1;
175	buffer[0x22] = 0x03;
176	buffer[0] = address;
177	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
178	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
179	if (err < B_OK)
180		return err;
181
182	buffer[0] = 0xaa;
183	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
184	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
185	if (err < B_OK)
186		return err;
187
188	*data = buffer[0];
189	PRINT((CH ": 0x%02x" CT, *data));
190	return 1;
191}
192
193
194ssize_t
195QuickCamDevice::ReadIIC16(uint8 address, uint16 *data)
196{
197	status_t err;
198	uint8 buffer[0x23];
199	memset(buffer, 0, sizeof(buffer));
200	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
201	buffer[0x21] = 1 - 1;
202	buffer[0x22] = 0x03;
203	buffer[0] = address;
204	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
205	if (err < B_OK)
206		return err;
207
208	buffer[0] = 0xaa;
209	buffer[1] = 0xaa;
210	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
211	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
212	if (err < B_OK)
213		return err;
214
215	if (fChipIsBigEndian)
216		*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
217	else
218		*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
219	PRINT((CH ": 0x%04x" CT, *data));
220	return 2;
221}
222
223
224status_t
225QuickCamDevice::SetIICBitsMode(size_t bits)
226{
227	switch (bits) {
228		case 8:
229			WriteReg8(STV_REG23, 0);
230			break;
231		case 16:
232			WriteReg8(STV_REG23, 1);
233			break;
234		default:
235			return EINVAL;
236	}
237	return B_OK;
238}
239
240
241status_t
242QuickCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
243							uint16 index, uint16 length, void* data)
244{
245	size_t ret;
246	if (!GetDevice())
247		return ENODEV;
248	if (length > GetDevice()->MaxEndpoint0PacketSize())
249		return EINVAL;
250	ret = GetDevice()->ControlTransfer(
251				USB_REQTYPE_VENDOR | dir,
252				request, value, index, length, data);
253	return ret;
254}
255
256
257QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam)
258	: CamDeviceAddon(webcam)
259{
260	SetSupportedDevices(kSupportedDevices);
261}
262
263
264QuickCamDeviceAddon::~QuickCamDeviceAddon()
265{
266}
267
268
269const char *
270QuickCamDeviceAddon::BrandName()
271{
272	return "QuickCam";
273}
274
275
276QuickCamDevice *
277QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
278{
279	return new QuickCamDevice(*this, from);
280}
281
282
283extern "C" status_t
284B_WEBCAM_MKINTFUNC(quickcam)
285(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
286{
287	*addon = new QuickCamDeviceAddon(webcam);
288	return B_OK;
289}
290