Skip to content

Commit

Permalink
[media] usbvision: add Nogatech USB MicroCam
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ondrej Zary authored and Mauro Carvalho Chehab committed May 20, 2011
1 parent 449a0ba commit 240d57b
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 5 deletions.
33 changes: 31 additions & 2 deletions drivers/media/video/usbvision/usbvision-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,34 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.y_offset = -1,
.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);

Expand All @@ -1042,6 +1070,8 @@ struct usb_device_id usbvision_table[] = {
{ 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, 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, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
{ USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
Expand Down Expand Up @@ -1088,8 +1118,7 @@ struct usb_device_id usbvision_table[] = {
{ USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
{ USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
{ USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
{ USB_DEVICE(0x2304, 0x0113),
.driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
{ USB_DEVICE(0x2304, 0x0113), .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
{ 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, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/video/usbvision/usbvision-cards.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,7 @@
#define PINNA_PCTV_BUNGEE_PAL_FM 62
#define HPG_WINTV 63
#define PINNA_PCTV_USB_NTSC_FM_V3 64
#define MICROCAM_NTSC 65
#define MICROCAM_PAL 66

extern const int usbvision_device_data_size;
73 changes: 72 additions & 1 deletion drivers/media/video/usbvision/usbvision-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,55 @@ int usbvision_power_off(struct usb_usbvision *usbvision)
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()
*
Expand Down Expand Up @@ -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 */

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_skip = 4;
=> frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
Expand Down Expand Up @@ -2046,6 +2102,12 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
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) {
value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
Expand Down Expand Up @@ -2148,7 +2210,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
(__u16) USBVISION_DRM_PRM1, value, 8, HZ);

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;
}

Expand Down Expand Up @@ -2180,8 +2242,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
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_SSPND_EN | USBVISION_PWR_VID);
mdelay(10);
err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
if (err_code == 1)
Expand Down Expand Up @@ -2310,6 +2379,8 @@ int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)

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_dram_settings(usbvision);
usbvision_set_compress_params(usbvision);
Expand Down
2 changes: 1 addition & 1 deletion drivers/media/video/usbvision/usbvision-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);

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;
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/media/video/usbvision/usbvision-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)

/* This should be here to make i2c clients to be able to register */
/* first switch off audio */
usbvision_audio_off(usbvision);
if (usbvision_device_data[model].audio_channels > 0)
usbvision_audio_off(usbvision);
if (!power_on_at_open) {
/* and then power up the noisy tuner */
usbvision_power_on(usbvision);
Expand Down
6 changes: 6 additions & 0 deletions drivers/media/video/usbvision/usbvision.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
#define USBVISION_AUDIO_RADIO 2
#define USBVISION_AUDIO_MUTE 3
#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_CONT 0x09
#define USBVISION_SER_DAT1 0x0A
Expand Down Expand Up @@ -328,6 +333,7 @@ struct usbvision_frame {

#define CODEC_SAA7113 7113
#define CODEC_SAA7111 7111
#define CODEC_WEBCAM 3000
#define BRIDGE_NT1003 1003
#define BRIDGE_NT1004 1004
#define BRIDGE_NT1005 1005
Expand Down

0 comments on commit 240d57b

Please sign in to comment.