xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
1 #include "QuickCamDevice.h"
2 #include "CamDebug.h"
3 #include "CamSensor.h"
4 
5 
6 const usb_webcam_support_descriptor kSupportedDevices[] = {
7 {{ 0, 0, 0, 0x046d, 0x0840 }, "Logitech", "QuickCam Express", NULL },
8 {{ 0, 0, 0, 0x046d, 0x0850 }, "Logitech", "QuickCam Express LEGO", NULL },
9 {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
10 };
11 
12 
13 
14 QuickCamDevice::QuickCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
15           :CamDevice(_addon, _device)
16 {
17 	status_t err;
18 
19 	// linux seems to infer this sets I2C controller to 8 or 16 bit mode...
20 	// sensors will set to the mode they want when probing
21 	SetIICBitsMode(8);
22 	err = ProbeSensor();
23 	if (err < B_OK) {
24 		// reset I2C mode to 8 bit as linux driver does
25 		SetIICBitsMode(8);
26 		// not much we can do anyway
27 	}
28 
29 	fInitStatus = B_OK;
30 }
31 
32 
33 QuickCamDevice::~QuickCamDevice()
34 {
35 
36 }
37 
38 
39 bool
40 QuickCamDevice::SupportsBulk()
41 {
42 	return true;
43 }
44 
45 
46 bool
47 QuickCamDevice::SupportsIsochronous()
48 {
49 	return true;
50 }
51 
52 
53 status_t
54 QuickCamDevice::StartTransfer()
55 {
56 	status_t err;
57 	uint8 r;
58 
59 	SetScale(1);
60 	if (Sensor())
61 		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
62 
63 	//SetVideoFrame(BRect(0, 0, 320-1, 240-1));
64 
65 DumpRegs();
66 #if 0
67 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
68 	if (err < 0)
69 		return err;
70 	r |= 0x04;
71 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
72 	if (err < 0)
73 		return err;
74 #endif
75 	return CamDevice::StartTransfer();
76 }
77 
78 
79 status_t
80 QuickCamDevice::StopTransfer()
81 {
82 	status_t err;
83 	uint8 r;
84 
85 DumpRegs();
86 	err = CamDevice::StopTransfer();
87 #if 0
88 //	if (err < 0)
89 //		return err;
90 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
91 	if (err < 0)
92 		return err;
93 	r &= ~0x04;
94 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
95 	if (err < 0)
96 		return err;
97 #endif
98 	return err;
99 }
100 
101 
102 ssize_t
103 QuickCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
104 {
105 	PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
106 	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, address, 0, count, data);
107 }
108 
109 
110 ssize_t
111 QuickCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
112 {
113 	PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
114 	memset(data, 0xaa, count); // linux drivers do that without explaining why !?
115 	return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data);
116 }
117 
118 
119 status_t
120 QuickCamDevice::GetStatusIIC()
121 {
122 	status_t err;
123 	uint8 status = 0;
124 #warning WRITEME
125 	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
126 	if (err < 0)
127 		return err;
128 	return (status&0x08)?EIO:0;
129 }
130 
131 
132 status_t
133 QuickCamDevice::WaitReadyIIC()
134 {
135 	status_t err;
136 #warning WRITEME
137 	return EBUSY;
138 }
139 
140 
141 ssize_t
142 QuickCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
143 {
144 	status_t err;
145 	int 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 
161 ssize_t
162 QuickCamDevice::ReadIIC(uint8 address, uint8 *data)
163 {
164 	return ReadIIC(address, data);
165 }
166 
167 
168 ssize_t
169 QuickCamDevice::ReadIIC8(uint8 address, uint8 *data)
170 {
171 	status_t err;
172 	int i;
173 	uint8 buffer[0x23];
174 	memset(buffer, 0, sizeof(buffer));
175 	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
176 	buffer[0x21] = 1 - 1;
177 	buffer[0x22] = 0x03;
178 	buffer[0] = address;
179 	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
180 	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
181 	if (err < B_OK)
182 		return err;
183 
184 	buffer[0] = 0xaa;
185 	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
186 	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
187 	if (err < B_OK)
188 		return err;
189 
190 	*data = buffer[0];
191 	PRINT((CH ": 0x%02x" CT, *data));
192 	return 1;
193 }
194 
195 
196 ssize_t
197 QuickCamDevice::ReadIIC16(uint8 address, uint16 *data)
198 {
199 	status_t err;
200 	int i;
201 	uint8 buffer[0x23];
202 	memset(buffer, 0, sizeof(buffer));
203 	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
204 	buffer[0x21] = 1 - 1;
205 	buffer[0x22] = 0x03;
206 	buffer[0] = address;
207 	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
208 	if (err < B_OK)
209 		return err;
210 
211 	buffer[0] = 0xaa;
212 	buffer[1] = 0xaa;
213 	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
214 	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
215 	if (err < B_OK)
216 		return err;
217 
218 	if (fChipIsBigEndian)
219 		*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
220 	else
221 		*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
222 	PRINT((CH ": 0x%04x" CT, *data));
223 	return 2;
224 }
225 
226 
227 status_t
228 QuickCamDevice::SetIICBitsMode(size_t bits)
229 {
230 	switch (bits) {
231 		case 8:
232 			WriteReg8(STV_REG23, 0);
233 			break;
234 		case 16:
235 			WriteReg8(STV_REG23, 1);
236 			break;
237 		default:
238 			return EINVAL;
239 	}
240 	return B_OK;
241 }
242 
243 
244 status_t
245 QuickCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
246 							uint16 index, uint16 length, void* data)
247 {
248 	size_t ret;
249 	if (!GetDevice())
250 		return ENODEV;
251 	if (length > GetDevice()->MaxEndpoint0PacketSize())
252 		return EINVAL;
253 	ret = GetDevice()->ControlTransfer(
254 				USB_REQTYPE_VENDOR | dir,
255 				request, value, index, length, data);
256 	return ret;
257 }
258 
259 
260 QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam)
261 	: CamDeviceAddon(webcam)
262 {
263 	SetSupportedDevices(kSupportedDevices);
264 }
265 
266 
267 QuickCamDeviceAddon::~QuickCamDeviceAddon()
268 {
269 }
270 
271 
272 const char *
273 QuickCamDeviceAddon::BrandName()
274 {
275 	return "QuickCam";
276 }
277 
278 
279 QuickCamDevice *
280 QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
281 {
282 	return new QuickCamDevice(*this, from);
283 }
284 
285 
286 extern "C" status_t
287 B_WEBCAM_MKINTFUNC(quickcam)
288 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
289 {
290 	*addon = new QuickCamDeviceAddon(webcam);
291 	return B_OK;
292 }
293