[media] usbvision: add Nogatech USB MicroCam
Add Nogatech USB MicroCam PAL (NV3001P) and NTSC (NV3000N) support to usbvision driver. PAL version is tested, NTSC untested. Data captured using usbsnoop, init_values are listed in the INF file along with image dimensions, offsets and frame rates. Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
449a0bada3
commit
240d57bb82
6 changed files with 114 additions and 5 deletions
|
@ -1025,6 +1025,34 @@ struct usbvision_device_data_st usbvision_device_data[] = {
|
||||||
.y_offset = -1,
|
.y_offset = -1,
|
||||||
.model_string = "Hauppauge WinTv-USB",
|
.model_string = "Hauppauge WinTv-USB",
|
||||||
},
|
},
|
||||||
|
[MICROCAM_NTSC] = {
|
||||||
|
.interface = -1,
|
||||||
|
.codec = CODEC_WEBCAM,
|
||||||
|
.video_channels = 1,
|
||||||
|
.video_norm = V4L2_STD_NTSC,
|
||||||
|
.audio_channels = 0,
|
||||||
|
.radio = 0,
|
||||||
|
.vbi = 0,
|
||||||
|
.tuner = 0,
|
||||||
|
.tuner_type = 0,
|
||||||
|
.x_offset = 71,
|
||||||
|
.y_offset = 15,
|
||||||
|
.model_string = "Nogatech USB MicroCam NTSC (NV3000N)",
|
||||||
|
},
|
||||||
|
[MICROCAM_PAL] = {
|
||||||
|
.interface = -1,
|
||||||
|
.codec = CODEC_WEBCAM,
|
||||||
|
.video_channels = 1,
|
||||||
|
.video_norm = V4L2_STD_PAL,
|
||||||
|
.audio_channels = 0,
|
||||||
|
.radio = 0,
|
||||||
|
.vbi = 0,
|
||||||
|
.tuner = 0,
|
||||||
|
.tuner_type = 0,
|
||||||
|
.x_offset = 71,
|
||||||
|
.y_offset = 18,
|
||||||
|
.model_string = "Nogatech USB MicroCam PAL (NV3001P)",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
|
const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
|
||||||
|
|
||||||
|
@ -1042,6 +1070,8 @@ struct usb_device_id usbvision_table[] = {
|
||||||
{ USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
|
{ USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
|
||||||
{ USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
|
{ USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
|
||||||
{ USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
|
{ USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
|
||||||
|
{ USB_DEVICE(0x0573, 0x3000), .driver_info = MICROCAM_NTSC },
|
||||||
|
{ USB_DEVICE(0x0573, 0x3001), .driver_info = MICROCAM_PAL },
|
||||||
{ USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
|
{ USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
|
||||||
{ USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
|
{ USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
|
||||||
{ USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
|
{ USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
|
||||||
|
@ -1088,8 +1118,7 @@ struct usb_device_id usbvision_table[] = {
|
||||||
{ USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
|
{ USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
|
||||||
{ USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
|
{ USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
|
||||||
{ USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
|
{ USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
|
||||||
{ USB_DEVICE(0x2304, 0x0113),
|
{ USB_DEVICE(0x2304, 0x0113), .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
|
||||||
.driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
|
|
||||||
{ USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
|
{ USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
|
||||||
{ USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
|
{ USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
|
||||||
{ USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
|
{ USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
|
||||||
|
|
|
@ -63,5 +63,7 @@
|
||||||
#define PINNA_PCTV_BUNGEE_PAL_FM 62
|
#define PINNA_PCTV_BUNGEE_PAL_FM 62
|
||||||
#define HPG_WINTV 63
|
#define HPG_WINTV 63
|
||||||
#define PINNA_PCTV_USB_NTSC_FM_V3 64
|
#define PINNA_PCTV_USB_NTSC_FM_V3 64
|
||||||
|
#define MICROCAM_NTSC 65
|
||||||
|
#define MICROCAM_PAL 66
|
||||||
|
|
||||||
extern const int usbvision_device_data_size;
|
extern const int usbvision_device_data_size;
|
||||||
|
|
|
@ -1679,6 +1679,55 @@ int usbvision_power_off(struct usb_usbvision *usbvision)
|
||||||
return err_code;
|
return err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* configure webcam image sensor using the serial port */
|
||||||
|
static int usbvision_init_webcam(struct usb_usbvision *usbvision)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
static char init_values[38][3] = {
|
||||||
|
{ 0x04, 0x12, 0x08 }, { 0x05, 0xff, 0xc8 }, { 0x06, 0x18, 0x07 }, { 0x07, 0x90, 0x00 },
|
||||||
|
{ 0x09, 0x00, 0x00 }, { 0x0a, 0x00, 0x00 }, { 0x0b, 0x08, 0x00 }, { 0x0d, 0xcc, 0xcc },
|
||||||
|
{ 0x0e, 0x13, 0x14 }, { 0x10, 0x9b, 0x83 }, { 0x11, 0x5a, 0x3f }, { 0x12, 0xe4, 0x73 },
|
||||||
|
{ 0x13, 0x88, 0x84 }, { 0x14, 0x89, 0x80 }, { 0x15, 0x00, 0x20 }, { 0x16, 0x00, 0x00 },
|
||||||
|
{ 0x17, 0xff, 0xa0 }, { 0x18, 0x6b, 0x20 }, { 0x19, 0x22, 0x40 }, { 0x1a, 0x10, 0x07 },
|
||||||
|
{ 0x1b, 0x00, 0x47 }, { 0x1c, 0x03, 0xe0 }, { 0x1d, 0x00, 0x00 }, { 0x1e, 0x00, 0x00 },
|
||||||
|
{ 0x1f, 0x00, 0x00 }, { 0x20, 0x00, 0x00 }, { 0x21, 0x00, 0x00 }, { 0x22, 0x00, 0x00 },
|
||||||
|
{ 0x23, 0x00, 0x00 }, { 0x24, 0x00, 0x00 }, { 0x25, 0x00, 0x00 }, { 0x26, 0x00, 0x00 },
|
||||||
|
{ 0x27, 0x00, 0x00 }, { 0x28, 0x00, 0x00 }, { 0x29, 0x00, 0x00 }, { 0x08, 0x80, 0x60 },
|
||||||
|
{ 0x0f, 0x2d, 0x24 }, { 0x0c, 0x80, 0x80 }
|
||||||
|
};
|
||||||
|
char value[3];
|
||||||
|
|
||||||
|
/* the only difference between PAL and NTSC init_values */
|
||||||
|
if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_NTSC)
|
||||||
|
init_values[4][1] = 0x34;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(init_values) / 3; i++) {
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
|
||||||
|
memcpy(value, init_values[i], 3);
|
||||||
|
rc = usb_control_msg(usbvision->dev,
|
||||||
|
usb_sndctrlpipe(usbvision->dev, 1),
|
||||||
|
USBVISION_OP_CODE,
|
||||||
|
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||||
|
USB_RECIP_ENDPOINT, 0,
|
||||||
|
(__u16) USBVISION_SER_DAT1, value,
|
||||||
|
3, HZ);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SIO);
|
||||||
|
/* write 3 bytes to the serial port using SIO mode */
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_CONT, 3 | 0x10);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_IO_2);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_DAT_IO);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT | USBVISION_DAT_IO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* usbvision_set_video_format()
|
* usbvision_set_video_format()
|
||||||
*
|
*
|
||||||
|
@ -1797,6 +1846,13 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
|
||||||
|
|
||||||
frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */
|
frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */
|
||||||
|
|
||||||
|
if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
|
||||||
|
if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_PAL)
|
||||||
|
frame_drop = 25;
|
||||||
|
else
|
||||||
|
frame_drop = 30;
|
||||||
|
}
|
||||||
|
|
||||||
/* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
|
/* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
|
||||||
=> frame_skip = 4;
|
=> frame_skip = 4;
|
||||||
=> frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
|
=> frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
|
||||||
|
@ -2046,6 +2102,12 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
|
||||||
value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */
|
value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* webcam is only 480 pixels wide, both PAL and NTSC version */
|
||||||
|
if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
|
||||||
|
value[0] = 0xe0;
|
||||||
|
value[1] = 0x01; /* 0x01E0 -> 480 Input video line length */
|
||||||
|
}
|
||||||
|
|
||||||
if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
|
if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
|
||||||
value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
|
value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
|
||||||
value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
|
value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
|
||||||
|
@ -2148,7 +2210,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
|
||||||
(__u16) USBVISION_DRM_PRM1, value, 8, HZ);
|
(__u16) USBVISION_DRM_PRM1, value, 8, HZ);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
|
dev_err(&usbvision->dev->dev, "%s: ERROR=%d\n", __func__, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2180,8 +2242,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
|
||||||
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
|
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
|
||||||
USBVISION_SSPND_EN | USBVISION_RES2);
|
USBVISION_SSPND_EN | USBVISION_RES2);
|
||||||
|
|
||||||
|
if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_VIN_REG1,
|
||||||
|
USBVISION_16_422_SYNC | USBVISION_HVALID_PO);
|
||||||
|
usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
|
||||||
|
USBVISION_NOHVALID | USBVISION_KEEP_BLANK);
|
||||||
|
}
|
||||||
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
|
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
|
||||||
USBVISION_SSPND_EN | USBVISION_PWR_VID);
|
USBVISION_SSPND_EN | USBVISION_PWR_VID);
|
||||||
|
mdelay(10);
|
||||||
err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
|
err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
|
||||||
USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
|
USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
|
||||||
if (err_code == 1)
|
if (err_code == 1)
|
||||||
|
@ -2310,6 +2379,8 @@ int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)
|
||||||
|
|
||||||
int usbvision_setup(struct usb_usbvision *usbvision, int format)
|
int usbvision_setup(struct usb_usbvision *usbvision, int format)
|
||||||
{
|
{
|
||||||
|
if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM)
|
||||||
|
usbvision_init_webcam(usbvision);
|
||||||
usbvision_set_video_format(usbvision, format);
|
usbvision_set_video_format(usbvision, format);
|
||||||
usbvision_set_dram_settings(usbvision);
|
usbvision_set_dram_settings(usbvision);
|
||||||
usbvision_set_compress_params(usbvision);
|
usbvision_set_compress_params(usbvision);
|
||||||
|
|
|
@ -222,7 +222,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
|
||||||
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
|
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
|
||||||
|
|
||||||
if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
|
if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
|
||||||
printk(KERN_ERR "usbvision_register: can't write reg\n");
|
printk(KERN_ERR "usbvision_i2c_register: can't write reg\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1470,6 +1470,7 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
|
||||||
|
|
||||||
/* This should be here to make i2c clients to be able to register */
|
/* This should be here to make i2c clients to be able to register */
|
||||||
/* first switch off audio */
|
/* first switch off audio */
|
||||||
|
if (usbvision_device_data[model].audio_channels > 0)
|
||||||
usbvision_audio_off(usbvision);
|
usbvision_audio_off(usbvision);
|
||||||
if (!power_on_at_open) {
|
if (!power_on_at_open) {
|
||||||
/* and then power up the noisy tuner */
|
/* and then power up the noisy tuner */
|
||||||
|
|
|
@ -59,6 +59,11 @@
|
||||||
#define USBVISION_AUDIO_RADIO 2
|
#define USBVISION_AUDIO_RADIO 2
|
||||||
#define USBVISION_AUDIO_MUTE 3
|
#define USBVISION_AUDIO_MUTE 3
|
||||||
#define USBVISION_SER_MODE 0x07
|
#define USBVISION_SER_MODE 0x07
|
||||||
|
#define USBVISION_CLK_OUT (1 << 0)
|
||||||
|
#define USBVISION_DAT_IO (1 << 1)
|
||||||
|
#define USBVISION_SENS_OUT (1 << 2)
|
||||||
|
#define USBVISION_SER_MODE_SOFT (0 << 4)
|
||||||
|
#define USBVISION_SER_MODE_SIO (1 << 4)
|
||||||
#define USBVISION_SER_ADRS 0x08
|
#define USBVISION_SER_ADRS 0x08
|
||||||
#define USBVISION_SER_CONT 0x09
|
#define USBVISION_SER_CONT 0x09
|
||||||
#define USBVISION_SER_DAT1 0x0A
|
#define USBVISION_SER_DAT1 0x0A
|
||||||
|
@ -328,6 +333,7 @@ struct usbvision_frame {
|
||||||
|
|
||||||
#define CODEC_SAA7113 7113
|
#define CODEC_SAA7113 7113
|
||||||
#define CODEC_SAA7111 7111
|
#define CODEC_SAA7111 7111
|
||||||
|
#define CODEC_WEBCAM 3000
|
||||||
#define BRIDGE_NT1003 1003
|
#define BRIDGE_NT1003 1003
|
||||||
#define BRIDGE_NT1004 1004
|
#define BRIDGE_NT1004 1004
|
||||||
#define BRIDGE_NT1005 1005
|
#define BRIDGE_NT1005 1005
|
||||||
|
|
Loading…
Add table
Reference in a new issue