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
16const 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
65static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 };
66static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 };
67static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 };
68
69static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 };
70static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 };
71static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 };
72static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 };
73static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 };
74
75void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
76void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
77
78
79SonixCamDevice::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
213SonixCamDevice::~SonixCamDevice()
214{
215	if (Sensor())
216		delete fSensor;
217	fSensor = NULL;
218}
219
220
221bool
222SonixCamDevice::SupportsBulk()
223{
224	return true;
225}
226
227
228bool
229SonixCamDevice::SupportsIsochronous()
230{
231	return true;
232}
233
234
235status_t
236SonixCamDevice::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
247DumpRegs();
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
259status_t
260SonixCamDevice::StopTransfer()
261{
262	status_t err;
263	uint8 r;
264
265DumpRegs();
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
280status_t
281SonixCamDevice::PowerOnSensor(bool on)
282{
283	if (OrReg8(SN9C102_CHIP_CTRL, on ? 0x01 : 0x00) < 0)
284		return EIO;
285	return B_OK;
286}
287
288
289ssize_t
290SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
291{
292	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ")" CT, address, data, count));
293	status_t err;
294	if (address + count > SN9C102_REG_COUNT) {
295		PRINT((CH ": Invalid register range [%u;%" B_PRIuSIZE "]" CT, address,
296			address + count));
297		return EINVAL;
298	}
299	memcpy(&fCachedRegs[address], data, count);
300	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data);
301	if (err < B_OK)
302		return err;
303	return count;
304}
305
306
307ssize_t
308SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
309{
310	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ", %d)" CT, address, data, count,
311		cached));
312	status_t err;
313	if (address + count > SN9C102_REG_COUNT) {
314		PRINT((CH ": Invalid register range [%u;%" B_PRIuSIZE "]" CT, address,
315			address + count));
316		return EINVAL;
317	}
318	if (cached) {
319		memcpy(data, &fCachedRegs[address], count);
320		return count;
321	}
322	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data);
323	if (err < B_OK)
324		return err;
325	return count;
326}
327
328
329status_t
330SonixCamDevice::GetStatusIIC()
331{
332	status_t err;
333	uint8 status = 0;
334	err = ReadReg(SN9C102_I2C_SETUP, &status);
335	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
336	if (err < 0)
337		return err;
338	return (status&0x08)?EIO:0;
339}
340
341
342status_t
343SonixCamDevice::WaitReadyIIC()
344{
345	status_t err;
346	uint8 status = 0;
347	int tries = 5;
348	if (!Sensor())
349		return B_NO_INIT;
350	while (tries--) {
351		err = ReadReg(SN9C102_I2C_SETUP, &status);
352		//dprintf(ID "i2c_wait_ready: error 0x%08lx, status = %02x\n", err, status);
353		if (err < 0) return err;
354		if (status & 0x04) return B_OK;
355		//XXX:FIXME:spin((1+5+11*dev->sensor->use_400kHz)*8);
356		snooze((1+5+11*Sensor()->Use400kHz())*8);
357	}
358	return EBUSY;
359}
360
361
362ssize_t
363SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
364{
365	status_t err;
366	uint8 buffer[8];
367	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ")" CT, address, data, count));
368
369	if (!Sensor())
370		return B_NO_INIT;
371	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
372	count++; // includes address
373	if (count > 5)
374		return EINVAL;
375	buffer[0] = ((count) << 4) | (Sensor()->Use400kHz()?0x01:0)
376							 | (Sensor()->UseRealIIC()?0x80:0);
377	buffer[1] = Sensor()->IICWriteAddress();
378	buffer[2] = address;
379	memset(&buffer[3], 0, 5);
380	memcpy(&buffer[3], data, count-1);
381	buffer[7] = 0x16; /* V4L2 driver uses 0x10, XP driver uses 0x16 ? */
382	for (int i = 0; i < 8; i++) {
383		PRINT(("[%d] = %02x\n", i, buffer[i]));
384	}
385	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
386	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
387	//PRINT((CH ": WriteReg: %s" CT, strerror(err)));
388	if (err < 0) return err;
389	err = WaitReadyIIC();
390	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
391	//PRINT((CH ": Wait: %s" CT, strerror(err)));
392	if (err) return err;
393	err = GetStatusIIC();
394	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
395	//PRINT((CH ": Status: %s" CT, strerror(err)));
396	if (err) return err;
397	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
398	PRINT((CH ": success" CT));
399	return B_OK;
400}
401
402
403ssize_t
404SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
405{
406	status_t err, lasterr = B_OK;
407	uint8 buffer[8];
408	PRINT((CH "(%u, @%p)" CT, address, data));
409
410	if (!Sensor())
411		return B_NO_INIT;
412	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
413	buffer[0] = (1 << 4) | (Sensor()->Use400kHz()?0x01:0)
414						| (Sensor()->UseRealIIC()?0x80:0);
415	buffer[1] = Sensor()->IICWriteAddress();
416	buffer[2] = address;
417	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
418	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
419	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
420	if (err < 8) return EIO;
421	err = WaitReadyIIC();
422	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
423	//if (err) return err;
424
425
426	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
427	buffer[0] = (1 << 4) | (Sensor()->Use400kHz()?0x01:0)
428				  | 0x02 | (Sensor()->UseRealIIC()?0x80:0); /* read 1 byte */
429	buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress
430	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
431	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
432	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
433	if (err < 8) return EIO;
434	err = WaitReadyIIC();
435	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
436	if (err < B_OK) return err;
437
438	err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
439	if (err < 5) return EIO;
440
441	err = GetStatusIIC();
442	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
443	if (err < B_OK) return err;
444	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
445	if (lasterr) return err;
446
447	/* we should get what we want in buffer[4] according to the V4L2 driver...
448	 * probably because the 5 bytes are a bit shift register?
449	 */
450	*data = buffer[4];
451
452	return 1;
453}
454
455
456status_t
457SonixCamDevice::SetVideoFrame(BRect frame)
458{
459	uint16 x, y, width, height;
460	x = (uint16)frame.left;
461	y = (uint16)frame.top;
462	width = (uint16)(frame.right - frame.left + 1) / 16;
463	height = (uint16)(frame.bottom - frame.top + 1) / 16;
464	PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height));
465
466	WriteReg8(SN9C102_H_START, x);
467	WriteReg8(SN9C102_V_START, y);
468	WriteReg8(SN9C102_H_SIZE, width);
469	WriteReg8(SN9C102_V_SIZE, height);
470	if (Sensor()) {
471		Sensor()->SetVideoFrame(frame);
472	}
473	return CamDevice::SetVideoFrame(frame);
474}
475
476
477status_t
478SonixCamDevice::SetScale(float scale)
479{
480	status_t err;
481	uint8 r;
482	int iscale = (int)scale;
483
484	PRINT((CH "(%u)" CT, iscale));
485	err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true);
486	if (err < 0)
487		return err;
488	r &= ~0x30;
489	switch (iscale) {
490	case 1:
491	case 2:
492	case 4:
493		r |= ((iscale-1) << 4);
494		break;
495	default:
496		return EINVAL;
497	}
498	err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
499	return err;
500}
501
502
503status_t
504SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
505{
506	return B_OK;
507}
508
509void
510SonixCamDevice::AddParameters(BParameterGroup *group, int32 &index)
511{
512	BParameterGroup *g;
513	BContinuousParameter *p;
514	CamDevice::AddParameters(group, index);
515
516	// R,G,B gains
517	g = group->MakeGroup("RGB gain");
518	p = g->MakeContinuousParameter(index++,
519		B_MEDIA_RAW_VIDEO, "RGB gain",
520		B_GAIN, "", 1.0, 1.0+(float)(SN9C102_RGB_GAIN_MAX)/8, (float)1.0/8);
521
522	p->SetChannelCount(3);
523#if 0
524	// Contrast - NON FUNCTIONAL
525	g = group->MakeGroup("Contrast");
526	p = g->MakeContinuousParameter(index++,
527		B_MEDIA_RAW_VIDEO, "Contrast",
528		B_GAIN, "", 0.0, 1.0, 1.0/256);
529
530	// Brightness - NON FUNCTIONAL
531	g = group->MakeGroup("Brightness");
532	p = g->MakeContinuousParameter(index++,
533		B_MEDIA_RAW_VIDEO, "Brightness",
534		B_GAIN, "", 0.0, 1.0, 1.0/256);
535
536#endif
537}
538
539status_t
540SonixCamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
541{
542	float *gains;
543	switch (id - fFirstParameterID) {
544		case 0:
545			*size = 3 * sizeof(float);
546			gains = ((float *)value);
547			gains[0] = 1.0 + (float)fRGain / 8;
548			gains[1] = 1.0 + (float)fGGain / 8;
549			gains[2] = 1.0 + (float)fBGain / 8;
550			*last_change = fLastParameterChanges;
551			return B_OK;
552#if 0
553		case 1:
554			*size = sizeof(float);
555			gains = ((float *)value);
556			gains[0] = fContrast;
557			*last_change = fLastParameterChanges;
558			return B_OK;
559		case 2:
560			*size = sizeof(float);
561			gains = ((float *)value);
562			gains[0] = fBrightness;
563			*last_change = fLastParameterChanges;
564			return B_OK;
565#endif
566	}
567	return B_BAD_VALUE;
568}
569
570status_t
571SonixCamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
572{
573	float *gains;
574	switch (id - fFirstParameterID) {
575		case 0:
576			if (!value || (size != 3 * sizeof(float)))
577				return B_BAD_VALUE;
578			gains = ((float *)value);
579			if ((gains[0] == 1.0 + (float)fRGain / 8)
580				&& (gains[1] == 1.0 + (float)fGGain / 8)
581				&& (gains[2] == 1.0 + (float)fBGain / 8))
582				return B_OK;
583
584			fRGain = (int)(8 * (gains[0] - 1.0)) & SN9C102_RGB_GAIN_MAX;
585			fGGain = (int)(8 * (gains[1] - 1.0)) & SN9C102_RGB_GAIN_MAX;
586			fBGain = (int)(8 * (gains[2] - 1.0)) & SN9C102_RGB_GAIN_MAX;
587			fLastParameterChanges = when;
588			PRINT((CH ": gain: %d,%d,%d" CT, fRGain, fGGain, fBGain));
589			//WriteReg8(SN9C102_R_B_GAIN, (fBGain << 4) | fRGain);	/* red, blue gain = 1+0/8 = 1 */
590			/* Datasheet says:
591			 * reg 0x10 [0:3] is rgain, [4:7] is bgain and 0x11 [0:3] is ggain
592			 * according to sn9c102-1.15 linux driver it's wrong for reg 0x10,
593			 * but it doesn't seem to work any better for a rev 2 chip.
594			 * XXX
595			 */
596#if 1
597			WriteReg8(SN9C102_R_GAIN, fRGain);
598			WriteReg8(SN9C102_B_GAIN, fBGain);
599			if (fChipVersion >= 3)
600				WriteReg8(SN9C103_G_GAIN, fGGain);
601			else
602				WriteReg8(SN9C102_G_GAIN, (fGGain / 16));
603#endif
604#if 0
605			uint8 buf[2];
606			buf[0] = (fBGain << 4) | fRGain;
607			buf[1] = fGGain;
608			WriteReg(SN9C102_R_B_GAIN, buf, 2);
609#endif
610			return B_OK;
611#if 0
612		case 1:
613			if (!value || (size != sizeof(float)))
614				return B_BAD_VALUE;
615			gains = ((float *)value);
616			fContrast = gains[0];
617			WriteReg8(SN9C10x_CONTRAST, ((uint8)(fContrast * 256)));
618			return B_OK;
619		case 2:
620			if (!value || (size != sizeof(float)))
621				return B_BAD_VALUE;
622			gains = ((float *)value);
623			fBrightness = gains[0];
624			// it actually ends up writing to SN9C102_V_SIZE...
625			WriteReg8(SN9C10x_BRIGHTNESS, ((uint8)(fBrightness * 256)));
626
627			return B_OK;
628#endif
629	}
630	return B_BAD_VALUE;
631}
632
633
634
635size_t
636SonixCamDevice::MinRawFrameSize()
637{
638	// if (fCompressionEnabled) { ... return ; }
639	BRect vf(VideoFrame());
640	size_t w = vf.IntegerWidth()+1;
641	size_t h = vf.IntegerHeight()+1;
642	// 1 byte/pixel
643	return w * h;
644}
645
646
647size_t
648SonixCamDevice::MaxRawFrameSize()
649{
650	// if (fCompressionEnabled) { ... return ; }
651	return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
652}
653
654
655bool
656SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
657{
658	// SOF come with an 00, 40, 80, C0 sequence,
659	// supposedly corresponding with an equal byte in the end tag
660	fFrameTagState = tag[7] & 0xC0;
661	PRINT((CH "(, %" B_PRIuSIZE ") state %x" CT, taglen, fFrameTagState));
662
663	// which seems to be the same as of the EOF tag
664	return true;
665}
666
667
668bool
669SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
670{
671	//PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState));
672	// make sure the tag corresponds to the SOF we refer to
673	if ((tag[0] & 0xC0) != fFrameTagState) {
674		PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0));
675		return false;
676	}
677	//PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
678	return true;
679}
680
681
682status_t
683SonixCamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp /* = NULL */)
684{
685	BBitmap *b;
686	CamFrame *f;
687	status_t err;
688	PRINT((CH "()" CT));
689	err = fDeframer->WaitFrame(200000);
690	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
691	if (err < B_OK)
692		return err;
693	err = fDeframer->GetFrame(&f, stamp);
694	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
695	if (err < B_OK)
696		return err;
697	PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom));
698
699	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
700	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
701	b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4);
702	PRINT((CH ": Frame: %ldx%ld" CT, w, h));
703
704	bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
705
706	PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
707	*bm = b;
708	return B_OK;
709}
710
711
712status_t
713SonixCamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
714{
715	CamFrame *f;
716	status_t err;
717	PRINT((CH "()" CT));
718
719	memset(buffer->Data(), 0, buffer->SizeAvailable());
720	err = fDeframer->WaitFrame(2000000);
721	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
722	if (err < B_OK)
723		return err;
724
725	err = fDeframer->GetFrame(&f, stamp);
726	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
727	if (err < B_OK)
728		return err;
729
730	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
731	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
732	PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %ldx%ld" CT,
733		VideoFrame().left, VideoFrame().top, VideoFrame().right,
734		VideoFrame().bottom, w, h));
735
736	if (buffer->SizeAvailable() >= (size_t)w*h*4)
737		bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
738
739	delete f;
740
741	PRINT((CH ": available %" B_PRIuSIZE ", required %ld" CT,
742		buffer->SizeAvailable(), w*h*4));
743	if (buffer->SizeAvailable() < (size_t)w*h*4)
744		return E2BIG;
745	PRINT((CH ": got 1 frame (len %" B_PRIuSIZE ")" CT, buffer->SizeUsed()));
746	return B_OK;
747}
748
749
750void
751/* DEBUG: dump the SN regs */
752SonixCamDevice::DumpRegs()
753{
754	uint8 regs[SN9C102_REG_COUNT];
755	status_t err;
756
757	//err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
758	err = ReadReg(0, regs, SN9C102_REG_COUNT);
759	if (err < 0)
760		return;
761	printf("REG1: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
762			regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
763	printf("   2: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
764			regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]);
765	printf("   3: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
766			regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]);
767	printf("   4: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
768			regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]);
769}
770
771#if 0
772
773status_t
774SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
775							uint16 index, uint16 length, void* data)
776{
777	size_t ret;
778	if (!GetDevice())
779		return ENODEV;
780	if (length > GetDevice()->MaxEndpoint0PacketSize())
781		return EINVAL;
782	ret = GetDevice()->ControlTransfer(
783				USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
784				request, value, index, length, data);
785	return ret;
786}
787#endif
788
789
790SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
791	: CamDeviceAddon(webcam)
792{
793	SetSupportedDevices(kSupportedDevices);
794}
795
796
797SonixCamDeviceAddon::~SonixCamDeviceAddon()
798{
799}
800
801
802const char *
803SonixCamDeviceAddon::BrandName()
804{
805	return "Sonix";
806}
807
808
809SonixCamDevice *
810SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
811{
812	return new SonixCamDevice(*this, from);
813}
814
815extern "C" status_t
816B_WEBCAM_MKINTFUNC(sonix)
817(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
818{
819	*addon = new SonixCamDeviceAddon(webcam);
820	return B_OK;
821}
822
823// XXX: REMOVE ME
824
825
826
827/*
828 * BAYER2RGB24 ROUTINE TAKEN FROM:
829 *
830 * Sonix SN9C101 based webcam basic I/F routines
831 * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
832 *
833 * Redistribution and use in source and binary forms, with or without
834 * modification, are permitted provided that the following conditions
835 * are met:
836 * 1. Redistributions of source code must retain the above copyright
837 *    notice, this list of conditions and the following disclaimer.
838 * 2. Redistributions in binary form must reproduce the above copyright
839 *    notice, this list of conditions and the following disclaimer in the
840 *    documentation and/or other materials provided with the distribution.
841 *
842 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
843 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
844 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
845 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
846 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
847 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
848 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
849 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
850 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
851 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
852 * SUCH DAMAGE.
853 */
854
855void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
856{
857    long int i;
858    unsigned char *rawpt, *scanpt;
859    long int size;
860
861    rawpt = src;
862    scanpt = dst;
863    size = WIDTH*HEIGHT;
864
865    for ( i = 0; i < size; i++ ) {
866	if ( (i/WIDTH) % 2 == 0 ) {
867	    if ( (i % 2) == 0 ) {
868		/* B */
869		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
870		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
871				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
872		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
873				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
874		    *scanpt++ = *rawpt;					/* B */
875		} else {
876		    /* first line or left column */
877		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
878		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
879		    *scanpt++ = *rawpt;				/* B */
880		}
881	    } else {
882		/* (B)G */
883		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
884		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
885		    *scanpt++ = *rawpt;					/* G */
886		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
887		} else {
888		    /* first line or right column */
889		    *scanpt++ = *(rawpt+WIDTH);	/* R */
890		    *scanpt++ = *rawpt;		/* G */
891		    *scanpt++ = *(rawpt-1);	/* B */
892		}
893	    }
894	} else {
895	    if ( (i % 2) == 0 ) {
896		/* G(R) */
897		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
898		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
899		    *scanpt++ = *rawpt;					/* G */
900		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
901		} else {
902		    /* bottom line or left column */
903		    *scanpt++ = *(rawpt+1);		/* R */
904		    *scanpt++ = *rawpt;			/* G */
905		    *scanpt++ = *(rawpt-WIDTH);		/* B */
906		}
907	    } else {
908		/* R */
909		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
910		    *scanpt++ = *rawpt;					/* R */
911		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
912				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
913		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
914				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
915		} else {
916		    /* bottom line or right column */
917		    *scanpt++ = *rawpt;				/* R */
918		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
919		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
920		}
921	    }
922	}
923	rawpt++;
924    }
925
926}
927
928/* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
929 * Fran��ois Revol
930 */
931
932void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
933{
934    long int i;
935    unsigned char *rawpt, *scanpt;
936    long int size;
937
938    rawpt = src;
939    scanpt = dst;
940    size = WIDTH*HEIGHT;
941
942    for ( i = 0; i < size; i++ ) {
943	if ( (i/WIDTH) % 2 == 0 ) {
944	    if ( (i % 2) == 0 ) {
945		/* B */
946		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
947		    *scanpt++ = *rawpt;					/* B */
948		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
949				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
950		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
951				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
952		} else {
953		    /* first line or left column */
954		    *scanpt++ = *rawpt;				/* B */
955		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
956		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
957		}
958	    } else {
959		/* (B)G */
960		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
961		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
962		    *scanpt++ = *rawpt;					/* G */
963		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
964		} else {
965		    /* first line or right column */
966		    *scanpt++ = *(rawpt-1);	/* B */
967		    *scanpt++ = *rawpt;		/* G */
968		    *scanpt++ = *(rawpt+WIDTH);	/* R */
969		}
970	    }
971	} else {
972	    if ( (i % 2) == 0 ) {
973		/* G(R) */
974		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
975		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
976		    *scanpt++ = *rawpt;					/* G */
977		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
978		} else {
979		    /* bottom line or left column */
980		    *scanpt++ = *(rawpt-WIDTH);		/* B */
981		    *scanpt++ = *rawpt;			/* G */
982		    *scanpt++ = *(rawpt+1);		/* R */
983		}
984	    } else {
985		/* R */
986		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
987		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
988				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
989		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
990				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
991		    *scanpt++ = *rawpt;					/* R */
992		} else {
993		    /* bottom line or right column */
994		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
995		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
996		    *scanpt++ = *rawpt;				/* R */
997		}
998	    }
999	}
1000	rawpt++;
1001	scanpt++;
1002    }
1003
1004}
1005