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