2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
6 #include "SonixCamDevice.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
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
}
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 */
86 fRGain
= fGGain
= fBGain
= 0;
90 memset(fCachedRegs
, 0, SN9C102_REG_COUNT
);
92 if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) {
93 fChipVersion
= 3; // says V4L2
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
);
105 const BUSBConfiguration
*config
= GetDevice()->ConfigurationAt(0);
107 const BUSBInterface
*inter
= config
->InterfaceAt(0);
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()) {
116 PRINT((CH
": Using inter[0].endpoint[%d]; maxpktsz: %d" CT
, i
, e
->MaxPacketSize()));
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));
130 //XXX: the XP driver sends this to the ICECAM... need to investigate.
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);
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)
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);
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);
197 //WriteReg8(SN9C102_PIX_CLK, 0x4b);
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));
213 SonixCamDevice::~SonixCamDevice()
222 SonixCamDevice::SupportsBulk()
229 SonixCamDevice::SupportsIsochronous()
236 SonixCamDevice::StartTransfer()
243 SetVideoFrame(fVideoFrame
);
245 //SetVideoFrame(BRect(0, 0, 320-1, 240-1));
248 err
= ReadReg(SN9C102_CHIP_CTRL
, &r
, 1, true);
252 err
= WriteReg8(SN9C102_CHIP_CTRL
, r
);
255 return CamDevice::StartTransfer();
260 SonixCamDevice::StopTransfer()
266 err
= CamDevice::StopTransfer();
269 err
= ReadReg(SN9C102_CHIP_CTRL
, &r
, 1, true);
273 err
= WriteReg8(SN9C102_CHIP_CTRL
, r
);
281 SonixCamDevice::PowerOnSensor(bool on
)
283 if (OrReg8(SN9C102_CHIP_CTRL
, on
? 0x01 : 0x00) < 0)
290 SonixCamDevice::WriteReg(uint16 address
, uint8
*data
, size_t count
)
292 PRINT((CH
"(%u, @%p, %u)" CT
, address
, data
, count
));
294 if (address
+ count
> SN9C102_REG_COUNT
) {
295 PRINT((CH
": Invalid register range [%u;%u]" CT
, address
, address
+count
));
298 memcpy(&fCachedRegs
[address
], data
, count
);
299 err
= SendCommand(USB_REQTYPE_DEVICE_OUT
, 0x08, address
, 0, count
, data
);
307 SonixCamDevice::ReadReg(uint16 address
, uint8
*data
, size_t count
, bool cached
)
309 PRINT((CH
"(%u, @%p, %u, %d)" CT
, address
, data
, count
, cached
));
311 if (address
+ count
> SN9C102_REG_COUNT
) {
312 PRINT((CH
": Invalid register range [%u;%u]" CT
, address
, address
+count
));
316 memcpy(data
, &fCachedRegs
[address
], count
);
319 err
= SendCommand(USB_REQTYPE_DEVICE_IN
, 0x00, address
, 0, count
, data
);
327 SonixCamDevice::GetStatusIIC()
331 err
= ReadReg(SN9C102_I2C_SETUP
, &status
);
332 //dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
335 return (status
&0x08)?EIO
:0;
340 SonixCamDevice::WaitReadyIIC()
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);
360 SonixCamDevice::WriteIIC(uint8 address
, uint8
*data
, size_t count
)
364 PRINT((CH
"(%u, @%p, %u)" CT
, address
, data
, count
));
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
372 buffer
[0] = ((count
) << 4) | (Sensor()->Use400kHz()?0x01:0)
373 | (Sensor()->UseRealIIC()?0x80:0);
374 buffer
[1] = Sensor()->IICWriteAddress();
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)));
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)));
394 //dprintf(ID "sonix_i2c_write_multi: succeeded\n");
395 PRINT((CH
": success" CT
));
401 SonixCamDevice::ReadIIC(uint8 address
, uint8
*data
)
403 status_t err
, lasterr
= B_OK
;
405 PRINT((CH
"(%u, @%p)" CT
, address
, data
));
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();
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?
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
);
468 Sensor()->SetVideoFrame(frame
);
470 return CamDevice::SetVideoFrame(frame
);
475 SonixCamDevice::SetScale(float scale
)
479 int iscale
= (int)scale
;
481 PRINT((CH
"(%u)" CT
, iscale
));
482 err
= ReadReg(SN9C102_SYNC_N_SCALE
, &r
, 1, true);
490 r
|= ((iscale
-1) << 4);
495 err
= WriteReg8(SN9C102_SYNC_N_SCALE
, r
);
501 SonixCamDevice::SetVideoParams(float brightness
, float contrast
, float hue
, float red
, float green
, float blue
)
507 SonixCamDevice::AddParameters(BParameterGroup
*group
, int32
&index
)
510 BContinuousParameter
*p
;
511 CamDevice::AddParameters(group
, index
);
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);
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);
537 SonixCamDevice::GetParameterValue(int32 id
, bigtime_t
*last_change
, void *value
, size_t *size
)
540 switch (id
- fFirstParameterID
) {
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
;
551 *size
= sizeof(float);
552 gains
= ((float *)value
);
553 gains
[0] = fContrast
;
554 *last_change
= fLastParameterChanges
;
557 *size
= sizeof(float);
558 gains
= ((float *)value
);
559 gains
[0] = fBrightness
;
560 *last_change
= fLastParameterChanges
;
568 SonixCamDevice::SetParameterValue(int32 id
, bigtime_t when
, const void *value
, size_t size
)
571 switch (id
- fFirstParameterID
) {
573 if (!value
|| (size
!= 3 * sizeof(float)))
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))
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 */
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.
594 WriteReg8(SN9C102_R_GAIN
, fRGain
);
595 WriteReg8(SN9C102_B_GAIN
, fBGain
);
596 if (fChipVersion
>= 3)
597 WriteReg8(SN9C103_G_GAIN
, fGGain
);
599 WriteReg8(SN9C102_G_GAIN
, (fGGain
/ 16));
603 buf
[0] = (fBGain
<< 4) | fRGain
;
605 WriteReg(SN9C102_R_B_GAIN
, buf
, 2);
610 if (!value
|| (size
!= sizeof(float)))
612 gains
= ((float *)value
);
613 fContrast
= gains
[0];
614 WriteReg8(SN9C10x_CONTRAST
, ((uint8
)(fContrast
* 256)));
617 if (!value
|| (size
!= sizeof(float)))
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)));
633 SonixCamDevice::MinRawFrameSize()
635 // if (fCompressionEnabled) { ... return ; }
636 BRect
vf(VideoFrame());
637 int w
= vf
.IntegerWidth()+1;
638 int h
= vf
.IntegerHeight()+1;
640 return (size_t)(w
*h
);
645 SonixCamDevice::MaxRawFrameSize()
647 // if (fCompressionEnabled) { ... return ; }
648 return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
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
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));
674 //PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
680 SonixCamDevice::GetFrameBitmap(BBitmap
**bm
, bigtime_t
*stamp
/* = NULL */)
686 err
= fDeframer
->WaitFrame(200000);
687 if (err
< B_OK
) { PRINT((CH
": WaitFrame: %s" CT
, strerror(err
))); }
690 err
= fDeframer
->GetFrame(&f
, stamp
);
691 if (err
< B_OK
) { PRINT((CH
": GetFrame: %s" CT
, strerror(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()));
710 SonixCamDevice::FillFrameBuffer(BBuffer
*buffer
, bigtime_t
*stamp
)
716 memset(buffer
->Data(), 0, buffer
->SizeAvailable());
717 err
= fDeframer
->WaitFrame(2000000);
718 if (err
< B_OK
) { PRINT((CH
": WaitFrame: %s" CT
, strerror(err
))); }
722 err
= fDeframer
->GetFrame(&f
, stamp
);
723 if (err
< B_OK
) { PRINT((CH
": GetFrame: %s" CT
, strerror(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
);
736 PRINT((CH
": available %d, required %d" CT
, buffer
->SizeAvailable(), w
*h
*4));
737 if (buffer
->SizeAvailable() < (size_t)w
*h
*4)
739 PRINT((CH
": got 1 frame (len %d)" CT
, buffer
->SizeUsed()));
745 /* DEBUG: dump the SN regs */
746 SonixCamDevice::DumpRegs()
748 uint8 regs
[SN9C102_REG_COUNT
];
751 //err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
752 err
= ReadReg(0, regs
, SN9C102_REG_COUNT
);
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]);
768 SonixCamDevice::SendCommand(uint8 dir
, uint8 request
, uint16 value
,
769 uint16 index
, uint16 length
, void* data
)
774 if (length
> GetDevice()->MaxEndpoint0PacketSize())
776 ret
= GetDevice()->ControlTransfer(
777 USB_REQTYPE_VENDOR
| USB_REQTYPE_INTERFACE_OUT
| dir
,
778 request
, value
, index
, length
, data
);
784 SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn
* webcam
)
785 : CamDeviceAddon(webcam
)
787 SetSupportedDevices(kSupportedDevices
);
791 SonixCamDeviceAddon::~SonixCamDeviceAddon()
797 SonixCamDeviceAddon::BrandName()
804 SonixCamDeviceAddon::Instantiate(CamRoster
&roster
, BUSBDevice
*from
)
806 return new SonixCamDevice(*this, from
);
810 B_WEBCAM_MKINTFUNC(sonix
)
811 (WebCamMediaAddOn
* webcam
, CamDeviceAddon
**addon
)
813 *addon
= new SonixCamDeviceAddon(webcam
);
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
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
849 void bayer2rgb24(unsigned char *dst
, unsigned char *src
, long int WIDTH
, long int HEIGHT
)
852 unsigned char *rawpt
, *scanpt
;
859 for ( i
= 0; i
< size
; i
++ ) {
860 if ( (i
/WIDTH
) % 2 == 0 ) {
861 if ( (i
% 2) == 0 ) {
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 */
870 /* first line or left column */
871 *scanpt
++ = *(rawpt
+WIDTH
+1); /* R */
872 *scanpt
++ = (*(rawpt
+1)+*(rawpt
+WIDTH
))/2; /* G */
873 *scanpt
++ = *rawpt
; /* B */
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 */
882 /* first line or right column */
883 *scanpt
++ = *(rawpt
+WIDTH
); /* R */
884 *scanpt
++ = *rawpt
; /* G */
885 *scanpt
++ = *(rawpt
-1); /* B */
889 if ( (i
% 2) == 0 ) {
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 */
896 /* bottom line or left column */
897 *scanpt
++ = *(rawpt
+1); /* R */
898 *scanpt
++ = *rawpt
; /* G */
899 *scanpt
++ = *(rawpt
-WIDTH
); /* B */
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 */
910 /* bottom line or right column */
911 *scanpt
++ = *rawpt
; /* R */
912 *scanpt
++ = (*(rawpt
-1)+*(rawpt
-WIDTH
))/2; /* G */
913 *scanpt
++ = *(rawpt
-WIDTH
-1); /* B */
922 /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
926 void bayer2rgb32le(unsigned char *dst
, unsigned char *src
, long int WIDTH
, long int HEIGHT
)
929 unsigned char *rawpt
, *scanpt
;
936 for ( i
= 0; i
< size
; i
++ ) {
937 if ( (i
/WIDTH
) % 2 == 0 ) {
938 if ( (i
% 2) == 0 ) {
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 */
947 /* first line or left column */
948 *scanpt
++ = *rawpt
; /* B */
949 *scanpt
++ = (*(rawpt
+1)+*(rawpt
+WIDTH
))/2; /* G */
950 *scanpt
++ = *(rawpt
+WIDTH
+1); /* R */
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 */
959 /* first line or right column */
960 *scanpt
++ = *(rawpt
-1); /* B */
961 *scanpt
++ = *rawpt
; /* G */
962 *scanpt
++ = *(rawpt
+WIDTH
); /* R */
966 if ( (i
% 2) == 0 ) {
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 */
973 /* bottom line or left column */
974 *scanpt
++ = *(rawpt
-WIDTH
); /* B */
975 *scanpt
++ = *rawpt
; /* G */
976 *scanpt
++ = *(rawpt
+1); /* 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 */
987 /* bottom line or right column */
988 *scanpt
++ = *(rawpt
-WIDTH
-1); /* B */
989 *scanpt
++ = (*(rawpt
-1)+*(rawpt
-WIDTH
))/2; /* G */
990 *scanpt
++ = *rawpt
; /* R */