From fb086488a9cfb386e73a31e0303940f0176df11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Fri, 28 Aug 2009 22:08:22 +0000 Subject: [PATCH] - style fixes, - fix error handling in CamDevice.cpp, - implemented PowerOnSensor() for Sonix, - add a ProbeByIICSignature method to CamSensor, that takes a list of regs and values to match, as some Linux drivers do, - add (unfinished, mostly copied from TAS5110C1B) support for TAS5130D1B sensor, - add (unfinished) support for PAS106 sensor, probe by IIC signature as the Linux driver does, - add probing by IIC signature for the HV7131E1 sensor as the Linux driver does, - use -lusb for BeOS (actually ZETA) builds, don't try to use the Haiku USB Kit, - for the TAS5110C1B sensor, use remove code dup and call SetVideoFrame(), tweaked the values to match those sniffed from the XP driver, - disabled gain control for now on sonix, doesn't seem to work on all models. This gets another sonix-based webcam working, partially at least, so if you want to get one to try until UVC works, try this one: http://www.macally.com/EN/product/ArticleShow.asp?ArticleID=119 We should at least have one webcam supported in the alpha :D +alphabranch git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32795 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media-add-ons/usb_webcam/CamDevice.cpp | 2 +- .../media/media-add-ons/usb_webcam/Jamfile | 12 +- .../addons/sonix/SonixCamDevice.cpp | 109 +++++++- .../usb_webcam/addons/sonix/SonixCamDevice.h | 3 + .../usb_webcam/sensors/hv7131e1.cpp | 28 +- .../usb_webcam/sensors/pas106b.cpp | 75 ++++++ .../usb_webcam/sensors/tas5110c1b.cpp | 47 +++- .../usb_webcam/sensors/tas5130d1b.cpp | 242 ++++++++++++++++++ 8 files changed, 489 insertions(+), 29 deletions(-) create mode 100644 src/add-ons/media/media-add-ons/usb_webcam/sensors/pas106b.cpp create mode 100644 src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5130d1b.cpp diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp index 51965b9a15..16406b0518 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp @@ -524,7 +524,7 @@ CamDevice::DataPumpThread() len = fBulkIn->BulkTransfer(fBuffer, fBufferLen); #endif - PRINT((CH ": got %ld bytes" CT, len)); + //PRINT((CH ": got %ld bytes" CT, len)); #ifdef DEBUG_WRITE_DUMP write(fDumpFD, fBuffer, len); #endif diff --git a/src/add-ons/media/media-add-ons/usb_webcam/Jamfile b/src/add-ons/media/media-add-ons/usb_webcam/Jamfile index e2e91f2188..3af246323a 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/Jamfile +++ b/src/add-ons/media/media-add-ons/usb_webcam/Jamfile @@ -6,10 +6,11 @@ SetSubDirSupportedPlatformsBeOSCompatible ; if $(TARGET_PLATFORM_HAIKU_COMPATIBLE) { usbKitLibraryName = libdevice.so ; } else { -# usbKitLibraryName = usb ; - usbKitLibraryName = USBKit.a ; - UsePublicHeaders [ FDirName drivers ] ; - UsePublicHeaders [ FDirName device ] ; +# usbKitLibraryName = USBKit.a ; +# UsePublicHeaders [ FDirName drivers ] ; +# UsePublicHeaders [ FDirName device ] ; + # use -lusb on ZETA + usbKitLibraryName = usb ; } # source directories @@ -38,7 +39,8 @@ csTransformsSources = Bayer.cpp ; ## sensors sources local sensorsSources ; -sensorsSources = hdcs1000.cpp hv7131e1.cpp pb0100.cpp tas5110c1b.cpp ; +sensorsSources = hdcs1000.cpp hv7131e1.cpp pas106b.cpp pb0100.cpp + tas5110c1b.cpp tas5130d1b.cpp ; ## how to build header files from sources to include the list of built-in addons. # but it doesn't seem to work for some reason... diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp index 14d5d40a43..bf7984978e 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp @@ -15,6 +15,7 @@ const usb_webcam_support_descriptor kSupportedDevices[] = { {{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix", "tas5110c1b" }, // mine +{{ 0, 0, 0, 0x0c45, 0x6007 }, "Sonix", "macally ICECAM", "tas5110c1b" }, // Rajah's cam - SN9C101R {{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120", NULL }, {{ 0, 0, 0, 0x0c45, 0x600d }, "Trust", "spacec@m 120", NULL }, @@ -126,10 +127,81 @@ SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) return; } + //XXX: the XP driver sends this to the ICECAM... need to investigate. +#if 1 + uint8 tmp_3[] = { + 0x44, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa0, + 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x41, 0x09, 0x00, 0x16, 0x12, 0x60, 0x86, + 0x3b, 0x0f, 0x0e, 0x06, 0x00, 0x00, 0x03 }; + WriteReg(SN9C102_CHIP_CTRL, tmp_3, 0x1f); +#endif + //XXX:DEBUG + +#if 0 + //XXX: the XP driver sends all this... investigate. + uint8 tmp_1[] = {0x09, 0x44}; + WriteReg(SN9C102_CHIP_CTRL, tmp_1, sizeof(tmp_1)); + WriteReg8(SN9C102_CHIP_CTRL, 0x44); + + WriteReg8(SN9C102_CLOCK_SEL /*0x17*/, 0x29); + + uint8 tmp_2[] = {0x44, 0x44}; + WriteReg(SN9C102_CHIP_CTRL, tmp_2, 2); + //URB_FUNCTION_VENDOR_INTERFACE: + //(USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK) + + uint8 tmp_3[] = { + 0x44, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa0, + 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x41, 0x09, 0x00, 0x16, 0x12, 0x60, 0x86, + 0x3b, 0x0f, 0x0e, 0x06, 0x00, 0x00, 0x03 }; + WriteReg(SN9C102_CHIP_CTRL, tmp_3, 0x1f); + + uint8 tmp_4[] = {0x01, 0x01, 0x07, 0x06}; + //WriteReg(SN9C102_AE_STRX, tmp_4, 4); + + uint8 tmp_5[] = {0x14, 0x0f}; + //WriteReg(SN9C102_H_SIZE, tmp_5, 2); + + WriteReg8(SN9C102_SYNC_N_SCALE, 0x86); + + WriteReg8(SN9C102_CHIP_CTRL, 0x44); // again ?? + + uint8 tmp_6[] = { 0x60, 0x86 }; + WriteReg(SN9C102_CLOCK_SEL /*0x17*/, tmp_6, 2); + + WriteReg8(SN9C102_PIX_CLK, 0x2b); + + // some IIC stuff for the sensor + uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 }; + //WriteReg(SN9C102_I2C_SETUP, tmp_7, 8); + + WriteReg8(SN9C102_PIX_CLK, 0x4b); + + uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16 }; + //WriteReg(SN9C102_I2C_SETUP, tmp_8, 8); + +#endif +#if 0 + // some IIC stuff for the sensor + uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 }; + WriteReg(SN9C102_I2C_SETUP, tmp_7, 8); + + WriteReg8(SN9C102_PIX_CLK, 0x4b); + + uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16}; + WriteReg(SN9C102_I2C_SETUP, tmp_8, 8); +#endif + + //WriteReg8(SN9C102_PIX_CLK, 0x4b); + +//############### if (Sensor()) { PRINT((CH ": CamSensor: %s" CT, Sensor()->Name())); fInitStatus = Sensor()->Setup(); + fVideoFrame = BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1); // SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1)); // SetVideoFrame(BRect(0, 0, 320-1, 240-1)); @@ -205,16 +277,29 @@ DumpRegs(); } +status_t +SonixCamDevice::PowerOnSensor(bool on) +{ + if (OrReg8(SN9C102_CHIP_CTRL, on ? 0x01 : 0x00) < 0) + return EIO; + return B_OK; +} + + ssize_t SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count) { PRINT((CH "(%u, @%p, %u)" CT, address, data, count)); + status_t err; if (address + count > SN9C102_REG_COUNT) { PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count)); return EINVAL; } memcpy(&fCachedRegs[address], data, count); - return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data); + err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data); + if (err < B_OK) + return err; + return count; } @@ -222,6 +307,7 @@ ssize_t SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached) { PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached)); + status_t err; if (address + count > SN9C102_REG_COUNT) { PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count)); return EINVAL; @@ -230,7 +316,10 @@ SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached) memcpy(data, &fCachedRegs[address], count); return count; } - return SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data); + err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data); + if (err < B_OK) + return err; + return count; } @@ -272,6 +361,8 @@ SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count) { status_t err; uint8 buffer[8]; + PRINT((CH "(%u, @%p, %u)" CT, address, data, count)); + if (!Sensor()) return B_NO_INIT; //dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4); @@ -284,7 +375,7 @@ SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count) buffer[2] = address; memset(&buffer[3], 0, 5); memcpy(&buffer[3], data, count-1); - buffer[7] = 0x10; /*0x14;*/ /* absolutely no idea why V4L2 driver use that value */ + buffer[7] = 0x16; /* V4L2 driver uses 0x10, XP driver uses 0x16 ? */ for (int i = 0; i < 8; i++) { PRINT(("[%d] = %02x\n", i, buffer[i])); } @@ -311,6 +402,8 @@ SonixCamDevice::ReadIIC(uint8 address, uint8 *data) { status_t err, lasterr = B_OK; uint8 buffer[8]; + PRINT((CH "(%u, @%p)" CT, address, data)); + if (!Sensor()) return B_NO_INIT; //dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4); @@ -321,7 +414,7 @@ SonixCamDevice::ReadIIC(uint8 address, uint8 *data) buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */ err = WriteReg(SN9C102_I2C_SETUP, buffer, 8); //dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err); - if (err) return err; + if (err < 8) return EIO; err = WaitReadyIIC(); //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err); //if (err) return err; @@ -334,17 +427,17 @@ SonixCamDevice::ReadIIC(uint8 address, uint8 *data) buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */ err = WriteReg(SN9C102_I2C_SETUP, buffer, 8); //dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err); - if (err) return err; + if (err < 8) return EIO; err = WaitReadyIIC(); //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err); - if (err) return err; + if (err < B_OK) return err; err = ReadReg(SN9C102_I2C_DATA0, buffer, 5); - if (err) lasterr = err; + if (err < 5) return EIO; err = GetStatusIIC(); //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err); - if (err) return err; + if (err < B_OK) return err; //dprintf(ID "sonix_i2c_write_multi: succeeded\n"); if (lasterr) return err; diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h index 3676b10936..d9b4a21c2c 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h @@ -64,6 +64,9 @@ class SonixCamDevice : public CamDevice virtual status_t StartTransfer(); virtual status_t StopTransfer(); + // sensor chip handling + virtual status_t PowerOnSensor(bool on); + // generic register-like access virtual ssize_t WriteReg(uint16 address, uint8 *data, size_t count=1); virtual ssize_t ReadReg(uint16 address, uint8 *data, size_t count=1, bool cached=false); diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1.cpp index 6cdd77503f..dadf06de0d 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1.cpp +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1.cpp @@ -5,33 +5,53 @@ #include "CamSensor.h" +static const uint8 sProbeAddressList[] = { + 0x00,0x01,0x02,0x11,0x13,0x14,0x15,0x16,0x17 +}; +static const uint8 sProbeMatchList[] = { + 0x02,0x09,0x01,0x02,0x02,0x01,0xe2,0x02,0x82 +}; + class HV7131E1Sensor : public CamSensor { public: HV7131E1Sensor(CamDevice *_camera); ~HV7131E1Sensor(); + status_t Probe(); const char* Name(); +//XXX not sure + virtual bool Use400kHz() const { return false; }; + virtual bool UseRealIIC() const { return false; }; + }; -// ----------------------------------------------------------------------------- + HV7131E1Sensor::HV7131E1Sensor(CamDevice *_camera) : CamSensor(_camera) { } -// ----------------------------------------------------------------------------- + HV7131E1Sensor::~HV7131E1Sensor() { } -// ----------------------------------------------------------------------------- + +status_t +HV7131E1Sensor::Probe() +{ + return ProbeByIICSignature(sProbeAddressList, sProbeMatchList, + sizeof(sProbeMatchList)); +} + + const char * HV7131E1Sensor::Name() { return "Hynix hv7131e1"; } -// ----------------------------------------------------------------------------- + B_WEBCAM_DECLARE_SENSOR(HV7131E1Sensor, hv7131e1) diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/pas106b.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/pas106b.cpp new file mode 100644 index 0000000000..87ad9ac46f --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/pas106b.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2004-2008, François Revol, . + * Distributed under the terms of the MIT License. + */ + +#include "CamDebug.h" +#include "CamSensor.h" +#include "addons/sonix/SonixCamDevice.h" + +//XXX: unfinished! + +static const uint8 sProbeAddressList[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x10 +}; +static const uint8 sProbeMatchList[] = { + 0x70,0x02,0x12,0x05,0x05,0x06,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x06 +}; + +class PAS106BSensor : public CamSensor { +public: + PAS106BSensor(CamDevice *_camera); + ~PAS106BSensor(); + status_t Probe(); + const char* Name(); + + virtual bool Use400kHz() const { return true; }; // supports both + virtual bool UseRealIIC() const { return true; }; + +private: + bool fIsSonix; +}; + + +PAS106BSensor::PAS106BSensor(CamDevice *_camera) +: CamSensor(_camera) +{ + fIsSonix = (dynamic_cast(_camera) != NULL); + if (fIsSonix) { + fInitStatus = B_OK; + } else { + PRINT((CH ": unknown camera device!" CT)); + fInitStatus = ENODEV; + } +} + + +PAS106BSensor::~PAS106BSensor() +{ +} + + +status_t +PAS106BSensor::Probe() +{ + Device()->PowerOnSensor(false); + Device()->PowerOnSensor(true); + if (fIsSonix) { + Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x00); /* power on the sensor, Fsys_clk=12MHz */ + Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x17); /* enable sensor, force 24MHz */ + } + + return ProbeByIICSignature(sProbeAddressList, sProbeMatchList, + sizeof(sProbeMatchList)); +} + + +const char * +PAS106BSensor::Name() +{ + return "PixArt Imaging pas106b"; +} + + +B_WEBCAM_DECLARE_SENSOR(PAS106BSensor, pas106b) + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b.cpp index 26fbb52314..83d2ba1e56 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b.cpp +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b.cpp @@ -9,18 +9,20 @@ #include "CamDebug.h" #include "addons/sonix/SonixCamDevice.h" -#define ENABLE_GAIN 1 +//#define ENABLE_GAIN 1 + class TAS5110C1BSensor : public CamSensor { public: TAS5110C1BSensor(CamDevice *_camera); ~TAS5110C1BSensor(); + virtual status_t Probe(); virtual status_t Setup(); const char *Name(); virtual bool Use400kHz() const { return false; }; - virtual bool UseRealIIC() const { return false; }; + virtual bool UseRealIIC() const { return true /*false*/; }; virtual uint8 IICReadAddress() const { return 0x00; }; - virtual uint8 IICWriteAddress() const { return 0x11; /*0xff;*/ }; + virtual uint8 IICWriteAddress() const { return 0x61; /*0x11;*/ /*0xff;*/ }; virtual int MaxWidth() const { return 352; }; virtual int MaxHeight() const { return 288; }; @@ -56,43 +58,66 @@ TAS5110C1BSensor::~TAS5110C1BSensor() } +status_t +TAS5110C1BSensor::Probe() +{ + PRINT((CH "()" CT)); + + return B_OK; +} + + status_t TAS5110C1BSensor::Setup() { PRINT((CH "()" CT)); if (InitCheck()) return InitCheck(); + Device()->PowerOnSensor(false); + Device()->PowerOnSensor(true); if (fIsSonix) { +#if 1 Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x01); /* power down the sensor */ Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x44); /* power up the sensor, enable tx, sysclk@24MHz */ + Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x04); /* power up the sensor, enable tx, sysclk@24MHz */ Device()->WriteReg8(SN9C102_R_B_GAIN, 0x00); /* red, blue gain = 1+0/8 = 1 */ Device()->WriteReg8(SN9C102_G_GAIN, 0x00); /* green gain = 1+0/8 = 1 */ Device()->WriteReg8(SN9C102_OFFSET, 0x0a); /* 10 pix offset */ Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x60); /* enable sensor clk, and invert it */ + Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x60); /* enable sensor clk, and invert it */ Device()->WriteReg8(SN9C102_SYNC_N_SCALE, 0x06); /* no compression, normal curve, * no scaling, vsync active low, * v/hsync change at rising edge, * falling edge of sensor pck */ Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb); /* pixclk = 2 * masterclk, sensor is slave mode */ + + // some IIC stuff for the sensor + // though it seems more data is sent than told the controller + // this is what the XP driver sends to the ICECAM... + uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 }; + Device()->WriteReg(SN9C102_I2C_SETUP, tmp_7, 8); + + Device()->WriteReg8(SN9C102_PIX_CLK, 0x4b); + + uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16 }; + Device()->WriteReg(SN9C102_I2C_SETUP, tmp_8, 8); + +#endif } if (fIsSonix) { //sonix_i2c_write_multi(dev, dev->sensor->i2c_wid, 2, 0xc0, 0x80, 0, 0, 0); /* AEC = 0x203 ??? */ - Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */ + //Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */ + //Device()->WriteIIC8(0x1c, 0x80); /* AEC = 0x203 ??? */ // set crop Device()->WriteReg8(SN9C102_H_SIZE, 69); Device()->WriteReg8(SN9C102_V_SIZE, 9); - Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb); - Device()->WriteReg8(SN9C102_HO_SIZE, 0x14); - Device()->WriteReg8(SN9C102_VO_SIZE, 0x0a); - fVideoFrame.Set(0, 0, 352-1, 288-1); - /* HACK: TEST IMAGE */ - //Device()->WriteReg8(SN_CLOCK_SEL, 0x70); /* enable sensor clk, and invert it, test img */ + SetVideoFrame(BRect(0, 0, 352-1, 288-1)); } - + //Device()->SetScale(1); return B_OK; diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5130d1b.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5130d1b.cpp new file mode 100644 index 0000000000..95eb582045 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5130d1b.cpp @@ -0,0 +1,242 @@ +/* + * Copyright 2004-2008, François Revol, . + * Distributed under the terms of the MIT License. + */ + +#include + +#include "CamSensor.h" +#include "CamDebug.h" +#include "addons/sonix/SonixCamDevice.h" + +//XXX: unfinished! + +#define ENABLE_GAIN 1 + + +class TAS5130D1BSensor : public CamSensor { +public: + TAS5130D1BSensor(CamDevice *_camera); + ~TAS5130D1BSensor(); + virtual status_t Probe(); + virtual status_t Setup(); + const char *Name(); + virtual bool Use400kHz() const { return false; }; + virtual bool UseRealIIC() const { return false; }; + virtual uint8 IICReadAddress() const { return 0x00; }; + virtual uint8 IICWriteAddress() const { return 0x11; /*0xff;*/ }; + + virtual int MaxWidth() const { return 640; }; + virtual int MaxHeight() const { return 480; }; + + virtual status_t AcceptVideoFrame(uint32 &width, uint32 &height); + virtual status_t SetVideoFrame(BRect rect); + virtual void AddParameters(BParameterGroup *group, int32 &firstID); + virtual status_t GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size); + virtual status_t SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size); + +private: + bool fIsSonix; + float fGain; +}; + + +TAS5130D1BSensor::TAS5130D1BSensor(CamDevice *_camera) +: CamSensor(_camera) +{ + fIsSonix = (dynamic_cast(_camera) != NULL); + if (fIsSonix) { + fInitStatus = B_OK; + } else { + PRINT((CH ": unknown camera device!" CT)); + fInitStatus = ENODEV; + } + fGain = (float)0x40; // default +} + + +TAS5130D1BSensor::~TAS5130D1BSensor() +{ +} + + +status_t +TAS5130D1BSensor::Probe() +{ + PRINT((CH "()" CT)); + + return B_OK; +} + + +status_t +TAS5130D1BSensor::Setup() +{ + PRINT((CH "()" CT)); + if (InitCheck()) + return InitCheck(); + /* + Device()->PowerOnSensor(false); + Device()->PowerOnSensor(true); + */ + if (fIsSonix) { + // linux driver seems to do this, but doesn't say why + Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x01); /* power down the sensor */ + Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x20); /* enable sensor clk */ + Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x04); /* power up the sensor, enable tx, sysclk@12MHz */ + Device()->WriteReg8(SN9C102_R_B_GAIN, 0x01); /* red gain = 1+0/8 = 1, red gain = 1+1/8 !!? */ + Device()->WriteReg8(SN9C102_G_GAIN, 0x00); /* green gain = 1+0/8 = 1 */ + Device()->WriteReg8(SN9C102_OFFSET, 0x0a); /* 0 pix offset */ + Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x60); /* enable sensor clk, and invert it */ + Device()->WriteReg8(SN9C102_SYNC_N_SCALE, 0x06); /* no compression, normal curve, + * no scaling, vsync active low, + * v/hsync change at rising edge, + * raising edge of sensor pck */ + Device()->WriteReg8(SN9C102_PIX_CLK, 0xf3); /* pixclk = masterclk, sensor is slave mode */ + } + + + if (fIsSonix) { + //sonix_i2c_write_multi(dev, dev->sensor->i2c_wid, 2, 0xc0, 0x80, 0, 0, 0); /* AEC = 0x203 ??? */ +#if 0 + Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */ +#endif + +#if 1 + Device()->WriteIIC8(0x20, 0xf6 - 0xd0); /* GAIN */ + Device()->WriteIIC8(0x40, 0x47 - 0x40); /* Exposure */ + // set crop + Device()->WriteReg8(SN9C102_H_SIZE, 104); + Device()->WriteReg8(SN9C102_V_SIZE, 12); + SetVideoFrame(BRect(0, 0, 320-1, 240-1)); +#endif + +#if 0 +//XXX + Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */ + Device()->WriteReg8(SN9C102_H_SIZE, 69); + Device()->WriteReg8(SN9C102_V_SIZE, 9); + SetVideoFrame(BRect(0, 0, 352-1, 288-1)); +#endif + + } + + //Device()->SetScale(1); + + return B_OK; +} + + +const char * +TAS5130D1BSensor::Name() +{ + return "TASC tas5130d1b"; +} + + +status_t +TAS5130D1BSensor::AcceptVideoFrame(uint32 &width, uint32 &height) +{ + // default sanity checks + status_t err = CamSensor::AcceptVideoFrame(width, height); + if (err < B_OK) + return err; + // must be modulo 16 + width /= 16; + width *= 16; + height /= 16; + height *= 16; + return B_OK; +} + + +status_t +TAS5130D1BSensor::SetVideoFrame(BRect rect) +{ + if (fIsSonix) { + // set crop + Device()->WriteReg8(SN9C102_H_START, /*rect.left + */104); + Device()->WriteReg8(SN9C102_V_START, /*rect.top + */12); + Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb); + Device()->WriteReg8(SN9C102_HO_SIZE, 0x14); + Device()->WriteReg8(SN9C102_VO_SIZE, 0x0a); +#if 0 + Device()->WriteReg8(SN9C102_H_START, /*rect.left + */104); + Device()->WriteReg8(SN9C102_V_START, /*rect.top + */12); + Device()->WriteReg8(SN9C102_PIX_CLK, 0xf3); + Device()->WriteReg8(SN9C102_HO_SIZE, 0x1f); + Device()->WriteReg8(SN9C102_VO_SIZE, 0x1a); +#endif + fVideoFrame = rect; + /* HACK: TEST IMAGE */ + //Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x70); /* enable sensor clk, and invert it, test img */ + + } + + return B_OK; +} + + +void +TAS5130D1BSensor::AddParameters(BParameterGroup *group, int32 &index) +{ + BContinuousParameter *p; + CamSensor::AddParameters(group, index); + +#ifdef ENABLE_GAIN + // NON-FUNCTIONAL + BParameterGroup *g = group->MakeGroup("global gain"); + p = g->MakeContinuousParameter(index++, + B_MEDIA_RAW_VIDEO, "global gain", + B_GAIN, "", (float)0x00, (float)0xf6, (float)1); +#endif +} + + +status_t +TAS5130D1BSensor::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size) +{ +#ifdef ENABLE_GAIN + if (id == fFirstParameterID) { + *size = sizeof(float); + *((float *)value) = fGain; + *last_change = fLastParameterChanges; + } +#endif + return B_BAD_VALUE; +} + + +status_t +TAS5130D1BSensor::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size) +{ +#ifdef ENABLE_GAIN + if (id == fFirstParameterID) { + if (!value || (size != sizeof(float))) + return B_BAD_VALUE; + if (*(float *)value == fGain) + return B_OK; + fGain = *(float *)value; + fLastParameterChanges = when; + PRINT((CH ": gain: %f" CT, fGain)); + + if (fIsSonix) { + // some drivers do: + //Device()->WriteIIC8(0x20, (uint8)0xf6 - (uint8)fGain); + // but it doesn't seem to work + + // works, not sure why yet, XXX check datasheet for AEG/AEC + uint8 buf[2] = { 0x20, 0x70 }; + buf[1] = (uint8)0xff - (uint8)fGain; + Device()->WriteIIC(0x02, buf, 2); + } + + return B_OK; + } +#endif + return B_BAD_VALUE; +} + + +B_WEBCAM_DECLARE_SENSOR(TAS5130D1BSensor, tas5130d1b) +