Turns out my QuickCam is not a usual quickcam with an WTV600 chip but an NW80x based one...

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25321 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol 2008-05-05 17:58:51 +00:00
parent 74b3713ab9
commit d55e0f83f2
13 changed files with 578 additions and 12 deletions

View File

@ -359,6 +359,28 @@ CamDevice::WriteIIC16(uint8 address, uint16 data)
ssize_t
CamDevice::ReadIIC(uint8 address, uint8 *data)
{
//TODO: make it mode generic
return ENOSYS;
}
ssize_t
CamDevice::ReadIIC8(uint8 address, uint8 *data)
{
return ReadIIC(address, data);
}
ssize_t
CamDevice::ReadIIC16(uint8 address, uint16 *data)
{
return ENOSYS;
}
status_t
CamDevice::SetIICBitsMode(size_t bits)
{
return ENOSYS;
}

View File

@ -99,6 +99,9 @@ class CamDevice {
virtual ssize_t WriteIIC8(uint8 address, uint8 data);
virtual ssize_t WriteIIC16(uint8 address, uint16 data);
virtual ssize_t ReadIIC(uint8 address, uint8 *data);
virtual ssize_t ReadIIC8(uint8 address, uint8 *data);
virtual ssize_t ReadIIC16(uint8 address, uint16 *data);
virtual status_t SetIICBitsMode(size_t bits=8);
void SetDataInput(BDataIO *input);

View File

@ -27,7 +27,7 @@ class CamSensor
virtual bool Use400kHz() const { return false; };
virtual bool UseRealIIC() const { return true; };
virtual uint8 IICReadAddress() const { return 0; };
virtual uint8 IICWriteAddress() const { return 0; };;
virtual uint8 IICWriteAddress() const { return 0; };
virtual int MaxWidth() const { return -1; };
virtual int MaxHeight() const { return -1; };

View File

@ -16,6 +16,7 @@ if $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
local sourceDirs =
addons/quickcam
addons/sonix
addons
cstransforms
sensors
;
@ -28,7 +29,7 @@ for sourceDir in $(sourceDirs) {
## addon sources
local addonSources ;
addonSources = QuickCamDevice.cpp SonixCamDevice.cpp ;
addonSources = QuickCamDevice.cpp SonixCamDevice.cpp NW80xCamDevice.cpp ;
## colorspace transforms sources
local csTransformsSources ;

View File

@ -64,11 +64,13 @@ http://www.mnementh.co.uk/sonix/sn9c102.pdf
* some of the (many!) linux quickcam drivers:
http://www.lrr.in.tum.de/~acher/quickcam/quickcam.html
http://www.seismo.ethz.ch/linux/webcam.html
http://tuukkat.awardspace.com/quickcam/quickcam.html for PID 0xd001
* Creative's own list of linux drivers:
http://connect.creativelabs.com/opensource/Lists/Webcam%20Support/AllItems.aspx
* Other webcam drivers:
http://nw802.cvs.sourceforge.net NW80x based (like the QuickCam I have here)
http://zc0302.sourceforge.net/zc0302.php?page=cams
http://www.medias.ne.jp/~takam/bsd/NetBSD.html

View File

@ -0,0 +1,298 @@
#include "NW80xCamDevice.h"
#include "CamDebug.h"
#include "CamSensor.h"
// reference: http://nw802.cvs.sourceforge.net
const usb_webcam_support_descriptor kSupportedDevices[] = {
{{ 0, 0, 0, 0x046d, 0xd001 }, "Logitech", "QuickCam Pro", "??" }, // Alan's
// other IDs according to nw802 linux driver:
{{ 0, 0, 0, 0x052b, 0xd001 }, "Ezonics", "EZCam Pro", "??" },
{{ 0, 0, 0, 0x055f, 0xd001 }, "Mustek"/*"PCLine"*/, "WCam 300"/*"PCL-W300"*/, "??" },
{{ 0, 0, 0, 0x06a5, 0xd001 }, "Generic", "NW802", "??" },
{{ 0, 0, 0, 0x06a5, 0x0000 }, "Generic", "NW800", "??" },
{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
};
#warning TODO!
NW80xCamDevice::NW80xCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
:CamDevice(_addon, _device)
{
status_t err;
// linux seems to infer this sets I2C controller to 8 or 16 bit mode...
// sensors will set to the mode they want when probing
SetIICBitsMode(8);
err = ProbeSensor();
if (err < B_OK) {
// reset I2C mode to 8 bit as linux driver does
SetIICBitsMode(8);
// not much we can do anyway
}
fInitStatus = B_OK;
}
NW80xCamDevice::~NW80xCamDevice()
{
}
bool
NW80xCamDevice::SupportsBulk()
{
return true;
}
bool
NW80xCamDevice::SupportsIsochronous()
{
return true;
}
status_t
NW80xCamDevice::StartTransfer()
{
status_t err;
uint8 r;
SetScale(1);
if (Sensor())
SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
//SetVideoFrame(BRect(0, 0, 320-1, 240-1));
DumpRegs();
#if 0
err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
if (err < 0)
return err;
r |= 0x04;
err = WriteReg8(SN9C102_CHIP_CTRL, r);
if (err < 0)
return err;
#endif
return CamDevice::StartTransfer();
}
status_t
NW80xCamDevice::StopTransfer()
{
status_t err;
uint8 r;
DumpRegs();
err = CamDevice::StopTransfer();
#if 0
// if (err < 0)
// return err;
err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
if (err < 0)
return err;
r &= ~0x04;
err = WriteReg8(SN9C102_CHIP_CTRL, r);
if (err < 0)
return err;
#endif
return err;
}
ssize_t
NW80xCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
{
PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, address, 0, count, data);
}
ssize_t
NW80xCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
{
PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
memset(data, 0xaa, count); // linux drivers do that without explaining why !?
return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data);
}
status_t
NW80xCamDevice::GetStatusIIC()
{
status_t err;
uint8 status = 0;
#warning WRITEME
//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
if (err < 0)
return err;
return (status&0x08)?EIO:0;
}
status_t
NW80xCamDevice::WaitReadyIIC()
{
status_t err;
#warning WRITEME
return EBUSY;
}
ssize_t
NW80xCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
{
status_t err;
int i;
uint8 buffer[0x23];
if (count > 16)
return EINVAL;
memset(buffer, 0, sizeof(buffer));
buffer[0x20] = Sensor() ? Sensor()->IICWriteAddress() : 0;
buffer[0x21] = count - 1;
buffer[0x22] = 0x01;
for (i = 0; i < count; i++) {
buffer[i] = address + i;
buffer[i+16] = data[i];
}
return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
}
ssize_t
NW80xCamDevice::ReadIIC(uint8 address, uint8 *data)
{
return ReadIIC(address, data);
}
ssize_t
NW80xCamDevice::ReadIIC8(uint8 address, uint8 *data)
{
status_t err;
int i;
uint8 buffer[0x23];
memset(buffer, 0, sizeof(buffer));
buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
buffer[0x21] = 1 - 1;
buffer[0x22] = 0x03;
buffer[0] = address;
err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
PRINT((CH ": SendCommand: %s" CT, strerror(err)));
if (err < B_OK)
return err;
buffer[0] = 0xaa;
err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
PRINT((CH ": SendCommand: %s" CT, strerror(err)));
if (err < B_OK)
return err;
*data = buffer[0];
PRINT((CH ": 0x%02x" CT, *data));
return 1;
}
ssize_t
NW80xCamDevice::ReadIIC16(uint8 address, uint16 *data)
{
status_t err;
int i;
uint8 buffer[0x23];
memset(buffer, 0, sizeof(buffer));
buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
buffer[0x21] = 1 - 1;
buffer[0x22] = 0x03;
buffer[0] = address;
err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
if (err < B_OK)
return err;
buffer[0] = 0xaa;
buffer[1] = 0xaa;
err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
PRINT((CH ": SendCommand: %s" CT, strerror(err)));
if (err < B_OK)
return err;
if (fChipIsBigEndian)
*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
else
*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
PRINT((CH ": 0x%04x" CT, *data));
return 2;
}
status_t
NW80xCamDevice::SetIICBitsMode(size_t bits)
{
switch (bits) {
case 8:
WriteReg8(STV_REG23, 0);
break;
case 16:
WriteReg8(STV_REG23, 1);
break;
default:
return EINVAL;
}
return B_OK;
}
status_t
NW80xCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
uint16 index, uint16 length, void* data)
{
size_t ret;
if (!GetDevice())
return ENODEV;
if (length > GetDevice()->MaxEndpoint0PacketSize())
return EINVAL;
ret = GetDevice()->ControlTransfer(
USB_REQTYPE_VENDOR | dir,
request, value, index, length, data);
return ret;
}
NW80xCamDeviceAddon::NW80xCamDeviceAddon(WebCamMediaAddOn* webcam)
: CamDeviceAddon(webcam)
{
SetSupportedDevices(kSupportedDevices);
}
NW80xCamDeviceAddon::~NW80xCamDeviceAddon()
{
}
const char *
NW80xCamDeviceAddon::BrandName()
{
return "NW80x-based";
}
NW80xCamDevice *
NW80xCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
{
return new NW80xCamDevice(*this, from);
}
extern "C" status_t
B_WEBCAM_MKINTFUNC(nw80xcam)
(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
{
*addon = new NW80xCamDeviceAddon(webcam);
return B_OK;
}

View File

@ -0,0 +1,66 @@
#ifndef _NW80X_CAM_DEVICE_H
#define _NW80X_CAM_DEVICE_H
#include "CamDevice.h"
#define STV_REG_COUNT 0x0c
// Control registers of the STV0600 ASIC
#define STV_I2C_WRITE 0x400
#define STV_I2C_WRITE1 0x400
#define STV_I2C_READ 0x1410
#define STV_ISO_ENABLE 0x1440
#define STV_SCAN_RATE 0x1443
#define STV_ISO_SIZE 0x15c1
#define STV_Y_CTRL 0x15c3
#define STV_X_CTRL 0x1680
#define STV_REG00 0x1500
#define STV_REG01 0x1501
#define STV_REG02 0x1502
#define STV_REG03 0x1503
#define STV_REG04 0x1504
#define STV_REG23 0x0423
// This class represents each webcam
class NW80xCamDevice : public CamDevice
{
public:
NW80xCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device);
~NW80xCamDevice();
virtual bool SupportsBulk();
virtual bool SupportsIsochronous();
virtual status_t StartTransfer();
virtual status_t StopTransfer();
// 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);
// I2C-like access
virtual status_t GetStatusIIC();
virtual status_t WaitReadyIIC();
virtual ssize_t WriteIIC(uint8 address, uint8 *data, size_t count=1);
virtual ssize_t ReadIIC(uint8 address, uint8 *data);
virtual ssize_t ReadIIC8(uint8 address, uint8 *data);
virtual ssize_t ReadIIC16(uint8 address, uint16 *data);
virtual status_t SetIICBitsMode(size_t bits=8);
private:
virtual status_t SendCommand(uint8 dir, uint8 request, uint16 value,
uint16 index, uint16 length, void* data);
};
// the addon itself, that instanciate
class NW80xCamDeviceAddon : public CamDeviceAddon
{
public:
NW80xCamDeviceAddon(WebCamMediaAddOn* webcam);
virtual ~NW80xCamDeviceAddon();
virtual const char *BrandName();
virtual NW80xCamDevice *Instantiate(CamRoster &roster, BUSBDevice *from);
};
#endif /* _NW80X_CAM_CAM_DEVICE_H */

View File

@ -6,7 +6,6 @@
const usb_webcam_support_descriptor kSupportedDevices[] = {
{{ 0, 0, 0, 0x046d, 0x0840 }, "Logitech", "QuickCam Express", NULL },
{{ 0, 0, 0, 0x046d, 0x0850 }, "Logitech", "QuickCam Express LEGO", NULL },
{{ 0, 0, 0, 0x046d, 0xd001 }, "Logitech", "QuickCam Express", NULL }, // Alan's
{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
};
@ -15,6 +14,18 @@ const usb_webcam_support_descriptor kSupportedDevices[] = {
QuickCamDevice::QuickCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
:CamDevice(_addon, _device)
{
status_t err;
// linux seems to infer this sets I2C controller to 8 or 16 bit mode...
// sensors will set to the mode they want when probing
SetIICBitsMode(8);
err = ProbeSensor();
if (err < B_OK) {
// reset I2C mode to 8 bit as linux driver does
SetIICBitsMode(8);
// not much we can do anyway
}
fInitStatus = B_OK;
}
@ -100,6 +111,7 @@ ssize_t
QuickCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
{
PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
memset(data, 0xaa, count); // linux drivers do that without explaining why !?
return SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, address, 0, count, data);
}
@ -142,18 +154,92 @@ QuickCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
buffer[i] = address + i;
buffer[i+16] = data[i];
}
return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, data);
return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
}
ssize_t
QuickCamDevice::ReadIIC(uint8 address, uint8 *data)
{
#warning WRITEME
return ReadIIC(address, data);
}
ssize_t
QuickCamDevice::ReadIIC8(uint8 address, uint8 *data)
{
status_t err;
int i;
uint8 buffer[0x23];
memset(buffer, 0, sizeof(buffer));
buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
buffer[0x21] = 1 - 1;
buffer[0x22] = 0x03;
buffer[0] = address;
err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
PRINT((CH ": SendCommand: %s" CT, strerror(err)));
if (err < B_OK)
return err;
buffer[0] = 0xaa;
err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x1, buffer);
PRINT((CH ": SendCommand: %s" CT, strerror(err)));
if (err < B_OK)
return err;
*data = buffer[0];
PRINT((CH ": 0x%02x" CT, *data));
return 1;
}
ssize_t
QuickCamDevice::ReadIIC16(uint8 address, uint16 *data)
{
status_t err;
int i;
uint8 buffer[0x23];
memset(buffer, 0, sizeof(buffer));
buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
buffer[0x21] = 1 - 1;
buffer[0x22] = 0x03;
buffer[0] = address;
err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
if (err < B_OK)
return err;
buffer[0] = 0xaa;
buffer[1] = 0xaa;
err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
PRINT((CH ": SendCommand: %s" CT, strerror(err)));
if (err < B_OK)
return err;
if (fChipIsBigEndian)
*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
else
*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
PRINT((CH ": 0x%04x" CT, *data));
return 2;
}
status_t
QuickCamDevice::SetIICBitsMode(size_t bits)
{
switch (bits) {
case 8:
WriteReg8(STV_REG23, 0);
break;
case 16:
WriteReg8(STV_REG23, 1);
break;
default:
return EINVAL;
}
return B_OK;
}
status_t
QuickCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,

View File

@ -41,6 +41,9 @@ class QuickCamDevice : public CamDevice
virtual status_t WaitReadyIIC();
virtual ssize_t WriteIIC(uint8 address, uint8 *data, size_t count=1);
virtual ssize_t ReadIIC(uint8 address, uint8 *data);
virtual ssize_t ReadIIC8(uint8 address, uint8 *data);
virtual ssize_t ReadIIC16(uint8 address, uint16 *data);
virtual status_t SetIICBitsMode(size_t bits=8);
private:
virtual status_t SendCommand(uint8 dir, uint8 request, uint16 value,

View File

@ -9,7 +9,7 @@
#include <media/Buffer.h>
const usb_webcam_support_descriptor kSupportedDevices[] = {
{{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix", "foo,bar,tas5110c1b" }, // mine
{{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix", "tas5110c1b" }, // mine
{{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120", NULL },
{{ 0, 0, 0, 0x0c45, 0x600d }, "Trust", "spacec@m 120", NULL },

View File

@ -34,6 +34,7 @@ TYPE := ADDON
# in folder names do not work well with this makefile.
SRCS := $(wildcard *.cpp) \
$(wildcard addons/*/*.cpp) \
$(wildcard addons/*.cpp) \
$(wildcard sensors/*.cpp) \
$(wildcard cstransforms/*.cpp)
@ -193,8 +194,8 @@ CamRoster.cpp: CamInternalAddons.h
CamDevice.cpp: CamInternalSensors.h
CamColorSpaceTransform.cpp: CamInternalColorSpaceTransforms.h
CamInternalAddons.h: $(wildcard addons/*/*CamDevice.cpp)
grep -h B_WEBCAM_MKINTFUNC $(CURDIR)/addons/*/*CamDevice.cpp > $@
CamInternalAddons.h: $(wildcard addons/*/*CamDevice.cpp) $(wildcard addons/*CamDevice.cpp)
grep -h B_WEBCAM_MKINTFUNC $(CURDIR)/addons/*/*CamDevice.cpp $(CURDIR)/addons/*CamDevice.cpp > $@
CamInternalSensors.h: $(wildcard sensors/*.cpp)
grep -h B_WEBCAM_DECLARE_SENSOR $(CURDIR)/sensors/*.cpp > $@

View File

@ -2,25 +2,53 @@
*/
#include "CamSensor.h"
#include "CamDebug.h"
#define HDCS_ADDR_QC 0xaa
#define HDCS_IDENT 0x00
class HDCS1000Sensor : public CamSensor {
public:
HDCS1000Sensor(CamDevice *_camera);
~HDCS1000Sensor();
virtual status_t Probe();
virtual uint8 IICReadAddress() const { return HDCS_ADDR_QC; };
virtual uint8 IICWriteAddress() const { return HDCS_ADDR_QC; };
};
// -----------------------------------------------------------------------------
HDCS1000Sensor::HDCS1000Sensor(CamDevice *_camera)
: CamSensor(_camera)
{
}
// -----------------------------------------------------------------------------
HDCS1000Sensor::~HDCS1000Sensor()
{
}
// -----------------------------------------------------------------------------
status_t
HDCS1000Sensor::Probe()
{
status_t err;
uint8 data;
PRINT((CH "()" CT));
Device()->SetIICBitsMode(8);
// QuickCam only ?
err = Device()->ReadIIC8(HDCS_IDENT+1, &data);
if (err < B_OK)
return ENODEV;
if (data == 8) {
PRINT((CH ": found %s sensor!" CT, Name()));
return B_OK;
}
return ENODEV;
}
B_WEBCAM_DECLARE_SENSOR(HDCS1000Sensor, hdcs1000)

View File

@ -0,0 +1,56 @@
/*
*/
#include "CamSensor.h"
#include "CamDebug.h"
#define PB_ADDR_QC 0xba
#define PB_IDENT 0x00
class PB0100Sensor : public CamSensor {
public:
PB0100Sensor(CamDevice *_camera);
~PB0100Sensor();
virtual status_t Probe();
virtual uint8 IICReadAddress() const { return PB_ADDR_QC; };
virtual uint8 IICWriteAddress() const { return PB_ADDR_QC; };
};
PB0100Sensor::PB0100Sensor(CamDevice *_camera)
: CamSensor(_camera)
{
Device()->SetIICBitsMode(16);
}
PB0100Sensor::~PB0100Sensor()
{
}
status_t
PB0100Sensor::Probe()
{
status_t err;
uint16 data;
PRINT((CH "()" CT));
Device()->SetIICBitsMode(16);
// QuickCam only ?
err = Device()->ReadIIC16(PB_IDENT, &data);
if (err < B_OK)
return ENODEV;
if (data == 0x64) {
PRINT((CH ": found %s sensor!" CT, Name()));
return B_OK;
}
return ENODEV;
}
B_WEBCAM_DECLARE_SENSOR(PB0100Sensor, pb0100)