vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / usb_webcam / addons / sonix / SonixCamDevice.cpp
blobeb20ace8eb5591e79b4f8eadbc14665e770544d6
1 /*
2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "SonixCamDevice.h"
7 #include "CamDebug.h"
8 #include "CamSensor.h"
9 #include "CamBufferingDeframer.h"
10 #include "CamStreamingDeframer.h"
12 #include <ParameterWeb.h>
13 #include <interface/Bitmap.h>
14 #include <media/Buffer.h>
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 },
22 /* other devices that should be supported,
23 * cf. sn9c102-1.15 linux driver, sn9c102_sensor.h
24 * for IDs and sensors
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 }
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 };
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 };
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);
79 SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
80 :CamDevice(_addon, _device)
82 uchar data[8]; /* store bytes returned from sonix commands */
83 status_t err;
84 fFrameTagState = 0;
86 fRGain = fGGain = fBGain = 0;
87 // unknown
88 fBrightness = 0.5;
90 memset(fCachedRegs, 0, SN9C102_REG_COUNT);
91 fChipVersion = 2;
92 if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) {
93 fChipVersion = 3; // says V4L2
95 err = ProbeSensor();
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);
103 /* init hw */
105 const BUSBConfiguration *config = GetDevice()->ConfigurationAt(0);
106 if (config) {
107 const BUSBInterface *inter = config->InterfaceAt(0);
108 uint32 i;
110 GetDevice()->SetConfiguration(config);
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;
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;
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
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);
147 WriteReg8(SN9C102_CLOCK_SEL /*0x17*/, 0x29);
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)
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);
161 uint8 tmp_4[] = {0x01, 0x01, 0x07, 0x06};
162 //WriteReg(SN9C102_AE_STRX, tmp_4, 4);
164 uint8 tmp_5[] = {0x14, 0x0f};
165 //WriteReg(SN9C102_H_SIZE, tmp_5, 2);
167 WriteReg8(SN9C102_SYNC_N_SCALE, 0x86);
169 WriteReg8(SN9C102_CHIP_CTRL, 0x44); // again ??
171 uint8 tmp_6[] = { 0x60, 0x86 };
172 WriteReg(SN9C102_CLOCK_SEL /*0x17*/, tmp_6, 2);
174 WriteReg8(SN9C102_PIX_CLK, 0x2b);
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);
180 WriteReg8(SN9C102_PIX_CLK, 0x4b);
182 uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16 };
183 //WriteReg(SN9C102_I2C_SETUP, tmp_8, 8);
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);
191 WriteReg8(SN9C102_PIX_CLK, 0x4b);
193 uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16};
194 WriteReg(SN9C102_I2C_SETUP, tmp_8, 8);
195 #endif
197 //WriteReg8(SN9C102_PIX_CLK, 0x4b);
199 //###############
201 if (Sensor()) {
202 PRINT((CH ": CamSensor: %s" CT, Sensor()->Name()));
203 fInitStatus = Sensor()->Setup();
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));
209 //SetScale(1);
213 SonixCamDevice::~SonixCamDevice()
215 if (Sensor())
216 delete fSensor;
217 fSensor = NULL;
221 bool
222 SonixCamDevice::SupportsBulk()
224 return true;
228 bool
229 SonixCamDevice::SupportsIsochronous()
231 return true;
235 status_t
236 SonixCamDevice::StartTransfer()
238 status_t err;
239 uint8 r;
241 SetScale(1);
242 if (Sensor())
243 SetVideoFrame(fVideoFrame);
245 //SetVideoFrame(BRect(0, 0, 320-1, 240-1));
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();
259 status_t
260 SonixCamDevice::StopTransfer()
262 status_t err;
263 uint8 r;
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;
280 status_t
281 SonixCamDevice::PowerOnSensor(bool on)
283 if (OrReg8(SN9C102_CHIP_CTRL, on ? 0x01 : 0x00) < 0)
284 return EIO;
285 return B_OK;
289 ssize_t
290 SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
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;
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;
306 ssize_t
307 SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
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;
315 if (cached) {
316 memcpy(data, &fCachedRegs[address], count);
317 return count;
319 err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data);
320 if (err < B_OK)
321 return err;
322 return count;
326 status_t
327 SonixCamDevice::GetStatusIIC()
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;
339 status_t
340 SonixCamDevice::WaitReadyIIC()
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);
355 return EBUSY;
359 ssize_t
360 SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
362 status_t err;
363 uint8 buffer[8];
364 PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
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]));
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;
400 ssize_t
401 SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
403 status_t err, lasterr = B_OK;
404 uint8 buffer[8];
405 PRINT((CH "(%u, @%p)" CT, address, data));
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;
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;
435 err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
436 if (err < 5) return EIO;
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;
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?
447 *data = buffer[4];
449 return 1;
453 status_t
454 SonixCamDevice::SetVideoFrame(BRect frame)
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));
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);
470 return CamDevice::SetVideoFrame(frame);
474 status_t
475 SonixCamDevice::SetScale(float scale)
477 status_t err;
478 uint8 r;
479 int iscale = (int)scale;
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;
495 err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
496 return err;
500 status_t
501 SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
503 return B_OK;
506 void
507 SonixCamDevice::AddParameters(BParameterGroup *group, int32 &index)
509 BParameterGroup *g;
510 BContinuousParameter *p;
511 CamDevice::AddParameters(group, index);
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);
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);
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);
533 #endif
536 status_t
537 SonixCamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
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
564 return B_BAD_VALUE;
567 status_t
568 SonixCamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
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;
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
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)));
624 return B_OK;
625 #endif
627 return B_BAD_VALUE;
632 size_t
633 SonixCamDevice::MinRawFrameSize()
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);
644 size_t
645 SonixCamDevice::MaxRawFrameSize()
647 // if (fCompressionEnabled) { ... return ; }
648 return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
652 bool
653 SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
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));
660 // which seems to be the same as of the EOF tag
661 return true;
665 bool
666 SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
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;
674 //PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
675 return true;
679 status_t
680 SonixCamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp /* = NULL */)
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));
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));
701 bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
703 PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
704 *bm = b;
705 return B_OK;
709 status_t
710 SonixCamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
712 CamFrame *f;
713 status_t err;
714 PRINT((CH "()" CT));
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;
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;
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));
731 if (buffer->SizeAvailable() >= (size_t)w*h*4)
732 bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
734 delete f;
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;
744 void
745 /* DEBUG: dump the SN regs */
746 SonixCamDevice::DumpRegs()
748 uint8 regs[SN9C102_REG_COUNT];
749 status_t err;
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]);
765 #if 0
767 status_t
768 SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
769 uint16 index, uint16 length, void* data)
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;
781 #endif
784 SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
785 : CamDeviceAddon(webcam)
787 SetSupportedDevices(kSupportedDevices);
791 SonixCamDeviceAddon::~SonixCamDeviceAddon()
796 const char *
797 SonixCamDeviceAddon::BrandName()
799 return "Sonix";
803 SonixCamDevice *
804 SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
806 return new SonixCamDevice(*this, from);
809 extern "C" status_t
810 B_WEBCAM_MKINTFUNC(sonix)
811 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
813 *addon = new SonixCamDeviceAddon(webcam);
814 return B_OK;
817 // XXX: REMOVE ME
822 * BAYER2RGB24 ROUTINE TAKEN FROM:
824 * Sonix SN9C101 based webcam basic I/F routines
825 * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
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.
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.
849 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
851 long int i;
852 unsigned char *rawpt, *scanpt;
853 long int size;
855 rawpt = src;
856 scanpt = dst;
857 size = WIDTH*HEIGHT;
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 */
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 */
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 */
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 */
917 rawpt++;
922 /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
923 * François Revol
926 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
928 long int i;
929 unsigned char *rawpt, *scanpt;
930 long int size;
932 rawpt = src;
933 scanpt = dst;
934 size = WIDTH*HEIGHT;
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 */
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 */
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 */
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 */
994 rawpt++;
995 scanpt++;