xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp (revision 71452e98334eaac603bf542d159e24788a46bebb)
1 /*
2  * Copyright 2004-2008, François Revol, <revol@free.fr>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "SonixCamDevice.h"
7 #include "CamDebug.h"
8 #include "CamSensor.h"
9 #include "CamBufferingDeframer.h"
10 #include "CamStreamingDeframer.h"
11 
12 #include <ParameterWeb.h>
13 #include <interface/Bitmap.h>
14 #include <media/Buffer.h>
15 
16 const usb_webcam_support_descriptor kSupportedDevices[] = {
17 {{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix", "tas5110c1b" }, // mine
18 {{ 0, 0, 0, 0x0c45, 0x6007 }, "Sonix", "macally ICECAM", "tas5110c1b" }, // Rajah's cam - SN9C101R
19 {{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120", NULL },
20 {{ 0, 0, 0, 0x0c45, 0x600d }, "Trust", "spacec@m 120", NULL },
21 
22 /* other devices that should be supported,
23  * cf. sn9c102-1.15 linux driver, sn9c102_sensor.h
24  * for IDs and sensors
25  */
26 {{ 0, 0, 0, 0x0c45, 0x6001 }, "Sonix", "Sonix generic", "tas5110c1b" },
27 {{ 0, 0, 0, 0x0c45, 0x6024 }, "Sonix", "Sonix generic", NULL },
28 {{ 0, 0, 0, 0x0c45, 0x6025 }, "Sonix", "Sonix generic", "tas5110c1b,XXX" },
29 {{ 0, 0, 0, 0x0c45, 0x6028 }, "Sonix", "Sonix generic", NULL },
30 {{ 0, 0, 0, 0x0c45, 0x6029 }, "Sonix", "Sonix generic", NULL },
31 {{ 0, 0, 0, 0x0c45, 0x602a }, "Sonix", "Sonix generic", NULL },
32 {{ 0, 0, 0, 0x0c45, 0x602b }, "Sonix", "Sonix generic", NULL },
33 {{ 0, 0, 0, 0x0c45, 0x602c }, "Sonix", "Sonix generic", NULL },
34 {{ 0, 0, 0, 0x0c45, 0x6030 }, "Sonix", "Sonix generic", NULL },
35 {{ 0, 0, 0, 0x0c45, 0x6080 }, "Sonix", "Sonix generic", NULL },
36 {{ 0, 0, 0, 0x0c45, 0x6082 }, "Sonix", "Sonix generic", NULL },
37 {{ 0, 0, 0, 0x0c45, 0x6083 }, "Sonix", "Sonix generic", NULL },
38 {{ 0, 0, 0, 0x0c45, 0x6088 }, "Sonix", "Sonix generic", NULL },
39 {{ 0, 0, 0, 0x0c45, 0x608a }, "Sonix", "Sonix generic", NULL },
40 {{ 0, 0, 0, 0x0c45, 0x608b }, "Sonix", "Sonix generic", NULL },
41 {{ 0, 0, 0, 0x0c45, 0x608c }, "Sonix", "Sonix generic", NULL },
42 {{ 0, 0, 0, 0x0c45, 0x608e }, "Sonix", "Sonix generic", NULL },
43 {{ 0, 0, 0, 0x0c45, 0x608f }, "Sonix", "Sonix generic", NULL },
44 {{ 0, 0, 0, 0x0c45, 0x60a0 }, "Sonix", "Sonix generic", NULL },
45 {{ 0, 0, 0, 0x0c45, 0x60a2 }, "Sonix", "Sonix generic", NULL },
46 {{ 0, 0, 0, 0x0c45, 0x60a3 }, "Sonix", "Sonix generic", NULL },
47 {{ 0, 0, 0, 0x0c45, 0x60a8 }, "Sonix", "Sonix generic", NULL },
48 {{ 0, 0, 0, 0x0c45, 0x60aa }, "Sonix", "Sonix generic", NULL },
49 {{ 0, 0, 0, 0x0c45, 0x60ab }, "Sonix", "Sonix generic", "tas5110c1b" },
50 {{ 0, 0, 0, 0x0c45, 0x60ac }, "Sonix", "Sonix generic", NULL },
51 {{ 0, 0, 0, 0x0c45, 0x60ae }, "Sonix", "Sonix generic", NULL },
52 {{ 0, 0, 0, 0x0c45, 0x60af }, "Sonix", "Sonix generic", NULL },
53 {{ 0, 0, 0, 0x0c45, 0x60b0 }, "Sonix", "Sonix generic", NULL },
54 {{ 0, 0, 0, 0x0c45, 0x60b2 }, "Sonix", "Sonix generic", NULL },
55 {{ 0, 0, 0, 0x0c45, 0x60b3 }, "Sonix", "Sonix generic", NULL },
56 {{ 0, 0, 0, 0x0c45, 0x60b8 }, "Sonix", "Sonix generic", NULL },
57 {{ 0, 0, 0, 0x0c45, 0x60ba }, "Sonix", "Sonix generic", NULL },
58 {{ 0, 0, 0, 0x0c45, 0x60bb }, "Sonix", "Sonix generic", NULL },
59 {{ 0, 0, 0, 0x0c45, 0x60bc }, "Sonix", "Sonix generic", NULL },
60 {{ 0, 0, 0, 0x0c45, 0x60be }, "Sonix", "Sonix generic", NULL },
61 {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
62 };
63 
64 // 12 bytes actually
65 static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 };
66 static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 };
67 static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 };
68 
69 static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 };
70 static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 };
71 static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 };
72 static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 };
73 static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 };
74 
75 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
76 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
77 
78 
79 SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
80           :CamDevice(_addon, _device)
81 {
82 	uchar data[8]; /* store bytes returned from sonix commands */
83 	status_t err;
84 	fFrameTagState = 0;
85 
86 	fRGain = fGGain = fBGain = 0;
87 	// unknown
88 	fBrightness = 0.5;
89 
90 	memset(fCachedRegs, 0, SN9C102_REG_COUNT);
91 	fChipVersion = 2;
92 	if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) {
93 		fChipVersion = 3; // says V4L2
94 	}
95 	err = ProbeSensor();
96 
97 //	fDeframer = new CamBufferingDeframer(this);
98 	fDeframer = new CamStreamingDeframer(this);
99 	fDeframer->RegisterSOFTags(sof_marks, 2, sizeof(sof_mark_1), 12);
100 	fDeframer->RegisterEOFTags(eof_marks, 4, sizeof(eof_mark_1), sizeof(eof_mark_1));
101 	SetDataInput(fDeframer);
102 
103 	/* init hw */
104 
105 	const BUSBConfiguration *config = GetDevice()->ConfigurationAt(0);
106 	if (config) {
107 		const BUSBInterface *inter = config->InterfaceAt(0);
108 		uint32 i;
109 
110 		GetDevice()->SetConfiguration(config);
111 
112 		for (i = 0; inter && (i < inter->CountEndpoints()); i++) {
113 			const BUSBEndpoint *e = inter->EndpointAt(i);
114 			if (e && e->IsBulk() && e->IsInput()) {
115 				fBulkIn = e;
116 				PRINT((CH ": Using inter[0].endpoint[%d]; maxpktsz: %d" CT, i, e->MaxPacketSize()));
117 				break;
118 			}
119 		}
120 
121 	}
122 
123 	/* sanity check */
124 	err = ReadReg(SN9C102_ASIC_ID, data);
125 	if (err < 0 || data[0] != 0x10) {
126 		PRINT((CH ": BAD ASIC signature! (%u != %u)" CT, data[0], 0x10));
127 		return;
128 	}
129 
130 		//XXX: the XP driver sends this to the ICECAM... need to investigate.
131 #if 1
132 	uint8 tmp_3[] = {
133 		0x44, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa0,
134 		0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
135 		0x00, 0x41, 0x09, 0x00, 0x16, 0x12, 0x60, 0x86,
136 		0x3b, 0x0f, 0x0e, 0x06, 0x00, 0x00, 0x03 };
137 	WriteReg(SN9C102_CHIP_CTRL, tmp_3, 0x1f);
138 #endif
139 		//XXX:DEBUG
140 
141 #if 0
142 		//XXX: the XP driver sends all this... investigate.
143 	uint8 tmp_1[] = {0x09, 0x44};
144 	WriteReg(SN9C102_CHIP_CTRL, tmp_1, sizeof(tmp_1));
145 	WriteReg8(SN9C102_CHIP_CTRL, 0x44);
146 
147 	WriteReg8(SN9C102_CLOCK_SEL /*0x17*/, 0x29);
148 
149 	uint8 tmp_2[] = {0x44, 0x44};
150 	WriteReg(SN9C102_CHIP_CTRL, tmp_2, 2);
151 		//URB_FUNCTION_VENDOR_INTERFACE:
152 		//(USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
153 
154 	uint8 tmp_3[] = {
155 		0x44, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa0,
156 		0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
157 		0x00, 0x41, 0x09, 0x00, 0x16, 0x12, 0x60, 0x86,
158 		0x3b, 0x0f, 0x0e, 0x06, 0x00, 0x00, 0x03 };
159 	WriteReg(SN9C102_CHIP_CTRL, tmp_3, 0x1f);
160 
161 	uint8 tmp_4[] = {0x01, 0x01, 0x07, 0x06};
162 	//WriteReg(SN9C102_AE_STRX, tmp_4, 4);
163 
164 	uint8 tmp_5[] = {0x14, 0x0f};
165 	//WriteReg(SN9C102_H_SIZE, tmp_5, 2);
166 
167 	WriteReg8(SN9C102_SYNC_N_SCALE, 0x86);
168 
169 	WriteReg8(SN9C102_CHIP_CTRL, 0x44);	// again ??
170 
171 	uint8 tmp_6[] = { 0x60, 0x86 };
172 	WriteReg(SN9C102_CLOCK_SEL /*0x17*/, tmp_6, 2);
173 
174 	WriteReg8(SN9C102_PIX_CLK, 0x2b);
175 
176 	// some IIC stuff for the sensor
177 	uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 };
178 	//WriteReg(SN9C102_I2C_SETUP, tmp_7, 8);
179 
180 	WriteReg8(SN9C102_PIX_CLK, 0x4b);
181 
182 	uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16 };
183 	//WriteReg(SN9C102_I2C_SETUP, tmp_8, 8);
184 
185 #endif
186 #if 0
187 	// some IIC stuff for the sensor
188 	uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 };
189 	WriteReg(SN9C102_I2C_SETUP, tmp_7, 8);
190 
191 	WriteReg8(SN9C102_PIX_CLK, 0x4b);
192 
193 	uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16};
194 	WriteReg(SN9C102_I2C_SETUP, tmp_8, 8);
195 #endif
196 
197 	//WriteReg8(SN9C102_PIX_CLK, 0x4b);
198 
199 //###############
200 
201 	if (Sensor()) {
202 		PRINT((CH ": CamSensor: %s" CT, Sensor()->Name()));
203 		fInitStatus = Sensor()->Setup();
204 
205 		fVideoFrame = BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1);
206 //		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
207 //		SetVideoFrame(BRect(0, 0, 320-1, 240-1));
208 	}
209 	//SetScale(1);
210 }
211 
212 
213 SonixCamDevice::~SonixCamDevice()
214 {
215 	if (Sensor())
216 		delete fSensor;
217 	fSensor = NULL;
218 }
219 
220 
221 bool
222 SonixCamDevice::SupportsBulk()
223 {
224 	return true;
225 }
226 
227 
228 bool
229 SonixCamDevice::SupportsIsochronous()
230 {
231 	return true;
232 }
233 
234 
235 status_t
236 SonixCamDevice::StartTransfer()
237 {
238 	status_t err;
239 	uint8 r;
240 
241 	SetScale(1);
242 	if (Sensor())
243 		SetVideoFrame(fVideoFrame);
244 
245 	//SetVideoFrame(BRect(0, 0, 320-1, 240-1));
246 
247 DumpRegs();
248 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
249 	if (err < 0)
250 		return err;
251 	r |= 0x04;
252 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
253 	if (err < 0)
254 		return err;
255 	return CamDevice::StartTransfer();
256 }
257 
258 
259 status_t
260 SonixCamDevice::StopTransfer()
261 {
262 	status_t err;
263 	uint8 r;
264 
265 DumpRegs();
266 	err = CamDevice::StopTransfer();
267 //	if (err < 0)
268 //		return err;
269 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
270 	if (err < 0)
271 		return err;
272 	r &= ~0x04;
273 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
274 	if (err < 0)
275 		return err;
276 	return err;
277 }
278 
279 
280 status_t
281 SonixCamDevice::PowerOnSensor(bool on)
282 {
283 	if (OrReg8(SN9C102_CHIP_CTRL, on ? 0x01 : 0x00) < 0)
284 		return EIO;
285 	return B_OK;
286 }
287 
288 
289 ssize_t
290 SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
291 {
292 	PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
293 	status_t err;
294 	if (address + count > SN9C102_REG_COUNT) {
295 		PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count));
296 		return EINVAL;
297 	}
298 	memcpy(&fCachedRegs[address], data, count);
299 	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data);
300 	if (err < B_OK)
301 		return err;
302 	return count;
303 }
304 
305 
306 ssize_t
307 SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
308 {
309 	PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
310 	status_t err;
311 	if (address + count > SN9C102_REG_COUNT) {
312 		PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count));
313 		return EINVAL;
314 	}
315 	if (cached) {
316 		memcpy(data, &fCachedRegs[address], count);
317 		return count;
318 	}
319 	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data);
320 	if (err < B_OK)
321 		return err;
322 	return count;
323 }
324 
325 
326 status_t
327 SonixCamDevice::GetStatusIIC()
328 {
329 	status_t err;
330 	uint8 status = 0;
331 	err = ReadReg(SN9C102_I2C_SETUP, &status);
332 	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
333 	if (err < 0)
334 		return err;
335 	return (status&0x08)?EIO:0;
336 }
337 
338 
339 status_t
340 SonixCamDevice::WaitReadyIIC()
341 {
342 	status_t err;
343 	uint8 status = 0;
344 	int tries = 5;
345 	if (!Sensor())
346 		return B_NO_INIT;
347 	while (tries--) {
348 		err = ReadReg(SN9C102_I2C_SETUP, &status);
349 		//dprintf(ID "i2c_wait_ready: error 0x%08lx, status = %02x\n", err, status);
350 		if (err < 0) return err;
351 		if (status & 0x04) return B_OK;
352 		//XXX:FIXME:spin((1+5+11*dev->sensor->use_400kHz)*8);
353 		snooze((1+5+11*Sensor()->Use400kHz())*8);
354 	}
355 	return EBUSY;
356 }
357 
358 
359 ssize_t
360 SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
361 {
362 	status_t err;
363 	uint8 buffer[8];
364 	PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
365 
366 	if (!Sensor())
367 		return B_NO_INIT;
368 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
369 	count++; // includes address
370 	if (count > 5)
371 		return EINVAL;
372 	buffer[0] = ((count) << 4) | (Sensor()->Use400kHz()?0x01:0)
373 							 | (Sensor()->UseRealIIC()?0x80:0);
374 	buffer[1] = Sensor()->IICWriteAddress();
375 	buffer[2] = address;
376 	memset(&buffer[3], 0, 5);
377 	memcpy(&buffer[3], data, count-1);
378 	buffer[7] = 0x16; /* V4L2 driver uses 0x10, XP driver uses 0x16 ? */
379 	for (int i = 0; i < 8; i++) {
380 		PRINT(("[%d] = %02x\n", i, buffer[i]));
381 	}
382 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
383 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
384 	//PRINT((CH ": WriteReg: %s" CT, strerror(err)));
385 	if (err < 0) return err;
386 	err = WaitReadyIIC();
387 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
388 	//PRINT((CH ": Wait: %s" CT, strerror(err)));
389 	if (err) return err;
390 	err = GetStatusIIC();
391 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
392 	//PRINT((CH ": Status: %s" CT, strerror(err)));
393 	if (err) return err;
394 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
395 	PRINT((CH ": success" CT));
396 	return B_OK;
397 }
398 
399 
400 ssize_t
401 SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
402 {
403 	status_t err, lasterr = B_OK;
404 	uint8 buffer[8];
405 	PRINT((CH "(%u, @%p)" CT, address, data));
406 
407 	if (!Sensor())
408 		return B_NO_INIT;
409 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
410 	buffer[0] = (1 << 4) | (Sensor()->Use400kHz()?0x01:0)
411 						| (Sensor()->UseRealIIC()?0x80:0);
412 	buffer[1] = Sensor()->IICWriteAddress();
413 	buffer[2] = address;
414 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
415 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
416 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
417 	if (err < 8) return EIO;
418 	err = WaitReadyIIC();
419 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
420 	//if (err) return err;
421 
422 
423 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
424 	buffer[0] = (1 << 4) | (Sensor()->Use400kHz()?0x01:0)
425 				  | 0x02 | (Sensor()->UseRealIIC()?0x80:0); /* read 1 byte */
426 	buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress
427 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
428 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
429 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
430 	if (err < 8) return EIO;
431 	err = WaitReadyIIC();
432 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
433 	if (err < B_OK) return err;
434 
435 	err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
436 	if (err < 5) return EIO;
437 
438 	err = GetStatusIIC();
439 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
440 	if (err < B_OK) return err;
441 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
442 	if (lasterr) return err;
443 
444 	/* we should get what we want in buffer[4] according to the V4L2 driver...
445 	 * probably because the 5 bytes are a bit shift register?
446 	 */
447 	*data = buffer[4];
448 
449 	return 1;
450 }
451 
452 
453 status_t
454 SonixCamDevice::SetVideoFrame(BRect frame)
455 {
456 	uint16 x, y, width, height;
457 	x = (uint16)frame.left;
458 	y = (uint16)frame.top;
459 	width = (uint16)(frame.right - frame.left + 1) / 16;
460 	height = (uint16)(frame.bottom - frame.top + 1) / 16;
461 	PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height));
462 
463 	WriteReg8(SN9C102_H_START, x);
464 	WriteReg8(SN9C102_V_START, y);
465 	WriteReg8(SN9C102_H_SIZE, width);
466 	WriteReg8(SN9C102_V_SIZE, height);
467 	if (Sensor()) {
468 		Sensor()->SetVideoFrame(frame);
469 	}
470 	return CamDevice::SetVideoFrame(frame);
471 }
472 
473 
474 status_t
475 SonixCamDevice::SetScale(float scale)
476 {
477 	status_t err;
478 	uint8 r;
479 	int iscale = (int)scale;
480 
481 	PRINT((CH "(%u)" CT, iscale));
482 	err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true);
483 	if (err < 0)
484 		return err;
485 	r &= ~0x30;
486 	switch (iscale) {
487 	case 1:
488 	case 2:
489 	case 4:
490 		r |= ((iscale-1) << 4);
491 		break;
492 	default:
493 		return EINVAL;
494 	}
495 	err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
496 	return err;
497 }
498 
499 
500 status_t
501 SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
502 {
503 	return B_OK;
504 }
505 
506 void
507 SonixCamDevice::AddParameters(BParameterGroup *group, int32 &index)
508 {
509 	BParameterGroup *g;
510 	BContinuousParameter *p;
511 	CamDevice::AddParameters(group, index);
512 
513 	// R,G,B gains
514 	g = group->MakeGroup("RGB gain");
515 	p = g->MakeContinuousParameter(index++,
516 		B_MEDIA_RAW_VIDEO, "RGB gain",
517 		B_GAIN, "", 1.0, 1.0+(float)(SN9C102_RGB_GAIN_MAX)/8, (float)1.0/8);
518 
519 	p->SetChannelCount(3);
520 #if 0
521 	// Contrast - NON FUNCTIONAL
522 	g = group->MakeGroup("Contrast");
523 	p = g->MakeContinuousParameter(index++,
524 		B_MEDIA_RAW_VIDEO, "Contrast",
525 		B_GAIN, "", 0.0, 1.0, 1.0/256);
526 
527 	// Brightness - NON FUNCTIONAL
528 	g = group->MakeGroup("Brightness");
529 	p = g->MakeContinuousParameter(index++,
530 		B_MEDIA_RAW_VIDEO, "Brightness",
531 		B_GAIN, "", 0.0, 1.0, 1.0/256);
532 
533 #endif
534 }
535 
536 status_t
537 SonixCamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
538 {
539 	float *gains;
540 	switch (id - fFirstParameterID) {
541 		case 0:
542 			*size = 3 * sizeof(float);
543 			gains = ((float *)value);
544 			gains[0] = 1.0 + (float)fRGain / 8;
545 			gains[1] = 1.0 + (float)fGGain / 8;
546 			gains[2] = 1.0 + (float)fBGain / 8;
547 			*last_change = fLastParameterChanges;
548 			return B_OK;
549 #if 0
550 		case 1:
551 			*size = sizeof(float);
552 			gains = ((float *)value);
553 			gains[0] = fContrast;
554 			*last_change = fLastParameterChanges;
555 			return B_OK;
556 		case 2:
557 			*size = sizeof(float);
558 			gains = ((float *)value);
559 			gains[0] = fBrightness;
560 			*last_change = fLastParameterChanges;
561 			return B_OK;
562 #endif
563 	}
564 	return B_BAD_VALUE;
565 }
566 
567 status_t
568 SonixCamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
569 {
570 	float *gains;
571 	switch (id - fFirstParameterID) {
572 		case 0:
573 			if (!value || (size != 3 * sizeof(float)))
574 				return B_BAD_VALUE;
575 			gains = ((float *)value);
576 			if ((gains[0] == 1.0 + (float)fRGain / 8)
577 				&& (gains[1] == 1.0 + (float)fGGain / 8)
578 				&& (gains[2] == 1.0 + (float)fBGain / 8))
579 				return B_OK;
580 
581 			fRGain = (int)(8 * (gains[0] - 1.0)) & SN9C102_RGB_GAIN_MAX;
582 			fGGain = (int)(8 * (gains[1] - 1.0)) & SN9C102_RGB_GAIN_MAX;
583 			fBGain = (int)(8 * (gains[2] - 1.0)) & SN9C102_RGB_GAIN_MAX;
584 			fLastParameterChanges = when;
585 			PRINT((CH ": gain: %d,%d,%d" CT, fRGain, fGGain, fBGain));
586 			//WriteReg8(SN9C102_R_B_GAIN, (fBGain << 4) | fRGain);	/* red, blue gain = 1+0/8 = 1 */
587 			/* Datasheet says:
588 			 * reg 0x10 [0:3] is rgain, [4:7] is bgain and 0x11 [0:3] is ggain
589 			 * according to sn9c102-1.15 linux driver it's wrong for reg 0x10,
590 			 * but it doesn't seem to work any better for a rev 2 chip.
591 			 * XXX
592 			 */
593 #if 1
594 			WriteReg8(SN9C102_R_GAIN, fRGain);
595 			WriteReg8(SN9C102_B_GAIN, fBGain);
596 			if (fChipVersion >= 3)
597 				WriteReg8(SN9C103_G_GAIN, fGGain);
598 			else
599 				WriteReg8(SN9C102_G_GAIN, (fGGain / 16));
600 #endif
601 #if 0
602 			uint8 buf[2];
603 			buf[0] = (fBGain << 4) | fRGain;
604 			buf[1] = fGGain;
605 			WriteReg(SN9C102_R_B_GAIN, buf, 2);
606 #endif
607 			return B_OK;
608 #if 0
609 		case 1:
610 			if (!value || (size != sizeof(float)))
611 				return B_BAD_VALUE;
612 			gains = ((float *)value);
613 			fContrast = gains[0];
614 			WriteReg8(SN9C10x_CONTRAST, ((uint8)(fContrast * 256)));
615 			return B_OK;
616 		case 2:
617 			if (!value || (size != sizeof(float)))
618 				return B_BAD_VALUE;
619 			gains = ((float *)value);
620 			fBrightness = gains[0];
621 			// it actually ends up writing to SN9C102_V_SIZE...
622 			WriteReg8(SN9C10x_BRIGHTNESS, ((uint8)(fBrightness * 256)));
623 
624 			return B_OK;
625 #endif
626 	}
627 	return B_BAD_VALUE;
628 }
629 
630 
631 
632 size_t
633 SonixCamDevice::MinRawFrameSize()
634 {
635 	// if (fCompressionEnabled) { ... return ; }
636 	BRect vf(VideoFrame());
637 	int w = vf.IntegerWidth()+1;
638 	int h = vf.IntegerHeight()+1;
639 	// 1 byte/pixel
640 	return (size_t)(w*h);
641 }
642 
643 
644 size_t
645 SonixCamDevice::MaxRawFrameSize()
646 {
647 	// if (fCompressionEnabled) { ... return ; }
648 	return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
649 }
650 
651 
652 bool
653 SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
654 {
655 	// SOF come with an 00, 40, 80, C0 sequence,
656 	// supposedly corresponding with an equal byte in the end tag
657 	fFrameTagState = tag[7] & 0xC0;
658 	PRINT((CH "(, %d) state %x" CT, taglen, fFrameTagState));
659 
660 	// which seems to be the same as of the EOF tag
661 	return true;
662 }
663 
664 
665 bool
666 SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
667 {
668 	//PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState));
669 	// make sure the tag corresponds to the SOF we refer to
670 	if ((tag[0] & 0xC0) != fFrameTagState) {
671 		PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0));
672 		return false;
673 	}
674 	//PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
675 	return true;
676 }
677 
678 
679 status_t
680 SonixCamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp /* = NULL */)
681 {
682 	BBitmap *b;
683 	CamFrame *f;
684 	status_t err;
685 	PRINT((CH "()" CT));
686 	err = fDeframer->WaitFrame(200000);
687 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
688 	if (err < B_OK)
689 		return err;
690 	err = fDeframer->GetFrame(&f, stamp);
691 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
692 	if (err < B_OK)
693 		return err;
694 	PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom));
695 
696 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
697 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
698 	b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4);
699 	PRINT((CH ": Frame: %dx%d" CT, w, h));
700 
701 	bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
702 
703 	PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
704 	*bm = b;
705 	return B_OK;
706 }
707 
708 
709 status_t
710 SonixCamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
711 {
712 	CamFrame *f;
713 	status_t err;
714 	PRINT((CH "()" CT));
715 
716 	memset(buffer->Data(), 0, buffer->SizeAvailable());
717 	err = fDeframer->WaitFrame(2000000);
718 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
719 	if (err < B_OK)
720 		return err;
721 
722 	err = fDeframer->GetFrame(&f, stamp);
723 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
724 	if (err < B_OK)
725 		return err;
726 
727 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
728 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
729 	PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %dx%d" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom, w, h));
730 
731 	if (buffer->SizeAvailable() >= (size_t)w*h*4)
732 		bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
733 
734 	delete f;
735 
736 	PRINT((CH ": available %d, required %d" CT, buffer->SizeAvailable(), w*h*4));
737 	if (buffer->SizeAvailable() < (size_t)w*h*4)
738 		return E2BIG;
739 	PRINT((CH ": got 1 frame (len %d)" CT, buffer->SizeUsed()));
740 	return B_OK;
741 }
742 
743 
744 void
745 /* DEBUG: dump the SN regs */
746 SonixCamDevice::DumpRegs()
747 {
748 	uint8 regs[SN9C102_REG_COUNT];
749 	status_t err;
750 
751 	//err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
752 	err = ReadReg(0, regs, SN9C102_REG_COUNT);
753 	if (err < 0)
754 		return;
755 	printf("REG1: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
756 			regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
757 	printf("   2: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
758 			regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]);
759 	printf("   3: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
760 			regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]);
761 	printf("   4: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
762 			regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]);
763 }
764 
765 #if 0
766 
767 status_t
768 SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
769 							uint16 index, uint16 length, void* data)
770 {
771 	size_t ret;
772 	if (!GetDevice())
773 		return ENODEV;
774 	if (length > GetDevice()->MaxEndpoint0PacketSize())
775 		return EINVAL;
776 	ret = GetDevice()->ControlTransfer(
777 				USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
778 				request, value, index, length, data);
779 	return ret;
780 }
781 #endif
782 
783 
784 SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
785 	: CamDeviceAddon(webcam)
786 {
787 	SetSupportedDevices(kSupportedDevices);
788 }
789 
790 
791 SonixCamDeviceAddon::~SonixCamDeviceAddon()
792 {
793 }
794 
795 
796 const char *
797 SonixCamDeviceAddon::BrandName()
798 {
799 	return "Sonix";
800 }
801 
802 
803 SonixCamDevice *
804 SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
805 {
806 	return new SonixCamDevice(*this, from);
807 }
808 
809 extern "C" status_t
810 B_WEBCAM_MKINTFUNC(sonix)
811 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
812 {
813 	*addon = new SonixCamDeviceAddon(webcam);
814 	return B_OK;
815 }
816 
817 // XXX: REMOVE ME
818 
819 
820 
821 /*
822  * BAYER2RGB24 ROUTINE TAKEN FROM:
823  *
824  * Sonix SN9C101 based webcam basic I/F routines
825  * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
826  *
827  * Redistribution and use in source and binary forms, with or without
828  * modification, are permitted provided that the following conditions
829  * are met:
830  * 1. Redistributions of source code must retain the above copyright
831  *    notice, this list of conditions and the following disclaimer.
832  * 2. Redistributions in binary form must reproduce the above copyright
833  *    notice, this list of conditions and the following disclaimer in the
834  *    documentation and/or other materials provided with the distribution.
835  *
836  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
837  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
838  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
839  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
840  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
841  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
842  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
843  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
844  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
845  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
846  * SUCH DAMAGE.
847  */
848 
849 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
850 {
851     long int i;
852     unsigned char *rawpt, *scanpt;
853     long int size;
854 
855     rawpt = src;
856     scanpt = dst;
857     size = WIDTH*HEIGHT;
858 
859     for ( i = 0; i < size; i++ ) {
860 	if ( (i/WIDTH) % 2 == 0 ) {
861 	    if ( (i % 2) == 0 ) {
862 		/* B */
863 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
864 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
865 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
866 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
867 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
868 		    *scanpt++ = *rawpt;					/* B */
869 		} else {
870 		    /* first line or left column */
871 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
872 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
873 		    *scanpt++ = *rawpt;				/* B */
874 		}
875 	    } else {
876 		/* (B)G */
877 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
878 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
879 		    *scanpt++ = *rawpt;					/* G */
880 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
881 		} else {
882 		    /* first line or right column */
883 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
884 		    *scanpt++ = *rawpt;		/* G */
885 		    *scanpt++ = *(rawpt-1);	/* B */
886 		}
887 	    }
888 	} else {
889 	    if ( (i % 2) == 0 ) {
890 		/* G(R) */
891 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
892 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
893 		    *scanpt++ = *rawpt;					/* G */
894 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
895 		} else {
896 		    /* bottom line or left column */
897 		    *scanpt++ = *(rawpt+1);		/* R */
898 		    *scanpt++ = *rawpt;			/* G */
899 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
900 		}
901 	    } else {
902 		/* R */
903 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
904 		    *scanpt++ = *rawpt;					/* R */
905 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
906 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
907 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
908 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
909 		} else {
910 		    /* bottom line or right column */
911 		    *scanpt++ = *rawpt;				/* R */
912 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
913 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
914 		}
915 	    }
916 	}
917 	rawpt++;
918     }
919 
920 }
921 
922 /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
923  * François Revol
924  */
925 
926 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
927 {
928     long int i;
929     unsigned char *rawpt, *scanpt;
930     long int size;
931 
932     rawpt = src;
933     scanpt = dst;
934     size = WIDTH*HEIGHT;
935 
936     for ( i = 0; i < size; i++ ) {
937 	if ( (i/WIDTH) % 2 == 0 ) {
938 	    if ( (i % 2) == 0 ) {
939 		/* B */
940 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
941 		    *scanpt++ = *rawpt;					/* B */
942 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
943 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
944 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
945 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
946 		} else {
947 		    /* first line or left column */
948 		    *scanpt++ = *rawpt;				/* B */
949 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
950 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
951 		}
952 	    } else {
953 		/* (B)G */
954 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
955 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
956 		    *scanpt++ = *rawpt;					/* G */
957 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
958 		} else {
959 		    /* first line or right column */
960 		    *scanpt++ = *(rawpt-1);	/* B */
961 		    *scanpt++ = *rawpt;		/* G */
962 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
963 		}
964 	    }
965 	} else {
966 	    if ( (i % 2) == 0 ) {
967 		/* G(R) */
968 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
969 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
970 		    *scanpt++ = *rawpt;					/* G */
971 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
972 		} else {
973 		    /* bottom line or left column */
974 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
975 		    *scanpt++ = *rawpt;			/* G */
976 		    *scanpt++ = *(rawpt+1);		/* R */
977 		}
978 	    } else {
979 		/* R */
980 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
981 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
982 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
983 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
984 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
985 		    *scanpt++ = *rawpt;					/* R */
986 		} else {
987 		    /* bottom line or right column */
988 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
989 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
990 		    *scanpt++ = *rawpt;				/* R */
991 		}
992 	    }
993 	}
994 	rawpt++;
995 	scanpt++;
996     }
997 
998 }
999