summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig6
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.c4
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c45
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-input.c27
-rw-r--r--linux/drivers/media/video/cafe_ccic.c2
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c2
-rw-r--r--linux/drivers/media/video/cx18/cx18-i2c.c37
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c4
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-cards.c4
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h8
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx.h2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c4
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c6
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-firmware.c35
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c21
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c23
-rw-r--r--linux/drivers/media/video/cx88/cx88-input.c89
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c6
-rw-r--r--linux/drivers/media/video/dabusb.c10
-rw-r--r--linux/drivers/media/video/davinci/vpif_display.c6
-rw-r--r--linux/drivers/media/video/em28xx/Makefile2
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c164
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c51
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h16
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-vbi.c142
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c609
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h37
-rw-r--r--linux/drivers/media/video/gspca/Kconfig17
-rw-r--r--linux/drivers/media/video/gspca/Makefile2
-rw-r--r--linux/drivers/media/video/gspca/conex.c2
-rw-r--r--linux/drivers/media/video/gspca/etoms.c4
-rw-r--r--linux/drivers/media/video/gspca/jeilinj.c388
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c13
-rw-r--r--linux/drivers/media/video/gspca/mr97310a.c853
-rw-r--r--linux/drivers/media/video/gspca/pac207.c37
-rw-r--r--linux/drivers/media/video/gspca/pac7311.c1
-rw-r--r--linux/drivers/media/video/gspca/sn9c20x.c197
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c24
-rw-r--r--linux/drivers/media/video/gspca/spca501.c2
-rw-r--r--linux/drivers/media/video/gspca/spca506.c2
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx.c4
-rw-r--r--linux/drivers/media/video/gspca/sunplus.c380
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c268
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c2
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-control.c24
-rw-r--r--linux/drivers/media/video/ir-kbd-i2c.c20
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.c18
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c4
-rw-r--r--linux/drivers/media/video/mt9m001.c435
-rw-r--r--linux/drivers/media/video/mt9m111.c524
-rw-r--r--linux/drivers/media/video/mt9t031.c491
-rw-r--r--linux/drivers/media/video/mt9v022.c434
-rw-r--r--linux/drivers/media/video/mx1_camera.c78
-rw-r--r--linux/drivers/media/video/mx3_camera.c207
-rw-r--r--linux/drivers/media/video/mxb.c14
-rw-r--r--linux/drivers/media/video/ov772x.c381
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c10
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c78
-rw-r--r--linux/drivers/media/video/pwc/pwc.h1
-rw-r--r--linux/drivers/media/video/pxa_camera.c358
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig1
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c2
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-alsa.c242
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c206
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c6
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c16
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c132
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h10
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c1058
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_devtable.h2
-rw-r--r--linux/drivers/media/video/soc_camera.c725
-rw-r--r--linux/drivers/media/video/soc_camera_platform.c163
-rw-r--r--linux/drivers/media/video/stk-webcam.c1
-rw-r--r--linux/drivers/media/video/tuner-core.c4
-rw-r--r--linux/drivers/media/video/tveeprom.c4
-rw-r--r--linux/drivers/media/video/tw9910.c361
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-i2c.c12
-rw-r--r--linux/drivers/media/video/v4l1-compat.c5
-rw-r--r--linux/drivers/media/video/v4l2-common.c209
-rw-r--r--linux/drivers/media/video/v4l2-compat-ioctl32.c67
-rw-r--r--linux/drivers/media/video/v4l2-dev.c156
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c10
-rw-r--r--linux/drivers/media/video/videobuf-dma-contig.c94
-rw-r--r--linux/drivers/media/video/vino.c9
-rw-r--r--linux/drivers/media/video/w9968cf.c4
-rw-r--r--linux/drivers/media/video/zoran/zoran_card.c8
89 files changed, 6849 insertions, 3299 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index e8a6e4de4..14a1b6160 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -203,9 +203,9 @@ config VIDEO_CS53L32A
module will be called cs53l32a.
config VIDEO_M52790
- tristate "Mitsubishi M52790 A/V switch"
- depends on VIDEO_V4L2 && I2C
- ---help---
+ tristate "Mitsubishi M52790 A/V switch"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
Support for the Mitsubishi M52790 A/V switch.
To compile this driver as a module, choose M here: the
diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c
index 830c4a933..57dd9195d 100644
--- a/linux/drivers/media/video/au0828/au0828-cards.c
+++ b/linux/drivers/media/video/au0828/au0828-cards.c
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "au8522", "au8522", 0x8e >> 1);
+ "au8522", "au8522", 0x8e >> 1, NULL);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.tuner_addr);
+ "tuner", "tuner", dev->board.tuner_addr, NULL);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index fdca5f67c..44c8da956 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -1285,6 +1285,7 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
+ .has_remote = 1,
},
/* ---- card 0x3c ---------------------------------- */
@@ -3561,8 +3562,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "saa6588", "saa6588", addrs);
+ sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs);
btv->has_saa6588 = (sd != NULL);
}
@@ -3586,8 +3587,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
- btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400", addrs);
+ btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
@@ -3600,16 +3601,16 @@ void __devinit bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
- if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", addrs))
+ if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
return;
goto no_audio;
}
case 3: {
/* The user specified that we should probe for tvaudio */
- btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
+ btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
@@ -3628,13 +3629,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
it really is a msp3400, so it will return NULL when the device
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
- btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
+ btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "msp3400", "msp3400",
- I2C_ADDR_MSP3400 >> 1);
+ 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
- btv->sd_msp34xx = v4l2_i2c_new_probed_subdev_addr(&btv->c.v4l2_dev,
+ btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "msp3400", "msp3400",
- I2C_ADDR_MSP3400_ALT >> 1);
+ 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
}
/* If we found a msp34xx, then we're done. */
@@ -3648,14 +3649,14 @@ void __devinit bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
- if (v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", addrs))
+ if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
return;
}
/* Now see if we can find one of the tvaudio devices. */
- btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", tvaudio_addrs());
+ btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
@@ -3678,15 +3679,15 @@ void __devinit bttv_init_tuner(struct bttv *btv)
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
- v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+ v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_RADIO));
- v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+ 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
- v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
&btv->c.i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
+ 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
tun_setup.type = btv->tuner_type;
diff --git a/linux/drivers/media/video/bt8xx/bttv-input.c b/linux/drivers/media/video/bt8xx/bttv-input.c
index a6b403a01..94eaef649 100644
--- a/linux/drivers/media/video/bt8xx/bttv-input.c
+++ b/linux/drivers/media/video/bt8xx/bttv-input.c
@@ -245,7 +245,7 @@ static void bttv_ir_stop(struct bttv *btv)
int bttv_input_init(struct bttv *btv)
{
struct card_ir *ir;
- IR_KEYTAB_TYPE *ir_codes = NULL;
+ struct ir_scancode_table *ir_codes = NULL;
struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
@@ -263,7 +263,7 @@ int bttv_input_init(struct bttv *btv)
case BTTV_BOARD_AVERMEDIA:
case BTTV_BOARD_AVPHONE98:
case BTTV_BOARD_AVERMEDIA98:
- ir_codes = ir_codes_avermedia;
+ ir_codes = &ir_codes_avermedia_table;
ir->mask_keycode = 0xf88000;
ir->mask_keydown = 0x010000;
ir->polling = 50; // ms
@@ -271,14 +271,14 @@ int bttv_input_init(struct bttv *btv)
case BTTV_BOARD_AVDVBT_761:
case BTTV_BOARD_AVDVBT_771:
- ir_codes = ir_codes_avermedia_dvbt;
+ ir_codes = &ir_codes_avermedia_dvbt_table;
ir->mask_keycode = 0x0f00c0;
ir->mask_keydown = 0x000020;
ir->polling = 50; // ms
break;
case BTTV_BOARD_PXELVWPLTVPAK:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
ir->mask_keycode = 0x003e00;
ir->mask_keyup = 0x010000;
ir->polling = 50; // ms
@@ -286,54 +286,55 @@ int bttv_input_init(struct bttv *btv)
case BTTV_BOARD_PV_M4900:
case BTTV_BOARD_PV_BT878P_9B:
case BTTV_BOARD_PV_BT878P_PLUS:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
break;
case BTTV_BOARD_WINFAST2000:
- ir_codes = ir_codes_winfast;
+ ir_codes = &ir_codes_winfast_table;
ir->mask_keycode = 0x1f8;
break;
case BTTV_BOARD_MAGICTVIEW061:
case BTTV_BOARD_MAGICTVIEW063:
- ir_codes = ir_codes_winfast;
+ ir_codes = &ir_codes_winfast_table;
ir->mask_keycode = 0x0008e000;
ir->mask_keydown = 0x00200000;
break;
case BTTV_BOARD_APAC_VIEWCOMP:
- ir_codes = ir_codes_apac_viewcomp;
+ ir_codes = &ir_codes_apac_viewcomp_table;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
break;
+ case BTTV_BOARD_ASKEY_CPH03X:
case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
case BTTV_BOARD_CONTVFMI:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
ir->mask_keycode = 0x001F00;
ir->mask_keyup = 0x006000;
ir->polling = 50; // ms
break;
case BTTV_BOARD_NEBULA_DIGITV:
- ir_codes = ir_codes_nebula;
+ ir_codes = &ir_codes_nebula_table;
btv->custom_irq = bttv_rc5_irq;
ir->rc5_gpio = 1;
break;
case BTTV_BOARD_MACHTV_MAGICTV:
- ir_codes = ir_codes_apac_viewcomp;
+ ir_codes = &ir_codes_apac_viewcomp_table;
ir->mask_keycode = 0x001F00;
ir->mask_keyup = 0x004000;
ir->polling = 50; /* ms */
break;
case BTTV_BOARD_KOZUMI_KTV_01C:
- ir_codes = ir_codes_pctv_sedna;
+ ir_codes = &ir_codes_pctv_sedna_table;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x006000;
ir->polling = 50; /* ms */
break;
case BTTV_BOARD_ENLTV_FM_2:
- ir_codes = ir_codes_encore_enltv2;
+ ir_codes = &ir_codes_encore_enltv2_table;
ir->mask_keycode = 0x00fd00;
ir->mask_keyup = 0x000080;
ir->polling = 1; /* ms */
diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c
index 2c78c35e8..7e86e9bfb 100644
--- a/linux/drivers/media/video/cafe_ccic.c
+++ b/linux/drivers/media/video/cafe_ccic.c
@@ -1956,7 +1956,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
cam->sensor_addr = 0x42;
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
- "ov7670", "ov7670", cam->sensor_addr);
+ "ov7670", "ov7670", cam->sensor_addr, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index ae13a1546..ede519748 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -231,7 +231,7 @@ MODULE_PARM_DESC(enc_pcm_bufs,
"Number of encoder PCM buffers\n"
"\t\t\tDefault is computed from other enc_pcm_* parameters");
-MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
+MODULE_PARM_DESC(cx18_first_minor, "Set device node number assigned to first card");
MODULE_AUTHOR("Hans Verkuil");
MODULE_DESCRIPTION("CX23418 driver");
diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c
index c551fcd47..b44220b68 100644
--- a/linux/drivers/media/video/cx18/cx18-i2c.c
+++ b/linux/drivers/media/video/cx18/cx18-i2c.c
@@ -99,12 +99,18 @@ static const char * const hw_devicenames[] = {
"ir_rx_z8f0811_haup",
};
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+static const struct IR_i2c_init_data z8f0811_ir_init_data = {
+ .ir_codes = &ir_codes_hauppauge_new_table,
+ .internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR,
+ .type = IR_TYPE_RC5,
+ .name = "CX23418 Z8F0811 Hauppauge",
+};
+
static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
u8 addr)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
struct i2c_board_info info;
- struct IR_i2c_init_data ir_init_data;
unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
memset(&info, 0, sizeof(struct i2c_board_info));
@@ -113,22 +119,21 @@ static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
/* Our default information for ir-kbd-i2c.c to use */
switch (hw) {
case CX18_HW_Z8F0811_IR_RX_HAUP:
- memset(&ir_init_data, 0, sizeof(struct IR_i2c_init_data));
- ir_init_data.ir_codes = ir_codes_hauppauge_new;
- ir_init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- ir_init_data.type = IR_TYPE_RC5;
- ir_init_data.name = "CX23418 Z8F0811 Hauppauge";
- info.platform_data = &ir_init_data;
+ info.platform_data = (void *) &z8f0811_ir_init_data;
break;
default:
break;
}
return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+}
#else
+static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
+ u8 addr)
+{
return -1;
-#endif
}
+#endif
int cx18_i2c_register(struct cx18 *cx, unsigned idx)
{
@@ -144,16 +149,16 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
- sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
- adap, mod, type, cx->card_i2c->radio);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
+ adap, mod, type, 0, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
- sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
- adap, mod, type, cx->card_i2c->demod);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
+ adap, mod, type, 0, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
- sd = v4l2_i2c_new_probed_subdev(&cx->v4l2_dev,
- adap, mod, type, cx->card_i2c->tv);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
+ adap, mod, type, 0, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
@@ -167,7 +172,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return -1;
/* It's an I2C device other than an analog tuner or IR chip */
- sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index c134927b3..dabe3fadc 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -250,9 +250,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
video_set_drvdata(s->video_dev, s);
/* Register device. First try the desired minor, then any free one. */
- ret = video_register_device(s->video_dev, vfl_type, num);
+ ret = video_register_device_no_warn(s->video_dev, vfl_type, num);
if (ret < 0) {
- CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+ CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
s->name, num);
video_device_release(s->video_dev);
s->video_dev = NULL;
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-cards.c b/linux/drivers/media/video/cx231xx/cx231xx-cards.c
index f388262bd..84b37a906 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -327,7 +327,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.decoder == CX231XX_AVDECODER) {
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[0].i2c_adap,
- "cx25840", "cx25840", 0x88 >> 1);
+ "cx25840", "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840 == NULL)
cx231xx_info("cx25840 subdev registration failure\n");
cx25840_call(dev, core, load_fw);
@@ -337,7 +337,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", 0xc2 >> 1);
+ "tuner", "tuner", 0xc2 >> 1, NULL);
if (dev->sd_tuner == NULL)
cx231xx_info("tuner subdev registration failure\n");
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h b/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h
index a6f398a17..31a8759f6 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h
+++ b/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h
@@ -60,10 +60,10 @@
#define PWR_RESETOUT_EN 0x100 /* bit8 */
enum AV_MODE{
- POLARIS_AVMODE_DEFAULT = 0,
- POLARIS_AVMODE_DIGITAL = 0x10,
- POLARIS_AVMODE_ANALOGT_TV = 0x20,
- POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
+ POLARIS_AVMODE_DEFAULT = 0,
+ POLARIS_AVMODE_DIGITAL = 0x10,
+ POLARIS_AVMODE_ANALOGT_TV = 0x20,
+ POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
};
diff --git a/linux/drivers/media/video/cx231xx/cx231xx.h b/linux/drivers/media/video/cx231xx/cx231xx.h
index 051ca21c1..ebcceaee2 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx.h
+++ b/linux/drivers/media/video/cx231xx/cx231xx.h
@@ -283,7 +283,7 @@ struct cx231xx_board {
struct cx231xx_input input[MAX_CX231XX_INPUT];
struct cx231xx_input radio;
- IR_KEYTAB_TYPE *ir_codes;
+ struct ir_scancode_table *ir_codes;
};
/* device states */
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index 2ffc83e60..8be8b819e 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -930,7 +930,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
- "cx25840", "cx25840", 0x88 >> 1);
+ "cx25840", "cx25840", 0x88 >> 1, NULL);
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
break;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 9c690a9bd..6333d7d18 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -256,15 +256,18 @@ static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = {
static struct tda18271_config hauppauge_tda18271_config = {
.std_map = &hauppauge_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static struct tda18271_config hauppauge_hvr1200_tuner_config = {
.std_map = &hauppauge_hvr1200_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static struct tda18271_config hauppauge_hvr1210_tuner_config = {
.gate = TDA18271_GATE_DIGITAL,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static struct tda18271_std_map hauppauge_hvr127x_std_map = {
@@ -276,6 +279,7 @@ static struct tda18271_std_map hauppauge_hvr127x_std_map = {
static struct tda18271_config hauppauge_hvr127x_config = {
.std_map = &hauppauge_hvr127x_std_map,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static struct lgdt3305_config hauppauge_lgdt3305_config = {
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index fc7af991e..1f8161829 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -1777,11 +1777,11 @@ int cx23885_video_register(struct cx23885_dev *dev)
if (dev->tuner_addr)
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", dev->tuner_addr);
+ "tuner", "tuner", dev->tuner_addr, NULL);
else
- sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV));
+ "tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
if (sd) {
struct tuner_setup tun_setup;
diff --git a/linux/drivers/media/video/cx25840/cx25840-firmware.c b/linux/drivers/media/video/cx25840/cx25840-firmware.c
index bdc630f0f..a19ab8644 100644
--- a/linux/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/linux/drivers/media/video/cx25840/cx25840-firmware.c
@@ -24,10 +24,6 @@
#include "cx25840-core.h"
-#define FWFILE "v4l-cx25840.fw"
-#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
-#define FWFILE_CX231XX "v4l-cx231xx-avcore-01.fw"
-
/*
* Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
* size of the firmware chunks sent down the I2C bus to the chip.
@@ -41,11 +37,11 @@
#define FWDEV(x) &((x)->dev)
-static char *firmware = FWFILE;
+static char *firmware = "";
module_param(firmware, charp, 0444);
-MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
+MODULE_PARM_DESC(firmware, "Firmware image to load");
static void start_fw_load(struct i2c_client *client)
{
@@ -66,6 +62,19 @@ static void end_fw_load(struct i2c_client *client)
cx25840_write(client, 0x803, 0x03);
}
+static const char *get_fw_name(struct i2c_client *client)
+{
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+ if (firmware[0])
+ return firmware;
+ if (state->is_cx23885)
+ return "v4l-cx23885-avcore-01.fw";
+ if (state->is_cx231xx)
+ return "v4l-cx231xx-avcore-01.fw";
+ return "v4l-cx25840.fw";
+}
+
static int check_fw_load(struct i2c_client *client, int size)
{
/* DL_ADDR_HB DL_ADDR_LB */
@@ -73,11 +82,13 @@ static int check_fw_load(struct i2c_client *client, int size)
s |= cx25840_read(client, 0x800);
if (size != s) {
- v4l_err(client, "firmware %s load failed\n", firmware);
+ v4l_err(client, "firmware %s load failed\n",
+ get_fw_name(client));
return -EINVAL;
}
- v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size);
+ v4l_info(client, "loaded %s firmware (%d bytes)\n",
+ get_fw_name(client), size);
return 0;
}
@@ -97,26 +108,24 @@ int cx25840_loadfw(struct i2c_client *client)
const struct firmware *fw = NULL;
u8 buffer[FWSEND];
const u8 *ptr;
+ const char *fwname = get_fw_name(client);
int size, retval;
int MAX_BUF_SIZE = FWSEND;
u32 gpio_oe = 0, gpio_da = 0;
if (state->is_cx23885) {
- firmware = FWFILE_CX23885;
/* Preserve the GPIO OE and output bits */
gpio_oe = cx25840_read(client, 0x160);
gpio_da = cx25840_read(client, 0x164);
}
- else if (state->is_cx231xx)
- firmware = FWFILE_CX231XX;
if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) {
v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */
}
- if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
- v4l_err(client, "unable to open firmware %s\n", firmware);
+ if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
+ v4l_err(client, "unable to open firmware %s\n", fwname);
return -EINVAL;
}
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index 19d57e698..11b1982ca 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -1986,7 +1986,8 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_DVB,
- .vmux = 1,
+ .vmux = 0,
+ .gpio0 = 0x8080,
} },
.mpeg = CX88_MPEG_DVB,
},
@@ -3244,7 +3245,11 @@ static void cx88_card_setup(struct cx88_core *core)
case CX88_BOARD_PROF_6200:
case CX88_BOARD_PROF_7300:
case CX88_BOARD_SATTRADE_ST4200:
+ cx_write(MO_GP0_IO, 0x8000);
+ msleep(100);
cx_write(MO_SRST_IO, 0);
+ msleep(10);
+ cx_write(MO_GP0_IO, 0x8080);
msleep(100);
cx_write(MO_SRST_IO, 1);
msleep(100);
@@ -3467,20 +3472,20 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
The radio_type is sometimes missing, or set to UNSET but
later code configures a tea5767.
*/
- v4l2_i2c_new_probed_subdev(&core->v4l2_dev, &core->i2c_adap,
+ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
"tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
if (has_demod)
- v4l2_i2c_new_probed_subdev(&core->v4l2_dev,
+ v4l2_i2c_new_subdev(&core->v4l2_dev,
&core->i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (core->board.tuner_addr == ADDR_UNSET) {
- v4l2_i2c_new_probed_subdev(&core->v4l2_dev,
+ v4l2_i2c_new_subdev(&core->v4l2_dev,
&core->i2c_adap, "tuner", "tuner",
- has_demod ? tv_addrs + 4 : tv_addrs);
+ 0, has_demod ? tv_addrs + 4 : tv_addrs);
} else {
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "tuner", "tuner", core->board.tuner_addr);
+ "tuner", "tuner", core->board.tuner_addr, NULL);
}
}
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index ab84c085f..28042ad5a 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -425,17 +425,16 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
+ cx_set(MO_GP0_IO, 0x6040);
switch (voltage) {
case SEC_VOLTAGE_13:
- printk("LNB Voltage SEC_VOLTAGE_13\n");
- cx_write(MO_GP0_IO, 0x00006040);
+ cx_clear(MO_GP0_IO, 0x20);
break;
case SEC_VOLTAGE_18:
- printk("LNB Voltage SEC_VOLTAGE_18\n");
- cx_write(MO_GP0_IO, 0x00006060);
+ cx_set(MO_GP0_IO, 0x20);
break;
case SEC_VOLTAGE_OFF:
- printk("LNB Voltage SEC_VOLTAGE_off\n");
+ cx_clear(MO_GP0_IO, 0x20);
break;
}
@@ -500,14 +499,14 @@ static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
};
static struct zl10353_config cx88_geniatech_x8000_mt = {
- .demod_address = (0x1e >> 1),
- .no_tuner = 1,
- .disable_i2c_gate_ctrl = 1,
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .disable_i2c_gate_ctrl = 1,
#if 0
- .input_frequency = 0xe609,
- .parallel_ts = 1,
- .r56_agc_targets = 0x2b,
- .r5c_clk_mpegts_output = 0x75,
+ .input_frequency = 0xe609,
+ .parallel_ts = 1,
+ .r56_agc_targets = 0x2b,
+ .r5c_clk_mpegts_output = 0x75,
#endif
};
diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c
index 8d0042ab2..426c8e62f 100644
--- a/linux/drivers/media/video/cx88/cx88-input.c
+++ b/linux/drivers/media/video/cx88/cx88-input.c
@@ -23,7 +23,7 @@
*/
#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/hrtimer.h>
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/module.h>
@@ -49,7 +49,7 @@ struct cx88_IR {
/* poll external decoder */
int polling;
- struct delayed_work work;
+ struct hrtimer timer;
u32 gpio_addr;
u32 last_gpio;
u32 mask_keycode;
@@ -145,31 +145,28 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
}
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-static void cx88_ir_work(void *data)
-#else
-static void cx88_ir_work(struct work_struct *work)
-#endif
+static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- struct cx88_IR *ir = data;
-#else
- struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work);
-#endif
+ unsigned long missed;
+ struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
cx88_ir_handle_key(ir);
- schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+ missed = hrtimer_forward_now(&ir->timer,
+ ktime_set(0, ir->polling * 1000000));
+ if (missed > 1)
+ ir_dprintk("Missed ticks %ld\n", missed - 1);
+
+ return HRTIMER_RESTART;
}
void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- INIT_DELAYED_WORK(&ir->work, cx88_ir_work, ir);
-#else
- INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
-#endif
- schedule_delayed_work(&ir->work, 0);
+ hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ir->timer.function = cx88_ir_work;
+ hrtimer_start(&ir->timer,
+ ktime_set(0, ir->polling * 1000000),
+ HRTIMER_MODE_REL);
}
if (ir->sampling) {
core->pci_irqmask |= PCI_INT_IR_SMPINT;
@@ -186,7 +183,7 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
}
if (ir->polling)
- cancel_delayed_work_sync(&ir->work);
+ hrtimer_cancel(&ir->timer);
}
/* ---------------------------------------------------------------------- */
@@ -195,7 +192,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
struct cx88_IR *ir;
struct input_dev *input_dev;
- IR_KEYTAB_TYPE *ir_codes = NULL;
+ struct ir_scancode_table *ir_codes = NULL;
int ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
@@ -211,14 +208,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_KWORLD_DVB_T_CX22702:
- ir_codes = ir_codes_dntv_live_dvb_t;
+ ir_codes = &ir_codes_dntv_live_dvb_t_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x1f;
ir->mask_keyup = 0x60;
ir->polling = 50; /* ms */
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
- ir_codes = ir_codes_cinergy_1400;
+ ir_codes = &ir_codes_cinergy_1400_table;
ir_type = IR_TYPE_PD;
ir->sampling = 0xeb04; /* address */
break;
@@ -233,14 +230,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_PCHDTV_HD3000:
case CX88_BOARD_PCHDTV_HD5500:
case CX88_BOARD_HAUPPAUGE_IRONLY:
- ir_codes = ir_codes_hauppauge_new;
+ ir_codes = &ir_codes_hauppauge_new_table;
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_WINFAST_DTV2000H_J:
case CX88_BOARD_WINFAST_DTV1800H:
- ir_codes = ir_codes_winfast;
+ ir_codes = &ir_codes_winfast_table;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
ir->mask_keyup = 0x100;
@@ -249,14 +246,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_WINFAST2000XP_EXPERT:
case CX88_BOARD_WINFAST_DTV1000:
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
- ir_codes = ir_codes_winfast;
+ ir_codes = &ir_codes_winfast_table;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
ir->mask_keyup = 0x100;
ir->polling = 1; /* ms */
break;
case CX88_BOARD_IODATA_GVBCTV7E:
- ir_codes = ir_codes_iodata_bctv7e;
+ ir_codes = &ir_codes_iodata_bctv7e_table;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0xfd;
ir->mask_keydown = 0x02;
@@ -264,7 +261,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_PROLINK_PLAYTVPVR:
case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x1f;
ir->mask_keyup = 0x80;
@@ -272,28 +269,28 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_PROLINK_PV_8000GT:
case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
- ir_codes = ir_codes_pixelview_new;
+ ir_codes = &ir_codes_pixelview_new_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x3f;
ir->mask_keyup = 0x80;
ir->polling = 1; /* ms */
break;
case CX88_BOARD_KWORLD_LTV883:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x1f;
ir->mask_keyup = 0x60;
ir->polling = 1; /* ms */
break;
case CX88_BOARD_ADSTECH_DVB_T_PCI:
- ir_codes = ir_codes_adstech_dvb_t_pci;
+ ir_codes = &ir_codes_adstech_dvb_t_pci_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0xbf;
ir->mask_keyup = 0x40;
ir->polling = 50; /* ms */
break;
case CX88_BOARD_MSI_TVANYWHERE_MASTER:
- ir_codes = ir_codes_msi_tvanywhere;
+ ir_codes = &ir_codes_msi_tvanywhere_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x1f;
ir->mask_keyup = 0x40;
@@ -301,40 +298,40 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_AVERTV_303:
case CX88_BOARD_AVERTV_STUDIO_303:
- ir_codes = ir_codes_avertv_303;
+ ir_codes = &ir_codes_avertv_303_table;
ir->gpio_addr = MO_GP2_IO;
ir->mask_keycode = 0xfb;
ir->mask_keydown = 0x02;
ir->polling = 50; /* ms */
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
- ir_codes = ir_codes_dntv_live_dvbt_pro;
- ir_type = IR_TYPE_PD;
- ir->sampling = 0xff00; /* address */
+ ir_codes = &ir_codes_dntv_live_dvbt_pro_table;
+ ir_type = IR_TYPE_PD;
+ ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_NORWOOD_MICRO:
- ir_codes = ir_codes_norwood;
+ ir_codes = &ir_codes_norwood_table;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x0e;
ir->mask_keyup = 0x80;
ir->polling = 50; /* ms */
break;
case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
- ir_codes = ir_codes_npgtech;
- ir->gpio_addr = MO_GP0_IO;
+ ir_codes = &ir_codes_npgtech_table;
+ ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0xfa;
- ir->polling = 50; /* ms */
+ ir->polling = 50; /* ms */
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- ir_codes = ir_codes_pinnacle_pctv_hd;
- ir_type = IR_TYPE_RC5;
- ir->sampling = 1;
+ ir_codes = &ir_codes_pinnacle_pctv_hd_table;
+ ir_type = IR_TYPE_RC5;
+ ir->sampling = 1;
break;
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
- ir_codes = ir_codes_powercolor_real_angel;
- ir->gpio_addr = MO_GP2_IO;
+ ir_codes = &ir_codes_powercolor_real_angel_table;
+ ir->gpio_addr = MO_GP2_IO;
ir->mask_keycode = 0x7e;
- ir->polling = 100; /* ms */
+ ir->polling = 100; /* ms */
break;
}
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index d4bd9ba68..9ec7d2f57 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -2155,14 +2155,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
if (core->board.audio_chip == V4L2_IDENT_WM8775)
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "wm8775", "wm8775", 0x36 >> 1);
+ "wm8775", "wm8775", 0x36 >> 1, NULL);
if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
/* This probes for a tda9874 as is used on some
Pixelview Ultra boards. */
- v4l2_i2c_new_probed_subdev_addr(&core->v4l2_dev,
+ v4l2_i2c_new_subdev(&core->v4l2_dev,
&core->i2c_adap,
- "tvaudio", "tvaudio", 0xb0 >> 1);
+ "tvaudio", "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
}
switch (core->boardnr) {
diff --git a/linux/drivers/media/video/dabusb.c b/linux/drivers/media/video/dabusb.c
index cb0a41c45..a0812ce91 100644
--- a/linux/drivers/media/video/dabusb.c
+++ b/linux/drivers/media/video/dabusb.c
@@ -813,8 +813,18 @@ static struct file_operations dabusb_fops =
.release = dabusb_release,
};
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+static char *dabusb_nodename(struct device *dev)
+{
+ return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
+#endif
static struct usb_class_driver dabusb_class = {
.name = "dabusb%d",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+ .nodename = dabusb_nodename,
+#endif
.fops = &dabusb_fops,
.minor_base = DABUSB_MINOR,
};
diff --git a/linux/drivers/media/video/davinci/vpif_display.c b/linux/drivers/media/video/davinci/vpif_display.c
index 969d4b3aa..a125a452d 100644
--- a/linux/drivers/media/video/davinci/vpif_display.c
+++ b/linux/drivers/media/video/davinci/vpif_display.c
@@ -1422,7 +1422,7 @@ vpif_init_free_channel_objects:
*/
static __init int vpif_probe(struct platform_device *pdev)
{
- const struct subdev_info *subdevdata;
+ const struct vpif_subdev_info *subdevdata;
int i, j = 0, k, q, m, err = 0;
struct i2c_adapter *i2c_adap;
struct vpif_config *config;
@@ -1566,10 +1566,10 @@ static __init int vpif_probe(struct platform_device *pdev)
}
for (i = 0; i < subdev_count; i++) {
- vpif_obj.sd[i] = v4l2_i2c_new_probed_subdev(&vpif_obj.v4l2_dev,
+ vpif_obj.sd[i] = v4l2_i2c_new_subdev(&vpif_obj.v4l2_dev,
i2c_adap, subdevdata[i].name,
subdevdata[i].name,
- &subdevdata[i].addr);
+ 0, I2C_ADDRS(subdevdata[i].addr));
if (!vpif_obj.sd[i]) {
vpif_err("Error registering v4l2 subdevice\n");
goto probe_subdev_out;
diff --git a/linux/drivers/media/video/em28xx/Makefile b/linux/drivers/media/video/em28xx/Makefile
index 8137a8c94..d0f093d1d 100644
--- a/linux/drivers/media/video/em28xx/Makefile
+++ b/linux/drivers/media/video/em28xx/Makefile
@@ -1,5 +1,5 @@
em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
- em28xx-input.o
+ em28xx-input.o em28xx-vbi.o
em28xx-alsa-objs := em28xx-audio.o
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index a38586176..8fb751d5c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -314,6 +314,7 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .has_ir_i2c = 1,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA711X,
.input = { {
@@ -333,6 +334,7 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_PINNACLE_USB_2] = {
.name = "Pinnacle PCTV USB 2",
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .has_ir_i2c = 1,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA711X,
.input = { {
@@ -357,6 +359,7 @@ struct em28xx_board em28xx_boards[] = {
TDA9887_PORT2_ACTIVE,
.decoder = EM28XX_TVP5150,
.has_msp34xx = 1,
+ .has_ir_i2c = 1,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -574,6 +577,27 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ [EM2861_BOARD_GADMEI_UTV330PLUS] = {
+ .name = "Gadmei UTV330+",
+ .tuner_type = TUNER_TNF_5335MF,
+ .tda9887_conf = TDA9887_PRESENT,
+ .ir_codes = &ir_codes_gadmei_rm008z_table,
+ .decoder = EM28XX_SAA711X,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = SAA7115_COMPOSITE2,
+ .amux = EM28XX_AMUX_VIDEO,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
[EM2860_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Cinergy A Hybrid XS",
.valid = EM28XX_BOARD_NOT_VALIDATED,
@@ -751,7 +775,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
- .ir_codes = ir_codes_hauppauge_new,
+ .ir_codes = &ir_codes_hauppauge_new_table,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -776,7 +800,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
- .ir_codes = ir_codes_hauppauge_new,
+ .ir_codes = &ir_codes_hauppauge_new_table,
.decoder = EM28XX_TVP5150,
#if 0 /* FIXME: add an entry at em28xx-dvb */
.has_dvb = 1,
@@ -806,7 +830,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
- .ir_codes = ir_codes_hauppauge_new,
+ .ir_codes = &ir_codes_hauppauge_new_table,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -832,7 +856,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
- .ir_codes = ir_codes_hauppauge_new,
+ .ir_codes = &ir_codes_hauppauge_new_table,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -858,7 +882,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
- .ir_codes = ir_codes_pinnacle_pctv_hd,
+ .ir_codes = &ir_codes_pinnacle_pctv_hd_table,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -884,7 +908,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
- .ir_codes = ir_codes_ati_tv_wonder_hd_600,
+ .ir_codes = &ir_codes_ati_tv_wonder_hd_600_table,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -910,7 +934,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_TVP5150,
.has_dvb = 1,
.dvb_gpio = default_digital,
- .ir_codes = ir_codes_terratec_cinergy_xs,
+ .ir_codes = &ir_codes_terratec_cinergy_xs_table,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -983,6 +1007,7 @@ struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_TERRATEC_CINERGY_200] = {
.name = "Terratec Cinergy 200 USB",
.is_em2800 = 1,
+ .has_ir_i2c = 1,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA711X,
@@ -1056,7 +1081,8 @@ struct em28xx_board em28xx_boards[] = {
} },
},
[EM2820_BOARD_PINNACLE_DVC_90] = {
- .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker",
+ .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker "
+ "/ Kworld DVD Maker 2",
.tuner_type = TUNER_ABSENT, /* capture only board */
.decoder = EM28XX_SAA711X,
.input = { {
@@ -1486,7 +1512,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.decoder = EM28XX_TVP5150,
.tuner_gpio = default_tuner_gpio,
- .ir_codes = ir_codes_kaiomy,
+ .ir_codes = &ir_codes_kaiomy_table,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1586,7 +1612,7 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_dvb = 1,
.dvb_gpio = evga_indtube_digital,
- .ir_codes = ir_codes_evga_indtube,
+ .ir_codes = &ir_codes_evga_indtube_table,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1661,6 +1687,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2870_BOARD_KWORLD_355U },
{ USB_DEVICE(0x1b80, 0xe302),
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
+ { USB_DEVICE(0x1b80, 0xe304),
+ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */
{ USB_DEVICE(0x0ccd, 0x0036),
.driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
{ USB_DEVICE(0x0ccd, 0x004c),
@@ -1744,6 +1772,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
{0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
+ {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
};
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -1896,7 +1925,7 @@ static int em28xx_hint_sensor(struct em28xx *dev)
break;
- case 0x143a: /* MT9M111 as found in the ECS G200 */
+ case 0x143a: /* MT9M111 as found in the ECS G200 */
dev->model = EM2750_BOARD_UNKNOWN;
em28xx_set_model(dev);
@@ -2253,11 +2282,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (disable_ir) {
ir->get_key = NULL;
- return ;
+ return;
}
#else
- struct i2c_board_info info;
- struct IR_i2c_init_data init_data;
const unsigned short addr_list[] = {
0x30, 0x47, I2C_CLIENT_END
};
@@ -2265,68 +2292,56 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
if (disable_ir)
return;
- memset(&info, 0, sizeof(struct i2c_board_info));
- memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ memset(&dev->info, 0, sizeof(&dev->info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
#endif
/* detect & configure */
switch (dev->model) {
- case (EM2800_BOARD_UNKNOWN):
- break;
- case (EM2820_BOARD_UNKNOWN):
- break;
- case (EM2800_BOARD_TERRATEC_CINERGY_200):
- case (EM2820_BOARD_TERRATEC_CINERGY_250):
+ case EM2800_BOARD_TERRATEC_CINERGY_200:
+ case EM2820_BOARD_TERRATEC_CINERGY_250:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
- ir->ir_codes = ir_codes_em_terratec;
+ ir->ir_codes = &ir_codes_em_terratec_table;
ir->get_key = em28xx_get_key_terratec;
snprintf(ir->name, sizeof(ir->name),
"i2c IR (EM28XX Terratec)");
#else
- init_data.ir_codes = ir_codes_em_terratec;
- init_data.get_key = em28xx_get_key_terratec;
- init_data.name = "i2c IR (EM28XX Terratec)";
+ dev->init_data.ir_codes = &ir_codes_em_terratec_table;
+ dev->init_data.get_key = em28xx_get_key_terratec;
+ dev->init_data.name = "i2c IR (EM28XX Terratec)";
#endif
break;
- case (EM2820_BOARD_PINNACLE_USB_2):
+ case EM2820_BOARD_PINNACLE_USB_2:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
- ir->ir_codes = ir_codes_pinnacle_grey;
+ ir->ir_codes = &ir_codes_pinnacle_grey_table;
ir->get_key = em28xx_get_key_pinnacle_usb_grey;
snprintf(ir->name, sizeof(ir->name),
"i2c IR (EM28XX Pinnacle PCTV)");
#else
- init_data.ir_codes = ir_codes_pinnacle_grey;
- init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
- init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
+ dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
+ dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+ dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
#endif
break;
- case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+ case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
- ir->ir_codes = ir_codes_hauppauge_new;
+ ir->ir_codes = &ir_codes_hauppauge_new_table;
ir->get_key = em28xx_get_key_em_haup;
snprintf(ir->name, sizeof(ir->name),
"i2c IR (EM2840 Hauppauge)");
#else
- init_data.ir_codes = ir_codes_hauppauge_new;
- init_data.get_key = em28xx_get_key_em_haup;
- init_data.name = "i2c IR (EM2840 Hauppauge)";
+ dev->init_data.ir_codes = &ir_codes_hauppauge_new_table;
+ dev->init_data.get_key = em28xx_get_key_em_haup;
+ dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
#endif
break;
- case (EM2820_BOARD_MSI_VOX_USB_2):
- break;
- case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
- break;
- case (EM2800_BOARD_KWORLD_USB2800):
- break;
- case (EM2800_BOARD_GRABBEEX_USB2800):
- break;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
- if (init_data.name)
- info.platform_data = &init_data;
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+ if (dev->init_data.name)
+ dev->info.platform_data = &dev->init_data;
+ i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
#endif
}
@@ -2363,7 +2378,7 @@ void em28xx_card_setup(struct em28xx *dev)
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
{
struct tveeprom tv;
-#ifdef CONFIG_MODULES
+#if defined(CONFIG_MODULES) && defined(MODULE)
request_module("tveeprom");
#endif
/* Call first TVeeprom */
@@ -2377,10 +2392,6 @@ void em28xx_card_setup(struct em28xx *dev)
dev->i2s_speed = 2048000;
dev->board.has_msp34xx = 1;
}
-#ifdef CONFIG_MODULES
- if (tv.has_ir)
- request_module("ir-kbd-i2c");
-#endif
break;
}
case EM2882_BOARD_KWORLD_ATSC_315U:
@@ -2421,6 +2432,10 @@ void em28xx_card_setup(struct em28xx *dev)
break;
}
+#if defined(CONFIG_MODULES) && defined(MODULE)
+ if (dev->board.has_ir_i2c && !disable_ir)
+ request_module("ir-kbd-i2c");
+#endif
if (dev->board.has_snapshot_button)
em28xx_register_snapshot_button(dev);
@@ -2439,66 +2454,68 @@ void em28xx_card_setup(struct em28xx *dev)
/* request some modules */
if (dev->board.has_msp34xx)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "msp3400", "msp3400", msp3400_addrs);
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "msp3400", "msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "saa7115", "saa7115_auto", saa711x_addrs);
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "saa7115", "saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvp5150", "tvp5150", tvp5150_addrs);
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "tvp5150", "tvp5150", 0, tvp5150_addrs);
if (dev->em28xx_sensor == EM28XX_MT9V011) {
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs);
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "mt9v011", "mt9v011", 0, mt9v011_addrs);
v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
}
#if 0
/* FIXME: use mt9m001 after their conversion to v4l dev/subdev */
if (dev->em28xx_sensor == EM28XX_MT9M001)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "mt9m001", "mt9m001", mt9v011_addrs);
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "mt9m001", "mt9m001", 0, mt9v011_addrs);
#endif
if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvaudio", "tvaudio", dev->board.tvaudio_addr);
+ "tvaudio", "tvaudio", dev->board.tvaudio_addr, NULL);
if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.radio_addr);
+ "tuner", "tuner", dev->board.radio_addr, NULL);
if (has_demod)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(type));
+ 0, v4l2_i2c_tuner_addrs(type));
if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->tuner_addr);
+ "tuner", "tuner", dev->tuner_addr, NULL);
}
}
em28xx_tuner_setup(dev);
- em28xx_ir_init(dev);
+
+ if(!disable_ir)
+ em28xx_ir_init(dev);
}
@@ -2676,7 +2693,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
* Default format, used for tvp5150 or saa711x output formats
*/
dev->vinmode = 0x10;
- dev->vinctl = 0x11;
+ dev->vinctl = EM28XX_VINCTRL_INTERLACED |
+ EM28XX_VINCTRL_CCIR656_ENABLE;
/* Do board specific init and eeprom reading */
em28xx_card_setup(dev);
@@ -2695,6 +2713,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
+ INIT_LIST_HEAD(&dev->vbiq.active);
+ INIT_LIST_HEAD(&dev->vbiq.queued);
#if 0
video_set_drvdata(dev->vbi_dev, dev);
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 46cb13182..1b9a0953e 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -54,6 +54,10 @@ static int alt = EM28XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
+
/* FIXME */
#define em28xx_isocdbg(fmt, arg...) do {\
if (core_debug) \
@@ -648,9 +652,24 @@ int em28xx_capture_start(struct em28xx *dev, int start)
return rc;
}
+int em28xx_vbi_supported(struct em28xx *dev)
+{
+ /* Modprobe option to manually disable */
+ if (disable_vbi == 1)
+ return 0;
+
+ if (dev->chip_id == CHIP_ID_EM2860 ||
+ dev->chip_id == CHIP_ID_EM2883)
+ return 1;
+
+ /* Version of em28xx that does not support VBI */
+ return 0;
+}
+
int em28xx_set_outfmt(struct em28xx *dev)
{
int ret;
+ u8 vinctrl;
ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
dev->format->reg | 0x20, 0xff);
@@ -661,7 +680,16 @@ int em28xx_set_outfmt(struct em28xx *dev)
if (ret < 0)
return ret;
- return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl);
+ vinctrl = dev->vinctl;
+ if (em28xx_vbi_supported(dev) == 1) {
+ vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+ em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, 0xb4);
+ em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, 0x0c);
+ }
+
+ return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
}
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -732,7 +760,14 @@ int em28xx_resolution_set(struct em28xx *dev)
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
- em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+
+ /* If we don't set the start position to 4 in VBI mode, we end up
+ with line 21 being YUYV encoded instead of being in 8-bit
+ greyscale */
+ if (em28xx_vbi_supported(dev) == 1)
+ em28xx_capture_area_set(dev, 0, 4, width >> 2, height >> 2);
+ else
+ em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
}
@@ -853,8 +888,7 @@ static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs)
static void em28xx_irq_callback(struct urb *urb)
#endif
{
- struct em28xx_dmaqueue *dma_q = urb->context;
- struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ struct em28xx *dev = urb->context;
int rc, i;
switch (urb->status) {
@@ -939,6 +973,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
{
struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
int i;
int sb_size, pipe;
struct urb *urb;
@@ -968,7 +1003,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
}
dev->isoc_ctl.max_pkt_size = max_pkt_size;
- dev->isoc_ctl.buf = NULL;
+ dev->isoc_ctl.vid_buf = NULL;
+ dev->isoc_ctl.vbi_buf = NULL;
sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
@@ -1003,7 +1039,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
usb_fill_int_urb(urb, dev->udev, pipe,
dev->isoc_ctl.transfer_buffer[i], sb_size,
- em28xx_irq_callback, dma_q, 1);
+ em28xx_irq_callback, dev, 1);
urb->number_of_packets = max_packets;
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
@@ -1018,6 +1054,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
}
init_waitqueue_head(&dma_q->wq);
+ init_waitqueue_head(&vbi_dma_q->wq);
em28xx_capture_start(dev, 1);
@@ -1103,7 +1140,7 @@ struct em28xx *em28xx_get_device(int minor,
list_for_each_entry(h, &em28xx_devlist, devlist) {
if (h->vdev->minor == minor)
dev = h;
- if (h->vbi_dev->minor == minor) {
+ if (h->vbi_dev && h->vbi_dev->minor == minor) {
dev = h;
*fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
index 6bf84bd78..ed12e7ffc 100644
--- a/linux/drivers/media/video/em28xx/em28xx-reg.h
+++ b/linux/drivers/media/video/em28xx/em28xx-reg.h
@@ -86,7 +86,19 @@
#define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b
#define EM28XX_R10_VINMODE 0x10
+
#define EM28XX_R11_VINCTRL 0x11
+
+/* em28xx Video Input Control Register 0x11 */
+#define EM28XX_VINCTRL_VBI_SLICED 0x80
+#define EM28XX_VINCTRL_VBI_RAW 0x40
+#define EM28XX_VINCTRL_VOUT_MODE_IN 0x20 /* HREF,VREF,VACT in output */
+#define EM28XX_VINCTRL_CCIR656_ENABLE 0x10
+#define EM28XX_VINCTRL_VBI_16BIT_RAW 0x08 /* otherwise 8-bit raw */
+#define EM28XX_VINCTRL_FID_ON_HREF 0x04
+#define EM28XX_VINCTRL_DUAL_EDGE_STROBE 0x02
+#define EM28XX_VINCTRL_INTERLACED 0x01
+
#define EM28XX_R12_VINENABLE 0x12 /* */
#define EM28XX_R14_GAMMA 0x14
@@ -135,6 +147,10 @@
#define EM28XX_R31_HSCALEHIGH 0x31
#define EM28XX_R32_VSCALELOW 0x32
#define EM28XX_R33_VSCALEHIGH 0x33
+#define EM28XX_R34_VBI_START_H 0x34
+#define EM28XX_R35_VBI_START_V 0x35
+#define EM28XX_R36_VBI_WIDTH 0x36
+#define EM28XX_R37_VBI_HEIGHT 0x37
#define EM28XX_R40_AC97LSB 0x40
#define EM28XX_R41_AC97MSB 0x41
diff --git a/linux/drivers/media/video/em28xx/em28xx-vbi.c b/linux/drivers/media/video/em28xx/em28xx-vbi.c
new file mode 100644
index 000000000..94943e5a1
--- /dev/null
+++ b/linux/drivers/media/video/em28xx/em28xx-vbi.c
@@ -0,0 +1,142 @@
+/*
+ em28xx-vbi.c - VBI driver for em28xx
+
+ Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+ This work was sponsored by EyeMagnet Limited.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "em28xx.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
+
+#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.vbi_buf == buf)
+ dev->isoc_ctl.vbi_buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+ *size = 720 * 12 * 2;
+ if (0 == *count)
+ *count = vbibufs;
+ if (*count < 2)
+ *count = 2;
+ if (*count > 32)
+ *count = 32;
+ return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ int rc = 0;
+ unsigned int size;
+
+ size = 720 * 12 * 2;
+
+ buf->vb.size = size;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = 720;
+ buf->vb.height = 12;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(q, buf);
+ return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb,
+ struct em28xx_buffer,
+ vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_dmaqueue *vbiq = &dev->vbiq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops em28xx_vbi_qops = {
+ .buf_setup = vbi_setup,
+ .buf_prepare = vbi_prepare,
+ .buf_queue = vbi_queue,
+ .buf_release = vbi_release,
+};
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index c7d723a03..edfe795ef 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -181,7 +181,24 @@ static inline void buffer_filled(struct em28xx *dev,
buf->vb.field_count++;
do_gettimeofday(&buf->vb.ts);
- dev->isoc_ctl.buf = NULL;
+ dev->isoc_ctl.vid_buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static inline void vbi_buffer_filled(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.vbi_buf = NULL;
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
@@ -257,7 +274,8 @@ static void em28xx_copy_video(struct em28xx *dev,
if ((char *)startwrite + lencopy > (char *)outp +
buf->vb.size) {
- em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+ "(2)\n",
((char *)startwrite + lencopy) -
((char *)outp + buf->vb.size));
lencopy = remain = (char *)outp + buf->vb.size -
@@ -274,6 +292,67 @@ static void em28xx_copy_video(struct em28xx *dev,
dma_q->pos += len;
}
+static void em28xx_copy_vbi(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *startwrite, *startread;
+ int offset;
+ int bytesperline = 720;
+
+ if (dev == NULL) {
+ em28xx_isocdbg("dev is null\n");
+ return;
+ }
+
+ if (dma_q == NULL) {
+ em28xx_isocdbg("dma_q is null\n");
+ return;
+ }
+ if (buf == NULL) {
+#if 0
+ /* Disable by default - too chatty */
+ em28xx_isocdbg("buf is null\n");
+#endif
+ return;
+ }
+ if (p == NULL) {
+ em28xx_isocdbg("p is null\n");
+ return;
+ }
+ if (outp == NULL) {
+ em28xx_isocdbg("outp is null\n");
+ return;
+ }
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ if ((p[0] == 0x33 && p[1] == 0x95) ||
+ (p[0] == 0x88 && p[1] == 0x88)) {
+ /* Header field, advance past it */
+ p += 4;
+ } else {
+ len += 4;
+ }
+
+ startread = p;
+
+ startwrite = outp + dma_q->pos;
+ offset = dma_q->pos;
+
+ /* Make sure the bottom field populates the second half of the frame */
+ if (buf->top_field == 0) {
+ startwrite += bytesperline * 0x0c;
+ offset += bytesperline * 0x0c;
+ }
+
+ memcpy(startwrite, startread, len);
+ dma_q->pos += len;
+}
+
static inline void print_err_status(struct em28xx *dev,
int packet, int status)
{
@@ -326,7 +405,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
if (list_empty(&dma_q->active)) {
em28xx_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.buf = NULL;
+ dev->isoc_ctl.vid_buf = NULL;
*buf = NULL;
return;
}
@@ -340,7 +419,38 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
memset(outp, 0, (*buf)->vb.size);
#endif
- dev->isoc_ctl.buf = *buf;
+ dev->isoc_ctl.vid_buf = *buf;
+
+ return;
+}
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer **buf)
+{
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
+#if 1
+ char *outp;
+#endif
+
+ if (list_empty(&dma_q->active)) {
+ em28xx_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.vbi_buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+#if 1
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0x00, (*buf)->vb.size);
+#endif
+
+ dev->isoc_ctl.vbi_buf = *buf;
return;
}
@@ -351,7 +461,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
{
struct em28xx_buffer *buf;
- struct em28xx_dmaqueue *dma_q = urb->context;
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
unsigned char *outp = NULL;
int i, len = 0, rc = 1;
unsigned char *p;
@@ -368,7 +478,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
return 0;
}
- buf = dev->isoc_ctl.buf;
+ buf = dev->isoc_ctl.vid_buf;
if (buf != NULL)
outp = videobuf_to_vmalloc(&buf->vb);
@@ -432,6 +542,153 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
return rc;
}
+/* Version of isoc handler that takes into account a mixture of video and
+ VBI data */
+static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
+{
+ struct em28xx_buffer *buf, *vbi_buf;
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+ unsigned char *outp = NULL;
+ unsigned char *vbioutp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+ int vbi_size;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.vid_buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ vbi_buf = dev->isoc_ctl.vbi_buf;
+ if (vbi_buf != NULL)
+ vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* capture type 0 = vbi start
+ capture type 1 = video start
+ capture type 2 = video in progress */
+ if (p[0] == 0x33 && p[1] == 0x95) {
+ dev->capture_type = 0;
+ dev->vbi_read = 0;
+ em28xx_isocdbg("VBI START HEADER!!!\n");
+ dev->cur_field = p[2];
+ }
+
+ /* FIXME: get rid of hard-coded value */
+ vbi_size = 720 * 0x0c;
+
+ if (dev->capture_type == 0) {
+ if (dev->vbi_read >= vbi_size) {
+ /* We've already read all the VBI data, so
+ treat the rest as video */
+ em28xx_isocdbg("dev->vbi_read > vbi_size\n");
+ } else if ((dev->vbi_read + len) < vbi_size) {
+ /* This entire frame is VBI data */
+ if (dev->vbi_read == 0 &&
+ (!(dev->cur_field & 1))) {
+ /* Brand new frame */
+ if (vbi_buf != NULL)
+ vbi_buffer_filled(dev,
+ vbi_dma_q,
+ vbi_buf);
+ vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+ if (vbi_buf == NULL)
+ vbioutp = NULL;
+ else
+ vbioutp = videobuf_to_vmalloc(
+ &vbi_buf->vb);
+ }
+
+ if (dev->vbi_read == 0) {
+ vbi_dma_q->pos = 0;
+ if (vbi_buf != NULL) {
+ if (dev->cur_field & 1)
+ vbi_buf->top_field = 0;
+ else
+ vbi_buf->top_field = 1;
+ }
+ }
+
+ dev->vbi_read += len;
+ em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, len);
+ } else {
+ /* Some of this frame is VBI data and some is
+ video data */
+ int vbi_data_len = vbi_size - dev->vbi_read;
+ dev->vbi_read += vbi_data_len;
+ em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, vbi_data_len);
+ dev->capture_type = 1;
+ p += vbi_data_len;
+ len -= vbi_data_len;
+ }
+ }
+
+ if (dev->capture_type == 1) {
+ dev->capture_type = 2;
+ em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+ len, (p[2] & 1) ? "odd" : "even");
+
+ if (dev->progressive || !(dev->cur_field & 1)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+ if (buf != NULL) {
+ if (dev->cur_field & 1)
+ buf->top_field = 0;
+ else
+ buf->top_field = 1;
+ }
+
+ dma_q->pos = 0;
+ }
+ if (buf != NULL && dev->capture_type == 2)
+ em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ return rc;
+}
+
+
/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
@@ -443,7 +700,8 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
struct em28xx *dev = fh->dev;
struct v4l2_frequency f;
- *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
+ >> 3;
if (0 == *count)
*count = EM28XX_DEF_BUF;
@@ -480,8 +738,8 @@ static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
VIDEOBUF_ACTIVE, it won't be, though.
*/
spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.buf == buf)
- dev->isoc_ctl.buf = NULL;
+ if (dev->isoc_ctl.vid_buf == buf)
+ dev->isoc_ctl.vid_buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
videobuf_vmalloc_free(&buf->vb);
@@ -497,7 +755,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct em28xx *dev = fh->dev;
int rc = 0, urb_init = 0;
- buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+ + 7) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -516,9 +775,16 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
urb_init = 1;
if (urb_init) {
- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
- EM28XX_NUM_BUFS, dev->max_pkt_size,
- em28xx_isoc_copy);
+ if (em28xx_vbi_supported(dev) == 1)
+ rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS,
+ dev->max_pkt_size,
+ em28xx_isoc_copy_vbi);
+ else
+ rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS,
+ dev->max_pkt_size,
+ em28xx_isoc_copy);
if (rc < 0)
goto fail;
}
@@ -600,34 +866,63 @@ static void video_mux(struct em28xx *dev, int index)
}
/* Usage lock check functions */
-static int res_get(struct em28xx_fh *fh)
+static int res_get(struct em28xx_fh *fh, unsigned int bit)
{
struct em28xx *dev = fh->dev;
- int rc = 0;
- /* This instance already has stream_on */
- if (fh->stream_on)
- return rc;
+ if (fh->resources & bit)
+ /* have it already allocated */
+ return 1;
- if (dev->stream_on)
- return -EBUSY;
+ /* is it free? */
+ mutex_lock(&dev->lock);
+ if (dev->resources & bit) {
+ /* no, someone else uses it */
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ dev->resources |= bit;
+ em28xx_videodbg("res: get %d\n", bit);
+ mutex_unlock(&dev->lock);
+ return 1;
+}
- dev->stream_on = 1;
- fh->stream_on = 1;
- return rc;
+static int res_check(struct em28xx_fh *fh, unsigned int bit)
+{
+ return fh->resources & bit;
}
-static int res_check(struct em28xx_fh *fh)
+static int res_locked(struct em28xx *dev, unsigned int bit)
{
- return fh->stream_on;
+ return dev->resources & bit;
}
-static void res_free(struct em28xx_fh *fh)
+static void res_free(struct em28xx_fh *fh, unsigned int bits)
{
struct em28xx *dev = fh->dev;
- fh->stream_on = 0;
- dev->stream_on = 0;
+ BUG_ON((fh->resources & bits) != bits);
+
+ mutex_lock(&dev->lock);
+ fh->resources &= ~bits;
+ dev->resources &= ~bits;
+ em28xx_videodbg("res: put %d\n", bits);
+ mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct em28xx_fh *fh)
+{
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return EM28XX_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return EM28XX_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
}
/*
@@ -804,7 +1099,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
} else {
/* width must even because of the YUYV format
height must be even because of interlacing */
- v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
+ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
+ 1, 0);
}
get_scale(dev, width, height, &hscale, &vscale);
@@ -870,12 +1166,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
goto out;
}
- if (dev->stream_on && !fh->stream_on) {
- em28xx_errdev("%s device in use by another fh\n", __func__);
- rc = -EBUSY;
- goto out;
- }
-
rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
f->fmt.pix.width, f->fmt.pix.height);
@@ -884,6 +1174,21 @@ out:
return rc;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ *norm = dev->norm;
+
+ return 0;
+}
+
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
{
struct em28xx_fh *fh = priv;
@@ -1441,20 +1746,25 @@ static int vidioc_streamon(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
+ int rc = -EINVAL;
rc = check_dev(dev);
if (rc < 0)
return rc;
+ if (unlikely(type != fh->type))
+ return -EINVAL;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
+ em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
- if (likely(rc >= 0))
- rc = videobuf_streamon(&fh->vb_vidq);
+ if (unlikely(!res_get(fh, get_ressource(fh))))
+ return -EBUSY;
- mutex_unlock(&dev->lock);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vidq);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vbiq);
return rc;
}
@@ -1470,17 +1780,22 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
return -EINVAL;
if (type != fh->type)
return -EINVAL;
- mutex_lock(&dev->lock);
-
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
+ em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
- mutex_unlock(&dev->lock);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
return 0;
}
@@ -1498,13 +1813,13 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->version = EM28XX_VERSION_CODE;
cap->capabilities =
-#if 0
- V4L2_CAP_VBI_CAPTURE |
-#endif
V4L2_CAP_SLICED_VBI_CAPTURE |
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->vbi_dev)
+ cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+
if (dev->audio_mode.has_audio)
cap->capabilities |= V4L2_CAP_AUDIO;
@@ -1572,40 +1887,45 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
return 0;
}
-#if 0
/* RAW VBI ioctls */
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *format)
{
- format->fmt.vbi.sampling_rate = 6750000 * 4;
- format->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
+ format->fmt.vbi.samples_per_line = 720;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 64 * 4;
- format->fmt.vbi.start[0] = norm->vbi_v_start_0;
- format->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1;
- format->fmt.vbi.start[1] = norm->vbi_v_start_1;
- format->fmt.vbi.count[1] = format->fmt.vbi.count[0];
- format->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
+ format->fmt.vbi.offset = 0;
+ format->fmt.vbi.flags = 0;
+
+ /* Varies by video standard (NTSC, PAL, etc.) */
+ /* FIXME: hard-coded for NTSC support */
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
+ format->fmt.vbi.count[0] = 12;
+ format->fmt.vbi.count[1] = 12;
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
return 0;
}
-static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *format)
{
- format->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- format->fmt.vbi.sampling_rate = HZ;
- format->fmt.vbi.samples_per_line = 2048;
+ format->fmt.vbi.samples_per_line = 720;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 244;
+ format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
- format->fmt.vbi.start[0] = 0;
- format->fmt.vbi.start[1] = 0;
+
+ /* Varies by video standard (NTSC, PAL, etc.) */
+ /* FIXME: hard-coded for NTSC support */
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
+ format->fmt.vbi.count[0] = 12;
+ format->fmt.vbi.count[1] = 12;
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
return 0;
}
-#endif
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
@@ -1618,7 +1938,10 @@ static int vidioc_reqbufs(struct file *file, void *priv,
if (rc < 0)
return rc;
- return videobuf_reqbufs(&fh->vb_vidq, rb);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+ else
+ return videobuf_reqbufs(&fh->vb_vbiq, rb);
}
static int vidioc_querybuf(struct file *file, void *priv,
@@ -1632,7 +1955,18 @@ static int vidioc_querybuf(struct file *file, void *priv,
if (rc < 0)
return rc;
- return videobuf_querybuf(&fh->vb_vidq, b);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_querybuf(&fh->vb_vidq, b);
+ else {
+ /* FIXME: I'm not sure yet whether this is a bug in zvbi or
+ the videobuf framework, but we probably shouldn't be
+ returning a buffer larger than that which was asked for.
+ At a minimum, it causes a crash in zvbi since it does
+ a memcpy based on the source buffer length */
+ int result = videobuf_querybuf(&fh->vb_vbiq, b);
+ b->length = 17280;
+ return result;
+ }
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1645,7 +1979,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
if (rc < 0)
return rc;
- return videobuf_qbuf(&fh->vb_vidq, b);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_qbuf(&fh->vb_vidq, b);
+ else
+ return videobuf_qbuf(&fh->vb_vbiq, b);
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1658,7 +1995,12 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
if (rc < 0)
return rc;
- return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
+ O_NONBLOCK);
+ else
+ return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
+ O_NONBLOCK);
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -1666,7 +2008,10 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
{
struct em28xx_fh *fh = priv;
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+ else
+ return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8);
}
#endif
@@ -1798,7 +2143,7 @@ static int em28xx_v4l2_open(struct file *filp)
#if 0
errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
if (errCode < 0) {
- em28xx_errdev("Device locked on digital mode. Can't open analog\n");
+ em28xx_errdev("Locked on digital mode. Can't open analog\n");
mutex_unlock(&dev->lock);
return -EBUSY;
}
@@ -1846,8 +2191,15 @@ static int em28xx_v4l2_open(struct file *filp)
field = V4L2_FIELD_INTERLACED;
videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
- NULL, &dev->slock, fh->type, field,
- sizeof(struct em28xx_buffer), fh);
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
+ sizeof(struct em28xx_buffer), fh);
+
+ videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_SEQ_TB,
+ sizeof(struct em28xx_buffer), fh);
mutex_unlock(&dev->lock);
@@ -1904,20 +2256,21 @@ static int em28xx_v4l2_close(struct file *filp)
em28xx_videodbg("users=%d\n", dev->users);
+ if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+ videobuf_stop(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ }
- mutex_lock(&dev->lock);
- if (res_check(fh))
- res_free(fh);
+ if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+ videobuf_stop(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
if (dev->users == 1) {
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
/* the device is already disconnect,
free the remaining resources */
if (dev->state & DEV_DISCONNECTED) {
em28xx_release_resources(dev);
- mutex_unlock(&dev->lock);
kfree(dev);
return 0;
}
@@ -1938,10 +2291,12 @@ static int em28xx_v4l2_close(struct file *filp)
"0 (error=%i)\n", errCode);
}
}
+
+ videobuf_mmap_free(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vbiq);
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1966,16 +2321,22 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
*/
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
+ if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
+ return -EBUSY;
return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
}
+
+
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VBI))
+ return -EBUSY;
+
+ return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
return 0;
}
@@ -1993,17 +2354,17 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return POLLERR;
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VBI))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+ } else {
return POLLERR;
-
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ }
}
/*
@@ -2019,14 +2380,10 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
-
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
@@ -2052,11 +2409,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-#if 0
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_try_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
-#endif
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
@@ -2069,6 +2423,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
@@ -2190,15 +2545,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->mute = 1;
dev->volume = 0x1f;
-#if 1
- /* enable vbi capturing */
-
/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
em28xx_write_reg(dev, EM28XX_R0F_XCLK,
(EM28XX_XCLK_AUDIO_UNMUTE | val));
- em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
-#endif
em28xx_set_outfmt(dev);
em28xx_colorlevels_set_default(dev);
@@ -2221,14 +2571,17 @@ int em28xx_register_analog_devices(struct em28xx *dev)
}
/* Allocate and fill vbi video_device struct */
- dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi");
+ if (em28xx_vbi_supported(dev) == 1) {
+ dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+ "vbi");
- /* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
- vbi_nr[dev->devno]);
- if (ret < 0) {
- em28xx_errdev("unable to register vbi device\n");
- return ret;
+ /* register v4l2 vbi video_device */
+ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ vbi_nr[dev->devno]);
+ if (ret < 0) {
+ em28xx_errdev("unable to register vbi device\n");
+ return ret;
+ }
}
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
@@ -2248,8 +2601,12 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->radio_dev->num);
}
- em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
- dev->vdev->num, dev->vbi_dev->num);
+ em28xx_info("V4L2 video device registered as /dev/video%d\n",
+ dev->vdev->num);
+
+ if (dev->vbi_dev)
+ em28xx_info("V4L2 VBI device registered as /dev/vbi%d\n",
+ dev->vbi_dev->num);
return 0;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 70a41b640..90e9e2fb5 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -109,6 +109,7 @@
#define EM2882_BOARD_KWORLD_ATSC_315U 69
#define EM2882_BOARD_EVGA_INDTUBE 70
#define EM2820_BOARD_SILVERCREST_WEBCAM 71
+#define EM2861_BOARD_GADMEI_UTV330PLUS 72
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -214,7 +215,8 @@ struct em28xx_usb_isoc_ctl {
int tmp_buf_len;
/* Stores already requested buffers */
- struct em28xx_buffer *buf;
+ struct em28xx_buffer *vid_buf;
+ struct em28xx_buffer *vbi_buf;
/* Stores the number of received fields */
int nfields;
@@ -368,7 +370,7 @@ enum em28xx_sensor {
EM28XX_NOSENSOR = 0,
EM28XX_MT9V011,
EM28XX_MT9M001,
- EM28XX_MT9M111,
+ EM28XX_MT9M111,
};
enum em28xx_adecoder {
@@ -400,6 +402,7 @@ struct em28xx_board {
unsigned int is_webcam:1;
unsigned int no_audio:1;
unsigned int valid:1;
+ unsigned int has_ir_i2c:1;
unsigned char xclk, i2c_speed;
unsigned char radio_addr;
@@ -410,7 +413,7 @@ struct em28xx_board {
struct em28xx_input input[MAX_EM28XX_INPUT];
struct em28xx_input radio;
- IR_KEYTAB_TYPE *ir_codes;
+ struct ir_scancode_table *ir_codes;
};
struct em28xx_eeprom {
@@ -443,6 +446,10 @@ enum em28xx_dev_state {
#define EM28XX_AUDIO 0x10
#define EM28XX_DVB 0x20
+/* em28xx resource types (used for res_get/res_lock etc */
+#define EM28XX_RESOURCE_VIDEO 0x01
+#define EM28XX_RESOURCE_VBI 0x02
+
struct em28xx_audio {
char name[50];
char *transfer_buffer[EM28XX_AUDIO_BUFS];
@@ -471,10 +478,11 @@ struct em28xx;
struct em28xx_fh {
struct em28xx *dev;
- unsigned int stream_on:1; /* Locks streams */
int radio;
+ unsigned int resources;
struct videobuf_queue vb_vidq;
+ struct videobuf_queue vb_vbiq;
enum v4l2_buf_type type;
};
@@ -501,7 +509,6 @@ struct em28xx {
/* Vinmode/Vinctl used at the driver */
int vinmode, vinctl;
- unsigned int stream_on:1; /* Locks streams */
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
@@ -552,6 +559,12 @@ struct em28xx {
enum em28xx_dev_state state;
enum em28xx_io_method io;
+ /* vbi related state tracking */
+ int capture_type;
+ int vbi_read;
+ unsigned char cur_field;
+
+
struct work_struct request_module_wk;
/* locks */
@@ -563,10 +576,14 @@ struct em28xx {
struct video_device *vbi_dev;
struct video_device *radio_dev;
+ /* resources in use */
+ unsigned int resources;
+
unsigned char eedata[256];
/* Isoc control struct */
struct em28xx_dmaqueue vidq;
+ struct em28xx_dmaqueue vbiq;
struct em28xx_usb_isoc_ctl isoc_ctl;
spinlock_t slock;
@@ -605,6 +622,12 @@ struct em28xx {
struct delayed_work sbutton_query_work;
struct em28xx_dvb *dvb;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ /* I2C keyboard data */
+ struct i2c_board_info info;
+ struct IR_i2c_init_data init_data;
+#endif
};
struct em28xx_ops {
@@ -643,6 +666,7 @@ int em28xx_audio_setup(struct em28xx *dev);
int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
+int em28xx_vbi_supported(struct em28xx *dev);
int em28xx_set_outfmt(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
@@ -690,6 +714,9 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev);
int em28xx_ir_init(struct em28xx *dev);
int em28xx_ir_fini(struct em28xx *dev);
+/* Provided by em28xx-vbi.c */
+extern struct videobuf_queue_ops em28xx_vbi_qops;
+
/* printk macros */
#define em28xx_err(fmt, arg...) do {\
diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig
index a14561956..8897283b0 100644
--- a/linux/drivers/media/video/gspca/Kconfig
+++ b/linux/drivers/media/video/gspca/Kconfig
@@ -47,6 +47,15 @@ config USB_GSPCA_FINEPIX
To compile this driver as a module, choose M here: the
module will be called gspca_finepix.
+config USB_GSPCA_JEILINJ
+ tristate "Jeilin JPEG USB V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on this Jeilin chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_jeilinj.
+
config USB_GSPCA_MARS
tristate "Mars USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -103,9 +112,9 @@ config USB_GSPCA_PAC7311
module will be called gspca_pac7311.
config USB_GSPCA_SN9C20X
- tristate "SN9C20X USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
+ tristate "SN9C20X USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
Say Y here if you want support for cameras based on the
sn9c20x chips (SN9C201 and SN9C202).
@@ -114,7 +123,7 @@ config USB_GSPCA_SN9C20X
config USB_GSPCA_SN9C20X_EVDEV
bool "Enable evdev support"
- depends on USB_GSPCA_SN9C20X
+ depends on USB_GSPCA_SN9C20X && INPUT
---help---
Say Y here in order to enable evdev support for sn9c20x webcam button.
diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile
index f6d3b86e9..035616b5e 100644
--- a/linux/drivers/media/video/gspca/Makefile
+++ b/linux/drivers/media/video/gspca/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o
obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
+obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
@@ -30,6 +31,7 @@ gspca_main-objs := gspca.o
gspca_conex-objs := conex.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
+gspca_jeilinj-objs := jeilinj.o
gspca_mars-objs := mars.o
gspca_mr97310a-objs := mr97310a.o
gspca_ov519-objs := ov519.o
diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c
index 8d48ea174..eca003566 100644
--- a/linux/drivers/media/video/gspca/conex.c
+++ b/linux/drivers/media/video/gspca/conex.c
@@ -820,7 +820,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c
index 84f3a5eb8..42b36b8b7 100644
--- a/linux/drivers/media/video/gspca/etoms.c
+++ b/linux/drivers/media/video/gspca/etoms.c
@@ -635,10 +635,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = id->driver_info;
if (sd->sensor == SENSOR_PAS106) {
cam->cam_mode = sif_mode;
- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ cam->nmodes = ARRAY_SIZE(sif_mode);
} else {
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->ctrl_dis = (1 << COLOR_IDX);
}
sd->brightness = BRIGHTNESS_DEF;
diff --git a/linux/drivers/media/video/gspca/jeilinj.c b/linux/drivers/media/video/gspca/jeilinj.c
new file mode 100644
index 000000000..dbfa3ed6e
--- /dev/null
+++ b/linux/drivers/media/video/gspca/jeilinj.c
@@ -0,0 +1,388 @@
+/*
+ * Jeilinj subdriver
+ *
+ * Supports some Jeilin dual-mode cameras which use bulk transport and
+ * download raw JPEG data.
+ *
+ * Copyright (C) 2009 Theodore Kilgore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "jeilinj"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define JEILINJ_CMD_TIMEOUT 500
+#define JEILINJ_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define JEILINJ_MAX_TRANSFER 0x200
+
+#define FRAME_HEADER_LEN 0x10
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ const struct v4l2_pix_format *cap_mode;
+ /* Driver stuff */
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
+ u8 quality; /* image quality */
+ u8 jpegqual; /* webcam quality */
+ u8 *jpeg_hdr;
+};
+
+ struct jlj_command {
+ unsigned char instruction[2];
+ unsigned char ack_wanted;
+ };
+
+/* AFAICT these cameras will only do 320x240. */
+static struct v4l2_pix_format jlj_mode[] = {
+ { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0}
+};
+
+/*
+ * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
+ * and 0x82 for bulk transfer.
+ */
+
+/* All commands are two bytes only */
+static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+{
+ int retval;
+
+ memcpy(gspca_dev->usb_buf, command, 2);
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_sndbulkpipe(gspca_dev->dev, 3),
+ gspca_dev->usb_buf, 2, NULL, 500);
+ if (retval < 0)
+ PDEBUG(D_ERR, "command write [%02x] error %d",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+/* Responses are one byte only */
+static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
+{
+ int retval;
+
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x84),
+ gspca_dev->usb_buf, 1, NULL, 500);
+ response = gspca_dev->usb_buf[0];
+ if (retval < 0)
+ PDEBUG(D_ERR, "read command [%02x] error %d",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+static int jlj_start(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ u8 response = 0xff;
+ struct jlj_command start_commands[] = {
+ {{0x71, 0x81}, 0},
+ {{0x70, 0x05}, 0},
+ {{0x95, 0x70}, 1},
+ {{0x71, 0x81}, 0},
+ {{0x70, 0x04}, 0},
+ {{0x95, 0x70}, 1},
+ {{0x71, 0x00}, 0},
+ {{0x70, 0x08}, 0},
+ {{0x95, 0x70}, 1},
+ {{0x94, 0x02}, 0},
+ {{0xde, 0x24}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xdd, 0xf0}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe3, 0x2c}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe4, 0x00}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe5, 0x00}, 0},
+ {{0x94, 0x02}, 0},
+ {{0xe6, 0x2c}, 0},
+ {{0x94, 0x03}, 0},
+ {{0xaa, 0x00}, 0},
+ {{0x71, 0x1e}, 0},
+ {{0x70, 0x06}, 0},
+ {{0x71, 0x80}, 0},
+ {{0x70, 0x07}, 0}
+ };
+ for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
+ retval = jlj_write2(gspca_dev, start_commands[i].instruction);
+ if (retval < 0)
+ return retval;
+ if (start_commands[i].ack_wanted)
+ retval = jlj_read1(gspca_dev, response);
+ if (retval < 0)
+ return retval;
+ }
+ PDEBUG(D_ERR, "jlj_start retval is %d", retval);
+ return retval;
+}
+
+static int jlj_stop(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval;
+ struct jlj_command stop_commands[] = {
+ {{0x71, 0x00}, 0},
+ {{0x70, 0x09}, 0},
+ {{0x71, 0x80}, 0},
+ {{0x70, 0x05}, 0}
+ };
+ for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
+ retval = jlj_write2(gspca_dev, stop_commands[i].instruction);
+ if (retval < 0)
+ return retval;
+ }
+ return retval;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface the gspca usb_lock is
+ * used when performing the one USB control operation inside the workqueue,
+ * which tells the camera to close the stream. In practice the only thing
+ * which needs to be protected against is the usb_set_interface call that
+ * gspca makes during stream_off. Otherwise the camera doesn't provide any
+ * controls that the user could try to change.
+ */
+
+static void jlj_dostream(struct work_struct *work)
+{
+ struct sd *dev = container_of(work, struct sd, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ struct gspca_frame *frame;
+ int blocks_left; /* 0x200-sized blocks remaining in current frame. */
+ int size_in_blocks;
+ int act_len;
+ int discarding = 0; /* true if we failed to get space for frame. */
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+ goto quit_stream;
+ }
+ while (gspca_dev->present && gspca_dev->streaming) {
+ if (!gspca_dev->present)
+ goto quit_stream;
+ /* Start a new frame, and add the JPEG header, first thing */
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame && !discarding)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ dev->jpeg_hdr, JPEG_HDR_SZ);
+ else
+ discarding = 1;
+ /*
+ * Now request data block 0. Line 0 reports the size
+ * to download, in blocks of size 0x200, and also tells the
+ * "actual" data size, in bytes, which seems best to ignore.
+ */
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, JEILINJ_MAX_TRANSFER, &act_len,
+ JEILINJ_DATA_TIMEOUT);
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for Block 0",
+ act_len, JEILINJ_MAX_TRANSFER);
+ if (ret < 0 || act_len < FRAME_HEADER_LEN)
+ goto quit_stream;
+ size_in_blocks = buffer[0x0a];
+ blocks_left = buffer[0x0a] - 1;
+ PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
+ packet_type = INTER_PACKET;
+ if (frame && !discarding)
+ /* Toss line 0 of data block 0, keep the rest. */
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer + FRAME_HEADER_LEN,
+ JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
+ else
+ discarding = 1;
+ while (blocks_left > 0) {
+ if (!gspca_dev->present)
+ goto quit_stream;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, JEILINJ_MAX_TRANSFER, &act_len,
+ JEILINJ_DATA_TIMEOUT);
+ if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER)
+ goto quit_stream;
+ PDEBUG(D_STREAM,
+ "%d blocks remaining for frame", blocks_left);
+ blocks_left -= 1;
+ if (blocks_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ if (frame && !discarding)
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer,
+ JEILINJ_MAX_TRANSFER);
+ else
+ discarding = 1;
+ }
+ }
+quit_stream:
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->present)
+ jlj_stop(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ kfree(buffer);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam = &gspca_dev->cam;
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ dev->quality = 85;
+ dev->jpegqual = 85;
+ PDEBUG(D_PROBE,
+ "JEILINJ camera detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ cam->cam_mode = jlj_mode;
+ cam->nmodes = 1;
+ cam->bulk = 1;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 32;
+ INIT_WORK(&dev->work_struct, jlj_dostream);
+ return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ /* wait for the work queue to terminate */
+ mutex_unlock(&gspca_dev->usb_lock);
+ /* This waits for jlj_dostream to finish */
+ destroy_workqueue(dev->work_thread);
+ dev->work_thread = NULL;
+ mutex_lock(&gspca_dev->usb_lock);
+ kfree(dev->jpeg_hdr);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
+
+ /* create the JPEG header */
+ dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(dev->jpeg_hdr, dev->quality);
+ PDEBUG(D_STREAM, "Start streaming at 320x240");
+ ret = jlj_start(gspca_dev);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Start streaming command failed");
+ return ret;
+ }
+ /* Start the workqueue function to do the streaming */
+ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(dev->work_thread, &dev->work_struct);
+
+ return 0;
+}
+
+/* Table of supported USB devices */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0979, 0x0280)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id,
+ &sd_desc,
+ sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 1dd7c161f..38a56294d 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -49,6 +49,12 @@ static
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
}
}, {
+ .ident = "Fujitsu-Siemens Amilo Pa 2548",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
+ }
+ }, {
.ident = "MSI GX700",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
@@ -56,6 +62,13 @@ static
DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
}
}, {
+ .ident = "MSI GX700",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
+ DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
+ }
+ }, {
.ident = "MSI GX700/GX705/EX700",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c
index 301325134..140c8f320 100644
--- a/linux/drivers/media/video/gspca/mr97310a.c
+++ b/linux/drivers/media/video/gspca/mr97310a.c
@@ -3,6 +3,21 @@
*
* Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
*
+ * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
+ * and for the routines for detecting and classifying these various cameras,
+ *
+ * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * Acknowledgements:
+ *
+ * The MR97311A support in gspca/mars.c has been helpful in understanding some
+ * of the registers in these cameras.
+ *
+ * Hans de Goede <hdgoede@redhat.com> and
+ * Thomas Kaiser <thomas@kaiser-linux.li>
+ * have assisted with their experience. Each of them has also helped by
+ * testing a previously unsupported camera.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -22,18 +37,108 @@
#include "gspca.h"
-MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>");
+#define CAM_TYPE_CIF 0
+#define CAM_TYPE_VGA 1
+
+#define MR97310A_BRIGHTNESS_MIN -254
+#define MR97310A_BRIGHTNESS_MAX 255
+#define MR97310A_BRIGHTNESS_DEFAULT 0
+
+#define MR97310A_EXPOSURE_MIN 300
+#define MR97310A_EXPOSURE_MAX 4095
+#define MR97310A_EXPOSURE_DEFAULT 1000
+
+#define MR97310A_GAIN_MIN 0
+#define MR97310A_GAIN_MAX 31
+#define MR97310A_GAIN_DEFAULT 25
+
+MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
+ "Theodore Kilgore <kilgota@auburn.edu>");
MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
MODULE_LICENSE("GPL");
+/* global parameters */
+int force_sensor_type = -1;
+module_param(force_sensor_type, int, 0644);
+MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
u8 sof_read;
+ u8 cam_type; /* 0 is CIF and 1 is VGA */
+ u8 sensor_type; /* We use 0 and 1 here, too. */
+ u8 do_lcd_stop;
+
+ int brightness;
+ u16 exposure;
+ u8 gain;
+};
+
+struct sensor_w_data {
+ u8 reg;
+ u8 flags;
+ u8 data[16];
+ int len;
};
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+
/* V4L2 controls supported by the driver */
static struct ctrl sd_ctrls[] = {
+ {
+#define BRIGHTNESS_IDX 0
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = MR97310A_BRIGHTNESS_MIN,
+ .maximum = MR97310A_BRIGHTNESS_MAX,
+ .step = 1,
+ .default_value = MR97310A_BRIGHTNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+#define EXPOSURE_IDX 1
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = MR97310A_EXPOSURE_MIN,
+ .maximum = MR97310A_EXPOSURE_MAX,
+ .step = 1,
+ .default_value = MR97310A_EXPOSURE_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+#define GAIN_IDX 2
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = MR97310A_GAIN_MIN,
+ .maximum = MR97310A_GAIN_MAX,
+ .step = 1,
+ .default_value = MR97310A_GAIN_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
};
static const struct v4l2_pix_format vga_mode[] = {
@@ -65,7 +170,7 @@ static const struct v4l2_pix_format vga_mode[] = {
};
/* the bytes to write are in gspca_dev->usb_buf */
-static int reg_w(struct gspca_dev *gspca_dev, int len)
+static int mr_write(struct gspca_dev *gspca_dev, int len)
{
int rc;
@@ -78,15 +183,249 @@ static int reg_w(struct gspca_dev *gspca_dev, int len)
return rc;
}
+/* the bytes are read into gspca_dev->usb_buf */
+static int mr_read(struct gspca_dev *gspca_dev, int len)
+{
+ int rc;
+
+ rc = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 3),
+ gspca_dev->usb_buf, len, NULL, 500);
+ if (rc < 0)
+ PDEBUG(D_ERR, "reg read [%02x] error %d",
+ gspca_dev->usb_buf[0], rc);
+ return rc;
+}
+
+static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags,
+ const u8 *data, int len)
+{
+ gspca_dev->usb_buf[0] = 0x1f;
+ gspca_dev->usb_buf[1] = flags;
+ gspca_dev->usb_buf[2] = reg;
+ memcpy(gspca_dev->usb_buf + 3, data, len);
+
+ return mr_write(gspca_dev, len + 3);
+}
+
+static int sensor_write_regs(struct gspca_dev *gspca_dev,
+ const struct sensor_w_data *data, int len)
+{
+ int i, rc;
+
+ for (i = 0; i < len; i++) {
+ rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags,
+ data[i].data, data[i].len);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 buf, confirm_reg;
+ int rc;
+
+ buf = data;
+ rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
+ if (rc < 0)
+ return rc;
+
+ buf = 0x01;
+ confirm_reg = sd->sensor_type ? 0x13 : 0x11;
+ rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int cam_get_response16(struct gspca_dev *gspca_dev)
+{
+ __u8 *data = gspca_dev->usb_buf;
+ int err_code;
+
+ data[0] = 0x21;
+ err_code = mr_write(gspca_dev, 1);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = mr_read(gspca_dev, 16);
+ return err_code;
+}
+
+static int zero_the_pointer(struct gspca_dev *gspca_dev)
+{
+ __u8 *data = gspca_dev->usb_buf;
+ int err_code;
+ u8 status = 0;
+ int tries = 0;
+
+ err_code = cam_get_response16(gspca_dev);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = mr_write(gspca_dev, 1);
+ data[0] = 0x19;
+ data[1] = 0x51;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = cam_get_response16(gspca_dev);
+ if (err_code < 0)
+ return err_code;
+
+ data[0] = 0x19;
+ data[1] = 0xba;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = cam_get_response16(gspca_dev);
+ if (err_code < 0)
+ return err_code;
+
+ data[0] = 0x19;
+ data[1] = 0x00;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = cam_get_response16(gspca_dev);
+ if (err_code < 0)
+ return err_code;
+
+ data[0] = 0x19;
+ data[1] = 0x00;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+ while (status != 0x0a && tries < 256) {
+ err_code = cam_get_response16(gspca_dev);
+ status = data[0];
+ tries++;
+ if (err_code < 0)
+ return err_code;
+ }
+ if (status != 0x0a)
+ PDEBUG(D_ERR, "status is %02x", status);
+
+ tries = 0;
+ while (tries < 4) {
+ data[0] = 0x19;
+ data[1] = 0x00;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = cam_get_response16(gspca_dev);
+ status = data[0];
+ tries++;
+ if (err_code < 0)
+ return err_code;
+ }
+
+ data[0] = 0x19;
+ err_code = mr_write(gspca_dev, 1);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = mr_read(gspca_dev, 16);
+ if (err_code < 0)
+ return err_code;
+
+ return 0;
+}
+
+static u8 get_sensor_id(struct gspca_dev *gspca_dev)
+{
+ int err_code;
+
+ gspca_dev->usb_buf[0] = 0x1e;
+ err_code = mr_write(gspca_dev, 1);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = mr_read(gspca_dev, 16);
+ if (err_code < 0)
+ return err_code;
+
+ PDEBUG(D_PROBE, "Byte zero reported is %01x", gspca_dev->usb_buf[0]);
+
+ return gspca_dev->usb_buf[0];
+}
+
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
+ struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
+ __u8 *data = gspca_dev->usb_buf;
+ int err_code;
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ if (id->idProduct == 0x010e) {
+ sd->cam_type = CAM_TYPE_CIF;
+ cam->nmodes--;
+
+ data[0] = 0x01;
+ data[1] = 0x01;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+ msleep(200);
+ data[0] = get_sensor_id(gspca_dev);
+ /*
+ * Known CIF cameras. If you have another to report, please do
+ *
+ * Name byte just read sd->sensor_type
+ * reported by
+ * Sakar Spy-shot 0x28 T. Kilgore 0
+ * Innovage 0xf5 (unstable) T. Kilgore 0
+ * Vivitar Mini 0x53 H. De Goede 0
+ * Vivitar Mini 0x04 / 0x24 E. Rodriguez 0
+ * Vivitar Mini 0x08 T. Kilgore 1
+ * Elta-Media 8212dc 0x23 T. Kaiser 1
+ * Philips dig. keych. 0x37 T. Kilgore 1
+ */
+ if ((data[0] & 0x78) == 8 ||
+ ((data[0] & 0x2) == 0x2 && data[0] != 0x53))
+ sd->sensor_type = 1;
+ else
+ sd->sensor_type = 0;
+
+ PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d",
+ sd->sensor_type);
+
+ if (force_sensor_type != -1) {
+ sd->sensor_type = !! force_sensor_type;
+ PDEBUG(D_PROBE, "Forcing sensor type to: %d",
+ sd->sensor_type);
+ }
+
+ if (sd->sensor_type == 0)
+ gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+ } else {
+ sd->cam_type = CAM_TYPE_VGA;
+ PDEBUG(D_PROBE, "MR97310A VGA camera detected");
+ gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) |
+ (1 << EXPOSURE_IDX) | (1 << GAIN_IDX);
+ }
+
+ sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
+ sd->exposure = MR97310A_EXPOSURE_DEFAULT;
+ sd->gain = MR97310A_GAIN_DEFAULT;
+
return 0;
}
@@ -96,183 +435,462 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
-static int sd_start(struct gspca_dev *gspca_dev)
+static int start_cif_cam(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 *data = gspca_dev->usb_buf;
int err_code;
-
- sd->sof_read = 0;
-
- /* Note: register descriptions guessed from MR97113A driver */
-
+ const __u8 startup_string[] = {
+ 0x00,
+ 0x0d,
+ 0x01,
+ 0x00, /* Hsize/8 for 352 or 320 */
+ 0x00, /* Vsize/4 for 288 or 240 */
+ 0x13, /* or 0xbb, depends on sensor */
+ 0x00, /* Hstart, depends on res. */
+ 0x00, /* reserved ? */
+ 0x00, /* Vstart, depends on res. and sensor */
+ 0x50, /* 0x54 to get 176 or 160 */
+ 0xc0
+ };
+
+ /* Note: Some of the above descriptions guessed from MR97113A driver */
data[0] = 0x01;
data[1] = 0x01;
- err_code = reg_w(gspca_dev, 2);
+ err_code = mr_write(gspca_dev, 2);
if (err_code < 0)
return err_code;
- data[0] = 0x00;
- data[1] = 0x0d;
- data[2] = 0x01;
- data[5] = 0x2b;
- data[7] = 0x00;
- data[9] = 0x50; /* reg 8, no scale down */
- data[10] = 0xc0;
+ memcpy(data, startup_string, 11);
+ if (sd->sensor_type)
+ data[5] = 0xbb;
switch (gspca_dev->width) {
case 160:
- data[9] |= 0x0c; /* reg 8, 4:1 scale down */
+ data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */
/* fall thru */
case 320:
- data[9] |= 0x04; /* reg 8, 2:1 scale down */
- /* fall thru */
- case 640:
default:
- data[3] = 0x50; /* reg 2, H size */
- data[4] = 0x78; /* reg 3, V size */
- data[6] = 0x04; /* reg 5, H start */
- data[8] = 0x03; /* reg 7, V start */
+ data[3] = 0x28; /* reg 2, H size/8 */
+ data[4] = 0x3c; /* reg 3, V size/4 */
+ data[6] = 0x14; /* reg 5, H start */
+ data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */
break;
-
case 176:
- data[9] |= 0x04; /* reg 8, 2:1 scale down */
+ data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */
/* fall thru */
case 352:
- data[3] = 0x2c; /* reg 2, H size */
- data[4] = 0x48; /* reg 3, V size */
- data[6] = 0x94; /* reg 5, H start */
- data[8] = 0x63; /* reg 7, V start */
+ data[3] = 0x2c; /* reg 2, H size/8 */
+ data[4] = 0x48; /* reg 3, V size/4 */
+ data[6] = 0x06; /* reg 5, H start */
+ data[8] = 0x06 + sd->sensor_type; /* reg 7, V start */
break;
}
-
- err_code = reg_w(gspca_dev, 11);
+ err_code = mr_write(gspca_dev, 11);
if (err_code < 0)
return err_code;
- data[0] = 0x0a;
- data[1] = 0x80;
- err_code = reg_w(gspca_dev, 2);
+ if (!sd->sensor_type) {
+ const struct sensor_w_data cif_sensor0_init_data[] = {
+ {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
+ 0x0f, 0x14, 0x0f, 0x10}, 8},
+ {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
+ {0x12, 0x00, {0x07}, 1},
+ {0x1f, 0x00, {0x06}, 1},
+ {0x27, 0x00, {0x04}, 1},
+ {0x29, 0x00, {0x0c}, 1},
+ {0x40, 0x00, {0x40, 0x00, 0x04}, 3},
+ {0x50, 0x00, {0x60}, 1},
+ {0x60, 0x00, {0x06}, 1},
+ {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6},
+ {0x72, 0x00, {0x1e, 0x56}, 2},
+ {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02,
+ 0x31, 0x80, 0x00}, 9},
+ {0x11, 0x00, {0x01}, 1},
+ {0, 0, {0}, 0}
+ };
+ err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
+ ARRAY_SIZE(cif_sensor0_init_data));
+ } else { /* sd->sensor_type = 1 */
+ const struct sensor_w_data cif_sensor1_init_data[] = {
+ /* Reg 3,4, 7,8 get set by the controls */
+ {0x02, 0x00, {0x10}, 1},
+ {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
+ {0x06, 0x01, {0x00}, 1},
+ {0x09, 0x02, {0x0e}, 1},
+ {0x0a, 0x02, {0x05}, 1},
+ {0x0b, 0x02, {0x05}, 1},
+ {0x0c, 0x02, {0x0f}, 1},
+ {0x0d, 0x02, {0x07}, 1},
+ {0x0e, 0x02, {0x0c}, 1},
+ {0x0f, 0x00, {0x00}, 1},
+ {0x10, 0x00, {0x06}, 1},
+ {0x11, 0x00, {0x07}, 1},
+ {0x12, 0x00, {0x00}, 1},
+ {0x13, 0x00, {0x01}, 1},
+ {0, 0, {0}, 0}
+ };
+ err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
+ ARRAY_SIZE(cif_sensor1_init_data));
+ }
if (err_code < 0)
return err_code;
- data[0] = 0x14;
- data[1] = 0x0a;
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ setbrightness(gspca_dev);
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
- data[0] = 0x1b;
- data[1] = 0x00;
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ msleep(200);
- data[0] = 0x15;
- data[1] = 0x16;
- err_code = reg_w(gspca_dev, 2);
+ data[0] = 0x00;
+ data[1] = 0x4d; /* ISOC transfering enable... */
+ err_code = mr_write(gspca_dev, 2);
if (err_code < 0)
return err_code;
- data[0] = 0x16;
- data[1] = 0x10;
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ return 0;
+}
- data[0] = 0x17;
- data[1] = 0x3a;
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+static int start_vga_cam(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 *data = gspca_dev->usb_buf;
+ int err_code;
+ const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
+ 0x00, 0x00, 0x00, 0x50, 0xc0};
- data[0] = 0x18;
- data[1] = 0x68;
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ /* What some of these mean is explained in start_cif_cam(), above */
+ sd->sof_read = 0;
- data[0] = 0x1f;
- data[1] = 0x00;
- data[2] = 0x02;
- data[3] = 0x06;
- data[4] = 0x59;
- data[5] = 0x0c;
- data[6] = 0x16;
- data[7] = 0x00;
- data[8] = 0x07;
- data[9] = 0x00;
- data[10] = 0x01;
- err_code = reg_w(gspca_dev, 11);
+ /*
+ * We have to know which camera we have, because the register writes
+ * depend upon the camera. This test, run before we actually enter
+ * the initialization routine, distinguishes most of the cameras, If
+ * needed, another routine is done later, too.
+ */
+ memset(data, 0, 16);
+ data[0] = 0x20;
+ err_code = mr_write(gspca_dev, 1);
if (err_code < 0)
return err_code;
- data[0] = 0x1f;
- data[1] = 0x04;
- data[2] = 0x11;
- data[3] = 0x01;
- err_code = reg_w(gspca_dev, 4);
+ err_code = mr_read(gspca_dev, 16);
if (err_code < 0)
return err_code;
- data[0] = 0x1f;
- data[1] = 0x00;
- data[2] = 0x0a;
- data[3] = 0x00;
- data[4] = 0x01;
- data[5] = 0x00;
- data[6] = 0x00;
- data[7] = 0x01;
- data[8] = 0x00;
- data[9] = 0x0a;
- err_code = reg_w(gspca_dev, 10);
- if (err_code < 0)
- return err_code;
+ PDEBUG(D_PROBE, "Byte reported is %02x", data[0]);
+
+ msleep(200);
+ /*
+ * Known VGA cameras. If you have another to report, please do
+ *
+ * Name byte just read sd->sensor_type
+ * sd->do_lcd_stop
+ * Aiptek Pencam VGA+ 0x31 0 1
+ * ION digital 0x31 0 1
+ * Argus DC-1620 0x30 1 0
+ * Argus QuickClix 0x30 1 1 (not caught here)
+ */
+ sd->sensor_type = data[0] & 1;
+ sd->do_lcd_stop = (~data[0]) & 1;
+
+
- data[0] = 0x1f;
- data[1] = 0x04;
- data[2] = 0x11;
- data[3] = 0x01;
- err_code = reg_w(gspca_dev, 4);
+ /* Streaming setup begins here. */
+
+
+ data[0] = 0x01;
+ data[1] = 0x01;
+ err_code = mr_write(gspca_dev, 2);
if (err_code < 0)
return err_code;
- data[0] = 0x1f;
- data[1] = 0x00;
- data[2] = 0x12;
- data[3] = 0x00;
- data[4] = 0x63;
- data[5] = 0x00;
- data[6] = 0x70;
- data[7] = 0x00;
- data[8] = 0x00;
- err_code = reg_w(gspca_dev, 9);
+ /*
+ * A second test can now resolve any remaining ambiguity in the
+ * identification of the camera type,
+ */
+ if (!sd->sensor_type) {
+ data[0] = get_sensor_id(gspca_dev);
+ if (data[0] == 0x7f) {
+ sd->sensor_type = 1;
+ PDEBUG(D_PROBE, "sensor_type corrected to 1");
+ }
+ msleep(200);
+ }
+
+ if (force_sensor_type != -1) {
+ sd->sensor_type = !! force_sensor_type;
+ PDEBUG(D_PROBE, "Forcing sensor type to: %d",
+ sd->sensor_type);
+ }
+
+ /*
+ * Known VGA cameras.
+ * This test is only run if the previous test returned 0x30, but
+ * here is the information for all others, too, just for reference.
+ *
+ * Name byte just read sd->sensor_type
+ *
+ * Aiptek Pencam VGA+ 0xfb (this test not run) 1
+ * ION digital 0xbd (this test not run) 1
+ * Argus DC-1620 0xe5 (no change) 0
+ * Argus QuickClix 0x7f (reclassified) 1
+ */
+ memcpy(data, startup_string, 11);
+ if (!sd->sensor_type) {
+ data[5] = 0x00;
+ data[10] = 0x91;
+ }
+
+ switch (gspca_dev->width) {
+ case 160:
+ data[9] |= 0x0c; /* reg 8, 4:1 scale down */
+ /* fall thru */
+ case 320:
+ data[9] |= 0x04; /* reg 8, 2:1 scale down */
+ /* fall thru */
+ case 640:
+ default:
+ data[3] = 0x50; /* reg 2, H size/8 */
+ data[4] = 0x78; /* reg 3, V size/4 */
+ data[6] = 0x04; /* reg 5, H start */
+ data[8] = 0x03; /* reg 7, V start */
+ if (sd->do_lcd_stop)
+ data[8] = 0x04; /* Bayer tile shifted */
+ break;
+
+ case 176:
+ data[9] |= 0x04; /* reg 8, 2:1 scale down */
+ /* fall thru */
+ case 352:
+ data[3] = 0x2c; /* reg 2, H size */
+ data[4] = 0x48; /* reg 3, V size */
+ data[6] = 0x94; /* reg 5, H start */
+ data[8] = 0x63; /* reg 7, V start */
+ if (sd->do_lcd_stop)
+ data[8] = 0x64; /* Bayer tile shifted */
+ break;
+ }
+
+ err_code = mr_write(gspca_dev, 11);
if (err_code < 0)
return err_code;
- data[0] = 0x1f;
- data[1] = 0x04;
- data[2] = 0x11;
- data[3] = 0x01;
- err_code = reg_w(gspca_dev, 4);
+ if (!sd->sensor_type) {
+ /* The only known sensor_type 0 cam is the Argus DC-1620 */
+ const struct sensor_w_data vga_sensor0_init_data[] = {
+ {0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
+ {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
+ {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
+ {0x25, 0x00, {0x03, 0xa9, 0x80}, 3},
+ {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4},
+ {0, 0, {0}, 0}
+ };
+ err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
+ ARRAY_SIZE(vga_sensor0_init_data));
+ } else { /* sd->sensor_type = 1 */
+ const struct sensor_w_data vga_sensor1_init_data[] = {
+ {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
+ 0x07, 0x00, 0x01}, 8},
+ {0x11, 0x04, {0x01}, 1},
+ /*{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, */
+ {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01,
+ 0x00, 0x0a}, 7},
+ {0x11, 0x04, {0x01}, 1},
+ {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6},
+ {0x11, 0x04, {0x01}, 1},
+ {0, 0, {0}, 0}
+ };
+ err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
+ ARRAY_SIZE(vga_sensor1_init_data));
+ }
if (err_code < 0)
return err_code;
+ msleep(200);
data[0] = 0x00;
data[1] = 0x4d; /* ISOC transfering enable... */
- err_code = reg_w(gspca_dev, 2);
+ err_code = mr_write(gspca_dev, 2);
+
+ return err_code;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err_code;
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+ sd->sof_read = 0;
+ /*
+ * Some of the supported cameras require the memory pointer to be
+ * set to 0, or else they will not stream.
+ */
+ zero_the_pointer(gspca_dev);
+ msleep(200);
+ if (sd->cam_type == CAM_TYPE_CIF) {
+ err_code = start_cif_cam(gspca_dev);
+ } else {
+ err_code = start_vga_cam(gspca_dev);
+ }
return err_code;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
int result;
gspca_dev->usb_buf[0] = 1;
gspca_dev->usb_buf[1] = 0;
- result = reg_w(gspca_dev, 2);
+ result = mr_write(gspca_dev, 2);
if (result < 0)
PDEBUG(D_ERR, "Camera Stop failed");
+
+ /* Not all the cams need this, but even if not, probably a good idea */
+ zero_the_pointer(gspca_dev);
+ if (sd->do_lcd_stop) {
+ gspca_dev->usb_buf[0] = 0x19;
+ gspca_dev->usb_buf[1] = 0x54;
+ result = mr_write(gspca_dev, 2);
+ if (result < 0)
+ PDEBUG(D_ERR, "Camera Stop failed");
+ }
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val;
+
+ if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX))
+ return;
+
+ /* Note register 7 is also seen as 0x8x or 0xCx in dumps */
+ if (sd->brightness > 0) {
+ sensor_write1(gspca_dev, 7, 0x00);
+ val = sd->brightness;
+ } else {
+ sensor_write1(gspca_dev, 7, 0x01);
+ val = 257 - sd->brightness;
+ }
+ sensor_write1(gspca_dev, 8, val);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val;
+
+ if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
+ return;
+
+ if (sd->sensor_type) {
+ val = sd->exposure >> 4;
+ sensor_write1(gspca_dev, 3, val);
+ val = sd->exposure & 0xf;
+ sensor_write1(gspca_dev, 4, val);
+ } else {
+ u8 clockdiv;
+ int exposure;
+
+ /* We have both a clock divider and an exposure register.
+ We first calculate the clock divider, as that determines
+ the maximum exposure and then we calculayte the exposure
+ register setting (which goes from 0 - 511).
+
+ Note our 0 - 4095 exposure is mapped to 0 - 511
+ milliseconds exposure time */
+ clockdiv = (60 * sd->exposure + 7999) / 8000;
+
+ /* Limit framerate to not exceed usb bandwidth */
+ if (clockdiv < 3 && gspca_dev->width >= 320)
+ clockdiv = 3;
+ else if (clockdiv < 2)
+ clockdiv = 2;
+
+ /* Frame exposure time in ms = 1000 * clockdiv / 60 ->
+ exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
+ exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
+ if (exposure > 511)
+ exposure = 511;
+
+ /* exposure register value is reversed! */
+ exposure = 511 - exposure;
+
+ sensor_write1(gspca_dev, 0x02, clockdiv);
+ sensor_write1(gspca_dev, 0x0e, exposure & 0xff);
+ sensor_write1(gspca_dev, 0x0f, exposure >> 8);
+ }
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
+ return;
+
+ if (sd->sensor_type) {
+ sensor_write1(gspca_dev, 0x0e, sd->gain);
+ } else {
+ sensor_write1(gspca_dev, 0x10, sd->gain);
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
}
/* Include pac common sof detection functions */
@@ -320,8 +938,9 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x08ca, 0x0111)},
- {USB_DEVICE(0x093a, 0x010f)},
+ {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */
+ {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */
+ {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c
index 95a97ab68..96659433d 100644
--- a/linux/drivers/media/video/gspca/pac207.c
+++ b/linux/drivers/media/video/gspca/pac207.c
@@ -35,25 +35,17 @@ MODULE_LICENSE("GPL");
#define PAC207_BRIGHTNESS_MIN 0
#define PAC207_BRIGHTNESS_MAX 255
-#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */
-
-/* An exposure value of 4 also works (3 does not) but then we need to lower
- the compression balance setting when in 352x288 mode, otherwise the usb
- bandwidth is not enough and packets get dropped resulting in corrupt
- frames. The problem with this is that when the compression balance gets
- lowered below 0x80, the pac207 starts using a different compression
- algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
- and currently we do not know how to decompress these lines, so for now
- we use a minimum exposure value of 5 */
-#define PAC207_EXPOSURE_MIN 5
+#define PAC207_BRIGHTNESS_DEFAULT 46
+
+#define PAC207_EXPOSURE_MIN 3
#define PAC207_EXPOSURE_MAX 26
-#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
-#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */
+#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */
#define PAC207_GAIN_MIN 0
#define PAC207_GAIN_MAX 31
#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
-#define PAC207_GAIN_KNEE 20
+#define PAC207_GAIN_KNEE 31
#define PAC207_AUTOGAIN_DEADZONE 30
@@ -166,16 +158,12 @@ static const struct v4l2_pix_format sif_mode[] = {
};
static const __u8 pac207_sensor_init[][8] = {
- {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
- {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
+ {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84},
+ {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
{0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
- {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
{0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
};
- /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
-static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
-
static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
const u8 *buffer, u16 length)
{
@@ -274,7 +262,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
* Bit_1=LED,
* Bit_2=Compression test mode enable */
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
- pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
return 0;
}
@@ -289,15 +276,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
- pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
- pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
- pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
+ pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8);
/* Compression Balance */
if (gspca_dev->width == 176)
pac207_write_reg(gspca_dev, 0x4a, 0xff);
else
- pac207_write_reg(gspca_dev, 0x4a, 0x88);
+ pac207_write_reg(gspca_dev, 0x4a, 0x30);
pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
pac207_write_reg(gspca_dev, 0x08, sd->brightness);
@@ -346,7 +331,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
- 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
+ 100, PAC207_AUTOGAIN_DEADZONE,
PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c
index ed10134c9..356111956 100644
--- a/linux/drivers/media/video/gspca/pac7311.c
+++ b/linux/drivers/media/video/gspca/pac7311.c
@@ -1071,6 +1071,7 @@ static struct sd_desc sd_desc = {
/* -- module initialisation -- */
static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
{USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
{USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
diff --git a/linux/drivers/media/video/gspca/sn9c20x.c b/linux/drivers/media/video/gspca/sn9c20x.c
index fc47f978e..99632a7d6 100644
--- a/linux/drivers/media/video/gspca/sn9c20x.c
+++ b/linux/drivers/media/video/gspca/sn9c20x.c
@@ -97,6 +97,16 @@ struct sd {
#endif
};
+struct i2c_reg_u8 {
+ u8 reg;
+ u8 val;
+};
+
+struct i2c_reg_u16 {
+ u8 reg;
+ u16 val;
+};
+
static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
@@ -406,7 +416,7 @@ static const struct v4l2_pix_format sxga_mode[] = {
.priv = 3 | MODE_RAW | MODE_SXGA},
};
-static const int hsv_red_x[] = {
+static const s16 hsv_red_x[] = {
41, 44, 46, 48, 50, 52, 54, 56,
58, 60, 62, 64, 66, 68, 70, 72,
74, 76, 78, 80, 81, 83, 85, 87,
@@ -454,7 +464,7 @@ static const int hsv_red_x[] = {
24, 26, 28, 30, 33, 35, 37, 39, 41
};
-static const int hsv_red_y[] = {
+static const s16 hsv_red_y[] = {
82, 80, 78, 76, 74, 73, 71, 69,
67, 65, 63, 61, 58, 56, 54, 52,
50, 48, 46, 44, 41, 39, 37, 35,
@@ -502,7 +512,7 @@ static const int hsv_red_y[] = {
96, 94, 92, 91, 89, 87, 85, 84, 82
};
-static const int hsv_green_x[] = {
+static const s16 hsv_green_x[] = {
-124, -124, -125, -125, -125, -125, -125, -125,
-125, -126, -126, -125, -125, -125, -125, -125,
-125, -124, -124, -124, -123, -123, -122, -122,
@@ -550,7 +560,7 @@ static const int hsv_green_x[] = {
-120, -120, -121, -122, -122, -123, -123, -124, -124
};
-static const int hsv_green_y[] = {
+static const s16 hsv_green_y[] = {
-100, -99, -98, -97, -95, -94, -93, -91,
-90, -89, -87, -86, -84, -83, -81, -80,
-78, -76, -75, -73, -71, -70, -68, -66,
@@ -598,7 +608,7 @@ static const int hsv_green_y[] = {
-109, -108, -107, -106, -105, -104, -103, -102, -100
};
-static const int hsv_blue_x[] = {
+static const s16 hsv_blue_x[] = {
112, 113, 114, 114, 115, 116, 117, 117,
118, 118, 119, 119, 120, 120, 120, 121,
121, 121, 122, 122, 122, 122, 122, 122,
@@ -646,7 +656,7 @@ static const int hsv_blue_x[] = {
104, 105, 106, 107, 108, 109, 110, 111, 112
};
-static const int hsv_blue_y[] = {
+static const s16 hsv_blue_y[] = {
-11, -13, -15, -17, -19, -21, -23, -25,
-27, -29, -31, -33, -35, -37, -39, -41,
-43, -45, -46, -48, -50, -52, -54, -55,
@@ -795,21 +805,21 @@ static u8 hv7131r_gain[] = {
0x78 /* 8x */
};
-static u8 soi968_init[][2] = {
+static struct i2c_reg_u8 soi968_init[] = {
{0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
{0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
{0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
{0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
- {0x13, 0x8a}, {0x12, 0x40}, {0x17, 0x13},
+ {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
{0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
{0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
{0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
{0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
};
-static u8 ov7660_init[][2] = {
+static struct i2c_reg_u8 ov7660_init[] = {
{0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
{0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
{0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
@@ -818,7 +828,7 @@ static u8 ov7660_init[][2] = {
{0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
};
-static u8 ov7670_init[][2] = {
+static struct i2c_reg_u8 ov7670_init[] = {
{0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
@@ -875,7 +885,7 @@ static u8 ov7670_init[][2] = {
{0x93, 0x00},
};
-static u8 ov9650_init[][2] = {
+static struct i2c_reg_u8 ov9650_init[] = {
{0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
@@ -905,7 +915,7 @@ static u8 ov9650_init[][2] = {
{0xaa, 0x92}, {0xab, 0x0a},
};
-static u8 ov9655_init[][2] = {
+static struct i2c_reg_u8 ov9655_init[] = {
{0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61},
{0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24},
{0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08},
@@ -942,7 +952,7 @@ static u8 ov9655_init[][2] = {
{0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
};
-static u16 mt9v112_init[][2] = {
+static struct i2c_reg_u16 mt9v112_init[] = {
{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
{0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
{0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
@@ -961,7 +971,7 @@ static u16 mt9v112_init[][2] = {
{0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
};
-static u16 mt9v111_init[][2] = {
+static struct i2c_reg_u16 mt9v111_init[] = {
{0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
{0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
{0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
@@ -988,7 +998,7 @@ static u16 mt9v111_init[][2] = {
{0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004},
};
-static u16 mt9v011_init[][2] = {
+static struct i2c_reg_u16 mt9v011_init[] = {
{0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
{0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
{0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
@@ -1015,7 +1025,7 @@ static u16 mt9v011_init[][2] = {
{0x06, 0x0029}, {0x05, 0x0009},
};
-static u16 mt9m001_init[][2] = {
+static struct i2c_reg_u16 mt9m001_init[] = {
{0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
{0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
{0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
@@ -1028,14 +1038,14 @@ static u16 mt9m001_init[][2] = {
{0x2e, 0x0029}, {0x07, 0x0002},
};
-static u16 mt9m111_init[][2] = {
- {0xf0, 0x0000}, {0x0d, 0x0008}, {0x0d, 0x0009},
- {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300},
- {0x9b, 0x4300}, {0xa1, 0x0280}, {0xa4, 0x0200},
- {0x06, 0x308e}, {0xf0, 0x0000},
+static struct i2c_reg_u16 mt9m111_init[] = {
+ {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
+ {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
+ {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
+ {0xf0, 0x0000},
};
-static u8 hv7131r_init[][2] = {
+static struct i2c_reg_u8 hv7131r_init[] = {
{0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
{0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
{0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
@@ -1046,7 +1056,7 @@ static u8 hv7131r_init[][2] = {
{0x23, 0x09}, {0x01, 0x08},
};
-int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
@@ -1065,7 +1075,8 @@ int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
return 0;
}
-int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length)
+static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+ const u8 *buffer, int length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
@@ -1085,13 +1096,13 @@ int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length)
return 0;
}
-int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
{
u8 data[1] = {value};
return reg_w(gspca_dev, reg, data, 1);
}
-int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
{
int i;
reg_w(gspca_dev, 0x10c0, buffer, 8);
@@ -1107,7 +1118,7 @@ int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
return -EIO;
}
-int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1129,7 +1140,7 @@ int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
return i2c_w(gspca_dev, row);
}
-int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1206,8 +1217,8 @@ static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
- if (i2c_w1(gspca_dev, ov9650_init[i][0],
- ov9650_init[i][1]) < 0) {
+ if (i2c_w1(gspca_dev, ov9650_init[i].reg,
+ ov9650_init[i].val) < 0) {
err("OV9650 sensor initialization failed");
return -ENODEV;
}
@@ -1223,8 +1234,8 @@ static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
- if (i2c_w1(gspca_dev, ov9655_init[i][0],
- ov9655_init[i][1]) < 0) {
+ if (i2c_w1(gspca_dev, ov9655_init[i].reg,
+ ov9655_init[i].val) < 0) {
err("OV9655 sensor initialization failed");
return -ENODEV;
}
@@ -1242,14 +1253,14 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
- if (i2c_w1(gspca_dev, soi968_init[i][0],
- soi968_init[i][1]) < 0) {
+ if (i2c_w1(gspca_dev, soi968_init[i].reg,
+ soi968_init[i].val) < 0) {
err("SOI968 sensor initialization failed");
return -ENODEV;
}
}
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
sd->hstart = 60;
sd->vstart = 11;
return 0;
@@ -1261,8 +1272,8 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
- if (i2c_w1(gspca_dev, ov7660_init[i][0],
- ov7660_init[i][1]) < 0) {
+ if (i2c_w1(gspca_dev, ov7660_init[i].reg,
+ ov7660_init[i].val) < 0) {
err("OV7660 sensor initialization failed");
return -ENODEV;
}
@@ -1280,8 +1291,8 @@ static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
- if (i2c_w1(gspca_dev, ov7670_init[i][0],
- ov7670_init[i][1]) < 0) {
+ if (i2c_w1(gspca_dev, ov7670_init[i].reg,
+ ov7670_init[i].val) < 0) {
err("OV7670 sensor initialization failed");
return -ENODEV;
}
@@ -1304,8 +1315,8 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
ret = i2c_r2(gspca_dev, 0xff, &value);
if ((ret == 0) && (value == 0x8243)) {
for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
- if (i2c_w2(gspca_dev, mt9v011_init[i][0],
- mt9v011_init[i][1]) < 0) {
+ if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
+ mt9v011_init[i].val) < 0) {
err("MT9V011 sensor initialization failed");
return -ENODEV;
}
@@ -1322,8 +1333,8 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
ret = i2c_r2(gspca_dev, 0xff, &value);
if ((ret == 0) && (value == 0x823a)) {
for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
- if (i2c_w2(gspca_dev, mt9v111_init[i][0],
- mt9v111_init[i][1]) < 0) {
+ if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
+ mt9v111_init[i].val) < 0) {
err("MT9V111 sensor initialization failed");
return -ENODEV;
}
@@ -1344,8 +1355,8 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
ret = i2c_r2(gspca_dev, 0x00, &value);
if ((ret == 0) && (value == 0x1229)) {
for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
- if (i2c_w2(gspca_dev, mt9v112_init[i][0],
- mt9v112_init[i][1]) < 0) {
+ if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
+ mt9v112_init[i].val) < 0) {
err("MT9V112 sensor initialization failed");
return -ENODEV;
}
@@ -1365,12 +1376,13 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int i;
for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
- if (i2c_w2(gspca_dev, mt9m111_init[i][0],
- mt9m111_init[i][1]) < 0) {
+ if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
+ mt9m111_init[i].val) < 0) {
err("MT9M111 sensor initialization failed");
return -ENODEV;
}
}
+ gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
sd->hstart = 0;
sd->vstart = 2;
return 0;
@@ -1381,8 +1393,8 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int i;
for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
- if (i2c_w2(gspca_dev, mt9m001_init[i][0],
- mt9m001_init[i][1]) < 0) {
+ if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
+ mt9m001_init[i].val) < 0) {
err("MT9M001 sensor initialization failed");
return -ENODEV;
}
@@ -1400,8 +1412,8 @@ static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
- if (i2c_w1(gspca_dev, hv7131r_init[i][0],
- hv7131r_init[i][1]) < 0) {
+ if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
+ hv7131r_init[i].val) < 0) {
err("HV7131R Sensor initialization failed");
return -ENODEV;
}
@@ -1625,7 +1637,6 @@ static int set_exposure(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
- case SENSOR_SOI968:
case SENSOR_OV9655:
case SENSOR_OV9650:
exp[0] |= (3 << 4);
@@ -1634,7 +1645,6 @@ static int set_exposure(struct gspca_dev *gspca_dev)
exp[4] = sd->exposure >> 8;
break;
case SENSOR_MT9M001:
- case SENSOR_MT9M111:
case SENSOR_MT9V112:
case SENSOR_MT9V111:
case SENSOR_MT9V011:
@@ -1650,6 +1660,8 @@ static int set_exposure(struct gspca_dev *gspca_dev)
exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8;
exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff;
break;
+ default:
+ return 0;
}
i2c_w(gspca_dev, exp);
return 0;
@@ -1676,7 +1688,6 @@ static int set_gain(struct gspca_dev *gspca_dev)
gain[4] = micron1_gain[sd->gain] & 0xff;
break;
case SENSOR_MT9V112:
- case SENSOR_MT9M111:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
gain[3] = micron1_gain[sd->gain] >> 8;
@@ -1693,6 +1704,8 @@ static int set_gain(struct gspca_dev *gspca_dev)
gain[2] = 0x30;
gain[3] = hv7131r_gain[sd->gain];
break;
+ default:
+ return 0;
}
i2c_w(gspca_dev, gain);
return 0;
@@ -1995,7 +2008,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->i2c_addr = id->driver_info & 0xff;
switch (sd->sensor) {
+ case SENSOR_MT9M111:
case SENSOR_OV9650:
+ case SENSOR_SOI968:
cam->cam_mode = sxga_mode;
cam->nmodes = ARRAY_SIZE(sxga_mode);
break;
@@ -2111,6 +2126,25 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
struct sd *sd = (struct sd *) gspca_dev;
u8 value;
switch (sd->sensor) {
+ case SENSOR_SOI968:
+ if (mode & MODE_SXGA) {
+ i2c_w1(gspca_dev, 0x17, 0x1d);
+ i2c_w1(gspca_dev, 0x18, 0xbd);
+ i2c_w1(gspca_dev, 0x19, 0x01);
+ i2c_w1(gspca_dev, 0x1a, 0x81);
+ i2c_w1(gspca_dev, 0x12, 0x00);
+ sd->hstart = 140;
+ sd->vstart = 19;
+ } else {
+ i2c_w1(gspca_dev, 0x17, 0x13);
+ i2c_w1(gspca_dev, 0x18, 0x63);
+ i2c_w1(gspca_dev, 0x19, 0x01);
+ i2c_w1(gspca_dev, 0x1a, 0x79);
+ i2c_w1(gspca_dev, 0x12, 0x40);
+ sd->hstart = 60;
+ sd->vstart = 11;
+ }
+ break;
case SENSOR_OV9650:
if (mode & MODE_SXGA) {
i2c_w1(gspca_dev, 0x17, 0x1b);
@@ -2128,6 +2162,17 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
}
break;
+ case SENSOR_MT9M111:
+ if (mode & MODE_SXGA) {
+ i2c_w2(gspca_dev, 0xf0, 0x0002);
+ i2c_w2(gspca_dev, 0xc8, 0x970b);
+ i2c_w2(gspca_dev, 0xf0, 0x0000);
+ } else {
+ i2c_w2(gspca_dev, 0xf0, 0x0002);
+ i2c_w2(gspca_dev, 0xc8, 0x8000);
+ i2c_w2(gspca_dev, 0xf0, 0x0000);
+ }
+ break;
}
}
@@ -2216,15 +2261,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
kfree(sd->jpeg_hdr);
}
-static void do_autoexposure(struct gspca_dev *gspca_dev)
+static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
{
struct sd *sd = (struct sd *) gspca_dev;
- int avg_lum, new_exp;
-
- if (!sd->auto_exposure)
- return;
-
- avg_lum = atomic_read(&sd->avg_lum);
+ s16 new_exp;
/*
* some hardcoded values are present
@@ -2271,6 +2311,39 @@ static void do_autoexposure(struct gspca_dev *gspca_dev)
}
}
+static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (avg_lum < MIN_AVG_LUM) {
+ if (sd->gain + 1 <= 28) {
+ sd->gain++;
+ set_gain(gspca_dev);
+ }
+ }
+ if (avg_lum > MAX_AVG_LUM) {
+ if (sd->gain - 1 >= 0) {
+ sd->gain--;
+ set_gain(gspca_dev);
+ }
+ }
+}
+
+static void sd_dqcallback(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int avg_lum;
+
+ if (!sd->auto_exposure)
+ return;
+
+ avg_lum = atomic_read(&sd->avg_lum);
+ if (sd->sensor == SENSOR_SOI968)
+ do_autogain(gspca_dev, avg_lum);
+ else
+ do_autoexposure(gspca_dev, avg_lum);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
u8 *data, /* isoc packet */
@@ -2338,7 +2411,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
- .dq_callback = do_autoexposure,
+ .dq_callback = sd_dqcallback,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.set_register = sd_dbg_s_register,
.get_register = sd_dbg_g_register,
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index 98fb39c99..3746ddbbe 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -741,7 +741,7 @@ static const u8 ov7660_sensor_init[][8] = {
/* COM 1 BAVE GEAVE AECHH */
{0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
{0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
-#if 1
+#if 0
{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
#else
{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
@@ -795,7 +795,7 @@ static const u8 ov7660_sensor_init[][8] = {
{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
- {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
/****** (some exchanges in the win trace) ******/
{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
/* bits[3..0]reserved */
@@ -1165,17 +1165,19 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w1(gspca_dev, 0x01, 0x42);
break;
case SENSOR_OV7660:
+#if 0
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0x20);
reg_w1(gspca_dev, 0x01, 0x60);
reg_w1(gspca_dev, 0x01, 0x40);
break;
+#endif
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
reg_w1(gspca_dev, 0x01, 0x62);
reg_w1(gspca_dev, 0x01, 0x42);
- mdelay(100);
+ msleep(100);
reg_w1(gspca_dev, 0x02, 0x62);
break;
/* case SENSOR_HV7131R: */
@@ -1654,6 +1656,8 @@ static void setvflip(struct sd *sd)
static void setinfrared(struct sd *sd)
{
+ if (sd->gspca_dev.ctrl_dis & (1 << INFRARED_IDX))
+ return;
/*fixme: different sequence for StarCam Clip and StarCam 370i */
#if 1
/* Clip */
@@ -1675,14 +1679,14 @@ static void setfreq(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_OV7660) {
u8 com8;
-#if 1
- com8 = 0xf8; /* no auto gain/wb/expo */
+#if 0
+ com8 = 0xd8; /* no auto gain/wb/expo */
#else
- com8 = 0xff;
+ com8 = 0xdf; /* auto gain/wb/expo */
#endif
switch (sd->freq) {
case 0: /* Banding filter disabled */
- i2c_w1(gspca_dev, 0x13, com8 & 0xdf);
+ i2c_w1(gspca_dev, 0x13, com8 | 0x20);
break;
case 1: /* 50 hz */
i2c_w1(gspca_dev, 0x13, com8);
@@ -1839,12 +1843,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x99, 0x60);
break;
case SENSOR_OV7660:
+#if 0
reg_w1(gspca_dev, 0x9a, 0x05);
if (sd->bridge == BRIDGE_SN9C105)
reg_w1(gspca_dev, 0x99, 0xff);
else
reg_w1(gspca_dev, 0x99, 0x5b);
break;
+#endif
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x9a, 0x05);
reg_w1(gspca_dev, 0x99, 0x59);
@@ -2373,14 +2379,14 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)},
/* {USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */
{USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)},
-/* {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6801, 0x??)}, */
+/* {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6802, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */
{USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)},
/* {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
{USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
- {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
#endif
{USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c
index 61dfc714f..9c4a2e6db 100644
--- a/linux/drivers/media/video/gspca/spca501.c
+++ b/linux/drivers/media/video/gspca/spca501.c
@@ -1948,7 +1948,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
sd->subtype = id->driver_info;
sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c
index 3a0c893f9..a199298a6 100644
--- a/linux/drivers/media/video/gspca/spca506.c
+++ b/linux/drivers/media/video/gspca/spca506.c
@@ -286,7 +286,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
index 0da8e0de0..7af511b5e 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -130,8 +130,8 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
STV06XX_URB_MSG_TIMEOUT);
if (err < 0)
return err;
- }
- return stv06xx_write_sensor_finish(sd);
+ }
+ return stv06xx_write_sensor_finish(sd);
}
int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c
index 270b86f24..32ff7cd32 100644
--- a/linux/drivers/media/video/gspca/sunplus.c
+++ b/linux/drivers/media/video/gspca/sunplus.c
@@ -32,22 +32,22 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
- unsigned char contrast;
- unsigned char colors;
- unsigned char autogain;
+ s8 brightness;
+ u8 contrast;
+ u8 colors;
+ u8 autogain;
u8 quality;
#define QUALITY_MIN 70
#define QUALITY_MAX 95
#define QUALITY_DEF 85
- char bridge;
+ u8 bridge;
#define BRIDGE_SPCA504 0
#define BRIDGE_SPCA504B 1
#define BRIDGE_SPCA504C 2
#define BRIDGE_SPCA533 3
#define BRIDGE_SPCA536 4
- char subtype;
+ u8 subtype;
#define AiptekMiniPenCam13 1
#define LogitechClickSmart420 2
#define LogitechClickSmart820 3
@@ -68,21 +68,20 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
{
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
- .minimum = 0,
- .maximum = 0xff,
+ .minimum = -128,
+ .maximum = 127,
.step = 1,
- .default_value = 0,
+#define BRIGHTNESS_DEF 0
+ .default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
-#define SD_CONTRAST 1
{
{
.id = V4L2_CID_CONTRAST,
@@ -91,12 +90,12 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
- .default_value = 0x20,
+#define CONTRAST_DEF 0x20
+ .default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
.get = sd_getcontrast,
},
-#define SD_COLOR 2
{
{
.id = V4L2_CID_SATURATION,
@@ -105,12 +104,12 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
- .default_value = 0x1a,
+#define COLOR_DEF 0x1a
+ .default_value = COLOR_DEF,
},
.set = sd_setcolors,
.get = sd_getcolors,
},
-#define SD_AUTOGAIN 3
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -119,7 +118,8 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
@@ -181,14 +181,20 @@ static const struct v4l2_pix_format vga_mode2[] = {
#define SPCA504_PCCAM600_OFFSET_MODE 5
#define SPCA504_PCCAM600_OFFSET_DATA 14
/* Frame packet header offsets for the spca533 */
-#define SPCA533_OFFSET_DATA 16
+#define SPCA533_OFFSET_DATA 16
#define SPCA533_OFFSET_FRAMSEQ 15
/* Frame packet header offsets for the spca536 */
-#define SPCA536_OFFSET_DATA 4
-#define SPCA536_OFFSET_FRAMSEQ 1
+#define SPCA536_OFFSET_DATA 4
+#define SPCA536_OFFSET_FRAMSEQ 1
+
+struct cmd {
+ u8 req;
+ u16 val;
+ u16 idx;
+};
/* Initialisation data for the Creative PC-CAM 600 */
-static const __u16 spca504_pccam600_init_data[][3] = {
+static const struct cmd spca504_pccam600_init_data[] = {
/* {0xa0, 0x0000, 0x0503}, * capture mode */
{0x00, 0x0000, 0x2000},
{0x00, 0x0013, 0x2301},
@@ -219,22 +225,20 @@ static const __u16 spca504_pccam600_init_data[][3] = {
{0x00, 0x0003, 0x2000},
{0x00, 0x0013, 0x2301},
{0x00, 0x0003, 0x2000},
- {}
};
/* Creative PC-CAM 600 specific open data, sent before using the
* generic initialisation data from spca504_open_data.
*/
-static const __u16 spca504_pccam600_open_data[][3] = {
+static const struct cmd spca504_pccam600_open_data[] = {
{0x00, 0x0001, 0x2501},
{0x20, 0x0500, 0x0001}, /* snapshot mode */
{0x00, 0x0003, 0x2880},
{0x00, 0x0001, 0x2881},
- {}
};
/* Initialisation data for the logitech clicksmart 420 */
-static const __u16 spca504A_clicksmart420_init_data[][3] = {
+static const struct cmd spca504A_clicksmart420_init_data[] = {
/* {0xa0, 0x0000, 0x0503}, * capture mode */
{0x00, 0x0000, 0x2000},
{0x00, 0x0013, 0x2301},
@@ -261,7 +265,7 @@ static const __u16 spca504A_clicksmart420_init_data[][3] = {
#endif
#if 1
- {0x0a1, 0x0080, 0x0001},
+ {0xa1, 0x0080, 0x0001},
{0x30, 0x0049, 0x0000},
{0x30, 0x0060, 0x0005},
{0x0c, 0x0004, 0x0000},
@@ -285,11 +289,10 @@ static const __u16 spca504A_clicksmart420_init_data[][3] = {
{0x00, 0x0013, 0x2301},
{0x00, 0x0003, 0x2000},
#endif
- {}
};
/* clicksmart 420 open data ? */
-static const __u16 spca504A_clicksmart420_open_data[][3] = {
+static const struct cmd spca504A_clicksmart420_open_data[] = {
{0x00, 0x0001, 0x2501},
{0x20, 0x0502, 0x0000},
{0x06, 0x0000, 0x0000},
@@ -433,10 +436,9 @@ static const __u16 spca504A_clicksmart420_open_data[][3] = {
{0x00, 0x0028, 0x287f},
{0xa0, 0x0000, 0x0503},
- {}
};
-static const __u8 qtable_creative_pccam[2][64] = {
+static const u8 qtable_creative_pccam[2][64] = {
{ /* Q-table Y-components */
0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
@@ -461,7 +463,7 @@ static const __u8 qtable_creative_pccam[2][64] = {
* except for one byte. Possibly a typo?
* NWG: 18/05/2003.
*/
-static const __u8 qtable_spca504_default[2][64] = {
+static const u8 qtable_spca504_default[2][64] = {
{ /* Q-table Y-components */
0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
@@ -485,9 +487,9 @@ static const __u8 qtable_spca504_default[2][64] = {
/* read <len> bytes to gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
- __u16 req,
- __u16 index,
- __u16 len)
+ u8 req,
+ u16 index,
+ u16 len)
{
#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
@@ -505,31 +507,26 @@ static void reg_r(struct gspca_dev *gspca_dev,
500);
}
-/* write <len> bytes from gspca_dev->usb_buf */
-static void reg_w(struct gspca_dev *gspca_dev,
- __u16 req,
- __u16 value,
- __u16 index,
- __u16 len)
+/* write one byte */
+static void reg_w_1(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 value,
+ u16 index,
+ u16 byte)
{
-#ifdef GSPCA_DEBUG
- if (len > USB_BUF_SZ) {
- err("reg_w: buffer overflow");
- return;
- }
-#endif
+ gspca_dev->usb_buf[0] = byte;
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index,
- len ? gspca_dev->usb_buf : NULL, len,
+ gspca_dev->usb_buf, 1,
500);
}
/* write req / index / value */
static int reg_w_riv(struct usb_device *dev,
- __u16 req, __u16 index, __u16 value)
+ u8 req, u16 index, u16 value)
{
int ret;
@@ -547,7 +544,7 @@ static int reg_w_riv(struct usb_device *dev,
/* read 1 byte */
static int reg_r_1(struct gspca_dev *gspca_dev,
- __u16 value) /* wValue */
+ u16 value) /* wValue */
{
int ret;
@@ -568,9 +565,9 @@ static int reg_r_1(struct gspca_dev *gspca_dev,
/* read 1 or 2 bytes - returns < 0 if error */
static int reg_r_12(struct gspca_dev *gspca_dev,
- __u16 req, /* bRequest */
- __u16 index, /* wIndex */
- __u16 length) /* wLength (1 or 2 only) */
+ u8 req, /* bRequest */
+ u16 index, /* wIndex */
+ u16 length) /* wLength (1 or 2 only) */
{
int ret;
@@ -591,43 +588,40 @@ static int reg_r_12(struct gspca_dev *gspca_dev,
}
static int write_vector(struct gspca_dev *gspca_dev,
- const __u16 data[][3])
+ const struct cmd *data, int ncmds)
{
struct usb_device *dev = gspca_dev->dev;
- int ret, i = 0;
+ int ret;
- while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
- ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
+ while (--ncmds >= 0) {
+ ret = reg_w_riv(dev, data->req, data->idx, data->val);
if (ret < 0) {
PDEBUG(D_ERR,
- "Register write failed for 0x%x,0x%x,0x%x",
- data[i][0], data[i][1], data[i][2]);
+ "Register write failed for 0x%02x, 0x%04x, 0x%04x",
+ data->req, data->val, data->idx);
return ret;
}
- i++;
+ data++;
}
return 0;
}
static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
- unsigned int request,
- unsigned int ybase,
- unsigned int cbase,
- const __u8 qtable[2][64])
+ const u8 qtable[2][64])
{
struct usb_device *dev = gspca_dev->dev;
int i, err;
/* loop over y components */
for (i = 0; i < 64; i++) {
- err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
+ err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]);
if (err < 0)
return err;
}
/* loop over c components */
for (i = 0; i < 64; i++) {
- err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
+ err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]);
if (err < 0)
return err;
}
@@ -635,34 +629,34 @@ static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
}
static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
- __u16 req, __u16 idx, __u16 val)
+ u8 req, u16 idx, u16 val)
{
struct usb_device *dev = gspca_dev->dev;
- __u8 notdone;
+ int notdone;
reg_w_riv(dev, req, idx, val);
notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
reg_w_riv(dev, req, idx, val);
- PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+ PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
msleep(200);
notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
- PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+ PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
}
static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
- __u16 req,
- __u16 idx, __u16 val, __u8 stat, __u8 count)
+ u8 req,
+ u16 idx, u16 val, u8 stat, u8 count)
{
struct usb_device *dev = gspca_dev->dev;
- __u8 status;
- __u8 endcode;
+ int status;
+ u8 endcode;
reg_w_riv(dev, req, idx, val);
status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
endcode = stat;
- PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+ PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat);
if (!count)
return;
count = 200;
@@ -672,7 +666,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
/* reg_w_riv(dev, req, idx, val); */
status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
if (status == endcode) {
- PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+ PDEBUG(D_FRAM, "status 0x%04x after wait %d",
status, 200 - count);
break;
}
@@ -699,8 +693,7 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
while (--count > 0) {
reg_r(gspca_dev, 0x21, 1, 1);
if (gspca_dev->usb_buf[0] != 0) {
- gspca_dev->usb_buf[0] = 0;
- reg_w(gspca_dev, 0x21, 0, 1, 1);
+ reg_w_1(gspca_dev, 0x21, 0, 1, 0);
reg_r(gspca_dev, 0x21, 1, 1);
spca504B_PollingDataReady(gspca_dev);
break;
@@ -711,7 +704,7 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
{
- __u8 *data;
+ u8 *data;
data = gspca_dev->usb_buf;
reg_r(gspca_dev, 0x20, 0, 5);
@@ -725,41 +718,34 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- __u8 Size;
- __u8 Type;
+ u8 Size;
int rc;
- Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- Type = 0;
+ Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (sd->bridge) {
case BRIDGE_SPCA533:
- reg_w(gspca_dev, 0x31, 0, 0, 0);
+ reg_w_riv(dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev);
spca50x_GetFirmware(gspca_dev);
- gspca_dev->usb_buf[0] = 2; /* type */
- reg_w(gspca_dev, 0x24, 0, 8, 1);
+ reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
reg_r(gspca_dev, 0x24, 8, 1);
- gspca_dev->usb_buf[0] = Size;
- reg_w(gspca_dev, 0x25, 0, 4, 1);
+ reg_w_1(gspca_dev, 0x25, 0, 4, Size);
reg_r(gspca_dev, 0x25, 4, 1); /* size */
rc = spca504B_PollingDataReady(gspca_dev);
/* Init the cam width height with some values get on init ? */
- reg_w(gspca_dev, 0x31, 0, 4, 0);
+ reg_w_riv(dev, 0x31, 0, 0x04);
spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev);
break;
default:
/* case BRIDGE_SPCA504B: */
/* case BRIDGE_SPCA536: */
- gspca_dev->usb_buf[0] = Size;
- reg_w(gspca_dev, 0x25, 0, 4, 1);
+ reg_w_1(gspca_dev, 0x25, 0, 4, Size);
reg_r(gspca_dev, 0x25, 4, 1); /* size */
- Type = 6;
- gspca_dev->usb_buf[0] = Type;
- reg_w(gspca_dev, 0x27, 0, 0, 1);
+ reg_w_1(gspca_dev, 0x27, 0, 0, 6);
reg_r(gspca_dev, 0x27, 0, 1); /* type */
rc = spca504B_PollingDataReady(gspca_dev);
break;
@@ -799,17 +785,51 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
static void spca504B_setQtable(struct gspca_dev *gspca_dev)
{
- gspca_dev->usb_buf[0] = 3;
- reg_w(gspca_dev, 0x26, 0, 0, 1);
+ reg_w_1(gspca_dev, 0x26, 0, 0, 3);
reg_r(gspca_dev, 0x26, 0, 1);
spca504B_PollingDataReady(gspca_dev);
}
-static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ u16 reg;
+
+ reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
+ reg_w_riv(dev, 0x00, reg, sd->brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ u16 reg;
+
+ reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
+ reg_w_riv(dev, 0x00, reg, sd->contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ u16 reg;
+
+ reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
+ reg_w_riv(dev, 0x00, reg, sd->colors);
+}
+
+static void init_ctl_reg(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
int pollreg = 1;
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors(gspca_dev);
+
switch (sd->bridge) {
case BRIDGE_SPCA504:
case BRIDGE_SPCA504C:
@@ -818,20 +838,14 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
default:
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA504B: */
- reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
- reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
- reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
- reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
- reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
- reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
+ reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */
+ reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */
+ reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */
break;
case BRIDGE_SPCA536:
- reg_w(gspca_dev, 0, 0, 0x20f0, 0);
- reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
- reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
- reg_w(gspca_dev, 0, 1, 0x20f4, 0);
- reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
- reg_w(gspca_dev, 0, 0, 0x2089, 0);
+ reg_w_riv(dev, 0, 0x40, 0x20f5);
+ reg_w_riv(dev, 0, 0x01, 0x20f4);
+ reg_w_riv(dev, 0, 0x00, 0x2089);
break;
}
if (pollreg)
@@ -872,7 +886,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* case BRIDGE_SPCA504: */
/* case BRIDGE_SPCA536: */
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes =ARRAY_SIZE(vga_mode);
break;
case BRIDGE_SPCA533:
cam->cam_mode = custom_mode;
@@ -883,12 +897,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
case BRIDGE_SPCA504C:
cam->cam_mode = vga_mode2;
- cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode2);
break;
}
- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
- sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
sd->quality = QUALITY_DEF;
return 0;
}
@@ -898,32 +913,29 @@ static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- int rc;
- __u8 i;
- __u8 info[6];
- int err_code;
+ int i, err_code;
+ u8 info[6];
switch (sd->bridge) {
case BRIDGE_SPCA504B:
- reg_w(gspca_dev, 0x1d, 0, 0, 0);
- reg_w(gspca_dev, 0, 1, 0x2306, 0);
- reg_w(gspca_dev, 0, 0, 0x0d04, 0);
- reg_w(gspca_dev, 0, 0, 0x2000, 0);
- reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
- reg_w(gspca_dev, 0, 0, 0x2306, 0);
+ reg_w_riv(dev, 0x1d, 0x00, 0);
+ reg_w_riv(dev, 0, 0x01, 0x2306);
+ reg_w_riv(dev, 0, 0x00, 0x0d04);
+ reg_w_riv(dev, 0, 0x00, 0x2000);
+ reg_w_riv(dev, 0, 0x13, 0x2301);
+ reg_w_riv(dev, 0, 0x00, 0x2306);
/* fall thru */
case BRIDGE_SPCA533:
- rc = spca504B_PollingDataReady(gspca_dev);
+ spca504B_PollingDataReady(gspca_dev);
spca50x_GetFirmware(gspca_dev);
break;
case BRIDGE_SPCA536:
spca50x_GetFirmware(gspca_dev);
reg_r(gspca_dev, 0x00, 0x5002, 1);
- gspca_dev->usb_buf[0] = 0;
- reg_w(gspca_dev, 0x24, 0, 0, 1);
+ reg_w_1(gspca_dev, 0x24, 0, 0, 0);
reg_r(gspca_dev, 0x24, 0, 1);
- rc = spca504B_PollingDataReady(gspca_dev);
- reg_w(gspca_dev, 0x34, 0, 0, 0);
+ spca504B_PollingDataReady(gspca_dev);
+ reg_w_riv(dev, 0x34, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
break;
case BRIDGE_SPCA504C: /* pccam600 */
@@ -933,12 +945,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
spca504_wait_status(gspca_dev);
if (sd->subtype == LogitechClickSmart420)
write_vector(gspca_dev,
- spca504A_clicksmart420_open_data);
+ spca504A_clicksmart420_open_data,
+ ARRAY_SIZE(spca504A_clicksmart420_open_data));
else
- write_vector(gspca_dev, spca504_pccam600_open_data);
+ write_vector(gspca_dev, spca504_pccam600_open_data,
+ ARRAY_SIZE(spca504_pccam600_open_data));
err_code = spca50x_setup_qtable(gspca_dev,
- 0x00, 0x2800,
- 0x2840, qtable_creative_pccam);
+ qtable_creative_pccam);
if (err_code < 0) {
PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
return err_code;
@@ -976,8 +989,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
6, 0, 0x86, 1); */
/* spca504A_acknowledged_command (gspca_dev, 0x24,
0, 0, 0x9D, 1); */
- reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
- reg_w_riv(dev, 0x0, 0x2310, 0x05);
+ reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */
+ reg_w_riv(dev, 0x00, 0x2310, 0x05);
spca504A_acknowledged_command(gspca_dev, 0x01,
0x0f, 0, 0xff, 0);
}
@@ -985,8 +998,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w_riv(dev, 0, 0x2000, 0);
reg_w_riv(dev, 0, 0x2883, 1);
err_code = spca50x_setup_qtable(gspca_dev,
- 0x00, 0x2800,
- 0x2840,
qtable_spca504_default);
if (err_code < 0) {
PDEBUG(D_ERR, "spca50x_setup_qtable failed");
@@ -1001,10 +1012,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- int rc;
int enable;
- __u8 i;
- __u8 info[6];
+ int i;
+ u8 info[6];
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
@@ -1022,17 +1032,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA504B: */
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA536: */
- if (sd->subtype == MegapixV4 ||
- sd->subtype == LogitechClickSmart820 ||
- sd->subtype == MegaImageVI) {
- reg_w(gspca_dev, 0xf0, 0, 0, 0);
+ switch (sd->subtype) {
+ case MegapixV4:
+ case LogitechClickSmart820:
+ case MegaImageVI:
+ reg_w_riv(dev, 0xf0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
reg_r(gspca_dev, 0xf0, 4, 0);
spca504B_WaitCmdStatus(gspca_dev);
- } else {
- reg_w(gspca_dev, 0x31, 0, 4, 0);
+ break;
+ default:
+ reg_w_riv(dev, 0x31, 0, 0x04);
spca504B_WaitCmdStatus(gspca_dev);
- rc = spca504B_PollingDataReady(gspca_dev);
+ spca504B_PollingDataReady(gspca_dev);
+ break;
}
break;
case BRIDGE_SPCA504:
@@ -1066,15 +1079,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
}
spca504B_SetSizeType(gspca_dev);
- reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
- reg_w_riv(dev, 0x0, 0x2310, 0x05);
+ reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */
+ reg_w_riv(dev, 0x00, 0x2310, 0x05);
break;
case BRIDGE_SPCA504C:
if (sd->subtype == LogitechClickSmart420) {
write_vector(gspca_dev,
- spca504A_clicksmart420_init_data);
+ spca504A_clicksmart420_init_data,
+ ARRAY_SIZE(spca504A_clicksmart420_init_data));
} else {
- write_vector(gspca_dev, spca504_pccam600_init_data);
+ write_vector(gspca_dev, spca504_pccam600_init_data,
+ ARRAY_SIZE(spca504_pccam600_init_data));
}
enable = (sd->autogain ? 0x04 : 0x01);
reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */
@@ -1086,7 +1101,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
spca504B_SetSizeType(gspca_dev);
break;
}
- sp5xx_initContBrigHueRegisters(gspca_dev);
+ init_ctl_reg(gspca_dev);
return 0;
}
@@ -1100,7 +1115,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA536: */
/* case BRIDGE_SPCA504B: */
- reg_w(gspca_dev, 0x31, 0, 0, 0);
+ reg_w_riv(dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
break;
@@ -1118,7 +1133,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
0x0f, 0x00, 0xff, 1);
} else {
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
- reg_w_riv(dev, 0x01, 0x000f, 0x00);
+ reg_w_riv(dev, 0x01, 0x000f, 0x0000);
}
break;
}
@@ -1133,12 +1148,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
- __u8 *data, /* isoc packet */
+ u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
int i, sof = 0;
- static unsigned char ffd9[] = {0xff, 0xd9};
+ static u8 ffd9[] = {0xff, 0xd9};
/* frames are jpeg 4.1.1 without 0xff escape */
switch (sd->bridge) {
@@ -1226,63 +1241,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
-
- switch (sd->bridge) {
- default:
-/* case BRIDGE_SPCA533: */
-/* case BRIDGE_SPCA504B: */
-/* case BRIDGE_SPCA504: */
-/* case BRIDGE_SPCA504C: */
- reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
- break;
- case BRIDGE_SPCA536:
- reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
- break;
- }
-}
-
-static void setcontrast(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
-
- switch (sd->bridge) {
- default:
-/* case BRIDGE_SPCA533: */
-/* case BRIDGE_SPCA504B: */
-/* case BRIDGE_SPCA504: */
-/* case BRIDGE_SPCA504C: */
- reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
- break;
- case BRIDGE_SPCA536:
- reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
- break;
- }
-}
-
-static void setcolors(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
-
- switch (sd->bridge) {
- default:
-/* case BRIDGE_SPCA533: */
-/* case BRIDGE_SPCA504B: */
-/* case BRIDGE_SPCA504: */
-/* case BRIDGE_SPCA504C: */
- reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
- break;
- case BRIDGE_SPCA536:
- reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
- break;
- }
-}
-
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index 6f9aab89c..9464454f1 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -1940,109 +1940,200 @@ static const u8 po3130_initQVGA_data[][4] = {
};
static const u8 hv7131r_gamma[17] = {
-/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- * 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
+#if 1
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+#else
0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+#endif
};
static const u8 hv7131r_matrix[9] = {
0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
};
static const u8 hv7131r_initVGA_data[][4] = {
- {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x20, 0xdd},
{0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x01, 0x45, 0xcc}, {0xb3, 0x03, 0x0b, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc},
+ {0xb3, 0x03, 0x0b, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x02, 0xcc},
{0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0x91, 0xcc}, {0xb3, 0x00, 0x27, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc},
{0xbc, 0x00, 0x73, 0xcc},
- {0xb8, 0x00, 0x23, 0xcc}, {0x00, 0x01, 0x0c, 0xaa},
- {0x00, 0x14, 0x01, 0xaa}, {0x00, 0x15, 0xe6, 0xaa},
- {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x17, 0x86, 0xaa}, {0x00, 0x23, 0x00, 0xaa},
- {0x00, 0x25, 0x09, 0xaa}, {0x00, 0x26, 0x27, 0xaa},
- {0x00, 0x27, 0xc0, 0xaa},
- {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x00, 0x23, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
{0xb8, 0x30, 0x50, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc},
- {0xb8, 0x33, 0xf8, 0xcc}, {0xb8, 0x34, 0x65, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x58, 0xcc},
{0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x01, 0x7d, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x7d, 0xcc},
{0xb8, 0x81, 0x09, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc},
- {0xb8, 0xff, 0x28, 0xcc}, {0xb9, 0x00, 0x28, 0xcc},
- {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
- {0xb9, 0x06, 0x3c, 0xcc},
- {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0x00, 0x01, 0x0c, 0xaa},
+ {0x00, 0x14, 0x01, 0xaa},
+ {0x00, 0x15, 0xe6, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa},
+ {0x00, 0x23, 0x00, 0xaa},
+ {0x00, 0x25, 0x03, 0xaa},
+ {0x00, 0x26, 0xa9, 0xaa},
+ {0x00, 0x27, 0x80, 0xaa},
{0x00, 0x30, 0x18, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
{}
};
static const u8 hv7131r_initQVGA_data[][4] = {
- {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x20, 0xdd},
{0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x03, 0x0b, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc},
+ {0xb3, 0x03, 0x0b, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
{0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x02, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
{0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0x91, 0xcc},
- {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
- {0xb8, 0x00, 0x21, 0xcc},
- {0x00, 0x01, 0x0c, 0xaa}, {0x00, 0x14, 0x01, 0xaa},
- {0x00, 0x15, 0xe6, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x17, 0x86, 0xaa},
- {0x00, 0x23, 0x00, 0xaa}, {0x00, 0x25, 0x01, 0xaa},
- {0x00, 0x26, 0xd4, 0xaa}, {0x00, 0x27, 0xc0, 0xaa},
- {0xbc, 0x02, 0x08, 0xcc},
- {0xbc, 0x03, 0x70, 0xcc}, {0xbc, 0x04, 0x08, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x3c, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x04, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
- {0xb8, 0xfe, 0x02, 0xcc},
- {0xb8, 0xff, 0x07, 0xcc}, {0xb9, 0x00, 0x14, 0xcc},
- {0xb9, 0x01, 0x14, 0xcc}, {0xb9, 0x02, 0x14, 0xcc},
- {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x02, 0xcc}, {0xb9, 0x05, 0x05, 0xcc},
- {0xb9, 0x06, 0x0f, 0xcc}, {0xb9, 0x07, 0x0f, 0xcc},
- {0xb9, 0x08, 0x0f, 0xcc},
- {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc},
+ {0xbc, 0x00, 0xd3, 0xcc},
+ {0xb8, 0x00, 0x23, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
{0xb8, 0x30, 0x50, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
{0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x65, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x34, 0x58, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
{0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc},
- {0xb8, 0xff, 0x28, 0xcc},
- {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc},
- {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
- {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x01, 0x7d, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
{0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc}, {0x00, 0x30, 0x18, 0xaa},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0x00, 0x01, 0x0c, 0xaa},
+ {0x00, 0x14, 0x01, 0xaa},
+ {0x00, 0x15, 0xe6, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa},
+ {0x00, 0x23, 0x00, 0xaa},
+ {0x00, 0x25, 0x03, 0xaa},
+ {0x00, 0x26, 0xa9, 0xaa},
+ {0x00, 0x27, 0x80, 0xaa},
+ {0x00, 0x30, 0x18, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc},
+ {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc},
+ {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc},
+ {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
{}
};
@@ -3319,21 +3410,22 @@ static int sd_start(struct gspca_dev *gspca_dev)
put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
/* set the led on 0x0892 0x0896 */
- if (sd->sensor == SENSOR_PO1200) {
- setsharpness(gspca_dev);
- sethvflip(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_PO1200:
+ case SENSOR_HV7131R:
reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
- } else if (sd->sensor == SENSOR_MI1310_SOC) {
+ break;
+ case SENSOR_MI1310_SOC:
reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
- msleep(100);
- sethvflip(gspca_dev);
- setlightfreq(gspca_dev);
- } else {
+ break;
+ default:
reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
- msleep(100);
- sethvflip(gspca_dev);
- setlightfreq(gspca_dev);
+ break;
}
+ msleep(100);
+ setsharpness(gspca_dev);
+ sethvflip(gspca_dev);
+ setlightfreq(gspca_dev);
}
return 0;
}
diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c
index 2a9480138..02b6e185f 100644
--- a/linux/drivers/media/video/gspca/zc3xx.c
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -7607,7 +7607,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
- .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
.start = sd_start,
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-control.c b/linux/drivers/media/video/hdpvr/hdpvr-control.c
index 06791749d..5a6b78b8d 100644
--- a/linux/drivers/media/video/hdpvr/hdpvr-control.c
+++ b/linux/drivers/media/video/hdpvr/hdpvr-control.c
@@ -178,24 +178,24 @@ error:
int hdpvr_set_options(struct hdpvr_device *dev)
{
- hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
+ hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
- hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
+ hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
dev->options.video_input+1);
- hdpvr_set_audio(dev, dev->options.audio_input+1,
+ hdpvr_set_audio(dev, dev->options.audio_input+1,
dev->options.audio_codec);
- hdpvr_set_bitrate(dev);
- hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+ hdpvr_set_bitrate(dev);
+ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
dev->options.bitrate_mode);
- hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
+ hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
- hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
- hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast);
- hdpvr_config_call(dev, CTRL_HUE, dev->options.hue);
- hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
- hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness);
+ hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
+ hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast);
+ hdpvr_config_call(dev, CTRL_HUE, dev->options.hue);
+ hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
+ hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness);
- return 0;
+ return 0;
}
diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c
index a1e8fb561..3b05bfcae 100644
--- a/linux/drivers/media/video/ir-kbd-i2c.c
+++ b/linux/drivers/media/video/ir-kbd-i2c.c
@@ -371,7 +371,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
#endif
{
- IR_KEYTAB_TYPE *ir_codes = NULL;
+ struct ir_scancode_table *ir_codes = NULL;
const char *name = NULL;
int ir_type;
struct IR_i2c *ir;
@@ -407,13 +407,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
name = "Pixelview";
ir->get_key = get_key_pixelview;
ir_type = IR_TYPE_OTHER;
- ir_codes = ir_codes_empty;
+ ir_codes = &ir_codes_empty_table;
break;
case 0x4b:
name = "PV951";
ir->get_key = get_key_pv951;
ir_type = IR_TYPE_OTHER;
- ir_codes = ir_codes_pv951;
+ ir_codes = &ir_codes_pv951_table;
break;
case 0x18:
case 0x1a:
@@ -421,22 +421,22 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir->get_key = get_key_haup;
ir_type = IR_TYPE_RC5;
if (hauppauge == 1) {
- ir_codes = ir_codes_hauppauge_new;
+ ir_codes = &ir_codes_hauppauge_new_table;
} else {
- ir_codes = ir_codes_rc5_tv;
+ ir_codes = &ir_codes_rc5_tv_table;
}
break;
case 0x30:
name = "KNC One";
ir->get_key = get_key_knc1;
ir_type = IR_TYPE_OTHER;
- ir_codes = ir_codes_empty;
+ ir_codes = &ir_codes_empty_table;
break;
case 0x6b:
name = "FusionHDTV";
ir->get_key = get_key_fusionhdtv;
ir_type = IR_TYPE_RC5;
- ir_codes = ir_codes_fusionhdtv_mce;
+ ir_codes = &ir_codes_fusionhdtv_mce_table;
break;
case 0x7a:
case 0x47:
@@ -450,9 +450,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir_type = IR_TYPE_RC5;
ir->get_key = get_key_haup_xvr;
if (hauppauge == 1) {
- ir_codes = ir_codes_hauppauge_new;
+ ir_codes = &ir_codes_hauppauge_new_table;
} else {
- ir_codes = ir_codes_rc5_tv;
+ ir_codes = &ir_codes_rc5_tv_table;
}
} else {
/* Handled by saa7134-input */
@@ -464,7 +464,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
name = "AVerMedia Cardbus remote";
ir->get_key = get_key_avermedia_cardbus;
ir_type = IR_TYPE_OTHER;
- ir_codes = ir_codes_avermedia_cardbus;
+ ir_codes = &ir_codes_avermedia_cardbus_table;
break;
default:
dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr);
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index fbb8586c5..383d401b4 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -246,7 +246,7 @@ MODULE_PARM_DESC(newi2c,
"\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
"\t\t\tDefault is autodetect");
-MODULE_PARM_DESC(ivtv_first_minor, "Set kernel number assigned to first card");
+MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card");
MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
MODULE_DESCRIPTION("CX23415/CX23416 driver");
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c
index b5c94d646..32d0b84d7 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -165,19 +165,19 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
return -1;
if (hw == IVTV_HW_TUNER) {
/* special tuner handling */
- sd = v4l2_i2c_new_probed_subdev(&itv->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
adap, mod, type,
- itv->card_i2c->radio);
+ 0, itv->card_i2c->radio);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_probed_subdev(&itv->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
adap, mod, type,
- itv->card_i2c->demod);
+ 0, itv->card_i2c->demod);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_probed_subdev(&itv->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
adap, mod, type,
- itv->card_i2c->tv);
+ 0, itv->card_i2c->tv);
if (sd)
sd->grp_id = 1 << idx;
return sd ? 0 : -1;
@@ -185,11 +185,11 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
if (!hw_addrs[idx])
return -1;
if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
- sd = v4l2_i2c_new_probed_subdev_addr(&itv->v4l2_dev,
- adap, mod, type, hw_addrs[idx]);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+ adap, mod, type, 0, I2C_ADDRS(hw_addrs[idx]));
} else {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type, hw_addrs[idx]);
+ adap, mod, type, hw_addrs[idx], NULL);
}
if (sd)
sd->grp_id = 1 << idx;
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 15da01710..67699e3f2 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -261,8 +261,8 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
video_set_drvdata(s->vdev, s);
/* Register device. First try the desired minor, then any free one. */
- if (video_register_device(s->vdev, vfl_type, num)) {
- IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+ if (video_register_device_no_warn(s->vdev, vfl_type, num)) {
+ IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
s->name, num);
video_device_release(s->vdev);
s->vdev = NULL;
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index e609d68c4..93052047c 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -13,13 +13,13 @@
#include <linux/i2c.h>
#include <linux/log2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/* mt9m001 i2c address 0x5d
- * The platform has to define i2c_board_info
- * and call i2c_register_board_info() */
+ * The platform has to define ctruct i2c_board_info objects and link to them
+ * from struct soc_camera_link */
/* mt9m001 selected register addresses */
#define MT9M001_CHIP_VERSION 0x00
@@ -39,6 +39,13 @@
#define MT9M001_GLOBAL_GAIN 0x35
#define MT9M001_CHIP_ENABLE 0xF1
+#define MT9M001_MAX_WIDTH 1280
+#define MT9M001_MAX_HEIGHT 1024
+#define MT9M001_MIN_WIDTH 48
+#define MT9M001_MIN_HEIGHT 32
+#define MT9M001_COLUMN_SKIP 20
+#define MT9M001_ROW_SKIP 12
+
static const struct soc_camera_data_format mt9m001_colour_formats[] = {
/* Order important: first natively supported,
* second supported with a GPIO extender */
@@ -69,12 +76,20 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
};
struct mt9m001 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
+ struct v4l2_rect rect; /* Sensor window */
+ __u32 fourcc;
int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ unsigned int gain;
+ unsigned int exposure;
unsigned char autoexposure;
};
+static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
@@ -109,35 +124,20 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
return reg_write(client, reg, ret & ~data);
}
-static int mt9m001_init(struct soc_camera_device *icd)
+static int mt9m001_init(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
- dev_dbg(icd->vdev->parent, "%s\n", __func__);
+ dev_dbg(&client->dev, "%s\n", __func__);
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
- /* The camera could have been already on, we reset it additionally */
- if (icl->reset)
- ret = icl->reset(&client->dev);
- else
- ret = -ENODEV;
+ /*
+ * We don't know, whether platform provides reset, issue a soft reset
+ * too. This returns all registers to their default values.
+ */
+ ret = reg_write(client, MT9M001_RESET, 1);
+ if (!ret)
+ ret = reg_write(client, MT9M001_RESET, 0);
- if (ret < 0) {
- /* Either no platform reset, or platform reset failed */
- ret = reg_write(client, MT9M001_RESET, 1);
- if (!ret)
- ret = reg_write(client, MT9M001_RESET, 0);
- }
/* Disable chip, synchronous option update */
if (!ret)
ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
@@ -145,36 +145,12 @@ static int mt9m001_init(struct soc_camera_device *icd)
return ret;
}
-static int mt9m001_release(struct soc_camera_device *icd)
+static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
-
- /* Disable the chip */
- reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
-
- if (icl->power)
- icl->power(&client->dev, 0);
-
- return 0;
-}
+ struct i2c_client *client = sd->priv;
-static int mt9m001_start_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Switch to master "normal" mode */
- if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0)
- return -EIO;
- return 0;
-}
-
-static int mt9m001_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Stop sensor readout */
- if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0)
+ /* Switch to master "normal" mode or stop sensor readout */
+ if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
return -EIO;
return 0;
}
@@ -182,8 +158,7 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd)
static int mt9m001_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
/* Only one width bit may be set */
@@ -205,8 +180,7 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
/* MT9M001 has all capture_format parameters fixed */
unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
@@ -220,13 +194,35 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int mt9m001_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_rect rect = a->c;
+ struct soc_camera_device *icd = client->dev.platform_data;
int ret;
const u16 hblank = 9, vblank = 25;
+ unsigned int total_h;
+
+ if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 ||
+ mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16)
+ /*
+ * Bayer format - even number of rows for simplicity,
+ * but let the user play with the top row.
+ */
+ rect.height = ALIGN(rect.height, 2);
+
+ /* Datasheet requirement: see register description */
+ rect.width = ALIGN(rect.width, 2);
+ rect.left = ALIGN(rect.left, 2);
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
+
+ total_h = rect.height + icd->y_skip_top + vblank;
/* Blanking and start values - default... */
ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
@@ -236,66 +232,126 @@ static int mt9m001_set_crop(struct soc_camera_device *icd,
/* The caller provides a supported format, as verified per
* call to icd->try_fmt() */
if (!ret)
- ret = reg_write(client, MT9M001_COLUMN_START, rect->left);
+ ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
if (!ret)
- ret = reg_write(client, MT9M001_ROW_START, rect->top);
+ ret = reg_write(client, MT9M001_ROW_START, rect.top);
if (!ret)
- ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1);
+ ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
if (!ret)
ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
- rect->height + icd->y_skip_top - 1);
+ rect.height + icd->y_skip_top - 1);
if (!ret && mt9m001->autoexposure) {
- ret = reg_write(client, MT9M001_SHUTTER_WIDTH,
- rect->height + icd->y_skip_top + vblank);
+ ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
if (!ret) {
const struct v4l2_queryctrl *qctrl =
soc_camera_find_qctrl(icd->ops,
V4L2_CID_EXPOSURE);
- icd->exposure = (524 + (rect->height + icd->y_skip_top +
- vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9m001->exposure = (524 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
1048 + qctrl->minimum;
}
}
+ if (!ret)
+ mt9m001->rect = rect;
+
return ret;
}
-static int mt9m001_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ a->c = mt9m001->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9M001_COLUMN_SKIP;
+ a->bounds.top = MT9M001_ROW_SKIP;
+ a->bounds.width = MT9M001_MAX_WIDTH;
+ a->bounds.height = MT9M001_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = f->fmt.pix.width,
- .height = f->fmt.pix.height,
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = mt9m001->rect.width;
+ pix->height = mt9m001->rect.height;
+ pix->pixelformat = mt9m001->fourcc;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_crop a = {
+ .c = {
+ .left = mt9m001->rect.left,
+ .top = mt9m001->rect.top,
+ .width = pix->width,
+ .height = pix->height,
+ },
};
+ int ret;
/* No support for scaling so far, just crop. TODO: use skipping */
- return mt9m001_set_crop(icd, &rect);
+ ret = mt9m001_s_crop(sd, &a);
+ if (!ret) {
+ pix->width = mt9m001->rect.width;
+ pix->height = mt9m001->rect.height;
+ mt9m001->fourcc = pix->pixelformat;
+ }
+
+ return ret;
}
-static int mt9m001_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
+ struct i2c_client *client = sd->priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
- v4l_bound_align_image(&pix->width, 48, 1280, 1,
- &pix->height, 32 + icd->y_skip_top,
- 1024 + icd->y_skip_top, 0, 0);
+ v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH,
+ MT9M001_MAX_WIDTH, 1,
+ &pix->height, MT9M001_MIN_HEIGHT + icd->y_skip_top,
+ MT9M001_MAX_HEIGHT + icd->y_skip_top, 0, 0);
+
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
+ pix->pixelformat == V4L2_PIX_FMT_SBGGR16)
+ pix->height = ALIGN(pix->height - 1, 2);
return 0;
}
-static int mt9m001_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9m001->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9m001->model;
@@ -305,10 +361,10 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m001_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m001_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -325,10 +381,10 @@ static int mt9m001_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9m001_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m001_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -381,39 +437,17 @@ static const struct v4l2_queryctrl mt9m001_controls[] = {
}
};
-static int mt9m001_video_probe(struct soc_camera_device *);
-static void mt9m001_video_remove(struct soc_camera_device *);
-static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *);
-
static struct soc_camera_ops mt9m001_ops = {
- .owner = THIS_MODULE,
- .probe = mt9m001_video_probe,
- .remove = mt9m001_video_remove,
- .init = mt9m001_init,
- .release = mt9m001_release,
- .start_capture = mt9m001_start_capture,
- .stop_capture = mt9m001_stop_capture,
- .set_crop = mt9m001_set_crop,
- .set_fmt = mt9m001_set_fmt,
- .try_fmt = mt9m001_try_fmt,
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.controls = mt9m001_controls,
.num_controls = ARRAY_SIZE(mt9m001_controls),
- .get_control = mt9m001_get_control,
- .set_control = mt9m001_set_control,
- .get_chip_id = mt9m001_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9m001_get_register,
- .set_register = mt9m001_set_register,
-#endif
};
-static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
int data;
switch (ctrl->id) {
@@ -426,14 +460,21 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9m001->autoexposure;
break;
+ case V4L2_CID_GAIN:
+ ctrl->value = mt9m001->gain;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = mt9m001->exposure;
+ break;
}
return 0;
}
-static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
int data;
@@ -460,7 +501,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
- dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
@@ -478,7 +519,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
else
data = ((gain - 64) * 7 + 28) / 56 + 96;
- dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+ dev_dbg(&client->dev, "Setting gain from %d to %d\n",
reg_read(client, MT9M001_GLOBAL_GAIN), data);
data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
if (data < 0)
@@ -486,7 +527,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
}
/* Success */
- icd->gain = ctrl->value;
+ mt9m001->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
/* mt9m001 has maximum == default */
@@ -497,23 +538,27 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 +
range / 2) / range + 1;
- dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n",
- reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+ dev_dbg(&client->dev,
+ "Setting shutter width from %d to %lu\n",
+ reg_read(client, MT9M001_SHUTTER_WIDTH),
+ shutter);
if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
+ mt9m001->exposure = ctrl->value;
mt9m001->autoexposure = 0;
}
break;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->value) {
const u16 vblank = 25;
- if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height +
- icd->y_skip_top + vblank) < 0)
+ unsigned int total_h = mt9m001->rect.height +
+ icd->y_skip_top + vblank;
+ if (reg_write(client, MT9M001_SHUTTER_WIDTH,
+ total_h) < 0)
return -EIO;
qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9m001->exposure = (524 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
1048 + qctrl->minimum;
mt9m001->autoexposure = 1;
} else
@@ -525,14 +570,14 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9m001_video_probe(struct soc_camera_device *icd)
+static int mt9m001_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
s32 data;
- int ret;
unsigned long flags;
+ int ret;
/* We must have a parent by now. And it cannot be a wrong one.
* So this entire test is completely redundant. */
@@ -542,7 +587,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
/* Enable the chip */
data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
- dev_dbg(&icd->dev, "write: %d\n", data);
+ dev_dbg(&client->dev, "write: %d\n", data);
/* Read out the chip version register */
data = reg_read(client, MT9M001_CHIP_VERSION);
@@ -559,10 +604,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
icd->formats = mt9m001_monochrome_formats;
break;
default:
- ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9M001 chip detected, register read %x\n", data);
- goto ei2c;
+ return -ENODEV;
}
icd->num_formats = 0;
@@ -585,33 +629,57 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
if (flags & SOCAM_DATAWIDTH_8)
icd->num_formats++;
- dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+ mt9m001->fourcc = icd->formats->fourcc;
+
+ dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
data == 0x8431 ? "C12STM" : "C12ST");
- /* Now that we know the model, we can start video */
- ret = soc_camera_video_start(icd);
- if (ret)
- goto eisis;
+ ret = mt9m001_init(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
- return 0;
+ /* mt9m001_init() has reset the chip, returning registers to defaults */
+ mt9m001->gain = 64;
+ mt9m001->exposure = 255;
-eisis:
-ei2c:
return ret;
}
static void mt9m001_video_remove(struct soc_camera_device *icd)
{
- struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
- struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
+ dev_dbg(&icd->dev, "Video removed: %p, %p\n",
icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
if (icl->free_bus)
icl->free_bus(icl);
}
+static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
+ .g_ctrl = mt9m001_g_ctrl,
+ .s_ctrl = mt9m001_s_ctrl,
+ .g_chip_ident = mt9m001_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m001_g_register,
+ .s_register = mt9m001_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
+ .s_stream = mt9m001_s_stream,
+ .s_fmt = mt9m001_s_fmt,
+ .g_fmt = mt9m001_g_fmt,
+ .try_fmt = mt9m001_try_fmt,
+ .s_crop = mt9m001_s_crop,
+ .g_crop = mt9m001_g_crop,
+ .cropcap = mt9m001_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9m001_subdev_ops = {
+ .core = &mt9m001_subdev_core_ops,
+ .video = &mt9m001_subdev_video_ops,
+};
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static int mt9m001_probe(struct i2c_client *client,
const struct i2c_device_id *did)
@@ -620,11 +688,17 @@ static int mt9m001_probe(struct i2c_client *client)
#endif
{
struct mt9m001 *mt9m001;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9M001 driver needs platform data\n");
return -EINVAL;
@@ -640,43 +714,40 @@ static int mt9m001_probe(struct i2c_client *client)
if (!mt9m001)
return -ENOMEM;
- mt9m001->client = client;
- i2c_set_clientdata(client, mt9m001);
+ v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
/* Second stage probe - when a capture adapter is there */
- icd = &mt9m001->icd;
- icd->ops = &mt9m001_ops;
- icd->control = &client->dev;
- icd->x_min = 20;
- icd->y_min = 12;
- icd->x_current = 20;
- icd->y_current = 12;
- icd->width_min = 48;
- icd->width_max = 1280;
- icd->height_min = 32;
- icd->height_max = 1024;
- icd->y_skip_top = 1;
- icd->iface = icl->bus_id;
+ icd->ops = &mt9m001_ops;
+ icd->y_skip_top = 0;
+
+ mt9m001->rect.left = MT9M001_COLUMN_SKIP;
+ mt9m001->rect.top = MT9M001_ROW_SKIP;
+ mt9m001->rect.width = MT9M001_MAX_WIDTH;
+ mt9m001->rect.height = MT9M001_MAX_HEIGHT;
+
/* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width */
mt9m001->autoexposure = 1;
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
-
- return 0;
+ ret = mt9m001_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9m001);
+ }
-eisdr:
- kfree(mt9m001);
return ret;
}
static int mt9m001_remove(struct i2c_client *client)
{
- struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&mt9m001->icd);
+ icd->ops = NULL;
+ mt9m001_video_remove(icd);
+ i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9m001);
return 0;
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
index 77639ae5c..8171edb72 100644
--- a/linux/drivers/media/video/mt9m111.c
+++ b/linux/drivers/media/video/mt9m111.c
@@ -148,12 +148,12 @@ enum mt9m111_context {
};
struct mt9m111 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
enum mt9m111_context context;
struct v4l2_rect rect;
u32 pixfmt;
+ unsigned int gain;
unsigned char autoexposure;
unsigned char datawidth;
unsigned int powered:1;
@@ -166,6 +166,11 @@ struct mt9m111 {
unsigned int autowhitebalance:1;
};
+static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
+}
+
static int reg_page_map_set(struct i2c_client *client, const u16 reg)
{
int ret;
@@ -190,7 +195,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
ret = reg_page_map_set(client, reg);
if (!ret)
- ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
+ ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff));
dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
return ret;
@@ -203,7 +208,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
ret = reg_page_map_set(client, reg);
if (!ret)
- ret = i2c_smbus_write_word_data(client, (reg & 0xff),
+ ret = i2c_smbus_write_word_data(client, reg & 0xff,
swab16(data));
dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
return ret;
@@ -229,10 +234,9 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
return mt9m111_reg_write(client, reg, ret & ~data);
}
-static int mt9m111_set_context(struct soc_camera_device *icd,
+static int mt9m111_set_context(struct i2c_client *client,
enum mt9m111_context ctxt)
{
- struct i2c_client *client = to_i2c_client(icd->control);
int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
| MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
| MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -246,17 +250,16 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
return reg_write(CONTEXT_CONTROL, valA);
}
-static int mt9m111_setup_rect(struct soc_camera_device *icd,
+static int mt9m111_setup_rect(struct i2c_client *client,
struct v4l2_rect *rect)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret, is_raw_format;
int width = rect->width;
int height = rect->height;
- if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
- || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
+ if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
+ mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)
is_raw_format = 1;
else
is_raw_format = 0;
@@ -292,9 +295,8 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
+static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
{
- struct i2c_client *client = to_i2c_client(icd->control);
int ret;
ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
@@ -303,19 +305,19 @@ static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
return ret;
}
-static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd)
+static int mt9m111_setfmt_bayer8(struct i2c_client *client)
{
- return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER);
+ return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER);
}
-static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
+static int mt9m111_setfmt_bayer10(struct i2c_client *client)
{
- return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP);
+ return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP);
}
-static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
+static int mt9m111_setfmt_rgb565(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int val = 0;
if (mt9m111->swap_rgb_red_blue)
@@ -324,12 +326,12 @@ static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
- return mt9m111_setup_pixfmt(icd, val);
+ return mt9m111_setup_pixfmt(client, val);
}
-static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
+static int mt9m111_setfmt_rgb555(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int val = 0;
if (mt9m111->swap_rgb_red_blue)
@@ -338,12 +340,12 @@ static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
- return mt9m111_setup_pixfmt(icd, val);
+ return mt9m111_setup_pixfmt(client, val);
}
-static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
+static int mt9m111_setfmt_yuv(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int val = 0;
if (mt9m111->swap_yuv_cb_cr)
@@ -351,52 +353,22 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
if (mt9m111->swap_yuv_y_chromas)
val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
- return mt9m111_setup_pixfmt(icd, val);
+ return mt9m111_setup_pixfmt(client, val);
}
-static int mt9m111_enable(struct soc_camera_device *icd)
+static int mt9m111_enable(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
if (!ret)
mt9m111->powered = 1;
return ret;
}
-static int mt9m111_disable(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
- int ret;
-
- ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
- if (!ret)
- mt9m111->powered = 0;
-
- if (icl->power)
- icl->power(&client->dev, 0);
-
- return ret;
-}
-
-static int mt9m111_reset(struct soc_camera_device *icd)
+static int mt9m111_reset(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -406,26 +378,12 @@ static int mt9m111_reset(struct soc_camera_device *icd)
ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
| MT9M111_RESET_RESET_SOC);
- if (icl->reset)
- icl->reset(&client->dev);
-
return ret;
}
-static int mt9m111_start_capture(struct soc_camera_device *icd)
-{
- return 0;
-}
-
-static int mt9m111_stop_capture(struct soc_camera_device *icd)
-{
- return 0;
-}
-
static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
- struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
@@ -438,62 +396,126 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
return 0;
}
-static int mt9m111_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9m111_make_rect(struct i2c_client *client,
+ struct v4l2_rect *rect)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
+ mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) {
+ /* Bayer format - even size lengths */
+ rect->width = ALIGN(rect->width, 2);
+ rect->height = ALIGN(rect->height, 2);
+ /* Let the user play with the starting pixel */
+ }
+
+ /* FIXME: the datasheet doesn't specify minimum sizes */
+ soc_camera_limit_side(&rect->left, &rect->width,
+ MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect->top, &rect->height,
+ MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
+
+ return mt9m111_setup_rect(client, rect);
+}
+
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct v4l2_rect rect = a->c;
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
- dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
- __func__, rect->left, rect->top, rect->width,
- rect->height);
+ dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
+ __func__, rect.left, rect.top, rect.width, rect.height);
- ret = mt9m111_setup_rect(icd, rect);
+ ret = mt9m111_make_rect(client, &rect);
if (!ret)
- mt9m111->rect = *rect;
+ mt9m111->rect = rect;
return ret;
}
-static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ a->c = mt9m111->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9M111_MIN_DARK_COLS;
+ a->bounds.top = MT9M111_MIN_DARK_ROWS;
+ a->bounds.width = MT9M111_MAX_WIDTH;
+ a->bounds.height = MT9M111_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = mt9m111->rect.width;
+ pix->height = mt9m111->rect.height;
+ pix->pixelformat = mt9m111->pixfmt;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt)
+{
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
switch (pixfmt) {
case V4L2_PIX_FMT_SBGGR8:
- ret = mt9m111_setfmt_bayer8(icd);
+ ret = mt9m111_setfmt_bayer8(client);
break;
case V4L2_PIX_FMT_SBGGR16:
- ret = mt9m111_setfmt_bayer10(icd);
+ ret = mt9m111_setfmt_bayer10(client);
break;
case V4L2_PIX_FMT_RGB555:
- ret = mt9m111_setfmt_rgb555(icd);
+ ret = mt9m111_setfmt_rgb555(client);
break;
case V4L2_PIX_FMT_RGB565:
- ret = mt9m111_setfmt_rgb565(icd);
+ ret = mt9m111_setfmt_rgb565(client);
break;
case V4L2_PIX_FMT_UYVY:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 0;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
case V4L2_PIX_FMT_VYUY:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 1;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
case V4L2_PIX_FMT_YUYV:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 0;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
case V4L2_PIX_FMT_YVYU:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 1;
- ret = mt9m111_setfmt_yuv(icd);
+ ret = mt9m111_setfmt_yuv(client);
break;
default:
- dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt);
+ dev_err(&client->dev, "Pixel format not handled : %x\n",
+ pixfmt);
ret = -EINVAL;
}
@@ -503,10 +525,10 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
return ret;
}
-static int mt9m111_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_rect rect = {
.left = mt9m111->rect.left,
@@ -516,40 +538,56 @@ static int mt9m111_set_fmt(struct soc_camera_device *icd,
};
int ret;
- dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
- __func__, pix->pixelformat, rect.left, rect.top, rect.width,
- rect.height);
+ dev_dbg(&client->dev,
+ "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
+ pix->pixelformat, rect.left, rect.top, rect.width, rect.height);
- ret = mt9m111_setup_rect(icd, &rect);
+ ret = mt9m111_make_rect(client, &rect);
if (!ret)
- ret = mt9m111_set_pixfmt(icd, pix->pixelformat);
+ ret = mt9m111_set_pixfmt(client, pix->pixelformat);
if (!ret)
mt9m111->rect = rect;
return ret;
}
-static int mt9m111_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
+ bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
+ pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
+
+ /*
+ * With Bayer format enforce even side lengths, but let the user play
+ * with the starting pixel
+ */
if (pix->height > MT9M111_MAX_HEIGHT)
pix->height = MT9M111_MAX_HEIGHT;
+ else if (pix->height < 2)
+ pix->height = 2;
+ else if (bayer)
+ pix->height = ALIGN(pix->height, 2);
+
if (pix->width > MT9M111_MAX_WIDTH)
pix->width = MT9M111_MAX_WIDTH;
+ else if (pix->width < 2)
+ pix->width = 2;
+ else if (bayer)
+ pix->width = ALIGN(pix->width, 2);
return 0;
}
-static int mt9m111_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9m111->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9m111->model;
@@ -559,11 +597,11 @@ static int mt9m111_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m111_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m111_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
+ struct i2c_client *client = sd->priv;
int val;
- struct i2c_client *client = to_i2c_client(icd->control);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
@@ -580,10 +618,10 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9m111_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9m111_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
@@ -635,45 +673,21 @@ static const struct v4l2_queryctrl mt9m111_controls[] = {
}
};
-static int mt9m111_video_probe(struct soc_camera_device *);
-static void mt9m111_video_remove(struct soc_camera_device *);
-static int mt9m111_get_control(struct soc_camera_device *,
- struct v4l2_control *);
-static int mt9m111_set_control(struct soc_camera_device *,
- struct v4l2_control *);
static int mt9m111_resume(struct soc_camera_device *icd);
-static int mt9m111_init(struct soc_camera_device *icd);
-static int mt9m111_release(struct soc_camera_device *icd);
+static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state);
static struct soc_camera_ops mt9m111_ops = {
- .owner = THIS_MODULE,
- .probe = mt9m111_video_probe,
- .remove = mt9m111_video_remove,
- .init = mt9m111_init,
+ .suspend = mt9m111_suspend,
.resume = mt9m111_resume,
- .release = mt9m111_release,
- .start_capture = mt9m111_start_capture,
- .stop_capture = mt9m111_stop_capture,
- .set_crop = mt9m111_set_crop,
- .set_fmt = mt9m111_set_fmt,
- .try_fmt = mt9m111_try_fmt,
.query_bus_param = mt9m111_query_bus_param,
.set_bus_param = mt9m111_set_bus_param,
.controls = mt9m111_controls,
.num_controls = ARRAY_SIZE(mt9m111_controls),
- .get_control = mt9m111_get_control,
- .set_control = mt9m111_set_control,
- .get_chip_id = mt9m111_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9m111_get_register,
- .set_register = mt9m111_set_register,
-#endif
};
-static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
+static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
if (mt9m111->context == HIGHPOWER) {
@@ -691,9 +705,8 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
return ret;
}
-static int mt9m111_get_global_gain(struct soc_camera_device *icd)
+static int mt9m111_get_global_gain(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
int data;
data = reg_read(GLOBAL_GAIN);
@@ -703,15 +716,15 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd)
return data;
}
-static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
+static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
u16 val;
if (gain > 63 * 2 * 2)
return -EINVAL;
- icd->gain = gain;
+ mt9m111->gain = gain;
if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
val = (1 << 10) | (1 << 9) | (gain / 4);
else if ((gain >= 64) && (gain < 64 * 2))
@@ -722,10 +735,9 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
return reg_write(GLOBAL_GAIN, val);
}
-static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
+static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
if (on)
@@ -739,10 +751,9 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
return ret;
}
-static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
+static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
if (on)
@@ -756,11 +767,10 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
return ret;
}
-static int mt9m111_get_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int data;
switch (ctrl->id) {
@@ -785,7 +795,7 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN:
- data = mt9m111_get_global_gain(icd);
+ data = mt9m111_get_global_gain(client);
if (data < 0)
return data;
ctrl->value = data;
@@ -800,37 +810,36 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
return 0;
}
-static int mt9m111_set_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
const struct v4l2_queryctrl *qctrl;
int ret;
qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
-
if (!qctrl)
return -EINVAL;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
mt9m111->vflip = ctrl->value;
- ret = mt9m111_set_flip(icd, ctrl->value,
+ ret = mt9m111_set_flip(client, ctrl->value,
MT9M111_RMB_MIRROR_ROWS);
break;
case V4L2_CID_HFLIP:
mt9m111->hflip = ctrl->value;
- ret = mt9m111_set_flip(icd, ctrl->value,
+ ret = mt9m111_set_flip(client, ctrl->value,
MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN:
- ret = mt9m111_set_global_gain(icd, ctrl->value);
+ ret = mt9m111_set_global_gain(client, ctrl->value);
break;
case V4L2_CID_EXPOSURE_AUTO:
- ret = mt9m111_set_autoexposure(icd, ctrl->value);
+ ret = mt9m111_set_autoexposure(client, ctrl->value);
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = mt9m111_set_autowhitebalance(icd, ctrl->value);
+ ret = mt9m111_set_autowhitebalance(client, ctrl->value);
break;
default:
ret = -EINVAL;
@@ -839,62 +848,62 @@ static int mt9m111_set_control(struct soc_camera_device *icd,
return ret;
}
-static int mt9m111_restore_state(struct soc_camera_device *icd)
+static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-
- mt9m111_set_context(icd, mt9m111->context);
- mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
- mt9m111_setup_rect(icd, &mt9m111->rect);
- mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
- mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
- mt9m111_set_global_gain(icd, icd->gain);
- mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
- mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ mt9m111->gain = mt9m111_get_global_gain(client);
+
+ return 0;
+}
+
+static int mt9m111_restore_state(struct i2c_client *client)
+{
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ mt9m111_set_context(client, mt9m111->context);
+ mt9m111_set_pixfmt(client, mt9m111->pixfmt);
+ mt9m111_setup_rect(client, &mt9m111->rect);
+ mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+ mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+ mt9m111_set_global_gain(client, mt9m111->gain);
+ mt9m111_set_autoexposure(client, mt9m111->autoexposure);
+ mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance);
return 0;
}
static int mt9m111_resume(struct soc_camera_device *icd)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret = 0;
if (mt9m111->powered) {
- ret = mt9m111_enable(icd);
+ ret = mt9m111_enable(client);
if (!ret)
- ret = mt9m111_reset(icd);
+ ret = mt9m111_reset(client);
if (!ret)
- ret = mt9m111_restore_state(icd);
+ ret = mt9m111_restore_state(client);
}
return ret;
}
-static int mt9m111_init(struct soc_camera_device *icd)
+static int mt9m111_init(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
mt9m111->context = HIGHPOWER;
- ret = mt9m111_enable(icd);
+ ret = mt9m111_enable(client);
if (!ret)
- ret = mt9m111_reset(icd);
+ ret = mt9m111_reset(client);
if (!ret)
- ret = mt9m111_set_context(icd, mt9m111->context);
+ ret = mt9m111_set_context(client, mt9m111->context);
if (!ret)
- ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+ ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure);
if (ret)
- dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret);
- return ret;
-}
-
-static int mt9m111_release(struct soc_camera_device *icd)
-{
- int ret;
-
- ret = mt9m111_disable(icd);
- if (ret < 0)
- dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret);
-
+ dev_err(&client->dev, "mt9m11x init failed: %d\n", ret);
return ret;
}
@@ -902,10 +911,10 @@ static int mt9m111_release(struct soc_camera_device *icd)
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
-static int mt9m111_video_probe(struct soc_camera_device *icd)
+static int mt9m111_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
s32 data;
int ret;
@@ -917,10 +926,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
return -ENODEV;
- ret = mt9m111_enable(icd);
- if (ret)
- goto ei2c;
- ret = mt9m111_reset(icd);
+ mt9m111->autoexposure = 1;
+ mt9m111->autowhitebalance = 1;
+
+ mt9m111->swap_rgb_even_odd = 1;
+ mt9m111->swap_rgb_red_blue = 1;
+
+ ret = mt9m111_init(client);
if (ret)
goto ei2c;
@@ -935,7 +947,7 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
break;
default:
ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9M11x chip detected, register read %x\n", data);
goto ei2c;
}
@@ -943,32 +955,35 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
icd->formats = mt9m111_colour_formats;
icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
- dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data);
+ dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data);
- ret = soc_camera_video_start(icd);
- if (ret)
- goto eisis;
-
- mt9m111->autoexposure = 1;
- mt9m111->autowhitebalance = 1;
-
- mt9m111->swap_rgb_even_odd = 1;
- mt9m111->swap_rgb_red_blue = 1;
-
- return 0;
-eisis:
ei2c:
return ret;
}
-static void mt9m111_video_remove(struct soc_camera_device *icd)
-{
- struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
+ .g_ctrl = mt9m111_g_ctrl,
+ .s_ctrl = mt9m111_s_ctrl,
+ .g_chip_ident = mt9m111_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m111_g_register,
+ .s_register = mt9m111_s_register,
+#endif
+};
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
- mt9m111->icd.dev.parent, mt9m111->icd.vdev);
- soc_camera_video_stop(&mt9m111->icd);
-}
+static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
+ .s_fmt = mt9m111_s_fmt,
+ .g_fmt = mt9m111_g_fmt,
+ .try_fmt = mt9m111_try_fmt,
+ .s_crop = mt9m111_s_crop,
+ .g_crop = mt9m111_g_crop,
+ .cropcap = mt9m111_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9m111_subdev_ops = {
+ .core = &mt9m111_subdev_core_ops,
+ .video = &mt9m111_subdev_video_ops,
+};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
static int mt9m111_probe(struct i2c_client *client)
@@ -978,11 +993,17 @@ static int mt9m111_probe(struct i2c_client *client,
#endif
{
struct mt9m111 *mt9m111;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9M11x driver needs platform data\n");
return -EINVAL;
@@ -998,38 +1019,35 @@ static int mt9m111_probe(struct i2c_client *client,
if (!mt9m111)
return -ENOMEM;
- mt9m111->client = client;
- i2c_set_clientdata(client, mt9m111);
+ v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
/* Second stage probe - when a capture adapter is there */
- icd = &mt9m111->icd;
- icd->ops = &mt9m111_ops;
- icd->control = &client->dev;
- icd->x_min = MT9M111_MIN_DARK_COLS;
- icd->y_min = MT9M111_MIN_DARK_ROWS;
- icd->x_current = icd->x_min;
- icd->y_current = icd->y_min;
- icd->width_min = MT9M111_MIN_DARK_ROWS;
- icd->width_max = MT9M111_MAX_WIDTH;
- icd->height_min = MT9M111_MIN_DARK_COLS;
- icd->height_max = MT9M111_MAX_HEIGHT;
- icd->y_skip_top = 0;
- icd->iface = icl->bus_id;
-
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
- return 0;
+ icd->ops = &mt9m111_ops;
+ icd->y_skip_top = 0;
+
+ mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
+ mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
+ mt9m111->rect.width = MT9M111_MAX_WIDTH;
+ mt9m111->rect.height = MT9M111_MAX_HEIGHT;
+
+ ret = mt9m111_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9m111);
+ }
-eisdr:
- kfree(mt9m111);
return ret;
}
static int mt9m111_remove(struct i2c_client *client)
{
- struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
- soc_camera_device_unregister(&mt9m111->icd);
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9m111);
return 0;
diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c
index a57051522..bf3b54f9f 100644
--- a/linux/drivers/media/video/mt9t031.c
+++ b/linux/drivers/media/video/mt9t031.c
@@ -13,13 +13,13 @@
#include <linux/i2c.h>
#include <linux/log2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/* mt9t031 i2c address 0x5d
- * The platform has to define i2c_board_info
- * and call i2c_register_board_info() */
+ * The platform has to define i2c_board_info and link to it from
+ * struct soc_camera_link */
/* mt9t031 selected register addresses */
#define MT9T031_CHIP_VERSION 0x00
@@ -47,7 +47,7 @@
#define MT9T031_MAX_HEIGHT 1536
#define MT9T031_MAX_WIDTH 2048
#define MT9T031_MIN_HEIGHT 2
-#define MT9T031_MIN_WIDTH 2
+#define MT9T031_MIN_WIDTH 18
#define MT9T031_HORIZONTAL_BLANK 142
#define MT9T031_VERTICAL_BLANK 25
#define MT9T031_COLUMN_SKIP 32
@@ -68,14 +68,21 @@ static const struct soc_camera_data_format mt9t031_colour_formats[] = {
};
struct mt9t031 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
+ struct v4l2_rect rect; /* Sensor window */
int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
- unsigned char autoexposure;
u16 xskip;
u16 yskip;
+ unsigned int gain;
+ unsigned int exposure;
+ unsigned char autoexposure;
};
+static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9t031, subdev);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
@@ -136,21 +143,10 @@ static int get_shutter(struct i2c_client *client, u32 *data)
return ret < 0 ? ret : 0;
}
-static int mt9t031_init(struct soc_camera_device *icd)
+static int mt9t031_idle(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
/* Disable chip output, synchronous option update */
ret = reg_write(client, MT9T031_RESET, 1);
if (ret >= 0)
@@ -158,50 +154,39 @@ static int mt9t031_init(struct soc_camera_device *icd)
if (ret >= 0)
ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- if (ret < 0 && icl->power)
- icl->power(&client->dev, 0);
-
return ret >= 0 ? 0 : -EIO;
}
-static int mt9t031_release(struct soc_camera_device *icd)
+static int mt9t031_disable(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
-
/* Disable the chip */
reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- if (icl->power)
- icl->power(&client->dev, 0);
-
return 0;
}
-static int mt9t031_start_capture(struct soc_camera_device *icd)
+static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Switch to master "normal" mode */
- if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
- return -EIO;
- return 0;
-}
+ struct i2c_client *client = sd->priv;
+ int ret;
-static int mt9t031_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
+ if (enable)
+ /* Switch to master "normal" mode */
+ ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2);
+ else
+ /* Stop sensor readout */
+ ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- /* Stop sensor readout */
- if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
+ if (ret < 0)
return -EIO;
+
return 0;
}
static int mt9t031_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
/* The caller should have queried our parameters, check anyway */
if (flags & ~MT9T031_BUS_PARAM)
@@ -217,69 +202,73 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
- struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
}
-/* Round up minima and round down maxima */
-static void recalculate_limits(struct soc_camera_device *icd,
- u16 xskip, u16 yskip)
+/* target must be _even_ */
+static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
{
- icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
- icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
- icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
- icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
- icd->width_max = MT9T031_MAX_WIDTH / xskip;
- icd->height_max = MT9T031_MAX_HEIGHT / yskip;
+ unsigned int skip;
+
+ if (*source < target + target / 2) {
+ *source = target;
+ return 1;
+ }
+
+ skip = min(max, *source + target / 2) / target;
+ if (skip > 8)
+ skip = 8;
+ *source = target * skip;
+
+ return skip;
}
+/* rect is the sensor rectangle, the caller guarantees parameter validity */
static int mt9t031_set_params(struct soc_camera_device *icd,
struct v4l2_rect *rect, u16 xskip, u16 yskip)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
int ret;
- u16 xbin, ybin, width, height, left, top;
+ u16 xbin, ybin;
const u16 hblank = MT9T031_HORIZONTAL_BLANK,
vblank = MT9T031_VERTICAL_BLANK;
- /* Make sure we don't exceed sensor limits */
- if (rect->left + rect->width > icd->width_max)
- rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
-
- if (rect->top + rect->height > icd->height_max)
- rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
-
- width = rect->width * xskip;
- height = rect->height * yskip;
- left = rect->left * xskip;
- top = rect->top * yskip;
-
xbin = min(xskip, (u16)3);
ybin = min(yskip, (u16)3);
- dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n",
- xskip, width, rect->width, yskip, height, rect->height);
-
- /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */
+ /*
+ * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper.
+ * There is always a valid suitably aligned value. The worst case is
+ * xbin = 3, width = 2048. Then we will start at 36, the last read out
+ * pixel will be 2083, which is < 2085 - first black pixel.
+ *
+ * MT9T031 datasheet imposes window left border alignment, depending on
+ * the selected xskip. Failing to conform to this requirement produces
+ * dark horizontal stripes in the image. However, even obeying to this
+ * requirement doesn't eliminate the stripes in all configurations. They
+ * appear "locally reproducibly," but can differ between tests under
+ * different lighting conditions.
+ */
switch (xbin) {
- case 2:
- left = (left + 3) & ~3;
+ case 1:
+ rect->left &= ~1;
break;
- case 3:
- left = roundup(left, 6);
- }
-
- switch (ybin) {
case 2:
- top = (top + 3) & ~3;
+ rect->left &= ~3;
break;
case 3:
- top = roundup(top, 6);
+ rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ?
+ (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6);
}
+ rect->top &= ~1;
+
+ dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n",
+ xskip, yskip, rect->width, rect->height, rect->left, rect->top);
+
/* Disable register update, reconfigure atomically */
ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
if (ret < 0)
@@ -299,29 +288,30 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
((ybin - 1) << 4) | (yskip - 1));
}
- dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
+ dev_dbg(&client->dev, "new physical left %u, top %u\n",
+ rect->left, rect->top);
/* The caller provides a supported format, as guaranteed by
* icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
if (ret >= 0)
- ret = reg_write(client, MT9T031_COLUMN_START, left);
+ ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
if (ret >= 0)
- ret = reg_write(client, MT9T031_ROW_START, top);
+ ret = reg_write(client, MT9T031_ROW_START, rect->top);
if (ret >= 0)
- ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1);
+ ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1);
if (ret >= 0)
ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
- height + icd->y_skip_top - 1);
+ rect->height + icd->y_skip_top - 1);
if (ret >= 0 && mt9t031->autoexposure) {
- ret = set_shutter(client, height + icd->y_skip_top + vblank);
+ unsigned int total_h = rect->height + icd->y_skip_top + vblank;
+ ret = set_shutter(client, total_h);
if (ret >= 0) {
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
const struct v4l2_queryctrl *qctrl =
soc_camera_find_qctrl(icd->ops,
V4L2_CID_EXPOSURE);
- icd->exposure = (shutter_max / 2 + (height +
- icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
}
}
@@ -330,58 +320,99 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
if (ret >= 0)
ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
+ if (ret >= 0) {
+ mt9t031->rect = *rect;
+ mt9t031->xskip = xskip;
+ mt9t031->yskip = yskip;
+ }
+
return ret < 0 ? ret : 0;
}
-static int mt9t031_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct v4l2_rect rect = a->c;
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT);
- /* CROP - no change in scaling, or in limits */
- return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
+ return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip);
}
-static int mt9t031_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
- int ret;
- u16 xskip, yskip;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = f->fmt.pix.width,
- .height = f->fmt.pix.height,
- };
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
- /*
- * try_fmt has put rectangle within limits.
- * S_FMT - use binning and skipping for scaling, recalculate
- * limits, used for cropping
- */
- /* Is this more optimal than just a division? */
- for (xskip = 8; xskip > 1; xskip--)
- if (rect.width * xskip <= MT9T031_MAX_WIDTH)
- break;
+ a->c = mt9t031->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- for (yskip = 8; yskip > 1; yskip--)
- if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
- break;
+ return 0;
+}
- recalculate_limits(icd, xskip, yskip);
+static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9T031_COLUMN_SKIP;
+ a->bounds.top = MT9T031_ROW_SKIP;
+ a->bounds.width = MT9T031_MAX_WIDTH;
+ a->bounds.height = MT9T031_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
- ret = mt9t031_set_params(icd, &rect, xskip, yskip);
- if (!ret) {
- mt9t031->xskip = xskip;
- mt9t031->yskip = yskip;
- }
+ return 0;
+}
- return ret;
+static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = mt9t031->rect.width / mt9t031->xskip;
+ pix->height = mt9t031->rect.height / mt9t031->yskip;
+ pix->pixelformat = V4L2_PIX_FMT_SGRBG10;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ u16 xskip, yskip;
+ struct v4l2_rect rect = mt9t031->rect;
+
+ /*
+ * try_fmt has put width and height within limits.
+ * S_FMT: use binning and skipping for scaling
+ */
+ xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH);
+ yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT);
+
+ /* mt9t031_set_params() doesn't change width and height */
+ return mt9t031_set_params(icd, &rect, xskip, yskip);
}
-static int mt9t031_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+/*
+ * If a user window larger than sensor window is requested, we'll increase the
+ * sensor window.
+ */
+static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -392,15 +423,16 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int mt9t031_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9t031->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9t031->model;
@@ -410,10 +442,10 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t031_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9t031_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -429,10 +461,10 @@ static int mt9t031_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9t031_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9t031_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -493,39 +525,17 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
}
};
-static int mt9t031_video_probe(struct soc_camera_device *);
-static void mt9t031_video_remove(struct soc_camera_device *);
-static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
-
static struct soc_camera_ops mt9t031_ops = {
- .owner = THIS_MODULE,
- .probe = mt9t031_video_probe,
- .remove = mt9t031_video_remove,
- .init = mt9t031_init,
- .release = mt9t031_release,
- .start_capture = mt9t031_start_capture,
- .stop_capture = mt9t031_stop_capture,
- .set_crop = mt9t031_set_crop,
- .set_fmt = mt9t031_set_fmt,
- .try_fmt = mt9t031_try_fmt,
.set_bus_param = mt9t031_set_bus_param,
.query_bus_param = mt9t031_query_bus_param,
.controls = mt9t031_controls,
.num_controls = ARRAY_SIZE(mt9t031_controls),
- .get_control = mt9t031_get_control,
- .set_control = mt9t031_set_control,
- .get_chip_id = mt9t031_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9t031_get_register,
- .set_register = mt9t031_set_register,
-#endif
};
-static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
int data;
switch (ctrl->id) {
@@ -544,14 +554,21 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9t031->autoexposure;
break;
+ case V4L2_CID_GAIN:
+ ctrl->value = mt9t031->gain;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = mt9t031->exposure;
+ break;
}
return 0;
}
-static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
int data;
@@ -586,7 +603,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
- dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
@@ -606,7 +623,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
- dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
+ dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n",
reg_read(client, MT9T031_GLOBAL_GAIN), data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
@@ -614,7 +631,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
}
/* Success */
- icd->gain = ctrl->value;
+ mt9t031->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
/* mt9t031 has maximum == default */
@@ -627,11 +644,11 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
u32 old;
get_shutter(client, &old);
- dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
+ dev_dbg(&client->dev, "Set shutter from %u to %u\n",
old, shutter);
if (set_shutter(client, shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
+ mt9t031->exposure = ctrl->value;
mt9t031->autoexposure = 0;
}
break;
@@ -639,13 +656,14 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
if (ctrl->value) {
const u16 vblank = MT9T031_VERTICAL_BLANK;
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
- if (set_shutter(client, icd->height +
- icd->y_skip_top + vblank) < 0)
+ unsigned int total_h = mt9t031->rect.height +
+ icd->y_skip_top + vblank;
+
+ if (set_shutter(client, total_h) < 0)
return -EIO;
qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = (shutter_max / 2 + (icd->height +
- icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+ mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
mt9t031->autoexposure = 1;
} else
@@ -657,22 +675,16 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9t031_video_probe(struct soc_camera_device *icd)
+static int mt9t031_video_probe(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
s32 data;
int ret;
- /* We must have a parent by now. And it cannot be a wrong one.
- * So this entire test is completely redundant. */
- if (!icd->dev.parent ||
- to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
- return -ENODEV;
-
/* Enable the chip */
data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
- dev_dbg(&icd->dev, "write: %d\n", data);
+ dev_dbg(&client->dev, "write: %d\n", data);
/* Read out the chip version register */
data = reg_read(client, MT9T031_CHIP_VERSION);
@@ -684,34 +696,48 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
break;
default:
- ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9T031 chip detected, register read %x\n", data);
- goto ei2c;
+ return -ENODEV;
}
- dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
+ dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
- /* Now that we know the model, we can start video */
- ret = soc_camera_video_start(icd);
- if (ret)
- goto evstart;
+ ret = mt9t031_idle(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
- return 0;
+ /* mt9t031_idle() has reset the chip to default. */
+ mt9t031->exposure = 255;
+ mt9t031->gain = 64;
-evstart:
-ei2c:
return ret;
}
-static void mt9t031_video_remove(struct soc_camera_device *icd)
-{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
+ .g_ctrl = mt9t031_g_ctrl,
+ .s_ctrl = mt9t031_s_ctrl,
+ .g_chip_ident = mt9t031_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9t031_g_register,
+ .s_register = mt9t031_s_register,
+#endif
+};
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
- icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
-}
+static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
+ .s_stream = mt9t031_s_stream,
+ .s_fmt = mt9t031_s_fmt,
+ .g_fmt = mt9t031_g_fmt,
+ .try_fmt = mt9t031_try_fmt,
+ .s_crop = mt9t031_s_crop,
+ .g_crop = mt9t031_g_crop,
+ .cropcap = mt9t031_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9t031_subdev_ops = {
+ .core = &mt9t031_subdev_core_ops,
+ .video = &mt9t031_subdev_video_ops,
+};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
static int mt9t031_probe(struct i2c_client *client)
@@ -721,11 +747,17 @@ static int mt9t031_probe(struct i2c_client *client,
#endif
{
struct mt9t031 *mt9t031;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9T031: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9T031 driver needs platform data\n");
return -EINVAL;
@@ -741,23 +773,17 @@ static int mt9t031_probe(struct i2c_client *client,
if (!mt9t031)
return -ENOMEM;
- mt9t031->client = client;
- i2c_set_clientdata(client, mt9t031);
+ v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
/* Second stage probe - when a capture adapter is there */
- icd = &mt9t031->icd;
- icd->ops = &mt9t031_ops;
- icd->control = &client->dev;
- icd->x_min = MT9T031_COLUMN_SKIP;
- icd->y_min = MT9T031_ROW_SKIP;
- icd->x_current = icd->x_min;
- icd->y_current = icd->y_min;
- icd->width_min = MT9T031_MIN_WIDTH;
- icd->width_max = MT9T031_MAX_WIDTH;
- icd->height_min = MT9T031_MIN_HEIGHT;
- icd->height_max = MT9T031_MAX_HEIGHT;
- icd->y_skip_top = 0;
- icd->iface = icl->bus_id;
+ icd->ops = &mt9t031_ops;
+ icd->y_skip_top = 0;
+
+ mt9t031->rect.left = MT9T031_COLUMN_SKIP;
+ mt9t031->rect.top = MT9T031_ROW_SKIP;
+ mt9t031->rect.width = MT9T031_MAX_WIDTH;
+ mt9t031->rect.height = MT9T031_MAX_HEIGHT;
+
/* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width */
mt9t031->autoexposure = 1;
@@ -765,24 +791,29 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031->xskip = 1;
mt9t031->yskip = 1;
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
+ mt9t031_idle(client);
- return 0;
+ ret = mt9t031_video_probe(client);
+
+ mt9t031_disable(client);
+
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9t031);
+ }
-eisdr:
- i2c_set_clientdata(client, NULL);
- kfree(mt9t031);
return ret;
}
static int mt9t031_remove(struct i2c_client *client)
{
- struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&mt9t031->icd);
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9t031);
return 0;
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index 4841e6eea..9da3dde10 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -14,13 +14,13 @@
#include <linux/delay.h>
#include <linux/log2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
- * The platform has to define i2c_board_info
- * and call i2c_register_board_info() */
+ * The platform has to define ctruct i2c_board_info objects and link to them
+ * from struct soc_camera_link */
static char *sensor_type;
module_param(sensor_type, charp, S_IRUGO);
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
#define MT9V022_PIXEL_OPERATION_MODE 0x0f
#define MT9V022_LED_OUT_CONTROL 0x1b
#define MT9V022_ADC_MODE_CONTROL 0x1c
-#define MT9V022_ANALOG_GAIN 0x34
+#define MT9V022_ANALOG_GAIN 0x35
#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
#define MT9V022_PIXCLK_FV_LV 0x74
#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
@@ -55,6 +55,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
/* Progressive scan, master, defaults */
#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
+#define MT9V022_MAX_WIDTH 752
+#define MT9V022_MAX_HEIGHT 480
+#define MT9V022_MIN_WIDTH 48
+#define MT9V022_MIN_HEIGHT 32
+#define MT9V022_COLUMN_SKIP 1
+#define MT9V022_ROW_SKIP 4
+
static const struct soc_camera_data_format mt9v022_colour_formats[] = {
/* Order important: first natively supported,
* second supported with a GPIO extender */
@@ -85,12 +92,18 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
};
struct mt9v022 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
+ struct v4l2_rect rect; /* Sensor window */
+ __u32 fourcc;
int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
u16 chip_control;
};
+static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
@@ -125,29 +138,11 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
return reg_write(client, reg, ret & ~data);
}
-static int mt9v022_init(struct soc_camera_device *icd)
+static int mt9v022_init(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
int ret;
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
-
- /*
- * The camera could have been already on, we hard-reset it additionally,
- * if available. Soft reset is done in video_probe().
- */
- if (icl->reset)
- icl->reset(&client->dev);
-
/* Almost the default mode: master, parallel, simultaneous, and an
* undocumented bit 0x200, which is present in table 7, but not in 8,
* plus snapshot mode to disable scan for now */
@@ -161,6 +156,10 @@ static int mt9v022_init(struct soc_camera_device *icd)
/* AEC, AGC on */
ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
if (!ret)
+ ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
+ if (!ret)
+ ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
+ if (!ret)
ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
if (!ret)
/* default - auto */
@@ -171,37 +170,19 @@ static int mt9v022_init(struct soc_camera_device *icd)
return ret;
}
-static int mt9v022_release(struct soc_camera_device *icd)
+static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
-
- if (icl->power)
- icl->power(&mt9v022->client->dev, 0);
-
- return 0;
-}
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
-static int mt9v022_start_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- /* Switch to master "normal" mode */
- mt9v022->chip_control &= ~0x10;
- if (reg_write(client, MT9V022_CHIP_CONTROL,
- mt9v022->chip_control) < 0)
- return -EIO;
- return 0;
-}
+ if (enable)
+ /* Switch to master "normal" mode */
+ mt9v022->chip_control &= ~0x10;
+ else
+ /* Switch to snapshot mode */
+ mt9v022->chip_control |= 0x10;
-static int mt9v022_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- /* Switch to snapshot mode */
- mt9v022->chip_control |= 0x10;
- if (reg_write(client, MT9V022_CHIP_CONTROL,
- mt9v022->chip_control) < 0)
+ if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
return -EIO;
return 0;
}
@@ -209,9 +190,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
static int mt9v022_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
int ret;
u16 pixclk = 0;
@@ -255,7 +236,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
if (ret < 0)
return ret;
- dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+ dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
pixclk, mt9v022->chip_control);
return 0;
@@ -263,8 +244,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned int width_flag;
if (icl->query_bus_param)
@@ -280,60 +260,121 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
width_flag;
}
-static int mt9v022_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct v4l2_rect rect = a->c;
+ struct soc_camera_device *icd = client->dev.platform_data;
int ret;
+ /* Bayer format - even size lengths */
+ if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 ||
+ mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) {
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
+ /* Let the user play with the starting pixel */
+ }
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
+
/* Like in example app. Contradicts the datasheet though */
ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
if (ret >= 0) {
if (ret & 1) /* Autoexposure */
ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
- rect->height + icd->y_skip_top + 43);
+ rect.height + icd->y_skip_top + 43);
else
ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
- rect->height + icd->y_skip_top + 43);
+ rect.height + icd->y_skip_top + 43);
}
/* Setup frame format: defaults apart from width and height */
if (!ret)
- ret = reg_write(client, MT9V022_COLUMN_START, rect->left);
+ ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
if (!ret)
- ret = reg_write(client, MT9V022_ROW_START, rect->top);
+ ret = reg_write(client, MT9V022_ROW_START, rect.top);
if (!ret)
/* Default 94, Phytec driver says:
* "width + horizontal blank >= 660" */
ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
- rect->width > 660 - 43 ? 43 :
- 660 - rect->width);
+ rect.width > 660 - 43 ? 43 :
+ 660 - rect.width);
if (!ret)
ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
if (!ret)
- ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width);
+ ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
if (!ret)
ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
- rect->height + icd->y_skip_top);
+ rect.height + icd->y_skip_top);
if (ret < 0)
return ret;
- dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
+ dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height);
+
+ mt9v022->rect = rect;
+
+ return 0;
+}
+
+static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ a->c = mt9v022->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
return 0;
}
-static int mt9v022_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ a->bounds.left = MT9V022_COLUMN_SKIP;
+ a->bounds.top = MT9V022_ROW_SKIP;
+ a->bounds.width = MT9V022_MAX_WIDTH;
+ a->bounds.height = MT9V022_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = pix->width,
- .height = pix->height,
+
+ pix->width = mt9v022->rect.width;
+ pix->height = mt9v022->rect.height;
+ pix->pixelformat = mt9v022->fourcc;
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_crop a = {
+ .c = {
+ .left = mt9v022->rect.left,
+ .top = mt9v022->rect.top,
+ .width = pix->width,
+ .height = pix->height,
+ },
};
+ int ret;
/* The caller provides a supported format, as verified per call to
* icd->try_fmt(), datawidth is from our supported format list */
@@ -356,30 +397,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd,
}
/* No support for scaling on this camera, just crop. */
- return mt9v022_set_crop(icd, &rect);
+ ret = mt9v022_s_crop(sd, &a);
+ if (!ret) {
+ pix->width = mt9v022->rect.width;
+ pix->height = mt9v022->rect.height;
+ mt9v022->fourcc = pix->pixelformat;
+ }
+
+ return ret;
}
-static int mt9v022_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
+ struct i2c_client *client = sd->priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
+ int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
+ pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
- v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */,
- &pix->height, 32 + icd->y_skip_top,
- 480 + icd->y_skip_top, 0, 0);
+ v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH,
+ MT9V022_MAX_WIDTH, align,
+ &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top,
+ MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0);
return 0;
}
-static int mt9v022_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct i2c_client *client = sd->priv;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9v022->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9v022->model;
@@ -389,10 +442,10 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9v022_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9v022_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -409,10 +462,10 @@ static int mt9v022_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9v022_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int mt9v022_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -481,41 +534,22 @@ static const struct v4l2_queryctrl mt9v022_controls[] = {
}
};
-static int mt9v022_video_probe(struct soc_camera_device *);
-static void mt9v022_video_remove(struct soc_camera_device *);
-static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
-
static struct soc_camera_ops mt9v022_ops = {
- .owner = THIS_MODULE,
- .probe = mt9v022_video_probe,
- .remove = mt9v022_video_remove,
- .init = mt9v022_init,
- .release = mt9v022_release,
- .start_capture = mt9v022_start_capture,
- .stop_capture = mt9v022_stop_capture,
- .set_crop = mt9v022_set_crop,
- .set_fmt = mt9v022_set_fmt,
- .try_fmt = mt9v022_try_fmt,
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.controls = mt9v022_controls,
.num_controls = ARRAY_SIZE(mt9v022_controls),
- .get_control = mt9v022_get_control,
- .set_control = mt9v022_set_control,
- .get_chip_id = mt9v022_get_chip_id,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9v022_get_register,
- .set_register = mt9v022_set_register,
-#endif
};
-static int mt9v022_get_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
+ const struct v4l2_queryctrl *qctrl;
+ unsigned long range;
int data;
+ qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
+
switch (ctrl->id) {
case V4L2_CID_VFLIP:
data = reg_read(client, MT9V022_READ_MODE);
@@ -541,19 +575,35 @@ static int mt9v022_get_control(struct soc_camera_device *icd,
return -EIO;
ctrl->value = !!(data & 0x2);
break;
+ case V4L2_CID_GAIN:
+ data = reg_read(client, MT9V022_ANALOG_GAIN);
+ if (data < 0)
+ return -EIO;
+
+ range = qctrl->maximum - qctrl->minimum;
+ ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum;
+
+ break;
+ case V4L2_CID_EXPOSURE:
+ data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
+ if (data < 0)
+ return -EIO;
+
+ range = qctrl->maximum - qctrl->minimum;
+ ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum;
+
+ break;
}
return 0;
}
-static int mt9v022_set_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int data;
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = sd->priv;
const struct v4l2_queryctrl *qctrl;
qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
-
if (!qctrl)
return -EINVAL;
@@ -580,12 +630,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
return -EINVAL;
else {
unsigned long range = qctrl->maximum - qctrl->minimum;
- /* Datasheet says 16 to 64. autogain only works properly
- * after setting gain to maximum 14. Larger values
- * produce "white fly" noise effect. On the whole,
- * manually setting analog gain does no good. */
+ /* Valid values 16 to 64, 32 to 64 must be even. */
unsigned long gain = ((ctrl->value - qctrl->minimum) *
- 10 + range / 2) / range + 4;
+ 48 + range / 2) / range + 16;
if (gain >= 32)
gain &= ~1;
/* The user wants to set gain manually, hope, she
@@ -594,11 +641,10 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
return -EIO;
- dev_info(&icd->dev, "Setting gain from %d to %lu\n",
- reg_read(client, MT9V022_ANALOG_GAIN), gain);
+ dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
+ reg_read(client, MT9V022_ANALOG_GAIN), gain);
if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
return -EIO;
- icd->gain = ctrl->value;
}
break;
case V4L2_CID_EXPOSURE:
@@ -615,13 +661,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
return -EIO;
- dev_dbg(&icd->dev, "Shutter width from %d to %lu\n",
+ dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
shutter);
if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
}
break;
case V4L2_CID_AUTOGAIN:
@@ -646,11 +691,11 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9v022_video_probe(struct soc_camera_device *icd)
+static int mt9v022_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
s32 data;
int ret;
unsigned long flags;
@@ -665,7 +710,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
/* must be 0x1311 or 0x1313 */
if (data != 0x1311 && data != 0x1313) {
ret = -ENODEV;
- dev_info(&icd->dev, "No MT9V022 detected, ID register 0x%x\n",
+ dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
data);
goto ei2c;
}
@@ -677,7 +722,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
/* 15 clock cycles */
udelay(200);
if (reg_read(client, MT9V022_RESET)) {
- dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
+ dev_err(&client->dev, "Resetting MT9V022 failed!\n");
+ if (ret > 0)
+ ret = -EIO;
goto ei2c;
}
@@ -694,7 +741,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
}
if (ret < 0)
- goto eisis;
+ goto ei2c;
icd->num_formats = 0;
@@ -716,33 +763,55 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
if (flags & SOCAM_DATAWIDTH_8)
icd->num_formats++;
- ret = soc_camera_video_start(icd);
- if (ret < 0)
- goto eisis;
+ mt9v022->fourcc = icd->formats->fourcc;
- dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+ dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
"monochrome" : "colour");
- return 0;
+ ret = mt9v022_init(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
-eisis:
ei2c:
return ret;
}
static void mt9v022_video_remove(struct soc_camera_device *icd)
{
- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
- struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
+ dev_dbg(&icd->dev, "Video removed: %p, %p\n",
icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
if (icl->free_bus)
icl->free_bus(icl);
}
+static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
+ .g_ctrl = mt9v022_g_ctrl,
+ .s_ctrl = mt9v022_s_ctrl,
+ .g_chip_ident = mt9v022_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9v022_g_register,
+ .s_register = mt9v022_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
+ .s_stream = mt9v022_s_stream,
+ .s_fmt = mt9v022_s_fmt,
+ .g_fmt = mt9v022_g_fmt,
+ .try_fmt = mt9v022_try_fmt,
+ .s_crop = mt9v022_s_crop,
+ .g_crop = mt9v022_g_crop,
+ .cropcap = mt9v022_cropcap,
+};
+
+static struct v4l2_subdev_ops mt9v022_subdev_ops = {
+ .core = &mt9v022_subdev_core_ops,
+ .video = &mt9v022_subdev_video_ops,
+};
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static int mt9v022_probe(struct i2c_client *client,
const struct i2c_device_id *did)
@@ -751,11 +820,17 @@ static int mt9v022_probe(struct i2c_client *client)
#endif
{
struct mt9v022 *mt9v022;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct soc_camera_link *icl;
int ret;
+ if (!icd) {
+ dev_err(&client->dev, "MT9V022: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9V022 driver needs platform data\n");
return -EINVAL;
@@ -771,40 +846,41 @@ static int mt9v022_probe(struct i2c_client *client)
if (!mt9v022)
return -ENOMEM;
+ v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
+
mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
- mt9v022->client = client;
- i2c_set_clientdata(client, mt9v022);
-
- icd = &mt9v022->icd;
- icd->ops = &mt9v022_ops;
- icd->control = &client->dev;
- icd->x_min = 1;
- icd->y_min = 4;
- icd->x_current = 1;
- icd->y_current = 4;
- icd->width_min = 48;
- icd->width_max = 752;
- icd->height_min = 32;
- icd->height_max = 480;
- icd->y_skip_top = 1;
- icd->iface = icl->bus_id;
-
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
- return 0;
+ icd->ops = &mt9v022_ops;
+ /*
+ * MT9V022 _really_ corrupts the first read out line.
+ * TODO: verify on i.MX31
+ */
+ icd->y_skip_top = 1;
+
+ mt9v022->rect.left = MT9V022_COLUMN_SKIP;
+ mt9v022->rect.top = MT9V022_ROW_SKIP;
+ mt9v022->rect.width = MT9V022_MAX_WIDTH;
+ mt9v022->rect.height = MT9V022_MAX_HEIGHT;
+
+ ret = mt9v022_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(mt9v022);
+ }
-eisdr:
- kfree(mt9v022);
return ret;
}
static int mt9v022_remove(struct i2c_client *client)
{
- struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&mt9v022->icd);
+ icd->ops = NULL;
+ mt9v022_video_remove(icd);
+ i2c_set_clientdata(client, NULL);
+ client->driver = NULL;
kfree(mt9v022);
return 0;
diff --git a/linux/drivers/media/video/mx1_camera.c b/linux/drivers/media/video/mx1_camera.c
index 736c31d23..5f37952c7 100644
--- a/linux/drivers/media/video/mx1_camera.c
+++ b/linux/drivers/media/video/mx1_camera.c
@@ -126,7 +126,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
{
struct soc_camera_device *icd = vq->priv_data;
- *size = icd->width * icd->height *
+ *size = icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3);
if (!*count)
@@ -135,7 +135,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
while (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
(*count)--;
- dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
return 0;
}
@@ -147,7 +147,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* This waits until this buffer is out of danger, i.e., until it is no
@@ -165,7 +165,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
int ret;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -178,12 +178,12 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
buf->inwork = 1;
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -216,10 +216,11 @@ out:
static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
{
struct videobuf_buffer *vbuf = &pcdev->active->vb;
+ struct device *dev = pcdev->icd->dev.parent;
int ret;
if (unlikely(!pcdev->active)) {
- dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
+ dev_err(dev, "DMA End IRQ with no active buffer\n");
return -EFAULT;
}
@@ -229,7 +230,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
vbuf->size, pcdev->res->start +
CSIRXR, DMA_MODE_READ);
if (unlikely(ret))
- dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n");
+ dev_err(dev, "Failed to setup DMA sg list\n");
return ret;
}
@@ -243,7 +244,7 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq,
struct mx1_camera_dev *pcdev = ici->priv;
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
list_add_tail(&vb->queue, &pcdev->capture);
@@ -270,22 +271,23 @@ static void mx1_videobuf_release(struct videobuf_queue *vq,
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
#ifdef DEBUG
struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
switch (vb->state) {
case VIDEOBUF_ACTIVE:
- dev_dbg(&icd->dev, "%s (active)\n", __func__);
+ dev_dbg(dev, "%s (active)\n", __func__);
break;
case VIDEOBUF_QUEUED:
- dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+ dev_dbg(dev, "%s (queued)\n", __func__);
break;
case VIDEOBUF_PREPARED:
- dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+ dev_dbg(dev, "%s (prepared)\n", __func__);
break;
default:
- dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+ dev_dbg(dev, "%s (unknown)\n", __func__);
break;
}
#endif
@@ -325,6 +327,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
static void mx1_camera_dma_irq(int channel, void *data)
{
struct mx1_camera_dev *pcdev = data;
+ struct device *dev = pcdev->icd->dev.parent;
struct mx1_buffer *buf;
struct videobuf_buffer *vb;
unsigned long flags;
@@ -334,14 +337,14 @@ static void mx1_camera_dma_irq(int channel, void *data)
imx_dma_disable(channel);
if (unlikely(!pcdev->active)) {
- dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
+ dev_err(dev, "DMA End IRQ with no active buffer\n");
goto out;
}
vb = &pcdev->active->vb;
buf = container_of(vb, struct mx1_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
mx1_camera_wakeup(pcdev, vb, buf);
@@ -362,7 +365,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx1_camera_dev *pcdev = ici->priv;
- videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev,
+ videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent,
&pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
@@ -381,8 +384,9 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
* they get a nice Oops */
div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
- dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, "
- "divisor %lu\n", lcdclk / 1000, mclk / 1000, div);
+ dev_dbg(pcdev->icd->dev.parent,
+ "System clock %lukHz, target freq %dkHz, divisor %lu\n",
+ lcdclk / 1000, mclk / 1000, div);
return div;
}
@@ -391,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
{
unsigned int csicr1 = CSICR1_EN;
- dev_dbg(pcdev->soc_host.dev, "Activate device\n");
+ dev_dbg(pcdev->icd->dev.parent, "Activate device\n");
clk_enable(pcdev->clk);
@@ -407,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
{
- dev_dbg(pcdev->soc_host.dev, "Deactivate device\n");
+ dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n");
/* Disable all CSI interface */
__raw_writel(0x00, pcdev->base + CSICR1);
@@ -428,14 +432,12 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
goto ebusy;
}
- dev_info(&icd->dev, "MX1 Camera driver attached to camera %d\n",
+ dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n",
icd->devnum);
mx1_camera_activate(pcdev);
- ret = icd->ops->init(icd);
- if (!ret)
- pcdev->icd = icd;
+ pcdev->icd = icd;
ebusy:
return ret;
@@ -456,20 +458,20 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
/* Stop DMA engine */
imx_dma_disable(pcdev->dma_chan);
- dev_info(&icd->dev, "MX1 Camera driver detached from camera %d\n",
+ dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n",
icd->devnum);
- icd->ops->release(icd);
-
mx1_camera_deactivate(pcdev);
pcdev->icd = NULL;
}
static int mx1_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
- return icd->ops->set_crop(icd, rect);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, video, s_crop, a);
}
static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
@@ -539,18 +541,19 @@ static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
static int mx1_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
+ dev_warn(icd->dev.parent, "Format %x not found\n",
+ pix->pixelformat);
return -EINVAL;
}
- ret = icd->ops->set_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
@@ -562,10 +565,11 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
static int mx1_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
/* TODO: limit to mx1 hardware capabilities */
/* limit to sensor capabilities */
- return icd->ops->try_fmt(icd, f);
+ return v4l2_subdev_call(sd, video, try_fmt, f);
}
static int mx1_camera_reqbufs(struct soc_camera_file *icf,
@@ -737,7 +741,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
pcdev->soc_host.drv_name = DRIVER_NAME;
pcdev->soc_host.ops = &mx1_soc_camera_host_ops;
pcdev->soc_host.priv = pcdev;
- pcdev->soc_host.dev = &pdev->dev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
err = soc_camera_host_register(&pcdev->soc_host);
if (err)
diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c
index 9770cb793..dff2e5e2d 100644
--- a/linux/drivers/media/video/mx3_camera.c
+++ b/linux/drivers/media/video/mx3_camera.c
@@ -178,7 +178,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/*
@@ -220,7 +220,7 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
if (!mx3_cam->idmac_channel[0])
return -EINVAL;
- *size = icd->width * icd->height * bpp;
+ *size = icd->user_width * icd->user_height * bpp;
if (!*count)
*count = 32;
@@ -241,7 +241,7 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
struct mx3_camera_buffer *buf =
container_of(vb, struct mx3_camera_buffer, vb);
/* current_fmt _must_ always be set */
- size_t new_size = icd->width * icd->height *
+ size_t new_size = icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3);
int ret;
@@ -251,12 +251,12 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
*/
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
if (vb->state != VIDEOBUF_NEEDS_INIT)
free_buffer(vq, buf);
@@ -354,9 +354,9 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
/* This is the configuration of one sg-element */
video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc);
- video->out_width = icd->width;
- video->out_height = icd->height;
- video->out_stride = icd->width;
+ video->out_width = icd->user_width;
+ video->out_height = icd->user_height;
+ video->out_stride = icd->user_width;
#ifdef DEBUG
/* helps to see what DMA actually has written */
@@ -375,7 +375,8 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
spin_unlock_irq(&mx3_cam->lock);
cookie = txd->tx_submit(txd);
- dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg));
+ dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n",
+ cookie, sg_dma_address(&buf->sg));
spin_lock_irq(&mx3_cam->lock);
@@ -402,9 +403,10 @@ static void mx3_videobuf_release(struct videobuf_queue *vq,
container_of(vb, struct mx3_camera_buffer, vb);
unsigned long flags;
- dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n",
+ dev_dbg(icd->dev.parent,
+ "Release%s DMA 0x%08x (state %d), queue %sempty\n",
mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
- vb->state, list_empty(&vb->queue) ? "" : "not ");
+ vb->state, list_empty(&vb->queue) ? "" : "not ");
spin_lock_irqsave(&mx3_cam->lock, flags);
if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
!list_empty(&vb->queue)) {
@@ -431,7 +433,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
- videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev,
+ videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, icd->dev.parent,
&mx3_cam->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
@@ -484,7 +486,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
clk_enable(mx3_cam->clk);
rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
- dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+ dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
if (rate)
clk_set_rate(mx3_cam->clk, rate);
}
@@ -494,29 +496,18 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
- int ret;
- if (mx3_cam->icd) {
- ret = -EBUSY;
- goto ebusy;
- }
+ if (mx3_cam->icd)
+ return -EBUSY;
mx3_camera_activate(mx3_cam, icd);
- ret = icd->ops->init(icd);
- if (ret < 0) {
- clk_disable(mx3_cam->clk);
- goto einit;
- }
mx3_cam->icd = icd;
-einit:
-ebusy:
- if (!ret)
- dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
- icd->devnum);
+ dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n",
+ icd->devnum);
- return ret;
+ return 0;
}
/* Called with .video_lock held */
@@ -533,13 +524,11 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
*ichan = NULL;
}
- icd->ops->release(icd);
-
clk_disable(mx3_cam->clk);
mx3_cam->icd = NULL;
- dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n",
+ dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n",
icd->devnum);
}
@@ -551,7 +540,8 @@ static bool channel_change_requested(struct soc_camera_device *icd,
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
/* Do buffers have to be re-allocated or channel re-configured? */
- return ichan && rect->width * rect->height > icd->width * icd->height;
+ return ichan && rect->width * rect->height >
+ icd->user_width * icd->user_height;
}
static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -599,8 +589,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
*flags |= SOCAM_DATAWIDTH_4;
break;
default:
- dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n",
- buswidth);
+ dev_warn(mx3_cam->soc_host.v4l2_dev.dev,
+ "Unsupported bus width %d\n", buswidth);
return -EINVAL;
}
@@ -615,7 +605,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
unsigned long bus_flags, camera_flags;
int ret = test_platform_param(mx3_cam, depth, &bus_flags);
- dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret);
+ dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret);
if (ret < 0)
return ret;
@@ -624,7 +614,8 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
if (ret < 0)
- dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n",
+ dev_warn(icd->dev.parent,
+ "Flags incompatible: camera %lx, host %lx\n",
camera_flags, bus_flags);
return ret;
@@ -638,7 +629,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
if (!rq)
return false;
- pdata = rq->mx3_cam->soc_host.dev->platform_data;
+ pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data;
return rq->id == chan->chan_id &&
pdata->dma_dev == chan->device->dev;
@@ -698,7 +689,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(icd->dev.parent,
+ "Providing format %s using %s\n",
mx3_camera_formats[0].name,
icd->formats[idx].name);
}
@@ -710,7 +702,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(icd->dev.parent,
+ "Providing format %s using %s\n",
mx3_camera_formats[0].name,
icd->formats[idx].name);
}
@@ -723,7 +716,7 @@ passthrough:
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev,
+ dev_dbg(icd->dev.parent,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
@@ -733,13 +726,13 @@ passthrough:
}
static void configure_geometry(struct mx3_camera_dev *mx3_cam,
- struct v4l2_rect *rect)
+ unsigned int width, unsigned int height)
{
u32 ctrl, width_field, height_field;
/* Setup frame size - this cannot be changed on-the-fly... */
- width_field = rect->width - 1;
- height_field = rect->height - 1;
+ width_field = width - 1;
+ height_field = height - 1;
csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
@@ -751,11 +744,6 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam,
ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
/* Sensor does the cropping */
csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
-
- /*
- * No need to free resources here if we fail, we'll see if we need to
- * do this next time we are called
- */
}
static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
@@ -792,25 +780,74 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
return 0;
}
+/*
+ * FIXME: learn to use stride != width, then we can keep stride properly aligned
+ * and support arbitrary (even) widths.
+ */
+static inline void stride_align(__s32 *width)
+{
+ if (((*width + 7) & ~7) < 4096)
+ *width = (*width + 7) & ~7;
+ else
+ *width = *width & ~7;
+}
+
+/*
+ * As long as we don't implement host-side cropping and scaling, we can use
+ * default g_crop and cropcap from soc_camera.c
+ */
static int mx3_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
+ struct v4l2_rect *rect = &a->c;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
+ struct v4l2_pix_format *pix = &f.fmt.pix;
+ int ret;
- /*
- * We now know pixel formats and can decide upon DMA-channel(s)
- * So far only direct camera-to-memory is supported
- */
- if (channel_change_requested(icd, rect)) {
- int ret = acquire_dma_channel(mx3_cam);
+ soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+ soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
+ if (ret < 0)
+ return ret;
+
+ /* The capture device might have changed its output */
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ if (pix->width & 7) {
+ /* Ouch! We can only handle 8-byte aligned width... */
+ stride_align(&pix->width);
+ ret = v4l2_subdev_call(sd, video, s_fmt, &f);
if (ret < 0)
return ret;
}
- configure_geometry(mx3_cam, rect);
+ if (pix->width != icd->user_width || pix->height != icd->user_height) {
+ /*
+ * We now know pixel formats and can decide upon DMA-channel(s)
+ * So far only direct camera-to-memory is supported
+ */
+ if (channel_change_requested(icd, rect)) {
+ int ret = acquire_dma_channel(mx3_cam);
+ if (ret < 0)
+ return ret;
+ }
+
+ configure_geometry(mx3_cam, pix->width, pix->height);
+ }
+
+ dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+ pix->width, pix->height);
- return icd->ops->set_crop(icd, rect);
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
+
+ return ret;
}
static int mx3_camera_set_fmt(struct soc_camera_device *icd,
@@ -818,22 +855,21 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = pix->width,
- .height = pix->height,
- };
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
+ dev_warn(icd->dev.parent, "Format %x not found\n",
+ pix->pixelformat);
return -EINVAL;
}
+ stride_align(&pix->width);
+ dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height);
+
ret = acquire_dma_channel(mx3_cam);
if (ret < 0)
return ret;
@@ -844,21 +880,23 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
* mxc_v4l2_s_fmt()
*/
- configure_geometry(mx3_cam, &rect);
+ configure_geometry(mx3_cam, pix->width, pix->height);
- ret = icd->ops->set_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
}
+ dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height);
+
return ret;
}
static int mx3_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
__u32 pixfmt = pix->pixelformat;
@@ -867,7 +905,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (pixfmt && !xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
return -EINVAL;
}
@@ -884,7 +922,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
/* camera has to see its format, but the user the original one */
pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = icd->ops->try_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
pix->pixelformat = xlate->host_fmt->fourcc;
field = pix->field;
@@ -892,7 +930,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
if (field == V4L2_FIELD_ANY) {
pix->field = V4L2_FIELD_NONE;
} else if (field != V4L2_FIELD_NONE) {
- dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+ dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
return -EINVAL;
}
@@ -931,14 +969,15 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
u32 dw, sens_conf;
int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags);
const struct soc_camera_format_xlate *xlate;
+ struct device *dev = icd->dev.parent;
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- dev_dbg(ici->dev, "requested bus width %d bit: %d\n",
+ dev_dbg(dev, "requested bus width %d bit: %d\n",
icd->buswidth, ret);
if (ret < 0)
@@ -947,9 +986,10 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
+ camera_flags, bus_flags, common_flags);
if (!common_flags) {
- dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n",
- camera_flags, bus_flags);
+ dev_dbg(dev, "no common flags");
return -EINVAL;
}
@@ -1002,8 +1042,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
SOCAM_DATAWIDTH_4;
ret = icd->ops->set_bus_param(icd, common_flags);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n",
+ common_flags, ret);
return ret;
+ }
/*
* So far only gated clock mode is supported. Add a line
@@ -1055,7 +1098,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
- dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+ dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw);
return 0;
}
@@ -1127,8 +1170,9 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mx3_cam->capture);
spin_lock_init(&mx3_cam->lock);
- base = ioremap(res->start, res->end - res->start + 1);
+ base = ioremap(res->start, resource_size(res));
if (!base) {
+ pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
err = -ENOMEM;
goto eioremap;
}
@@ -1139,7 +1183,7 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
soc_host->drv_name = MX3_CAM_DRV_NAME;
soc_host->ops = &mx3_soc_camera_host_ops;
soc_host->priv = mx3_cam;
- soc_host->dev = &pdev->dev;
+ soc_host->v4l2_dev.dev = &pdev->dev;
soc_host->nr = pdev->id;
err = soc_camera_host_register(soc_host);
@@ -1215,3 +1259,4 @@ module_exit(mx3_camera_exit);
MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c
index 411efcd34..d727acaa5 100644
--- a/linux/drivers/media/video/mxb.c
+++ b/linux/drivers/media/video/mxb.c
@@ -190,19 +190,19 @@ static int mxb_probe(struct saa7146_dev *dev)
}
mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "saa7115", "saa7111", I2C_SAA7111A);
+ "saa7115", "saa7111", I2C_SAA7111A, NULL);
mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6420", "tea6420", I2C_TEA6420_1);
+ "tea6420", "tea6420", I2C_TEA6420_1, NULL);
mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6420", "tea6420", I2C_TEA6420_2);
+ "tea6420", "tea6420", I2C_TEA6420_2, NULL);
mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6415c", "tea6415c", I2C_TEA6415C);
+ "tea6415c", "tea6415c", I2C_TEA6415C, NULL);
mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tda9840", "tda9840", I2C_TDA9840);
+ "tda9840", "tda9840", I2C_TDA9840, NULL);
mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tuner", "tuner", I2C_TUNER);
+ "tuner", "tuner", I2C_TUNER, NULL);
if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "saa5246a", "saa5246a", I2C_SAA5246A)) {
+ "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) {
printk(KERN_INFO "mxb: found teletext decoder\n");
}
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index 4b0363940..47e7c7c53 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/drivers/media/video/ov772x.c
@@ -22,7 +22,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/ov772x.h>
@@ -382,11 +382,10 @@ struct regval_list {
};
struct ov772x_color_format {
- char *name;
- __u32 fourcc;
- u8 dsp3;
- u8 com3;
- u8 com7;
+ const struct soc_camera_data_format *format;
+ u8 dsp3;
+ u8 com3;
+ u8 com7;
};
struct ov772x_win_size {
@@ -398,14 +397,15 @@ struct ov772x_win_size {
};
struct ov772x_priv {
+ struct v4l2_subdev subdev;
struct ov772x_camera_info *info;
- struct i2c_client *client;
- struct soc_camera_device icd;
const struct ov772x_color_format *fmt;
const struct ov772x_win_size *win;
int model;
- unsigned int flag_vflip:1;
- unsigned int flag_hflip:1;
+ unsigned short flag_vflip:1;
+ unsigned short flag_hflip:1;
+ /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
+ unsigned short band_filter;
};
#define ENDMARKER { 0xff, 0xff }
@@ -481,43 +481,43 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = {
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
- SETFOURCC(YUYV),
+ .format = &ov772x_fmt_lists[0],
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- SETFOURCC(YVYU),
+ .format = &ov772x_fmt_lists[1],
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- SETFOURCC(UYVY),
+ .format = &ov772x_fmt_lists[2],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = OFMT_YUV,
},
{
- SETFOURCC(RGB555),
+ .format = &ov772x_fmt_lists[3],
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
- SETFOURCC(RGB555X),
+ .format = &ov772x_fmt_lists[4],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
- SETFOURCC(RGB565),
+ .format = &ov772x_fmt_lists[5],
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB565 | OFMT_RGB,
},
{
- SETFOURCC(RGB565X),
+ .format = &ov772x_fmt_lists[6],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB565 | OFMT_RGB,
@@ -570,6 +570,15 @@ static const struct v4l2_queryctrl ov772x_controls[] = {
.step = 1,
.default_value = 0,
},
+ {
+ .id = V4L2_CID_BAND_STOP_FILTER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Band-stop filter",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
};
@@ -577,6 +586,12 @@ static const struct v4l2_queryctrl ov772x_controls[] = {
* general function
*/
+static struct ov772x_priv *to_ov772x(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov772x_priv,
+ subdev);
+}
+
static int ov772x_write_array(struct i2c_client *client,
const struct regval_list *vals)
{
@@ -617,58 +632,29 @@ static int ov772x_reset(struct i2c_client *client)
* soc_camera_ops function
*/
-static int ov772x_init(struct soc_camera_device *icd)
+static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret = 0;
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
- if (priv->info->link.power) {
- ret = priv->info->link.power(&priv->client->dev, 1);
- if (ret < 0)
- return ret;
+ if (!enable) {
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+ return 0;
}
- if (priv->info->link.reset)
- ret = priv->info->link.reset(&priv->client->dev);
-
- return ret;
-}
-
-static int ov772x_release(struct soc_camera_device *icd)
-{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret = 0;
-
- if (priv->info->link.power)
- ret = priv->info->link.power(&priv->client->dev, 0);
-
- return ret;
-}
-
-static int ov772x_start_capture(struct soc_camera_device *icd)
-{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
if (!priv->win || !priv->fmt) {
- dev_err(&icd->dev, "norm or win select error\n");
+ dev_err(&client->dev, "norm or win select error\n");
return -EPERM;
}
- ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
- dev_dbg(&icd->dev,
- "format %s, win %s\n", priv->fmt->name, priv->win->name);
+ dev_dbg(&client->dev, "format %s, win %s\n",
+ priv->fmt->format->name, priv->win->name);
return 0;
}
-static int ov772x_stop_capture(struct soc_camera_device *icd)
-{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
- return 0;
-}
-
static int ov772x_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
@@ -677,8 +663,9 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd,
static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- struct soc_camera_link *icl = &priv->info->link;
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct ov772x_priv *priv = i2c_get_clientdata(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
@@ -686,10 +673,10 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int ov772x_get_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -698,14 +685,17 @@ static int ov772x_get_control(struct soc_camera_device *icd,
case V4L2_CID_HFLIP:
ctrl->value = priv->flag_hflip;
break;
+ case V4L2_CID_BAND_STOP_FILTER:
+ ctrl->value = priv->band_filter;
+ break;
}
return 0;
}
-static int ov772x_set_control(struct soc_camera_device *icd,
- struct v4l2_control *ctrl)
+static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
int ret = 0;
u8 val;
@@ -715,24 +705,48 @@ static int ov772x_set_control(struct soc_camera_device *icd,
priv->flag_vflip = ctrl->value;
if (priv->info->flags & OV772X_FLAG_VFLIP)
val ^= VFLIP_IMG;
- ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
+ ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val);
break;
case V4L2_CID_HFLIP:
val = ctrl->value ? HFLIP_IMG : 0x00;
priv->flag_hflip = ctrl->value;
if (priv->info->flags & OV772X_FLAG_HFLIP)
val ^= HFLIP_IMG;
- ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
+ ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+ break;
+ case V4L2_CID_BAND_STOP_FILTER:
+ if ((unsigned)ctrl->value > 256)
+ ctrl->value = 256;
+ if (ctrl->value == priv->band_filter)
+ break;
+ if (!ctrl->value) {
+ /* Switch the filter off, it is on now */
+ ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+ if (!ret)
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, 0);
+ } else {
+ /* Switch the filter on, set AEC low limit */
+ val = 256 - ctrl->value;
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, BNDF_ON_OFF);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, val);
+ }
+ if (!ret)
+ priv->band_filter = ctrl->value;
break;
}
return ret;
}
-static int ov772x_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
+static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
id->ident = priv->model;
id->revision = 0;
@@ -741,17 +755,17 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov772x_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int ov772x_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret;
+ struct i2c_client *client = sd->priv;
+ int ret;
reg->size = 1;
if (reg->reg > 0xff)
return -EINVAL;
- ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
if (ret < 0)
return ret;
@@ -760,21 +774,20 @@ static int ov772x_get_register(struct soc_camera_device *icd,
return 0;
}
-static int ov772x_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int ov772x_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
if (reg->reg > 0xff ||
reg->val > 0xff)
return -EINVAL;
- return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
}
#endif
-static const struct ov772x_win_size*
-ov772x_select_win(u32 width, u32 height)
+static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
{
__u32 diff;
const struct ov772x_win_size *win;
@@ -793,9 +806,10 @@ ov772x_select_win(u32 width, u32 height)
return win;
}
-static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
- u32 pixfmt)
+static int ov772x_set_params(struct i2c_client *client,
+ u32 *width, u32 *height, u32 pixfmt)
{
+ struct ov772x_priv *priv = to_ov772x(client);
int ret = -EINVAL;
u8 val;
int i;
@@ -805,7 +819,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
*/
priv->fmt = NULL;
for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
- if (pixfmt == ov772x_cfmts[i].fourcc) {
+ if (pixfmt == ov772x_cfmts[i].format->fourcc) {
priv->fmt = ov772x_cfmts + i;
break;
}
@@ -816,12 +830,12 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
/*
* select win
*/
- priv->win = ov772x_select_win(width, height);
+ priv->win = ov772x_select_win(*width, *height);
/*
* reset hardware
*/
- ov772x_reset(priv->client);
+ ov772x_reset(client);
/*
* Edge Ctrl
@@ -835,17 +849,17 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
* Remove it when manual mode.
*/
- ret = ov772x_mask_set(priv->client, DSPAUTO, EDGE_ACTRL, 0x00);
+ ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_TRSHLD, EDGE_THRESHOLD_MASK,
priv->info->edgectrl.threshold);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_STRNGT, EDGE_STRENGTH_MASK,
priv->info->edgectrl.strength);
if (ret < 0)
@@ -857,13 +871,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
*
* set upper and lower limit
*/
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_UPPER, EDGE_UPPER_MASK,
priv->info->edgectrl.upper);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
EDGE_LOWER, EDGE_LOWER_MASK,
priv->info->edgectrl.lower);
if (ret < 0)
@@ -873,7 +887,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
/*
* set size format
*/
- ret = ov772x_write_array(priv->client, priv->win->regs);
+ ret = ov772x_write_array(client, priv->win->regs);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -882,7 +896,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
*/
val = priv->fmt->dsp3;
if (val) {
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
DSP_CTRL3, UV_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -901,7 +915,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
if (priv->flag_hflip)
val ^= HFLIP_IMG;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
COM3, SWAP_MASK | IMG_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -910,47 +924,99 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
* set COM7
*/
val = priv->win->com7_bit | priv->fmt->com7;
- ret = ov772x_mask_set(priv->client,
+ ret = ov772x_mask_set(client,
COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
val);
if (ret < 0)
goto ov772x_set_fmt_error;
+ /*
+ * set COM8
+ */
+ if (priv->band_filter) {
+ ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, 256 - priv->band_filter);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ *width = priv->win->width;
+ *height = priv->win->height;
+
return ret;
ov772x_set_fmt_error:
- ov772x_reset(priv->client);
+ ov772x_reset(client);
priv->win = NULL;
priv->fmt = NULL;
return ret;
}
-static int ov772x_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = VGA_WIDTH;
+ a->c.height = VGA_HEIGHT;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (!priv->fmt)
- return -EINVAL;
+ return 0;
+}
- return ov772x_set_params(priv, rect->width, rect->height,
- priv->fmt->fourcc);
+static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = VGA_WIDTH;
+ a->bounds.height = VGA_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
}
-static int ov772x_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct ov772x_priv *priv = to_ov772x(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (!priv->win || !priv->fmt) {
+ u32 width = VGA_WIDTH, height = VGA_HEIGHT;
+ int ret = ov772x_set_params(client, &width, &height,
+ V4L2_PIX_FMT_YUYV);
+ if (ret < 0)
+ return ret;
+ }
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ pix->width = priv->win->width;
+ pix->height = priv->win->height;
+ pix->pixelformat = priv->fmt->format->fourcc;
+ pix->colorspace = priv->fmt->format->colorspace;
+ pix->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct i2c_client *client = sd->priv;
struct v4l2_pix_format *pix = &f->fmt.pix;
- return ov772x_set_params(priv, pix->width, pix->height,
+ return ov772x_set_params(client, &pix->width, &pix->height,
pix->pixelformat);
}
-static int ov772x_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int ov772x_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct ov772x_win_size *win;
@@ -967,9 +1033,10 @@ static int ov772x_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int ov772x_video_probe(struct soc_camera_device *icd)
+static int ov772x_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ struct ov772x_priv *priv = to_ov772x(client);
u8 pid, ver;
const char *devname;
@@ -986,7 +1053,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
*/
if (SOCAM_DATAWIDTH_10 != priv->info->buswidth &&
SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
- dev_err(&icd->dev, "bus width error\n");
+ dev_err(&client->dev, "bus width error\n");
return -ENODEV;
}
@@ -996,8 +1063,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
/*
* check and show product ID and manufacturer ID
*/
- pid = i2c_smbus_read_byte_data(priv->client, PID);
- ver = i2c_smbus_read_byte_data(priv->client, VER);
+ pid = i2c_smbus_read_byte_data(client, PID);
+ ver = i2c_smbus_read_byte_data(client, VER);
switch (VERSION(pid, ver)) {
case OV7720:
@@ -1009,51 +1076,53 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
priv->model = V4L2_IDENT_OV7725;
break;
default:
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"Product ID error %x:%x\n", pid, ver);
return -ENODEV;
}
- dev_info(&icd->dev,
+ dev_info(&client->dev,
"%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
devname,
pid,
ver,
- i2c_smbus_read_byte_data(priv->client, MIDH),
- i2c_smbus_read_byte_data(priv->client, MIDL));
-
- return soc_camera_video_start(icd);
-}
+ i2c_smbus_read_byte_data(client, MIDH),
+ i2c_smbus_read_byte_data(client, MIDL));
-static void ov772x_video_remove(struct soc_camera_device *icd)
-{
- soc_camera_video_stop(icd);
+ return 0;
}
static struct soc_camera_ops ov772x_ops = {
- .owner = THIS_MODULE,
- .probe = ov772x_video_probe,
- .remove = ov772x_video_remove,
- .init = ov772x_init,
- .release = ov772x_release,
- .start_capture = ov772x_start_capture,
- .stop_capture = ov772x_stop_capture,
- .set_crop = ov772x_set_crop,
- .set_fmt = ov772x_set_fmt,
- .try_fmt = ov772x_try_fmt,
.set_bus_param = ov772x_set_bus_param,
.query_bus_param = ov772x_query_bus_param,
.controls = ov772x_controls,
.num_controls = ARRAY_SIZE(ov772x_controls),
- .get_control = ov772x_get_control,
- .set_control = ov772x_set_control,
- .get_chip_id = ov772x_get_chip_id,
+};
+
+static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+ .g_ctrl = ov772x_g_ctrl,
+ .s_ctrl = ov772x_s_ctrl,
+ .g_chip_ident = ov772x_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = ov772x_get_register,
- .set_register = ov772x_set_register,
+ .g_register = ov772x_g_register,
+ .s_register = ov772x_s_register,
#endif
};
+static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
+ .s_stream = ov772x_s_stream,
+ .g_fmt = ov772x_g_fmt,
+ .s_fmt = ov772x_s_fmt,
+ .try_fmt = ov772x_try_fmt,
+ .cropcap = ov772x_cropcap,
+ .g_crop = ov772x_g_crop,
+};
+
+static struct v4l2_subdev_ops ov772x_subdev_ops = {
+ .core = &ov772x_subdev_core_ops,
+ .video = &ov772x_subdev_video_ops,
+};
+
/*
* i2c_driver function
*/
@@ -1062,20 +1131,26 @@ static struct soc_camera_ops ov772x_ops = {
static int ov772x_probe(struct i2c_client *client)
#else
static int ov772x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+ const struct i2c_device_id *did)
#endif
{
struct ov772x_priv *priv;
struct ov772x_camera_info *info;
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
int ret;
- if (!client->dev.platform_data)
+ if (!icd) {
+ dev_err(&client->dev, "OV772X: missing soc-camera data!\n");
return -EINVAL;
+ }
- info = container_of(client->dev.platform_data,
- struct ov772x_camera_info, link);
+ icl = to_soc_camera_link(icd);
+ if (!icl)
+ return -EINVAL;
+
+ info = container_of(icl, struct ov772x_camera_info, link);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&adapter->dev,
@@ -1088,20 +1163,15 @@ static int ov772x_probe(struct i2c_client *client,
if (!priv)
return -ENOMEM;
- priv->info = info;
- priv->client = client;
- i2c_set_clientdata(client, priv);
+ priv->info = info;
- icd = &priv->icd;
- icd->ops = &ov772x_ops;
- icd->control = &client->dev;
- icd->width_max = MAX_WIDTH;
- icd->height_max = MAX_HEIGHT;
- icd->iface = priv->info->link.bus_id;
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
- ret = soc_camera_device_register(icd);
+ icd->ops = &ov772x_ops;
+ ret = ov772x_video_probe(icd, client);
if (ret) {
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1111,9 +1181,10 @@ static int ov772x_probe(struct i2c_client *client,
static int ov772x_remove(struct i2c_client *client)
{
- struct ov772x_priv *priv = i2c_get_clientdata(client);
+ struct ov772x_priv *priv = to_ov772x(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&priv->icd);
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 336a20ede..e4d7c13ca 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -298,6 +298,7 @@ static struct tda829x_config tda829x_no_probe = {
static struct tda18271_config hauppauge_tda18271_dvb_config = {
.gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
@@ -393,6 +394,7 @@ static struct tda18271_std_map hauppauge_tda18271_std_map = {
static struct tda18271_config hauppauge_tda18271_config = {
.std_map = &hauppauge_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 0bbd20f13..493232936 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2080,8 +2080,8 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
return -EINVAL;
}
- /* Note how the 2nd and 3rd arguments are the same for both
- * v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev(). Why?
+ /* Note how the 2nd and 3rd arguments are the same for
+ * v4l2_i2c_new_subdev(). Why?
* Well the 2nd argument is the module name to load, while the 3rd
* argument is documented in the framework as being the "chipid" -
* and every other place where I can find examples of this, the
@@ -2094,15 +2094,15 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
mid, i2caddr[0]);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
fname, fname,
- i2caddr[0]);
+ i2caddr[0], NULL);
} else {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with address probe list",
mid);
- sd = v4l2_i2c_new_probed_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
+ sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
fname, fname,
- i2caddr);
+ 0, i2caddr);
}
if (!sd) {
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index f695c6624..788de22df 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -1065,7 +1065,8 @@ static int pwc_create_sysfs_files(struct video_device *vdev)
goto err;
if (pdev->features & FEATURE_MOTOR_PANTILT) {
rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
- if (rc) goto err_button;
+ if (rc)
+ goto err_button;
}
return 0;
@@ -1080,6 +1081,7 @@ err:
static void pwc_remove_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
+
if (pdev->features & FEATURE_MOTOR_PANTILT)
device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
device_remove_file(&vdev->dev, &dev_attr_button);
@@ -1237,13 +1239,11 @@ static void pwc_cleanup(struct pwc_device *pdev)
video_unregister_device(pdev->vdev);
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
- if (pdev->button_dev) {
+ if (pdev->button_dev)
input_unregister_device(pdev->button_dev);
- input_free_device(pdev->button_dev);
- kfree(pdev->button_dev->phys);
- pdev->button_dev = NULL;
- }
#endif
+
+ kfree(pdev);
}
/* Note that all cleanup is done in the reverse order as in _open */
@@ -1289,8 +1289,6 @@ static int pwc_video_close(struct file *file)
PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
} else {
pwc_cleanup(pdev);
- /* Free memory (don't set pdev to 0 just yet) */
- kfree(pdev);
/* search device_hint[] table if we occupy a slot, by any chance */
for (hint = 0; hint < MAX_DEV_HINTS; hint++)
if (device_hint[hint].pdev == pdev)
@@ -1507,13 +1505,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
struct usb_device *udev = interface_to_usbdev(intf);
struct pwc_device *pdev = NULL;
int vendor_id, product_id, type_id;
- int i, hint, rc;
+ int hint, rc;
int features = 0;
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
-#ifdef CONFIG_USB_PWC_INPUT_EVDEV
- char *phys = NULL;
-#endif
vendor_id = le16_to_cpu(udev->descriptor.idVendor);
product_id = le16_to_cpu(udev->descriptor.idProduct);
@@ -1765,8 +1760,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vframes = default_fps;
strcpy(pdev->serial, serial_number);
pdev->features = features;
- if (vendor_id == 0x046D && product_id == 0x08B5)
- {
+ if (vendor_id == 0x046D && product_id == 0x08B5) {
/* Logitech QuickCam Orbit
The ranges have been determined experimentally; they may differ from cam to cam.
Also, the exact ranges left-right and up-down are different for my cam
@@ -1788,8 +1782,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev = video_device_alloc();
if (!pdev->vdev) {
PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
- kfree(pdev);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto err_free_mem;
}
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
pdev->vdev->parent = &intf->dev;
@@ -1814,25 +1808,23 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
pdev->vdev->release = video_device_release;
- i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
- if (i < 0) {
- PWC_ERROR("Failed to register as video device (%d).\n", i);
- rc = i;
- goto err;
- }
- else {
- PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
+ rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+ if (rc < 0) {
+ PWC_ERROR("Failed to register as video device (%d).\n", rc);
+ goto err_video_release;
}
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
+
/* occupy slot */
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev;
PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
- usb_set_intfdata (intf, pdev);
+ usb_set_intfdata(intf, pdev);
rc = pwc_create_sysfs_files(pdev->vdev);
if (rc)
- goto err_unreg;
+ goto err_video_unreg;
/* Set the leds off */
pwc_set_leds(pdev, 0, 0);
@@ -1843,16 +1835,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->button_dev = input_allocate_device();
if (!pdev->button_dev) {
PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
- return -ENOMEM;
+ rc = -ENOMEM;
+ pwc_remove_sysfs_files(pdev->vdev);
+ goto err_video_unreg;
}
+ usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
+ strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
+
pdev->button_dev->name = "PWC snapshot button";
- phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, pdev->udev->devpath);
- if (!phys) {
- input_free_device(pdev->button_dev);
- return -ENOMEM;
- }
- pdev->button_dev->phys = phys;
+ pdev->button_dev->phys = pdev->button_phys;
usb_to_input_id(pdev->udev, &pdev->button_dev->id);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
pdev->button_dev->dev.parent = &pdev->udev->dev;
@@ -1865,25 +1857,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
rc = input_register_device(pdev->button_dev);
if (rc) {
input_free_device(pdev->button_dev);
- kfree(pdev->button_dev->phys);
pdev->button_dev = NULL;
- return rc;
+ pwc_remove_sysfs_files(pdev->vdev);
+ goto err_video_unreg;
}
#endif
return 0;
-err_unreg:
+err_video_unreg:
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = NULL;
video_unregister_device(pdev->vdev);
-err:
- video_device_release(pdev->vdev); /* Drip... drip... drip... */
- kfree(pdev); /* Oops, no memory leaks please */
+ pdev->vdev = NULL; /* So we don't try to release it below */
+err_video_release:
+ video_device_release(pdev->vdev);
+err_free_mem:
+ kfree(pdev);
return rc;
}
-/* The user janked out the cable... */
+/* The user yanked out the cable... */
static void usb_pwc_disconnect(struct usb_interface *intf)
{
struct pwc_device *pdev;
@@ -1914,7 +1908,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
/* Alert waiting processes */
wake_up_interruptible(&pdev->frameq);
/* Wait until device is closed */
- if(pdev->vopen) {
+ if (pdev->vopen) {
mutex_lock(&pdev->modlock);
pdev->unplugged = 1;
mutex_unlock(&pdev->modlock);
@@ -1923,8 +1917,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
/* Device is closed, so we can safely unregister it */
PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
pwc_cleanup(pdev);
- /* Free memory (don't set pdev to 0 just yet) */
- kfree(pdev);
disconnect_out:
/* search device_hint[] table if we occupy a slot, by any chance */
diff --git a/linux/drivers/media/video/pwc/pwc.h b/linux/drivers/media/video/pwc/pwc.h
index 12c869d71..94c8e5a69 100644
--- a/linux/drivers/media/video/pwc/pwc.h
+++ b/linux/drivers/media/video/pwc/pwc.h
@@ -254,6 +254,7 @@ struct pwc_device
int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
struct input_dev *button_dev; /* webcam snapshot button input */
+ char button_phys[64];
#endif
/*** Misc. data ***/
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 92fb8b191..8ab1a5792 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -237,6 +237,10 @@ struct pxa_camera_dev {
u32 save_cicr[5];
};
+struct pxa_cam {
+ unsigned long flags;
+};
+
static const char *pxa_cam_driver_description = "PXA_Camera";
static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
@@ -249,9 +253,9 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
{
struct soc_camera_device *icd = vq->priv_data;
- dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
- *size = roundup(icd->width * icd->height *
+ *size = roundup(icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3), 8);
if (0 == *count)
@@ -271,7 +275,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
&buf->vb, buf->vb.baddr, buf->vb.bsize);
/* This waits until this buffer is out of danger, i.e., until it is no
@@ -282,7 +286,8 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
if (buf->dmas[i].sg_cpu)
- dma_free_coherent(ici->dev, buf->dmas[i].sg_size,
+ dma_free_coherent(ici->v4l2_dev.dev,
+ buf->dmas[i].sg_size,
buf->dmas[i].sg_cpu,
buf->dmas[i].sg_dma);
buf->dmas[i].sg_cpu = NULL;
@@ -337,19 +342,20 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
struct scatterlist **sg_first, int *sg_first_ofs)
{
struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct scatterlist *sg;
int i, offset, sglen;
int dma_len = 0, xfer_len = 0;
if (pxa_dma->sg_cpu)
- dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
+ dma_free_coherent(dev, pxa_dma->sg_size,
pxa_dma->sg_cpu, pxa_dma->sg_dma);
sglen = calculate_dma_sglen(*sg_first, dma->sglen,
*sg_first_ofs, size);
pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
- pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
+ pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size,
&pxa_dma->sg_dma, GFP_KERNEL);
if (!pxa_dma->sg_cpu)
return -ENOMEM;
@@ -357,7 +363,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
pxa_dma->sglen = sglen;
offset = *sg_first_ofs;
- dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
+ dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
*sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
@@ -380,7 +386,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
pxa_dma->sg_cpu[i].ddadr =
pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
- dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
+ dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
sg_dma_address(sg) + offset, xfer_len);
offset = 0;
@@ -430,11 +436,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
int ret;
int size_y, size_u = 0, size_v = 0;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -453,12 +460,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
buf->inwork = 1;
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -492,8 +499,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
&sg, &next_ofs);
if (ret) {
- dev_err(pcdev->soc_host.dev,
- "DMA initialization for Y/RGB failed\n");
+ dev_err(dev, "DMA initialization for Y/RGB failed\n");
goto fail;
}
@@ -502,8 +508,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
size_u, &sg, &next_ofs);
if (ret) {
- dev_err(pcdev->soc_host.dev,
- "DMA initialization for U failed\n");
+ dev_err(dev, "DMA initialization for U failed\n");
goto fail_u;
}
@@ -512,8 +517,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
size_v, &sg, &next_ofs);
if (ret) {
- dev_err(pcdev->soc_host.dev,
- "DMA initialization for V failed\n");
+ dev_err(dev, "DMA initialization for V failed\n");
goto fail_v;
}
@@ -526,10 +530,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
return 0;
fail_v:
- dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size,
+ dma_free_coherent(dev, buf->dmas[1].sg_size,
buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
fail_u:
- dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size,
+ dma_free_coherent(dev, buf->dmas[0].sg_size,
buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
fail:
free_buffer(vq, buf);
@@ -553,7 +557,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
active = pcdev->active;
for (i = 0; i < pcdev->channels; i++) {
- dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__,
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (channel=%d) ddadr=%08x\n", __func__,
i, active->dmas[i].sg_dma);
DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
@@ -565,7 +570,8 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
int i;
for (i = 0; i < pcdev->channels; i++) {
- dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (channel=%d)\n", __func__, i);
DCSR(pcdev->dma_chans[i]) = 0;
}
}
@@ -601,7 +607,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
{
unsigned long cicr0, cifr;
- dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
/* Reset the FIFOs */
cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
__raw_writel(cifr, pcdev->base + CIFR);
@@ -621,7 +627,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
__raw_writel(cicr0, pcdev->base + CICR0);
pcdev->active = NULL;
- dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
}
/* Called under spinlock_irqsave(&pcdev->lock, ...) */
@@ -633,8 +639,8 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
struct pxa_camera_dev *pcdev = ici->priv;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__,
- vb, vb->baddr, vb->bsize, pcdev->active);
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
+ __func__, vb, vb->baddr, vb->bsize, pcdev->active);
list_add_tail(&vb->queue, &pcdev->capture);
@@ -651,22 +657,23 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
#ifdef DEBUG
struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
switch (vb->state) {
case VIDEOBUF_ACTIVE:
- dev_dbg(&icd->dev, "%s (active)\n", __func__);
+ dev_dbg(dev, "%s (active)\n", __func__);
break;
case VIDEOBUF_QUEUED:
- dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+ dev_dbg(dev, "%s (queued)\n", __func__);
break;
case VIDEOBUF_PREPARED:
- dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+ dev_dbg(dev, "%s (prepared)\n", __func__);
break;
default:
- dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+ dev_dbg(dev, "%s (unknown)\n", __func__);
break;
}
#endif
@@ -686,7 +693,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
do_gettimeofday(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
- dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n",
+ __func__, vb);
if (list_empty(&pcdev->capture)) {
pxa_camera_stop_capture(pcdev);
@@ -722,7 +730,8 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
for (i = 0; i < pcdev->channels; i++)
if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
is_dma_stopped = 0;
- dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s : top queued buffer=%p, dma_stopped=%d\n",
__func__, pcdev->active, is_dma_stopped);
if (pcdev->active && is_dma_stopped)
pxa_camera_start_capture(pcdev);
@@ -731,6 +740,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
enum pxa_camera_active_dma act_dma)
{
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct pxa_buffer *buf;
unsigned long flags;
u32 status, camera_status, overrun;
@@ -747,13 +757,13 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
overrun |= CISR_IFO_1 | CISR_IFO_2;
if (status & DCSR_BUSERR) {
- dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n");
+ dev_err(dev, "DMA Bus Error IRQ!\n");
goto out;
}
if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
- dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, "
- "status: 0x%08x\n", status);
+ dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n",
+ status);
goto out;
}
@@ -776,7 +786,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
buf = container_of(vb, struct pxa_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
+ dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
__func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
@@ -787,7 +797,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
*/
if (camera_status & overrun &&
!list_is_last(pcdev->capture.next, &pcdev->capture)) {
- dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n",
+ dev_dbg(dev, "FIFO overrun! CISR: %x\n",
camera_status);
pxa_camera_stop_capture(pcdev);
pxa_camera_start_capture(pcdev);
@@ -842,9 +852,11 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
sizeof(struct pxa_buffer), icd);
}
-static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
+static u32 mclk_get_divisor(struct platform_device *pdev,
+ struct pxa_camera_dev *pcdev)
{
unsigned long mclk = pcdev->mclk;
+ struct device *dev = &pdev->dev;
u32 div;
unsigned long lcdclk;
@@ -854,7 +866,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
/* mclk <= ciclk / 4 (27.4.2) */
if (mclk > lcdclk / 4) {
mclk = lcdclk / 4;
- dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk);
+ dev_warn(dev, "Limiting master clock to %lu\n", mclk);
}
/* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
@@ -864,8 +876,8 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
pcdev->mclk = lcdclk / (2 * (div + 1));
- dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, "
- "divisor %u\n", lcdclk, mclk, div);
+ dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n",
+ lcdclk, mclk, div);
return div;
}
@@ -882,14 +894,15 @@ static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
{
struct pxacamera_platform_data *pdata = pcdev->pdata;
+ struct device *dev = pcdev->soc_host.v4l2_dev.dev;
u32 cicr4 = 0;
- dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n",
+ dev_dbg(dev, "Registered platform device at %p data %p\n",
pcdev, pdata);
if (pdata && pdata->init) {
- dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__);
- pdata->init(pcdev->soc_host.dev);
+ dev_dbg(dev, "%s: Init gpios\n", __func__);
+ pdata->init(dev);
}
/* disable all interrupts */
@@ -931,7 +944,8 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
struct videobuf_buffer *vb;
status = __raw_readl(pcdev->base + CISR);
- dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "Camera interrupt status 0x%lx\n", status);
if (!status)
return IRQ_NONE;
@@ -963,24 +977,18 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
- int ret;
- if (pcdev->icd) {
- ret = -EBUSY;
- goto ebusy;
- }
-
- dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
- icd->devnum);
+ if (pcdev->icd)
+ return -EBUSY;
pxa_camera_activate(pcdev);
- ret = icd->ops->init(icd);
- if (!ret)
- pcdev->icd = icd;
+ pcdev->icd = icd;
-ebusy:
- return ret;
+ dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
}
/* Called with .video_lock held */
@@ -991,7 +999,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
BUG_ON(icd != pcdev->icd);
- dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",
+ dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n",
icd->devnum);
/* disable capture, disable interrupts */
@@ -1002,8 +1010,6 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
DCSR(pcdev->dma_chans[1]) = 0;
DCSR(pcdev->dma_chans[2]) = 0;
- icd->ops->release(icd);
-
pxa_camera_deactivate(pcdev);
pcdev->icd = NULL;
@@ -1051,57 +1057,17 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
return 0;
}
-static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
+ unsigned long flags, __u32 pixfmt)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
- unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
+ unsigned long dw, bpp;
u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0;
- int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
-
- if (ret < 0)
- return ret;
-
- camera_flags = icd->ops->query_bus_param(icd);
-
- common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
- if (!common_flags)
- return -EINVAL;
-
- pcdev->channels = 1;
-
- /* Make choises, based on platform preferences */
- if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
- (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_HSP)
- common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
- }
-
- if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
- (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_VSP)
- common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
- }
-
- if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
- (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
- if (pcdev->platform_flags & PXA_CAMERA_PCP)
- common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
- else
- common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
- }
-
- ret = icd->ops->set_bus_param(icd, common_flags);
- if (ret < 0)
- return ret;
/* Datawidth is now guaranteed to be equal to one of the three values.
* We fix bit-per-pixel equal to data-width... */
- switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+ switch (flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_10:
dw = 4;
bpp = 0x40;
@@ -1122,18 +1088,18 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
cicr4 |= CICR4_PCLK_EN;
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
cicr4 |= CICR4_MCLK_EN;
- if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+ if (flags & SOCAM_PCLK_SAMPLE_FALLING)
cicr4 |= CICR4_PCP;
- if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+ if (flags & SOCAM_HSYNC_ACTIVE_LOW)
cicr4 |= CICR4_HSP;
- if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+ if (flags & SOCAM_VSYNC_ACTIVE_LOW)
cicr4 |= CICR4_VSP;
cicr0 = __raw_readl(pcdev->base + CICR0);
if (cicr0 & CICR0_ENB)
__raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
- cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+ cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw;
switch (pixfmt) {
case V4L2_PIX_FMT_YUV422P:
@@ -1162,7 +1128,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
}
cicr2 = 0;
- cicr3 = CICR3_LPF_VAL(icd->height - 1) |
+ cicr3 = CICR3_LPF_VAL(icd->user_height - 1) |
CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
cicr4 |= pcdev->mclk_divisor;
@@ -1176,6 +1142,59 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
__raw_writel(cicr0, pcdev->base + CICR0);
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ unsigned long bus_flags, camera_flags, common_flags;
+ int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+ struct pxa_cam *cam = icd->host_priv;
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ if (!common_flags)
+ return -EINVAL;
+
+ pcdev->channels = 1;
+
+ /* Make choises, based on platform preferences */
+ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ }
+
+ cam->flags = common_flags;
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
+ if (ret < 0)
+ return ret;
+
+ pxa_camera_setup_cicr(icd, common_flags, pixfmt);
return 0;
}
@@ -1239,8 +1258,9 @@ static int required_buswidth(const struct soc_camera_data_format *fmt)
static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
struct soc_camera_format_xlate *xlate)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct device *dev = icd->dev.parent;
int formats = 0, buswidth, ret;
+ struct pxa_cam *cam;
buswidth = required_buswidth(icd->formats + idx);
@@ -1251,6 +1271,16 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
if (ret < 0)
return 0;
+ if (!icd->host_priv) {
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam)
+ return -ENOMEM;
+
+ icd->host_priv = cam;
+ } else {
+ cam = icd->host_priv;
+ }
+
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
formats++;
@@ -1259,7 +1289,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(dev, "Providing format %s using %s\n",
pxa_camera_formats[0].name,
icd->formats[idx].name);
}
@@ -1274,7 +1304,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s packed\n",
+ dev_dbg(dev, "Providing format %s packed\n",
icd->formats[idx].name);
}
break;
@@ -1286,7 +1316,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
- dev_dbg(ici->dev,
+ dev_dbg(dev,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
@@ -1295,31 +1325,80 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
return formats;
}
+static void pxa_camera_put_formats(struct soc_camera_device *icd)
+{
+ kfree(icd->host_priv);
+ icd->host_priv = NULL;
+}
+
+static int pxa_camera_check_frame(struct v4l2_pix_format *pix)
+{
+ /* limit to pxa hardware capabilities */
+ return pix->height < 32 || pix->height > 2048 || pix->width < 48 ||
+ pix->width > 2048 || (pix->width & 0x01);
+}
+
static int pxa_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
+ struct v4l2_rect *rect = &a->c;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_sense sense = {
.master_clock = pcdev->mclk,
.pixel_clock_max = pcdev->ciclk / 4,
};
+ struct v4l2_format f;
+ struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp;
+ struct pxa_cam *cam = icd->host_priv;
int ret;
/* If PCLK is used to latch data from the sensor, check sense */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
icd->sense = &sense;
- ret = icd->ops->set_crop(icd, rect);
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
icd->sense = NULL;
if (ret < 0) {
- dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n",
+ dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n",
rect->width, rect->height, rect->left, rect->top);
- } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+ return ret;
+ }
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ pix_tmp = *pix;
+ if (pxa_camera_check_frame(pix)) {
+ /*
+ * Camera cropping produced a frame beyond our capabilities.
+ * FIXME: just extract a subframe, that we can process.
+ */
+ v4l_bound_align_image(&pix->width, 48, 2048, 1,
+ &pix->height, 32, 2048, 0,
+ icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?
+ 4 : 0);
+ ret = v4l2_subdev_call(sd, video, s_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ if (pxa_camera_check_frame(pix)) {
+ dev_warn(icd->dev.parent,
+ "Inconsistent state. Use S_FMT to repair\n");
+ return -EINVAL;
+ }
+ }
+
+ if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
if (sense.pixel_clock > sense.pixel_clock_max) {
- dev_err(ici->dev,
+ dev_err(dev,
"pixel clock %lu set by the camera too high!",
sense.pixel_clock);
return -EIO;
@@ -1327,6 +1406,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
recalculate_fifo_timeout(pcdev, sense.pixel_clock);
}
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
+
+ pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc);
+
return ret;
}
@@ -1335,6 +1419,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_data_format *cam_fmt = NULL;
const struct soc_camera_format_xlate *xlate = NULL;
struct soc_camera_sense sense = {
@@ -1347,7 +1433,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
+ dev_warn(dev, "Format %x not found\n", pix->pixelformat);
return -EINVAL;
}
@@ -1358,16 +1444,21 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
icd->sense = &sense;
cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
- ret = icd->ops->set_fmt(icd, &cam_f);
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
icd->sense = NULL;
if (ret < 0) {
- dev_warn(ici->dev, "Failed to configure for format %x\n",
+ dev_warn(dev, "Failed to configure for format %x\n",
pix->pixelformat);
+ } else if (pxa_camera_check_frame(pix)) {
+ dev_warn(dev,
+ "Camera driver produced an unsupported frame %dx%d\n",
+ pix->width, pix->height);
+ ret = -EINVAL;
} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
if (sense.pixel_clock > sense.pixel_clock_max) {
- dev_err(ici->dev,
+ dev_err(dev,
"pixel clock %lu set by the camera too high!",
sense.pixel_clock);
return -EIO;
@@ -1387,6 +1478,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
__u32 pixfmt = pix->pixelformat;
@@ -1395,7 +1487,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
@@ -1407,7 +1499,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
*/
v4l_bound_align_image(&pix->width, 48, 2048, 1,
&pix->height, 32, 2048, 0,
- xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+ pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
pix->bytesperline = pix->width *
DIV_ROUND_UP(xlate->host_fmt->depth, 8);
@@ -1416,15 +1508,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
/* camera has to see its format, but the user the original one */
pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = icd->ops->try_fmt(icd, f);
- pix->pixelformat = xlate->host_fmt->fourcc;
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
+ pix->pixelformat = pixfmt;
field = pix->field;
if (field == V4L2_FIELD_ANY) {
pix->field = V4L2_FIELD_NONE;
} else if (field != V4L2_FIELD_NONE) {
- dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+ dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
return -EINVAL;
}
@@ -1530,6 +1622,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.resume = pxa_camera_resume,
.set_crop = pxa_camera_set_crop,
.get_formats = pxa_camera_get_formats,
+ .put_formats = pxa_camera_put_formats,
.set_fmt = pxa_camera_set_fmt,
.try_fmt = pxa_camera_try_fmt,
.init_videobuf = pxa_camera_init_videobuf,
@@ -1587,8 +1680,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
pcdev->mclk = 20000000;
}
- pcdev->soc_host.dev = &pdev->dev;
- pcdev->mclk_divisor = mclk_get_divisor(pcdev);
+ pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev);
INIT_LIST_HEAD(&pcdev->capture);
spin_lock_init(&pcdev->lock);
@@ -1653,6 +1745,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME;
pcdev->soc_host.ops = &pxa_soc_camera_host_ops;
pcdev->soc_host.priv = pcdev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
err = soc_camera_host_register(&pcdev->soc_host);
@@ -1734,3 +1827,4 @@ module_exit(pxa_camera_exit);
MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index 5bcce092e..22bfd62c9 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -47,6 +47,7 @@ config VIDEO_SAA7134_DVB
select DVB_TDA10048 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+ select DVB_ZL10039 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index 860f271dd..32ecebe8c 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -475,7 +475,7 @@ static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
(!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
return -ERANGE;
- new = old;
+ params->au_encoding = new;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
old = params->au_l2_bitrate;
diff --git a/linux/drivers/media/video/saa7134/saa7134-alsa.c b/linux/drivers/media/video/saa7134/saa7134-alsa.c
index c09ec3e6f..0d9c833e7 100644
--- a/linux/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/linux/drivers/media/video/saa7134/saa7134-alsa.c
@@ -41,6 +41,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
*/
/* defaults */
+#define MIXER_ADDR_UNSELECTED -1
#define MIXER_ADDR_TVTUNER 0
#define MIXER_ADDR_LINE1 1
#define MIXER_ADDR_LINE2 2
@@ -69,7 +70,9 @@ typedef struct snd_card_saa7134 {
struct snd_card *card;
spinlock_t mixer_lock;
int mixer_volume[MIXER_ADDR_LAST+1][2];
- int capture_source[MIXER_ADDR_LAST+1][2];
+ int capture_source_addr;
+ int capture_source[2];
+ struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1];
struct pci_dev *pci;
struct saa7134_dev *dev;
@@ -319,6 +322,115 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
return 0;
}
+/*
+ * Setting the capture source and updating the ALSA controls
+ */
+static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol,
+ int left, int right, bool force_notify)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int change = 0, addr = kcontrol->private_value;
+ int active, old_addr;
+ u32 anabar, xbarin;
+ int analog_io, rate;
+ struct saa7134_dev *dev;
+
+ dev = chip->dev;
+
+ spin_lock_irq(&chip->mixer_lock);
+
+ active = left != 0 || right != 0;
+ old_addr = chip->capture_source_addr;
+
+ /* The active capture source cannot be deactivated */
+ if (active) {
+ change = old_addr != addr ||
+ chip->capture_source[0] != left ||
+ chip->capture_source[1] != right;
+
+ chip->capture_source[0] = left;
+ chip->capture_source[1] = right;
+ chip->capture_source_addr = addr;
+ dev->dmasound.input = addr;
+ }
+ spin_unlock_irq(&chip->mixer_lock);
+
+ if (change) {
+ switch (dev->pci->device) {
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+ 0xc0, 0xc0);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+ 0x03, 0x00);
+ break;
+ case MIXER_ADDR_LINE1:
+ case MIXER_ADDR_LINE2:
+ analog_io = (MIXER_ADDR_LINE1 == addr) ?
+ 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ?
+ 0x01 : 0x03;
+ saa_andorb(SAA7134_ANALOG_IO_SELECT,
+ 0x08, analog_io);
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+ 0xc0, 0x80);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+ 0x03, rate);
+ break;
+ }
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ xbarin = 0x03; /* adc */
+ anabar = 0;
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ xbarin = 0; /* Demodulator */
+ anabar = 2; /* DACs */
+ break;
+ case MIXER_ADDR_LINE1:
+ anabar = 0; /* aux1, aux1 */
+ break;
+ case MIXER_ADDR_LINE2:
+ anabar = 9; /* aux2, aux2 */
+ break;
+ }
+
+ /* output xbar always main channel */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1,
+ 0xbbbb10);
+
+ if (left || right) {
+ /* We've got data, turn the input on */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+ xbarin);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+ } else {
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+ 0);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+ }
+ break;
+ }
+ }
+
+ if (change) {
+ if (force_notify)
+ snd_ctl_notify(chip->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->capture_ctl[addr]->id);
+
+ if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr)
+ snd_ctl_notify(chip->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->capture_ctl[old_addr]->id);
+ }
+
+ return change;
+}
/*
* ALSA PCM preparation
@@ -406,6 +518,10 @@ static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream
dev->dmasound.rate = runtime->rate;
+ /* Setup and update the card/ALSA controls */
+ snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1,
+ true);
+
return 0;
}
@@ -440,6 +556,16 @@ snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
/*
* ALSA hardware capabilities definition
+ *
+ * Report only 32kHz for ALSA:
+ *
+ * - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz
+ * only
+ * - SAA7134 for TV mode uses DemDec mode (32kHz)
+ * - Radio works in 32kHz only
+ * - When recording 48kHz from Line1/Line2, switching of capture source to TV
+ * means
+ * switching to 32kHz without any frequency translation
*/
static struct snd_pcm_hardware snd_card_saa7134_capture =
@@ -453,9 +579,9 @@ static struct snd_pcm_hardware snd_card_saa7134_capture =
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_U16_BE,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .rates = SNDRV_PCM_RATE_32000,
.rate_min = 32000,
- .rate_max = 48000,
+ .rate_max = 32000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (256*1024),
@@ -841,8 +967,13 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
int addr = kcontrol->private_value;
spin_lock_irq(&chip->mixer_lock);
- ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
- ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+ if (chip->capture_source_addr == addr) {
+ ucontrol->value.integer.value[0] = chip->capture_source[0];
+ ucontrol->value.integer.value[1] = chip->capture_source[1];
+ } else {
+ ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.integer.value[1] = 0;
+ }
spin_unlock_irq(&chip->mixer_lock);
return 0;
@@ -851,87 +982,22 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
struct snd_ctl_elem_value * ucontrol)
{
- snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
- int change, addr = kcontrol->private_value;
int left, right;
- u32 anabar, xbarin;
- int analog_io, rate;
- struct saa7134_dev *dev;
-
- dev = chip->dev;
-
left = ucontrol->value.integer.value[0] & 1;
right = ucontrol->value.integer.value[1] & 1;
- spin_lock_irq(&chip->mixer_lock);
-
- change = chip->capture_source[addr][0] != left ||
- chip->capture_source[addr][1] != right;
- chip->capture_source[addr][0] = left;
- chip->capture_source[addr][1] = right;
- dev->dmasound.input=addr;
- spin_unlock_irq(&chip->mixer_lock);
-
-
- if (change) {
- switch (dev->pci->device) {
-
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- switch (addr) {
- case MIXER_ADDR_TVTUNER:
- saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
- saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
- break;
- case MIXER_ADDR_LINE1:
- case MIXER_ADDR_LINE2:
- analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
- rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
- saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
- saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
- saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
- break;
- }
-
- break;
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- xbarin = 0x03; // adc
- anabar = 0;
- switch (addr) {
- case MIXER_ADDR_TVTUNER:
- xbarin = 0; // Demodulator
- anabar = 2; // DACs
- break;
- case MIXER_ADDR_LINE1:
- anabar = 0; // aux1, aux1
- break;
- case MIXER_ADDR_LINE2:
- anabar = 9; // aux2, aux2
- break;
- }
-
- /* output xbar always main channel */
- saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
- if (left || right) { // We've got data, turn the input on
- saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
- saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
- } else {
- saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
- saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
- }
- break;
- }
- }
-
- return change;
+ return snd_saa7134_capsrc_set(kcontrol, left, right, false);
}
-static struct snd_kcontrol_new snd_saa7134_controls[] = {
+static struct snd_kcontrol_new snd_saa7134_volume_controls[] = {
SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
-SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
-SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+};
+
+static struct snd_kcontrol_new snd_saa7134_capture_controls[] = {
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
};
@@ -946,17 +1012,33 @@ SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
{
struct snd_card *card = chip->card;
+ struct snd_kcontrol *kcontrol;
unsigned int idx;
- int err;
+ int err, addr;
if (snd_BUG_ON(!chip))
return -EINVAL;
strcpy(card->mixername, "SAA7134 Mixer");
- for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
+ kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
+ chip);
+ err = snd_ctl_add(card, kcontrol);
+ if (err < 0)
return err;
}
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) {
+ kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx],
+ chip);
+ addr = snd_saa7134_capture_controls[idx].private_value;
+ chip->capture_ctl[addr] = kcontrol;
+ err = snd_ctl_add(card, kcontrol);
+ if (err < 0)
+ return err;
+ }
+
+ chip->capture_source_addr = MIXER_ADDR_UNSELECTED;
return 0;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 3ab7732e6..6ea54fa7c 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -32,6 +32,7 @@
#include <media/tveeprom.h>
#include "tea5767.h"
#include "tda18271.h"
+#include "xc5000.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -265,6 +266,56 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x10000,
},
},
+ [SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = {
+ /* RoverMedia TV Link Pro FM (LR138 REV:I) */
+ /* Eugene Yudin <Eugene.Yudin@gmail.com> */
+ .name = "RoverMedia TV Link Pro FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0xe000,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ .tv = 1,
+ }, {
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }, {
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
[SAA7134_BOARD_EMPRESS] = {
/* "Gert Vervoort" <gert.vervoort@philips.com> */
.name = "EMPRESS",
@@ -1364,6 +1415,42 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
},
},
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_505] = {
+ /* Vasiliy Temnikov <vaka@newmail.ru> */
+ .name = "AverMedia AverTV Studio 505",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
[SAA7134_BOARD_UPMOST_PURPLE_TV] = {
.name = "UPMOST PURPLE TV",
.audio_clock = 0x00187de7,
@@ -3702,8 +3789,8 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
.gpio = 0x0200000,
},
- },
- [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
.name = "ASUSTeK P7131 Analog",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_TDA8290,
@@ -4120,6 +4207,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
@@ -4184,6 +4272,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
@@ -4214,6 +4303,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x00008000,
.inputs = {{
@@ -4389,6 +4479,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4417,6 +4508,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4445,6 +4537,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4473,6 +4566,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -4579,6 +4673,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
.empress_addr = 0x20,
.tda9887_conf = TDA9887_PRESENT,
.inputs = { {
@@ -5155,6 +5250,53 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x00,
},
},
+ [SAA7134_BOARD_VIDEOMATE_S350] = {
+ /* Jan D. Louw <jd.louw@mweb.co.za */
+ .name = "Compro VideoMate S350/S300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8, /* Not tested */
+ .amux = LINE1
+ } },
+ },
+ [SAA7134_BOARD_BEHOLD_X7] = {
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV X7",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC5000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 2,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 9,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ },
+ },
+
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5413,6 +5555,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa115,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0x2108,
.driver_data = SAA7134_BOARD_AVERMEDIA_305,
},{
@@ -6262,7 +6410,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0xf31d,
.driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
-
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_S350,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7595,
+ .driver_data = SAA7134_BOARD_BEHOLD_X7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x19d1, /* RoverMedia */
+ .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */
+ .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM,
}, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -6386,11 +6551,20 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
return -EINVAL;
}
-#if 0
+#if 1
static int saa7134_xc5000_callback(struct saa7134_dev *dev,
int command, int arg)
{
switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_X7:
+ if (command == XC5000_TUNER_RESET) {
+ /* Down and UP pheripherial RESET pin for reset all chips */
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+ msleep(10);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ msleep(10);
+ }
+ break;
default:
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
@@ -6501,7 +6675,7 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg)
return saa7134_tda8290_callback(dev, command, arg);
case TUNER_XC2028:
return saa7134_xc2028_callback(dev, command, arg);
-#if 0
+#if 1
case TUNER_XC5000:
return saa7134_xc5000_callback(dev, command, arg);
#endif
@@ -6575,6 +6749,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
case SAA7134_BOARD_KWORLD_XPERT:
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
case SAA7134_BOARD_AVERMEDIA_305:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_307:
@@ -6599,7 +6774,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_PROTEUS_2309:
case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -6624,6 +6799,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_REAL_ANGEL_220:
case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -6756,6 +6932,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_M63:
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -6776,6 +6953,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00008000, 0x00008000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ break;
}
return 0;
}
@@ -7110,22 +7292,22 @@ int saa7134_board_init2(struct saa7134_dev *dev)
if (dev->radio_type != UNSET)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "tuner", "tuner",
- dev->radio_addr);
+ dev->radio_addr, NULL);
if (has_demod)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == ADDR_UNSET) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(type));
+ 0, v4l2_i2c_tuner_addrs(type));
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "tuner", "tuner",
- dev->tuner_addr);
+ dev->tuner_addr, NULL);
}
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index e466afd18..d0080370f 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -1061,7 +1061,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct v4l2_subdev *sd =
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"saa6752hs", "saa6752hs",
- saa7134_boards[dev->board].empress_addr);
+ saa7134_boards[dev->board].empress_addr, NULL);
if (sd)
sd->grp_id = GRP_EMPRESS;
@@ -1070,9 +1070,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (saa7134_boards[dev->board].rds_addr) {
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_probed_subdev_addr(&dev->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_adap, "saa6588", "saa6588",
- saa7134_boards[dev->board].rds_addr);
+ 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
dev->has_rds = 1;
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index afd9b7e5c..dc2428f12 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -56,6 +56,7 @@
#include "zl10353.h"
#include "zl10036.h"
+#include "zl10039.h"
#include "mt312.h"
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -968,6 +969,10 @@ static struct zl10036_config avertv_a700_tuner = {
.tuner_address = 0x60,
};
+static struct mt312_config zl10313_compro_s350_config = {
+ .demod_address = 0x0e,
+};
+
static struct lgdt3305_config hcw_lgdt3305_config = {
.i2c_addr = 0x0e,
.mpeg_mode = LGDT3305_MPEG_SERIAL,
@@ -1002,6 +1007,7 @@ static struct tda18271_config hcw_tda18271_config = {
.std_map = &hauppauge_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
.config = 3,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
};
static struct tda829x_config tda829x_no_probe = {
@@ -1477,6 +1483,16 @@ static int dvb_init(struct saa7134_dev *dev)
}
}
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &zl10313_compro_s350_config, &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap) == NULL)
+ wprintk("%s: No zl10039 found!\n",
+ __func__);
+
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index b54bfd645..153fb3c5b 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -435,7 +435,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
{
struct card_ir *ir;
struct input_dev *input_dev;
- IR_KEYTAB_TYPE *ir_codes = NULL;
+ struct ir_scancode_table *ir_codes = NULL;
u32 mask_keycode = 0;
u32 mask_keydown = 0;
u32 mask_keyup = 0;
@@ -456,27 +456,28 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_FLYVIDEO3000:
case SAA7134_BOARD_FLYTVPLATINUM_FM:
case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
- ir_codes = ir_codes_flyvideo;
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+ ir_codes = &ir_codes_flyvideo_table;
mask_keycode = 0xEC00000;
mask_keydown = 0x0040000;
break;
case SAA7134_BOARD_CINERGY400:
case SAA7134_BOARD_CINERGY600:
case SAA7134_BOARD_CINERGY600_MK3:
- ir_codes = ir_codes_cinergy;
+ ir_codes = &ir_codes_cinergy_table;
mask_keycode = 0x00003f;
mask_keyup = 0x040000;
break;
case SAA7134_BOARD_ECS_TVP3XP:
case SAA7134_BOARD_ECS_TVP3XP_4CB5:
- ir_codes = ir_codes_eztv;
+ ir_codes = &ir_codes_eztv_table;
mask_keycode = 0x00017c;
mask_keyup = 0x000002;
polling = 50; // ms
break;
case SAA7134_BOARD_KWORLD_XPERT:
case SAA7134_BOARD_AVACSSMARTTV:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
mask_keycode = 0x00001F;
mask_keyup = 0x000020;
polling = 50; // ms
@@ -486,13 +487,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_305:
case SAA7134_BOARD_AVERMEDIA_307:
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
case SAA7134_BOARD_AVERMEDIA_M102:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
- ir_codes = ir_codes_avermedia;
+ ir_codes = &ir_codes_avermedia_table;
mask_keycode = 0x0007C8;
mask_keydown = 0x000010;
polling = 50; // ms
@@ -501,14 +503,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
case SAA7134_BOARD_AVERMEDIA_M135A:
- ir_codes = ir_codes_avermedia_m135a;
+ ir_codes = &ir_codes_avermedia_m135a_table;
mask_keydown = 0x0040000;
mask_keycode = 0x00013f;
nec_gpio = 1;
break;
case SAA7134_BOARD_AVERMEDIA_777:
case SAA7134_BOARD_AVERMEDIA_A16AR:
- ir_codes = ir_codes_avermedia;
+ ir_codes = &ir_codes_avermedia_table;
mask_keycode = 0x02F200;
mask_keydown = 0x000400;
polling = 50; // ms
@@ -517,7 +519,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
break;
case SAA7134_BOARD_AVERMEDIA_A16D:
- ir_codes = ir_codes_avermedia_a16d;
+ ir_codes = &ir_codes_avermedia_a16d_table;
mask_keycode = 0x02F200;
mask_keydown = 0x000400;
polling = 50; /* ms */
@@ -526,14 +528,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
break;
case SAA7134_BOARD_KWORLD_TERMINATOR:
- ir_codes = ir_codes_pixelview;
+ ir_codes = &ir_codes_pixelview_table;
mask_keycode = 0x00001f;
mask_keyup = 0x000060;
polling = 50; // ms
break;
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
- ir_codes = ir_codes_manli;
+ ir_codes = &ir_codes_manli_table;
mask_keycode = 0x001f00;
mask_keyup = 0x004000;
polling = 50; /* ms */
@@ -552,25 +554,25 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_507_9FM:
case SAA7134_BOARD_BEHOLD_507RDS_MK3:
case SAA7134_BOARD_BEHOLD_507RDS_MK5:
- ir_codes = ir_codes_manli;
+ ir_codes = &ir_codes_manli_table;
mask_keycode = 0x003f00;
mask_keyup = 0x004000;
polling = 50; /* ms */
break;
case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
- ir_codes = ir_codes_behold_columbus;
+ ir_codes = &ir_codes_behold_columbus_table;
mask_keycode = 0x003f00;
mask_keyup = 0x004000;
polling = 50; // ms
break;
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
- ir_codes = ir_codes_pctv_sedna;
+ ir_codes = &ir_codes_pctv_sedna_table;
mask_keycode = 0x001f00;
mask_keyup = 0x004000;
polling = 50; // ms
break;
case SAA7134_BOARD_GOTVIEW_7135:
- ir_codes = ir_codes_gotview7135;
+ ir_codes = &ir_codes_gotview7135_table;
mask_keycode = 0x0003CC;
mask_keydown = 0x000010;
polling = 5; /* ms */
@@ -579,73 +581,78 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
- ir_codes = ir_codes_videomate_tv_pvr;
+ ir_codes = &ir_codes_videomate_tv_pvr_table;
mask_keycode = 0x00003F;
mask_keyup = 0x400000;
polling = 50; // ms
break;
case SAA7134_BOARD_PROTEUS_2309:
- ir_codes = ir_codes_proteus_2309;
+ ir_codes = &ir_codes_proteus_2309_table;
mask_keycode = 0x00007F;
mask_keyup = 0x000080;
polling = 50; // ms
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
- ir_codes = ir_codes_videomate_tv_pvr;
+ ir_codes = &ir_codes_videomate_tv_pvr_table;
mask_keycode = 0x003F00;
mask_keyup = 0x040000;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_FLYDVBTDUO:
- ir_codes = ir_codes_flydvb;
+ ir_codes = &ir_codes_flydvb_table;
mask_keycode = 0x0001F00;
mask_keydown = 0x0040000;
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
- ir_codes = ir_codes_asus_pc39;
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ ir_codes = &ir_codes_asus_pc39_table;
mask_keydown = 0x0040000;
rc5_gpio = 1;
break;
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
- ir_codes = ir_codes_encore_enltv;
+ ir_codes = &ir_codes_encore_enltv_table;
mask_keycode = 0x00007f;
mask_keyup = 0x040000;
polling = 50; // ms
break;
case SAA7134_BOARD_ENCORE_ENLTV_FM53:
- ir_codes = ir_codes_encore_enltv_fm53;
+ ir_codes = &ir_codes_encore_enltv_fm53_table;
mask_keydown = 0x0040000;
mask_keycode = 0x00007f;
nec_gpio = 1;
break;
case SAA7134_BOARD_10MOONSTVMASTER3:
- ir_codes = ir_codes_encore_enltv;
+ ir_codes = &ir_codes_encore_enltv_table;
mask_keycode = 0x5f80000;
mask_keyup = 0x8000000;
polling = 50; //ms
break;
case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
- ir_codes = ir_codes_genius_tvgo_a11mce;
+ ir_codes = &ir_codes_genius_tvgo_a11mce_table;
mask_keycode = 0xff;
mask_keydown = 0xf00000;
polling = 50; /* ms */
break;
case SAA7134_BOARD_REAL_ANGEL_220:
- ir_codes = ir_codes_real_audio_220_32_keys;
+ ir_codes = &ir_codes_real_audio_220_32_keys_table;
mask_keycode = 0x3f00;
mask_keyup = 0x4000;
polling = 50; /* ms */
break;
case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
- ir_codes = ir_codes_kworld_plus_tv_analog;
+ ir_codes = &ir_codes_kworld_plus_tv_analog_table;
mask_keycode = 0x7f;
polling = 40; /* ms */
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ ir_codes = &ir_codes_videomate_s350_table;
+ mask_keycode = 0x003f00;
+ mask_keydown = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -734,8 +741,6 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
- struct i2c_board_info info;
- struct IR_i2c_init_data init_data;
const unsigned short addr_list[] = {
0x7a, 0x47, 0x71, 0x2d,
I2C_CLIENT_END
@@ -762,9 +767,9 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
- memset(&info, 0, sizeof(struct i2c_board_info));
- memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ memset(&dev->info, 0, sizeof(dev->info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
#endif
switch (dev->board) {
@@ -773,23 +778,25 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
#else
- init_data.name = "Pinnacle PCTV";
+ dev->init_data.name = "Pinnacle PCTV";
#endif
if (pinnacle_remote == 0) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->get_key = get_key_pinnacle_color;
- ir->ir_codes = ir_codes_pinnacle_color;
+ ir->ir_codes = &ir_codes_pinnacle_color_table;
#else
- init_data.get_key = get_key_pinnacle_color;
- init_data.ir_codes = ir_codes_pinnacle_color;
+ dev->init_data.get_key = get_key_pinnacle_color;
+ dev->init_data.ir_codes = &ir_codes_pinnacle_color_table;
+ dev->info.addr = 0x47;
#endif
} else {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->get_key = get_key_pinnacle_grey;
- ir->ir_codes = ir_codes_pinnacle_grey;
+ ir->ir_codes = &ir_codes_pinnacle_grey_table;
#else
- init_data.get_key = get_key_pinnacle_grey;
- init_data.ir_codes = ir_codes_pinnacle_grey;
+ dev->init_data.get_key = get_key_pinnacle_grey;
+ dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
+ dev->info.addr = 0x47;
#endif
}
break;
@@ -797,23 +804,23 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
ir->get_key = get_key_purpletv;
- ir->ir_codes = ir_codes_purpletv;
+ ir->ir_codes = &ir_codes_purpletv_table;
#else
- init_data.name = "Purple TV";
- init_data.get_key = get_key_purpletv;
- init_data.ir_codes = ir_codes_purpletv;
+ dev->init_data.name = "Purple TV";
+ dev->init_data.get_key = get_key_purpletv;
+ dev->init_data.ir_codes = &ir_codes_purpletv_table;
#endif
break;
case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus");
ir->get_key = get_key_msi_tvanywhere_plus;
- ir->ir_codes = ir_codes_msi_tvanywhere_plus;
+ ir->ir_codes = &ir_codes_msi_tvanywhere_plus_table;
#else
- init_data.name = "MSI TV@nywhere Plus";
- init_data.get_key = get_key_msi_tvanywhere_plus;
- init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
- info.addr = 0x30;
+ dev->init_data.name = "MSI TV@nywhere Plus";
+ dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+ dev->init_data.ir_codes = &ir_codes_msi_tvanywhere_plus_table;
+ dev->info.addr = 0x30;
/* MSI TV@nywhere Plus controller doesn't seem to
respond to probes unless we read something from
an existing device. Weird...
@@ -828,11 +835,11 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
ir->get_key = get_key_hvr1110;
- ir->ir_codes = ir_codes_hauppauge_new;
+ ir->ir_codes = &ir_codes_hauppauge_new_table;
#else
- init_data.name = "HVR 1110";
- init_data.get_key = get_key_hvr1110;
- init_data.ir_codes = ir_codes_hauppauge_new;
+ dev->init_data.name = "HVR 1110";
+ dev->init_data.get_key = get_key_hvr1110;
+ dev->init_data.ir_codes = &ir_codes_hauppauge_new_table;
#endif
break;
case SAA7134_BOARD_BEHOLD_607FM_MK3:
@@ -847,14 +854,15 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_M63:
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
ir->get_key = get_key_beholdm6xx;
- ir->ir_codes = ir_codes_behold;
+ ir->ir_codes = &ir_codes_behold_table;
#else
- init_data.name = "BeholdTV";
- init_data.get_key = get_key_beholdm6xx;
- init_data.ir_codes = ir_codes_behold;
+ dev->init_data.name = "BeholdTV";
+ dev->init_data.get_key = get_key_beholdm6xx;
+ dev->init_data.ir_codes = &ir_codes_behold_table;
#endif
break;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
@@ -863,22 +871,22 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
#else
case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
- info.addr = 0x40;
+ dev->info.addr = 0x40;
#endif
break;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
- if (init_data.name)
- info.platform_data = &init_data;
+ if (dev->init_data.name)
+ dev->info.platform_data = &dev->init_data;
/* No need to probe if address is known */
- if (info.addr) {
- i2c_new_device(&dev->i2c_adap, &info);
+ if (dev->info.addr) {
+ i2c_new_device(&dev->i2c_adap, &dev->info);
return;
}
/* Address not known, fallback to probing */
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+ i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
#endif
}
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 6b0742ad7..1bf2837b4 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -293,6 +293,10 @@ struct saa7134_format {
#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166
#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167
#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168
+#define SAA7134_BOARD_VIDEOMATE_S350 169
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170
+#define SAA7134_BOARD_BEHOLD_X7 171
+#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -590,6 +594,12 @@ struct saa7134_dev {
int nosignal;
unsigned int insuspend;
+ /* I2C keyboard data */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ struct i2c_board_info info;
+ struct IR_i2c_init_data init_data;
+#endif
+
/* SAA7134_MPEG_* */
struct saa7134_ts ts;
struct saa7134_dmaqueue ts_q;
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index 1bae28a98..d35f66d8a 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -75,6 +75,13 @@
#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
+#undef DEBUG_GEOMETRY
+#ifdef DEBUG_GEOMETRY
+#define dev_geo dev_info
+#else
+#define dev_geo dev_dbg
+#endif
+
/* per video frame buffer */
struct sh_mobile_ceu_buffer {
struct videobuf_buffer vb; /* v4l buffer must be first */
@@ -94,10 +101,21 @@ struct sh_mobile_ceu_dev {
spinlock_t lock;
struct list_head capture;
struct videobuf_buffer *active;
- int is_interlaced;
struct sh_mobile_ceu_info *pdata;
+ u32 cflcr;
+
+ unsigned int is_interlaced:1;
+ unsigned int image_mode:1;
+ unsigned int is_16bit:1;
+};
+
+struct sh_mobile_ceu_cam {
+ struct v4l2_rect ceu_rect;
+ unsigned int cam_width;
+ unsigned int cam_height;
+ const struct soc_camera_data_format *extra_fmt;
const struct soc_camera_data_format *camera_fmt;
};
@@ -148,7 +166,8 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
struct sh_mobile_ceu_dev *pcdev = ici->priv;
int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
- *size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel);
+ *size = PAGE_ALIGN(icd->user_width * icd->user_height *
+ bytes_per_pixel);
if (0 == *count)
*count = 2;
@@ -158,7 +177,7 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
(*count)--;
}
- dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
return 0;
}
@@ -167,8 +186,9 @@ static void free_buffer(struct videobuf_queue *vq,
struct sh_mobile_ceu_buffer *buf)
{
struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+ dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
&buf->vb, buf->vb.baddr, buf->vb.bsize);
if (in_interrupt())
@@ -176,7 +196,7 @@ static void free_buffer(struct videobuf_queue *vq,
videobuf_waiton(&buf->vb, 0, 0);
videobuf_dma_contig_free(vq, &buf->vb);
- dev_dbg(&icd->dev, "%s freed\n", __func__);
+ dev_dbg(dev, "%s freed\n", __func__);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -207,7 +227,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
phys_addr_top = videobuf_to_dma_contig(pcdev->active);
ceu_write(pcdev, CDAYR, phys_addr_top);
if (pcdev->is_interlaced) {
- phys_addr_bottom = phys_addr_top + icd->width;
+ phys_addr_bottom = phys_addr_top + icd->user_width;
ceu_write(pcdev, CDBYR, phys_addr_bottom);
}
@@ -216,10 +236,12 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
- phys_addr_top += icd->width * icd->height;
+ phys_addr_top += icd->user_width *
+ icd->user_height;
ceu_write(pcdev, CDACR, phys_addr_top);
if (pcdev->is_interlaced) {
- phys_addr_bottom = phys_addr_top + icd->width;
+ phys_addr_bottom = phys_addr_top +
+ icd->user_width;
ceu_write(pcdev, CDBCR, phys_addr_bottom);
}
}
@@ -238,7 +260,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
buf = container_of(vb, struct sh_mobile_ceu_buffer, vb);
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -253,12 +275,12 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
BUG_ON(NULL == icd->current_fmt);
if (buf->fmt != icd->current_fmt ||
- vb->width != icd->width ||
- vb->height != icd->height ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
- vb->width = icd->width;
- vb->height = icd->height;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -291,7 +313,7 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+ dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
vb->state = VIDEOBUF_QUEUED;
@@ -306,6 +328,27 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (pcdev->active == vb) {
+ /* disable capture (release DMA buffer), reset */
+ ceu_write(pcdev, CAPSR, 1 << 16);
+ pcdev->active = NULL;
+ }
+
+ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+ !list_empty(&vb->queue)) {
+ vb->state = VIDEOBUF_ERROR;
+ list_del_init(&vb->queue);
+ }
+
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
}
@@ -325,6 +368,10 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
spin_lock_irqsave(&pcdev->lock, flags);
vb = pcdev->active;
+ if (!vb)
+ /* Stale interrupt from a released buffer */
+ goto out;
+
list_del_init(&vb->queue);
if (!list_empty(&pcdev->capture))
@@ -339,6 +386,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
do_gettimeofday(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
+
+out:
spin_unlock_irqrestore(&pcdev->lock, flags);
return IRQ_HANDLED;
@@ -349,19 +398,14 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- int ret = -EBUSY;
if (pcdev->icd)
- goto err;
+ return -EBUSY;
- dev_info(&icd->dev,
+ dev_info(icd->dev.parent,
"SuperH Mobile CEU driver attached to camera %d\n",
icd->devnum);
- ret = icd->ops->init(icd);
- if (ret)
- goto err;
-
clk_enable(pcdev->clk);
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
@@ -369,8 +413,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
msleep(1);
pcdev->icd = icd;
-err:
- return ret;
+
+ return 0;
}
/* Called with .video_lock held */
@@ -398,23 +442,149 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
clk_disable(pcdev->clk);
- icd->ops->release(icd);
-
- dev_info(&icd->dev,
+ dev_info(icd->dev.parent,
"SuperH Mobile CEU driver detached from camera %d\n",
icd->devnum);
pcdev->icd = NULL;
}
+/*
+ * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)"
+ * in SH7722 Hardware Manual
+ */
+static unsigned int size_dst(unsigned int src, unsigned int scale)
+{
+ unsigned int mant_pre = scale >> 12;
+ if (!src || !scale)
+ return src;
+ return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) *
+ mant_pre * 4096 / scale + 1;
+}
+
+static u16 calc_scale(unsigned int src, unsigned int *dst)
+{
+ u16 scale;
+
+ if (src == *dst)
+ return 0;
+
+ scale = (src * 4096 / *dst) & ~7;
+
+ while (scale > 4096 && size_dst(src, scale) < *dst)
+ scale -= 8;
+
+ *dst = size_dst(src, scale);
+
+ return scale;
+}
+
+/* rect is guaranteed to not exceed the scaled camera rectangle */
+static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd,
+ unsigned int out_width,
+ unsigned int out_height)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_rect *rect = &cam->ceu_rect;
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned int height, width, cdwdr_width, in_width, in_height;
+ unsigned int left_offset, top_offset;
+ u32 camor;
+
+ dev_dbg(icd->dev.parent, "Crop %ux%u@%u:%u\n",
+ rect->width, rect->height, rect->left, rect->top);
+
+ left_offset = rect->left;
+ top_offset = rect->top;
+
+ if (pcdev->image_mode) {
+ in_width = rect->width;
+ if (!pcdev->is_16bit) {
+ in_width *= 2;
+ left_offset *= 2;
+ }
+ width = cdwdr_width = out_width;
+ } else {
+ unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3;
+
+ width = out_width * w_factor / 2;
+
+ if (!pcdev->is_16bit)
+ w_factor *= 2;
+
+ in_width = rect->width * w_factor / 2;
+ left_offset = left_offset * w_factor / 2;
+
+ cdwdr_width = width * 2;
+ }
+
+ height = out_height;
+ in_height = rect->height;
+ if (pcdev->is_interlaced) {
+ height /= 2;
+ in_height /= 2;
+ top_offset /= 2;
+ cdwdr_width *= 2;
+ }
+
+ /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
+ camor = left_offset | (top_offset << 16);
+
+ dev_geo(icd->dev.parent,
+ "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor,
+ (in_height << 16) | in_width, (height << 16) | width,
+ cdwdr_width);
+
+ ceu_write(pcdev, CAMOR, camor);
+ ceu_write(pcdev, CAPWR, (in_height << 16) | in_width);
+ ceu_write(pcdev, CFSZR, (height << 16) | width);
+ ceu_write(pcdev, CDWDR, cdwdr_width);
+}
+
+static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev)
+{
+ u32 capsr = ceu_read(pcdev, CAPSR);
+ ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */
+ return capsr;
+}
+
+static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
+{
+ unsigned long timeout = jiffies + 10 * HZ;
+
+ /*
+ * Wait until the end of the current frame. It can take a long time,
+ * but if it has been aborted by a CAPSR reset, it shoule exit sooner.
+ */
+ while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout))
+ msleep(1);
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(pcdev->ici.v4l2_dev.dev,
+ "Timeout waiting for frame end! Interface problem?\n");
+ return;
+ }
+
+ /* Wait until reset clears, this shall not hang... */
+ while (ceu_read(pcdev, CAPSR) & (1 << 16))
+ udelay(10);
+
+ /* Anything to restore? */
+ if (capsr & ~(1 << 16))
+ ceu_write(pcdev, CAPSR, capsr);
+}
+
static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
__u32 pixfmt)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- int ret, buswidth, width, height, cfszr_width, cdwdr_width;
+ int ret;
unsigned long camera_flags, common_flags, value;
- int yuv_mode, yuv_lineskip;
+ int yuv_lineskip;
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ u32 capsr = capture_save_reset(pcdev);
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
@@ -428,10 +598,10 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_8:
- buswidth = 8;
+ pcdev->is_16bit = 0;
break;
case SOCAM_DATAWIDTH_16:
- buswidth = 16;
+ pcdev->is_16bit = 1;
break;
default:
return -EINVAL;
@@ -441,7 +611,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CRCMPR, 0);
value = 0x00000010; /* data fetch by default */
- yuv_mode = yuv_lineskip = 0;
+ yuv_lineskip = 0;
switch (icd->current_fmt->fourcc) {
case V4L2_PIX_FMT_NV12:
@@ -450,8 +620,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
/* fall-through */
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
- yuv_mode = 1;
- switch (pcdev->camera_fmt->fourcc) {
+ switch (cam->camera_fmt->fourcc) {
case V4L2_PIX_FMT_UYVY:
value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
break;
@@ -475,36 +644,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
- value |= buswidth == 16 ? 1 << 12 : 0;
+ value |= pcdev->is_16bit ? 1 << 12 : 0;
ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000);
ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0);
+ sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height);
mdelay(1);
- if (yuv_mode) {
- width = icd->width * 2;
- width = buswidth == 16 ? width / 2 : width;
- cfszr_width = cdwdr_width = icd->width;
- } else {
- width = icd->width * ((icd->current_fmt->depth + 7) >> 3);
- width = buswidth == 16 ? width / 2 : width;
- cfszr_width = buswidth == 8 ? width / 2 : width;
- cdwdr_width = buswidth == 16 ? width * 2 : width;
- }
-
- height = icd->height;
- if (pcdev->is_interlaced) {
- height /= 2;
- cdwdr_width *= 2;
- }
-
- ceu_write(pcdev, CAMOR, 0);
- ceu_write(pcdev, CAPWR, (height << 16) | width);
- ceu_write(pcdev, CFLCR, 0); /* no scaling */
- ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
- ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */
+ ceu_write(pcdev, CFLCR, pcdev->cflcr);
/* A few words about byte order (observed in Big Endian mode)
*
@@ -523,10 +672,15 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */
ceu_write(pcdev, CDOCR, value);
-
- ceu_write(pcdev, CDWDR, cdwdr_width);
ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
+ dev_dbg(icd->dev.parent, "S_FMT successful for %c%c%c%c %ux%u\n",
+ pixfmt & 0xff, (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
+ icd->user_width, icd->user_height);
+
+ capture_restore(pcdev, capsr);
+
/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
return 0;
}
@@ -576,24 +730,35 @@ static const struct soc_camera_data_format sh_mobile_ceu_formats[] = {
static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
struct soc_camera_format_xlate *xlate)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct device *dev = icd->dev.parent;
int ret, k, n;
int formats = 0;
+ struct sh_mobile_ceu_cam *cam;
ret = sh_mobile_ceu_try_bus_param(icd);
if (ret < 0)
return 0;
+ if (!icd->host_priv) {
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam)
+ return -ENOMEM;
+
+ icd->host_priv = cam;
+ } else {
+ cam = icd->host_priv;
+ }
+
/* Beginning of a pass */
if (!idx)
- icd->host_priv = NULL;
+ cam->extra_fmt = NULL;
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
- if (icd->host_priv)
+ if (cam->extra_fmt)
goto add_single_format;
/*
@@ -605,7 +770,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
* the host_priv pointer and check whether the format you're
* going to add now is already there.
*/
- icd->host_priv = (void *)sh_mobile_ceu_formats;
+ cam->extra_fmt = (void *)sh_mobile_ceu_formats;
n = ARRAY_SIZE(sh_mobile_ceu_formats);
formats += n;
@@ -614,7 +779,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
- dev_dbg(ici->dev, "Providing format %s using %s\n",
+ dev_dbg(dev, "Providing format %s using %s\n",
sh_mobile_ceu_formats[k].name,
icd->formats[idx].name);
}
@@ -627,7 +792,7 @@ add_single_format:
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
- dev_dbg(ici->dev,
+ dev_dbg(dev,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
@@ -636,82 +801,714 @@ add_single_format:
return formats;
}
+static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
+{
+ kfree(icd->host_priv);
+ icd->host_priv = NULL;
+}
+
+/* Check if any dimension of r1 is smaller than respective one of r2 */
+static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2)
+{
+ return r1->width < r2->width || r1->height < r2->height;
+}
+
+/* Check if r1 fails to cover r2 */
+static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
+{
+ return r1->left > r2->left || r1->top > r2->top ||
+ r1->left + r1->width < r2->left + r2->width ||
+ r1->top + r1->height < r2->top + r2->height;
+}
+
+static unsigned int scale_down(unsigned int size, unsigned int scale)
+{
+ return (size * 4096 + scale / 2) / scale;
+}
+
+static unsigned int scale_up(unsigned int size, unsigned int scale)
+{
+ return (size * scale + 2048) / 4096;
+}
+
+static unsigned int calc_generic_scale(unsigned int input, unsigned int output)
+{
+ return (input * 4096 + output / 2) / output;
+}
+
+static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
+{
+ struct v4l2_crop crop;
+ struct v4l2_cropcap cap;
+ int ret;
+
+ crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_crop, &crop);
+ if (!ret) {
+ *rect = crop.c;
+ return ret;
+ }
+
+ /* Camera driver doesn't support .g_crop(), assume default rectangle */
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ *rect = cap.defrect;
+
+ return ret;
+}
+
+/*
+ * The common for both scaling and cropping iterative approach is:
+ * 1. try if the client can produce exactly what requested by the user
+ * 2. if (1) failed, try to double the client image until we get one big enough
+ * 3. if (2) failed, try to request the maximum image
+ */
+static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop,
+ struct v4l2_crop *cam_crop)
+{
+ struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+ struct device *dev = sd->v4l2_dev->dev;
+ struct v4l2_cropcap cap;
+ int ret;
+ unsigned int width, height;
+
+ v4l2_subdev_call(sd, video, s_crop, crop);
+ ret = client_g_rect(sd, cam_rect);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now cam_crop contains the current camera input rectangle, and it must
+ * be within camera cropcap bounds
+ */
+ if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+ /* Even if camera S_CROP failed, but camera rectangle matches */
+ dev_dbg(dev, "Camera S_CROP successful for %ux%u@%u:%u\n",
+ rect->width, rect->height, rect->left, rect->top);
+ return 0;
+ }
+
+ /* Try to fix cropping, that camera hasn't managed to set */
+ dev_geo(dev, "Fix camera S_CROP for %ux%u@%u:%u to %ux%u@%u:%u\n",
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top,
+ rect->width, rect->height, rect->left, rect->top);
+
+ /* We need sensor maximum rectangle */
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+ cap.bounds.width);
+ soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+ cap.bounds.height);
+
+ /*
+ * Popular special case - some cameras can only handle fixed sizes like
+ * QVGA, VGA,... Take care to avoid infinite loop.
+ */
+ width = max(cam_rect->width, 2);
+ height = max(cam_rect->height, 2);
+
+ while (!ret && (is_smaller(cam_rect, rect) ||
+ is_inside(cam_rect, rect)) &&
+ (cap.bounds.width > width || cap.bounds.height > height)) {
+
+ width *= 2;
+ height *= 2;
+
+ cam_rect->width = width;
+ cam_rect->height = height;
+
+ /*
+ * We do not know what capabilities the camera has to set up
+ * left and top borders. We could try to be smarter in iterating
+ * them, e.g., if camera current left is to the right of the
+ * target left, set it to the middle point between the current
+ * left and minimum left. But that would add too much
+ * complexity: we would have to iterate each border separately.
+ */
+ if (cam_rect->left > rect->left)
+ cam_rect->left = cap.bounds.left;
+
+ if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+ cam_rect->width = rect->left + rect->width -
+ cam_rect->left;
+
+ if (cam_rect->top > rect->top)
+ cam_rect->top = cap.bounds.top;
+
+ if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+ cam_rect->height = rect->top + rect->height -
+ cam_rect->top;
+
+ v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ ret = client_g_rect(sd, cam_rect);
+ dev_geo(dev, "Camera S_CROP %d for %ux%u@%u:%u\n", ret,
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+ }
+
+ /* S_CROP must not modify the rectangle */
+ if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
+ /*
+ * The camera failed to configure a suitable cropping,
+ * we cannot use the current rectangle, set to max
+ */
+ *cam_rect = cap.bounds;
+ v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ ret = client_g_rect(sd, cam_rect);
+ dev_geo(dev, "Camera S_CROP %d for max %ux%u@%u:%u\n", ret,
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+ }
+
+ return ret;
+}
+
+static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect,
+ unsigned int *scale_h, unsigned int *scale_v)
+{
+ struct v4l2_format f;
+ int ret;
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ *scale_h = calc_generic_scale(rect->width, f.fmt.pix.width);
+ *scale_v = calc_generic_scale(rect->height, f.fmt.pix.height);
+
+ return 0;
+}
+
+static int get_camera_subwin(struct soc_camera_device *icd,
+ struct v4l2_rect *cam_subrect,
+ unsigned int cam_hscale, unsigned int cam_vscale)
+{
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_rect *ceu_rect = &cam->ceu_rect;
+
+ if (!ceu_rect->width) {
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ struct v4l2_format f;
+ struct v4l2_pix_format *pix = &f.fmt.pix;
+ int ret;
+ /* First time */
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "camera fmt %ux%u\n", pix->width, pix->height);
+
+ if (pix->width > 2560) {
+ ceu_rect->width = 2560;
+ ceu_rect->left = (pix->width - 2560) / 2;
+ } else {
+ ceu_rect->width = pix->width;
+ ceu_rect->left = 0;
+ }
+
+ if (pix->height > 1920) {
+ ceu_rect->height = 1920;
+ ceu_rect->top = (pix->height - 1920) / 2;
+ } else {
+ ceu_rect->height = pix->height;
+ ceu_rect->top = 0;
+ }
+
+ dev_geo(dev, "initialised CEU rect %ux%u@%u:%u\n",
+ ceu_rect->width, ceu_rect->height,
+ ceu_rect->left, ceu_rect->top);
+ }
+
+ cam_subrect->width = scale_up(ceu_rect->width, cam_hscale);
+ cam_subrect->left = scale_up(ceu_rect->left, cam_hscale);
+ cam_subrect->height = scale_up(ceu_rect->height, cam_vscale);
+ cam_subrect->top = scale_up(ceu_rect->top, cam_vscale);
+
+ return 0;
+}
+
+static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f,
+ bool ceu_can_scale)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h;
+ unsigned int max_width, max_height;
+ struct v4l2_cropcap cap;
+ int ret;
+
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ max_width = min(cap.bounds.width, 2560);
+ max_height = min(cap.bounds.height, 1920);
+
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "camera scaled to %ux%u\n", pix->width, pix->height);
+
+ if ((width == pix->width && height == pix->height) || !ceu_can_scale)
+ return 0;
+
+ /* Camera set a format, but geometry is not precise, try to improve */
+ tmp_w = pix->width;
+ tmp_h = pix->height;
+
+ /* width <= max_width && height <= max_height - guaranteed by try_fmt */
+ while ((width > tmp_w || height > tmp_h) &&
+ tmp_w < max_width && tmp_h < max_height) {
+ tmp_w = min(2 * tmp_w, max_width);
+ tmp_h = min(2 * tmp_h, max_height);
+ pix->width = tmp_w;
+ pix->height = tmp_h;
+ ret = v4l2_subdev_call(sd, video, s_fmt, f);
+ dev_geo(dev, "Camera scaled to %ux%u\n",
+ pix->width, pix->height);
+ if (ret < 0) {
+ /* This shouldn't happen */
+ dev_err(dev, "Client failed to set format: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @rect - camera cropped rectangle
+ * @sub_rect - CEU cropped rectangle, mapped back to camera input area
+ * @ceu_rect - on output calculated CEU crop rectangle
+ */
+static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect,
+ struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect,
+ struct v4l2_format *f, bool ceu_can_scale)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_format f_tmp = *f;
+ struct v4l2_pix_format *pix_tmp = &f_tmp.fmt.pix;
+ unsigned int scale_h, scale_v;
+ int ret;
+
+ /* 5. Apply iterative camera S_FMT for camera user window. */
+ ret = client_s_fmt(icd, &f_tmp, ceu_can_scale);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "5: camera scaled to %ux%u\n",
+ pix_tmp->width, pix_tmp->height);
+
+ /* 6. Retrieve camera output window (g_fmt) */
+
+ /* unneeded - it is already in "f_tmp" */
+
+ /* 7. Calculate new camera scales. */
+ ret = get_camera_scales(sd, rect, &scale_h, &scale_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v);
+
+ cam->cam_width = pix_tmp->width;
+ cam->cam_height = pix_tmp->height;
+ f->fmt.pix.width = pix_tmp->width;
+ f->fmt.pix.height = pix_tmp->height;
+
+ /*
+ * 8. Calculate new CEU crop - apply camera scales to previously
+ * calculated "effective" crop.
+ */
+ ceu_rect->left = scale_down(sub_rect->left, scale_h);
+ ceu_rect->width = scale_down(sub_rect->width, scale_h);
+ ceu_rect->top = scale_down(sub_rect->top, scale_v);
+ ceu_rect->height = scale_down(sub_rect->height, scale_v);
+
+ dev_geo(dev, "8: new CEU rect %ux%u@%u:%u\n",
+ ceu_rect->width, ceu_rect->height,
+ ceu_rect->left, ceu_rect->top);
+
+ return 0;
+}
+
+/* Get combined scales */
+static int get_scales(struct soc_camera_device *icd,
+ unsigned int *scale_h, unsigned int *scale_v)
+{
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_crop cam_crop;
+ unsigned int width_in, height_in;
+ int ret;
+
+ cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = client_g_rect(sd, &cam_crop.c);
+ if (ret < 0)
+ return ret;
+
+ ret = get_camera_scales(sd, &cam_crop.c, scale_h, scale_v);
+ if (ret < 0)
+ return ret;
+
+ width_in = scale_up(cam->ceu_rect.width, *scale_h);
+ height_in = scale_up(cam->ceu_rect.height, *scale_v);
+
+ *scale_h = calc_generic_scale(cam->ceu_rect.width, icd->user_width);
+ *scale_v = calc_generic_scale(cam->ceu_rect.height, icd->user_height);
+
+ return 0;
+}
+
+/*
+ * CEU can scale and crop, but we don't want to waste bandwidth and kill the
+ * framerate by always requesting the maximum image from the client. See
+ * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of
+ * scaling and cropping algorithms and for the meaning of referenced here steps.
+ */
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+ struct v4l2_crop *a)
{
- return icd->ops->set_crop(icd, rect);
+ struct v4l2_rect *rect = &a->c;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ struct v4l2_crop cam_crop;
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ struct v4l2_format f;
+ struct v4l2_pix_format *pix = &f.fmt.pix;
+ unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v,
+ out_width, out_height;
+ u32 capsr, cflcr;
+ int ret;
+
+ /* 1. Calculate current combined scales. */
+ ret = get_scales(icd, &scale_comb_h, &scale_comb_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "1: combined scales %u:%u\n", scale_comb_h, scale_comb_v);
+
+ /* 2. Apply iterative camera S_CROP for new input window. */
+ ret = client_s_crop(sd, a, &cam_crop);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "2: camera cropped to %ux%u@%u:%u\n",
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+
+ /* On success cam_crop contains current camera crop */
+
+ /*
+ * 3. If old combined scales applied to new crop produce an impossible
+ * user window, adjust scales to produce nearest possible window.
+ */
+ out_width = scale_down(rect->width, scale_comb_h);
+ out_height = scale_down(rect->height, scale_comb_v);
+
+ if (out_width > 2560)
+ out_width = 2560;
+ else if (out_width < 2)
+ out_width = 2;
+
+ if (out_height > 1920)
+ out_height = 1920;
+ else if (out_height < 4)
+ out_height = 4;
+
+ dev_geo(dev, "3: Adjusted output %ux%u\n", out_width, out_height);
+
+ /* 4. Use G_CROP to retrieve actual input window: already in cam_crop */
+
+ /*
+ * 5. Using actual input window and calculated combined scales calculate
+ * camera target output window.
+ */
+ pix->width = scale_down(cam_rect->width, scale_comb_h);
+ pix->height = scale_down(cam_rect->height, scale_comb_v);
+
+ dev_geo(dev, "5: camera target %ux%u\n", pix->width, pix->height);
+
+ /* 6. - 9. */
+ pix->pixelformat = cam->camera_fmt->fourcc;
+ pix->colorspace = cam->camera_fmt->colorspace;
+
+ capsr = capture_save_reset(pcdev);
+ dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
+
+ /* Make relative to camera rectangle */
+ rect->left -= cam_rect->left;
+ rect->top -= cam_rect->top;
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = client_scale(icd, cam_rect, rect, ceu_rect, &f,
+ pcdev->image_mode && !pcdev->is_interlaced);
+
+ dev_geo(dev, "6-9: %d\n", ret);
+
+ /* 10. Use CEU cropping to crop to the new window. */
+ sh_mobile_ceu_set_rect(icd, out_width, out_height);
+
+ dev_geo(dev, "10: CEU cropped to %ux%u@%u:%u\n",
+ ceu_rect->width, ceu_rect->height,
+ ceu_rect->left, ceu_rect->top);
+
+ /*
+ * 11. Calculate CEU scales from camera scales from results of (10) and
+ * user window from (3)
+ */
+ scale_ceu_h = calc_scale(ceu_rect->width, &out_width);
+ scale_ceu_v = calc_scale(ceu_rect->height, &out_height);
+
+ dev_geo(dev, "11: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v);
+
+ /* 12. Apply CEU scales. */
+ cflcr = scale_ceu_h | (scale_ceu_v << 16);
+ if (cflcr != pcdev->cflcr) {
+ pcdev->cflcr = cflcr;
+ ceu_write(pcdev, CFLCR, cflcr);
+ }
+
+ /* Restore capture */
+ if (pcdev->active)
+ capsr |= 1;
+ capture_restore(pcdev, capsr);
+
+ icd->user_width = out_width;
+ icd->user_height = out_height;
+
+ /* Even if only camera cropping succeeded */
+ return ret;
}
+/* Similar to set_crop multistage iterative algorithm */
static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- __u32 pixfmt = f->fmt.pix.pixelformat;
- const struct soc_camera_format_xlate *xlate;
+ struct sh_mobile_ceu_cam *cam = icd->host_priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_format cam_f = *f;
+ struct v4l2_pix_format *cam_pix = &cam_f.fmt.pix;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ __u32 pixfmt = pix->pixelformat;
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_crop cam_crop;
+ struct v4l2_rect *cam_rect = &cam_crop.c, cam_subrect, ceu_rect;
+ unsigned int scale_cam_h, scale_cam_v;
+ u16 scale_v, scale_h;
int ret;
+ bool is_interlaced, image_mode;
+
+ switch (pix->field) {
+ case V4L2_FIELD_INTERLACED:
+ is_interlaced = true;
+ break;
+ case V4L2_FIELD_ANY:
+ default:
+ pix->field = V4L2_FIELD_NONE;
+ /* fall-through */
+ case V4L2_FIELD_NONE:
+ is_interlaced = false;
+ break;
+ }
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
- ret = icd->ops->set_fmt(icd, &cam_f);
+ /* 1. Calculate current camera scales. */
+ cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (!ret) {
- icd->buswidth = xlate->buswidth;
- icd->current_fmt = xlate->host_fmt;
- pcdev->camera_fmt = xlate->cam_fmt;
+ ret = client_g_rect(sd, cam_rect);
+ if (ret < 0)
+ return ret;
+
+ ret = get_camera_scales(sd, cam_rect, &scale_cam_h, &scale_cam_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "1: camera scales %u:%u\n", scale_cam_h, scale_cam_v);
+
+ /*
+ * 2. Calculate "effective" input crop (sensor subwindow) - CEU crop
+ * scaled back at current camera scales onto input window.
+ */
+ ret = get_camera_subwin(icd, &cam_subrect, scale_cam_h, scale_cam_v);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
+ cam_subrect.width, cam_subrect.height,
+ cam_subrect.left, cam_subrect.top);
+
+ /*
+ * 3. Calculate new combined scales from "effective" input window to
+ * requested user window.
+ */
+ scale_h = calc_generic_scale(cam_subrect.width, pix->width);
+ scale_v = calc_generic_scale(cam_subrect.height, pix->height);
+
+ dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
+
+ /*
+ * 4. Calculate camera output window by applying combined scales to real
+ * input window.
+ */
+ cam_pix->width = scale_down(cam_rect->width, scale_h);
+ cam_pix->height = scale_down(cam_rect->height, scale_v);
+ cam_pix->pixelformat = xlate->cam_fmt->fourcc;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ image_mode = true;
+ break;
+ default:
+ image_mode = false;
}
- return ret;
+ dev_geo(dev, "4: camera output %ux%u\n",
+ cam_pix->width, cam_pix->height);
+
+ /* 5. - 9. */
+ ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f,
+ image_mode && !is_interlaced);
+
+ dev_geo(dev, "5-9: client scale %d\n", ret);
+
+ /* Done with the camera. Now see if we can improve the result */
+
+ dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
+ ret, cam_pix->width, cam_pix->height, pix->width, pix->height);
+ if (ret < 0)
+ return ret;
+
+ /* 10. Use CEU scaling to scale to the requested user window. */
+
+ /* We cannot scale up */
+ if (pix->width > cam_pix->width)
+ pix->width = cam_pix->width;
+ if (pix->width > ceu_rect.width)
+ pix->width = ceu_rect.width;
+
+ if (pix->height > cam_pix->height)
+ pix->height = cam_pix->height;
+ if (pix->height > ceu_rect.height)
+ pix->height = ceu_rect.height;
+
+ /* Let's rock: scale pix->{width x height} down to width x height */
+ scale_h = calc_scale(ceu_rect.width, &pix->width);
+ scale_v = calc_scale(ceu_rect.height, &pix->height);
+
+ dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n",
+ ceu_rect.width, scale_h, pix->width,
+ ceu_rect.height, scale_v, pix->height);
+
+ pcdev->cflcr = scale_h | (scale_v << 16);
+
+ icd->buswidth = xlate->buswidth;
+ icd->current_fmt = xlate->host_fmt;
+ cam->camera_fmt = xlate->cam_fmt;
+ cam->ceu_rect = ceu_rect;
+
+ pcdev->is_interlaced = is_interlaced;
+ pcdev->image_mode = image_mode;
+
+ return 0;
}
static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct sh_mobile_ceu_dev *pcdev = ici->priv;
const struct soc_camera_format_xlate *xlate;
- __u32 pixfmt = f->fmt.pix.pixelformat;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ __u32 pixfmt = pix->pixelformat;
+ int width, height;
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(ici->dev, "Format %x not found\n", pixfmt);
+ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
return -EINVAL;
}
/* FIXME: calculate using depth and bus width */
- v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1,
- &f->fmt.pix.height, 4, 1920, 2, 0);
+ v4l_bound_align_image(&pix->width, 2, 2560, 1,
+ &pix->height, 4, 1920, 2, 0);
+
+ width = pix->width;
+ height = pix->height;
- f->fmt.pix.bytesperline = f->fmt.pix.width *
+ pix->bytesperline = pix->width *
DIV_ROUND_UP(xlate->host_fmt->depth, 8);
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = icd->ops->try_fmt(icd, f);
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
+ pix->pixelformat = pixfmt;
if (ret < 0)
return ret;
- switch (f->fmt.pix.field) {
- case V4L2_FIELD_INTERLACED:
- pcdev->is_interlaced = 1;
- break;
- case V4L2_FIELD_ANY:
- f->fmt.pix.field = V4L2_FIELD_NONE;
- /* fall-through */
- case V4L2_FIELD_NONE:
- pcdev->is_interlaced = 0;
- break;
- default:
- ret = -EINVAL;
- break;
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ /* FIXME: check against rect_max after converting soc-camera */
+ /* We can scale precisely, need a bigger image from camera */
+ if (pix->width < width || pix->height < height) {
+ int tmp_w = pix->width, tmp_h = pix->height;
+ pix->width = 2560;
+ pix->height = 1920;
+ ret = v4l2_subdev_call(sd, video, try_fmt, f);
+ if (ret < 0) {
+ /* Shouldn't actually happen... */
+ dev_err(icd->dev.parent,
+ "FIXME: try_fmt() returned %d\n", ret);
+ pix->width = tmp_w;
+ pix->height = tmp_h;
+ }
+ }
+ if (pix->width > width)
+ pix->width = width;
+ if (pix->height > height)
+ pix->height = height;
}
return ret;
@@ -771,7 +1568,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
videobuf_queue_dma_contig_init(q,
&sh_mobile_ceu_videobuf_ops,
- ici->dev, &pcdev->lock,
+ icd->dev.parent, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
pcdev->is_interlaced ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
@@ -779,22 +1576,76 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
icd);
}
+static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ u32 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_SHARPNESS:
+ val = ceu_read(pcdev, CLFCR);
+ ctrl->value = val ^ 1;
+ return 0;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_SHARPNESS:
+ switch (icd->current_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ ceu_write(pcdev, CLFCR, !ctrl->value);
+ return 0;
+ }
+ return -EINVAL;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Low-pass filter",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.owner = THIS_MODULE,
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
.get_formats = sh_mobile_ceu_get_formats,
+ .put_formats = sh_mobile_ceu_put_formats,
.set_crop = sh_mobile_ceu_set_crop,
.set_fmt = sh_mobile_ceu_set_fmt,
.try_fmt = sh_mobile_ceu_try_fmt,
+ .set_ctrl = sh_mobile_ceu_set_ctrl,
+ .get_ctrl = sh_mobile_ceu_get_ctrl,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
.set_bus_param = sh_mobile_ceu_set_bus_param,
.init_videobuf = sh_mobile_ceu_init_videobuf,
+ .controls = sh_mobile_ceu_controls,
+ .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls),
};
-static int sh_mobile_ceu_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
{
struct sh_mobile_ceu_dev *pcdev;
struct resource *res;
@@ -872,7 +1723,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
}
pcdev->ici.priv = pcdev;
- pcdev->ici.dev = &pdev->dev;
+ pcdev->ici.v4l2_dev.dev = &pdev->dev;
pcdev->ici.nr = pdev->id;
pcdev->ici.drv_name = dev_name(&pdev->dev);
pcdev->ici.ops = &sh_mobile_ceu_host_ops;
@@ -898,7 +1749,7 @@ exit:
return err;
}
-static int sh_mobile_ceu_remove(struct platform_device *pdev)
+static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
{
struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
@@ -919,7 +1770,7 @@ static struct platform_driver sh_mobile_ceu_driver = {
.name = "sh_mobile_ceu",
},
.probe = sh_mobile_ceu_probe,
- .remove = sh_mobile_ceu_remove,
+ .remove = __exit_p(sh_mobile_ceu_remove),
};
static int __init sh_mobile_ceu_init(void)
@@ -938,3 +1789,4 @@ module_exit(sh_mobile_ceu_exit);
MODULE_DESCRIPTION("SuperH Mobile CEU driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh_mobile_ceu");
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
index 38a716020..36ee43a9e 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -123,8 +123,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
+#endif
{ }
};
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 4f315c1b7..cb7c9afd3 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -21,15 +21,15 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/vmalloc.h>
#include <media/soc_camera.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
#include <media/videobuf-core.h>
#include "compat.h"
@@ -39,7 +39,7 @@
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
-static DEFINE_MUTEX(list_lock);
+static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
const struct soc_camera_data_format *soc_camera_format_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
@@ -153,12 +153,9 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- int ret = 0;
-
- if (icd->ops->set_std)
- ret = icd->ops->set_std(icd, a);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return ret;
+ return v4l2_subdev_call(sd, core, s_std, *a);
}
static int soc_camera_reqbufs(struct file *file, void *priv,
@@ -171,8 +168,6 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
-
ret = videobuf_reqbufs(&icf->vb_vidq, p);
if (ret < 0)
return ret;
@@ -210,10 +205,11 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
+/* Always entered with .video_lock held */
static int soc_camera_init_user_formats(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int i, fmts = 0;
+ int i, fmts = 0, ret;
if (!ici->ops->get_formats)
/*
@@ -226,8 +222,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
* First pass - only count formats this host-sensor
* configuration can provide
*/
- for (i = 0; i < icd->num_formats; i++)
- fmts += ici->ops->get_formats(icd, i, NULL);
+ for (i = 0; i < icd->num_formats; i++) {
+ ret = ici->ops->get_formats(icd, i, NULL);
+ if (ret < 0)
+ return ret;
+ fmts += ret;
+ }
if (!fmts)
return -ENXIO;
@@ -249,20 +249,39 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
icd->user_formats[i].cam_fmt = icd->formats + i;
icd->user_formats[i].buswidth = icd->formats[i].depth;
} else {
- fmts += ici->ops->get_formats(icd, i,
- &icd->user_formats[fmts]);
+ ret = ici->ops->get_formats(icd, i,
+ &icd->user_formats[fmts]);
+ if (ret < 0)
+ goto egfmt;
+ fmts += ret;
}
icd->current_fmt = icd->user_formats[0].host_fmt;
return 0;
+
+egfmt:
+ icd->num_user_formats = 0;
+ vfree(icd->user_formats);
+ return ret;
}
+/* Always entered with .video_lock held */
static void soc_camera_free_user_formats(struct soc_camera_device *icd)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+
+ if (ici->ops->put_formats)
+ ici->ops->put_formats(icd);
+ icd->current_fmt = NULL;
+ icd->num_user_formats = 0;
vfree(icd->user_formats);
+ icd->user_formats = NULL;
}
+#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
+ ((x) >> 24) & 0xff
+
/* Called with .vb_lock held */
static int soc_camera_set_fmt(struct soc_camera_file *icf,
struct v4l2_format *f)
@@ -272,6 +291,9 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
+ dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n",
+ pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
/* We always call try_fmt() before set_fmt() or set_crop() */
ret = ici->ops->try_fmt(icd, f);
if (ret < 0)
@@ -282,13 +304,13 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
return ret;
} else if (!icd->current_fmt ||
icd->current_fmt->fourcc != pix->pixelformat) {
- dev_err(ici->dev,
+ dev_err(&icd->dev,
"Host driver hasn't set up current format correctly!\n");
return -EINVAL;
}
- icd->width = pix->width;
- icd->height = pix->height;
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
icf->vb_vidq.field =
icd->field = pix->field;
@@ -297,7 +319,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
f->type);
dev_dbg(&icd->dev, "set width: %d height: %d\n",
- icd->width, icd->height);
+ icd->user_width, icd->user_height);
/* set physical bus parameters */
return ici->ops->set_bus_param(icd, pix->pixelformat);
@@ -305,30 +327,24 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
static int soc_camera_open(struct file *file)
{
- struct video_device *vdev;
- struct soc_camera_device *icd;
+ struct video_device *vdev = video_devdata(file);
+ struct soc_camera_device *icd = container_of(vdev->parent,
+ struct soc_camera_device,
+ dev);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
struct soc_camera_host *ici;
struct soc_camera_file *icf;
int ret;
- icf = vmalloc(sizeof(*icf));
- if (!icf)
- return -ENOMEM;
-
- /*
- * It is safe to dereference these pointers now as long as a user has
- * the video device open - we are protected by the held cdev reference.
- */
+ if (!icd->ops)
+ /* No device driver attached */
+ return -ENODEV;
- vdev = video_devdata(file);
- icd = container_of(vdev->parent, struct soc_camera_device, dev);
ici = to_soc_camera_host(icd->dev.parent);
- if (!try_module_get(icd->ops->owner)) {
- dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
- ret = -EINVAL;
- goto emgd;
- }
+ icf = vmalloc(sizeof(*icf));
+ if (!icf)
+ return -ENOMEM;
if (!try_module_get(ici->ops->owner)) {
dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
@@ -336,7 +352,10 @@ static int soc_camera_open(struct file *file)
goto emgi;
}
- /* Protect against icd->remove() until we module_get() both drivers. */
+ /*
+ * Protect against icd->ops->remove() until we module_get() both
+ * drivers.
+ */
mutex_lock(&icd->video_lock);
icf->icd = icd;
@@ -348,14 +367,24 @@ static int soc_camera_open(struct file *file)
struct v4l2_format f = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.fmt.pix = {
- .width = icd->width,
- .height = icd->height,
+ .width = icd->user_width,
+ .height = icd->user_height,
.field = icd->field,
.pixelformat = icd->current_fmt->fourcc,
.colorspace = icd->current_fmt->colorspace,
},
};
+ if (icl->power) {
+ ret = icl->power(icd->pdev, 1);
+ if (ret < 0)
+ goto epower;
+ }
+
+ /* The camera could have been already on, try to reset */
+ if (icl->reset)
+ icl->reset(icd->pdev);
+
ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
@@ -368,28 +397,29 @@ static int soc_camera_open(struct file *file)
goto esfmt;
}
- mutex_unlock(&icd->video_lock);
-
file->private_data = icf;
dev_dbg(&icd->dev, "camera device open\n");
ici->ops->init_videobuf(&icf->vb_vidq, icd);
+ mutex_unlock(&icd->video_lock);
+
return 0;
/*
- * First three errors are entered with the .video_lock held
+ * First five errors are entered with the .video_lock held
* and use_count == 1
*/
esfmt:
ici->ops->remove(icd);
eiciadd:
+ if (icl->power)
+ icl->power(icd->pdev, 0);
+epower:
icd->use_count--;
mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
emgi:
- module_put(icd->ops->owner);
-emgd:
vfree(icf);
return ret;
}
@@ -399,21 +429,24 @@ static int soc_camera_close(struct file *file)
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct video_device *vdev = icd->vdev;
mutex_lock(&icd->video_lock);
icd->use_count--;
- if (!icd->use_count)
+ if (!icd->use_count) {
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
ici->ops->remove(icd);
+ if (icl->power)
+ icl->power(icd->pdev, 0);
+ }
mutex_unlock(&icd->video_lock);
- module_put(icd->ops->owner);
module_put(ici->ops->owner);
vfree(icf);
- dev_dbg(vdev->parent, "camera device close\n");
+ dev_dbg(&icd->dev, "camera device close\n");
return 0;
}
@@ -423,10 +456,9 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
- struct video_device *vdev = icd->vdev;
int err = -EINVAL;
- dev_err(vdev->parent, "camera device read not implemented\n");
+ dev_err(&icd->dev, "camera device read not implemented\n");
return err;
}
@@ -484,8 +516,8 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
mutex_lock(&icf->vb_vidq.vb_lock);
- if (videobuf_queue_is_busy(&icf->vb_vidq)) {
- dev_err(&icd->dev, "S_FMT denied: queue busy\n");
+ if (icf->vb_vidq.bufs[0]) {
+ dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
ret = -EBUSY;
goto unlock;
}
@@ -526,8 +558,8 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- pix->width = icd->width;
- pix->height = icd->height;
+ pix->width = icd->user_width;
+ pix->height = icd->user_height;
pix->field = icf->vb_vidq.field;
pix->pixelformat = icd->current_fmt->fourcc;
pix->bytesperline = pix->width *
@@ -556,18 +588,17 @@ static int soc_camera_streamon(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __func__);
-
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
mutex_lock(&icd->video_lock);
- icd->ops->start_capture(icd);
+ v4l2_subdev_call(sd, video, s_stream, 1);
/* This calls buf_queue from host driver's videobuf_queue_ops */
ret = videobuf_streamon(&icf->vb_vidq);
@@ -582,11 +613,10 @@ static int soc_camera_streamoff(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __func__);
-
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -596,7 +626,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
* remaining buffers. When the last buffer is freed, stop capture */
videobuf_streamoff(&icf->vb_vidq);
- icd->ops->stop_capture(icd);
+ v4l2_subdev_call(sd, video, s_stream, 0);
mutex_unlock(&icd->video_lock);
@@ -608,6 +638,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int i;
WARN_ON(priv != file->private_data);
@@ -615,6 +646,15 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
if (!qc->id)
return -EINVAL;
+ /* First check host controls */
+ for (i = 0; i < ici->ops->num_controls; i++)
+ if (qc->id == ici->ops->controls[i].id) {
+ memcpy(qc, &(ici->ops->controls[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ /* Then device controls */
for (i = 0; i < icd->ops->num_controls; i++)
if (qc->id == icd->ops->controls[i].id) {
memcpy(qc, &(icd->ops->controls[i]),
@@ -630,25 +670,19 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
WARN_ON(priv != file->private_data);
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- if (icd->gain == (unsigned short)~0)
- return -EINVAL;
- ctrl->value = icd->gain;
- return 0;
- case V4L2_CID_EXPOSURE:
- if (icd->exposure == (unsigned short)~0)
- return -EINVAL;
- ctrl->value = icd->exposure;
- return 0;
+ if (ici->ops->get_ctrl) {
+ ret = ici->ops->get_ctrl(icd, ctrl);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
}
- if (icd->ops->get_control)
- return icd->ops->get_control(icd, ctrl);
- return -EINVAL;
+ return v4l2_subdev_call(sd, core, g_ctrl, ctrl);
}
static int soc_camera_s_ctrl(struct file *file, void *priv,
@@ -656,12 +690,19 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
WARN_ON(priv != file->private_data);
- if (icd->ops->set_control)
- return icd->ops->set_control(icd, ctrl);
- return -EINVAL;
+ if (ici->ops->set_ctrl) {
+ ret = ici->ops->set_ctrl(icd, ctrl);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+ }
+
+ return v4l2_subdev_call(sd, core, s_ctrl, ctrl);
}
static int soc_camera_cropcap(struct file *file, void *fh,
@@ -669,20 +710,9 @@ static int soc_camera_cropcap(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->bounds.left = icd->x_min;
- a->bounds.top = icd->y_min;
- a->bounds.width = icd->width_max;
- a->bounds.height = icd->height_max;
- a->defrect.left = icd->x_min;
- a->defrect.top = icd->y_min;
- a->defrect.width = DEFAULT_WIDTH;
- a->defrect.height = DEFAULT_HEIGHT;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
+ return ici->ops->cropcap(icd, a);
}
static int soc_camera_g_crop(struct file *file, void *fh,
@@ -690,36 +720,53 @@ static int soc_camera_g_crop(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int ret;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->c.left = icd->x_current;
- a->c.top = icd->y_current;
- a->c.width = icd->width;
- a->c.height = icd->height;
+ mutex_lock(&icf->vb_vidq.vb_lock);
+ ret = ici->ops->get_crop(icd, a);
+ mutex_unlock(&icf->vb_vidq.vb_lock);
- return 0;
+ return ret;
}
+/*
+ * According to the V4L2 API, drivers shall not update the struct v4l2_crop
+ * argument with the actual geometry, instead, the user shall use G_CROP to
+ * retrieve it. However, we expect camera host and client drivers to update
+ * the argument, which we then use internally, but do not return to the user.
+ */
static int soc_camera_s_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop current_crop;
int ret;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
+ rect->width, rect->height, rect->left, rect->top);
+
/* Cropping is allowed during a running capture, guard consistency */
mutex_lock(&icf->vb_vidq.vb_lock);
- ret = ici->ops->set_crop(icd, &a->c);
- if (!ret) {
- icd->width = a->c.width;
- icd->height = a->c.height;
- icd->x_current = a->c.left;
- icd->y_current = a->c.top;
+ /* If get_crop fails, we'll let host and / or client drivers decide */
+ ret = ici->ops->get_crop(icd, &current_crop);
+
+ /* Prohibit window size change with initialised buffers */
+ if (icf->vb_vidq.bufs[0] && !ret &&
+ (a->c.width != current_crop.c.width ||
+ a->c.height != current_crop.c.height)) {
+ dev_err(&icd->dev,
+ "S_CROP denied: queue initialised and sizes differ\n");
+ ret = -EBUSY;
+ } else {
+ ret = ici->ops->set_crop(icd, a);
}
mutex_unlock(&icf->vb_vidq.vb_lock);
@@ -732,11 +779,9 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- if (!icd->ops->get_chip_id)
- return -EINVAL;
-
- return icd->ops->get_chip_id(icd, id);
+ return v4l2_subdev_call(sd, core, g_chip_ident, id);
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -745,11 +790,9 @@ static int soc_camera_g_register(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- if (!icd->ops->get_register)
- return -EINVAL;
-
- return icd->ops->get_register(icd, reg);
+ return v4l2_subdev_call(sd, core, g_register, reg);
}
static int soc_camera_s_register(struct file *file, void *fh,
@@ -757,37 +800,12 @@ static int soc_camera_s_register(struct file *file, void *fh,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- if (!icd->ops->set_register)
- return -EINVAL;
-
- return icd->ops->set_register(icd, reg);
+ return v4l2_subdev_call(sd, core, s_register, reg);
}
#endif
-static int device_register_link(struct soc_camera_device *icd)
-{
- int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
-
- if (!ret)
- ret = device_register(&icd->dev);
-
- if (ret < 0) {
- /* Prevent calling device_unregister() */
- icd->dev.parent = NULL;
- dev_err(&icd->dev, "Cannot register device: %d\n", ret);
- /* Even if probe() was unsuccessful for all registered drivers,
- * device_register() returns 0, and we add the link, just to
- * document this camera's control device */
- } else if (icd->control)
- /* Have to sysfs_remove_link() before device_unregister()? */
- if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
- "control"))
- dev_warn(&icd->dev,
- "Failed creating the control symlink\n");
- return ret;
-}
-
/* So far this function cannot fail */
static void scan_add_host(struct soc_camera_host *ici)
{
@@ -797,106 +815,193 @@ static void scan_add_host(struct soc_camera_host *ici)
list_for_each_entry(icd, &devices, list) {
if (icd->iface == ici->nr) {
- icd->dev.parent = ici->dev;
- device_register_link(icd);
+ int ret;
+ icd->dev.parent = ici->v4l2_dev.dev;
+ dev_set_name(&icd->dev, "%u-%u", icd->iface,
+ icd->devnum);
+ ret = device_register(&icd->dev);
+ if (ret < 0) {
+ icd->dev.parent = NULL;
+ dev_err(&icd->dev,
+ "Cannot register device: %d\n", ret);
+ }
}
}
mutex_unlock(&list_lock);
}
-/* return: 0 if no match found or a match found and
- * device_register() successful, error code otherwise */
-static int scan_add_device(struct soc_camera_device *icd)
+#ifdef CONFIG_I2C_BOARDINFO
+static int soc_camera_init_i2c(struct soc_camera_device *icd,
+ struct soc_camera_link *icl)
{
- struct soc_camera_host *ici;
- int ret = 0;
+ struct i2c_client *client;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+ struct v4l2_subdev *subdev;
+ int ret;
- mutex_lock(&list_lock);
+ if (!adap) {
+ ret = -ENODEV;
+ dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
+ icl->i2c_adapter_id);
+ goto ei2cga;
+ }
- list_add_tail(&icd->list, &devices);
+ icl->board_info->platform_data = icd;
- /* Watch out for class_for_each_device / class_find_device API by
- * Dave Young <hidave.darkstar@gmail.com> */
- list_for_each_entry(ici, &hosts, list) {
- if (icd->iface == ici->nr) {
- ret = 1;
- icd->dev.parent = ici->dev;
- break;
- }
+ subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
+ icl->module_name, icl->board_info, NULL);
+ if (!subdev) {
+ ret = -ENOMEM;
+ goto ei2cnd;
}
- mutex_unlock(&list_lock);
+ client = subdev->priv;
- if (ret)
- ret = device_register_link(icd);
+ /* Use to_i2c_client(dev) to recover the i2c client */
+ dev_set_drvdata(&icd->dev, &client->dev);
+ return 0;
+ei2cnd:
+ i2c_put_adapter(adap);
+ei2cga:
return ret;
}
+static void soc_camera_free_i2c(struct soc_camera_device *icd)
+{
+ struct i2c_client *client =
+ to_i2c_client(to_soc_camera_control(icd));
+ dev_set_drvdata(&icd->dev, NULL);
+ v4l2_device_unregister_subdev(i2c_get_clientdata(client));
+ i2c_unregister_device(client);
+ i2c_put_adapter(client->adapter);
+}
+#else
+#define soc_camera_init_i2c(icd, icl) (-ENODEV)
+#define soc_camera_free_i2c(icd) do {} while (0)
+#endif
+
+static int soc_camera_video_start(struct soc_camera_device *icd);
+static int video_dev_create(struct soc_camera_device *icd);
+/* Called during host-driver probe */
static int soc_camera_probe(struct device *dev)
{
struct soc_camera_device *icd = to_soc_camera_dev(dev);
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct device *control = NULL;
+ struct v4l2_subdev *sd;
+ struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
int ret;
- /*
- * Possible race scenario:
- * modprobe <camera-host-driver> triggers __func__
- * at this moment respective <camera-sensor-driver> gets rmmod'ed
- * to protect take module references.
- */
+ dev_info(dev, "Probing %s\n", dev_name(dev));
- if (!try_module_get(icd->ops->owner)) {
- dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
- ret = -EINVAL;
- goto emgd;
+ if (icl->power) {
+ ret = icl->power(icd->pdev, 1);
+ if (ret < 0) {
+ dev_err(dev,
+ "Platform failed to power-on the camera.\n");
+ goto epower;
+ }
}
- if (!try_module_get(ici->ops->owner)) {
- dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+ /* The camera could have been already on, try to reset */
+ if (icl->reset)
+ icl->reset(icd->pdev);
+
+ ret = ici->ops->add(icd);
+ if (ret < 0)
+ goto eadd;
+
+ /* Must have icd->vdev before registering the device */
+ ret = video_dev_create(icd);
+ if (ret < 0)
+ goto evdc;
+
+ /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
+ if (icl->board_info) {
+ ret = soc_camera_init_i2c(icd, icl);
+ if (ret < 0)
+ goto eadddev;
+ } else if (!icl->add_device || !icl->del_device) {
ret = -EINVAL;
- goto emgi;
+ goto eadddev;
+ } else {
+ if (icl->module_name)
+ ret = request_module(icl->module_name);
+
+ ret = icl->add_device(icl, &icd->dev);
+ if (ret < 0)
+ goto eadddev;
+
+ /*
+ * FIXME: this is racy, have to use driver-binding notification,
+ * when it is available
+ */
+ control = to_soc_camera_control(icd);
+ if (!control || !control->driver || !dev_get_drvdata(control) ||
+ !try_module_get(control->driver->owner)) {
+ icl->del_device(icl);
+ goto enodrv;
+ }
}
+ /* At this point client .probe() should have run already */
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
+
+ icd->field = V4L2_FIELD_ANY;
+
+ /* ..._video_start() will create a device node, so we have to protect */
mutex_lock(&icd->video_lock);
- /* We only call ->add() here to activate and probe the camera.
- * We shall ->remove() and deactivate it immediately afterwards. */
- ret = ici->ops->add(icd);
+ ret = soc_camera_video_start(icd);
if (ret < 0)
- goto eiadd;
+ goto evidstart;
+
+ /* Try to improve our guess of a reasonable window format */
+ sd = soc_camera_to_subdev(icd);
+ if (!v4l2_subdev_call(sd, video, g_fmt, &f)) {
+ icd->user_width = f.fmt.pix.width;
+ icd->user_height = f.fmt.pix.height;
+ }
- ret = icd->ops->probe(icd);
- if (ret >= 0) {
- const struct v4l2_queryctrl *qctrl;
+ /* Do we have to sysfs_remove_link() before device_unregister()? */
+ if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
+ "control"))
+ dev_warn(&icd->dev, "Failed creating the control symlink\n");
- qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
- icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
- qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = qctrl ? qctrl->default_value :
- (unsigned short)~0;
+ ici->ops->remove(icd);
- ret = soc_camera_init_user_formats(icd);
- if (ret < 0) {
- if (icd->ops->remove)
- icd->ops->remove(icd);
- goto eiufmt;
- }
+ if (icl->power)
+ icl->power(icd->pdev, 0);
- icd->height = DEFAULT_HEIGHT;
- icd->width = DEFAULT_WIDTH;
- icd->field = V4L2_FIELD_ANY;
- }
+ mutex_unlock(&icd->video_lock);
+ return 0;
+
+evidstart:
+ mutex_unlock(&icd->video_lock);
+ soc_camera_free_user_formats(icd);
eiufmt:
+ if (icl->board_info) {
+ soc_camera_free_i2c(icd);
+ } else {
+ icl->del_device(icl);
+ module_put(control->driver->owner);
+ }
+enodrv:
+eadddev:
+ video_device_release(icd->vdev);
+evdc:
ici->ops->remove(icd);
-eiadd:
- mutex_unlock(&icd->video_lock);
- module_put(ici->ops->owner);
-emgi:
- module_put(icd->ops->owner);
-emgd:
+eadd:
+ if (icl->power)
+ icl->power(icd->pdev, 0);
+epower:
return ret;
}
@@ -905,12 +1010,28 @@ emgd:
static int soc_camera_remove(struct device *dev)
{
struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct video_device *vdev = icd->vdev;
- mutex_lock(&icd->video_lock);
- if (icd->ops->remove)
- icd->ops->remove(icd);
- mutex_unlock(&icd->video_lock);
+ BUG_ON(!dev->parent);
+ if (vdev) {
+ mutex_lock(&icd->video_lock);
+ video_unregister_device(vdev);
+ icd->vdev = NULL;
+ mutex_unlock(&icd->video_lock);
+ }
+
+ if (icl->board_info) {
+ soc_camera_free_i2c(icd);
+ } else {
+ struct device_driver *drv = to_soc_camera_control(icd) ?
+ to_soc_camera_control(icd)->driver : NULL;
+ if (drv) {
+ icl->del_device(icl);
+ module_put(drv->owner);
+ }
+ }
soc_camera_free_user_formats(icd);
return 0;
@@ -958,14 +1079,33 @@ static void dummy_release(struct device *dev)
{
}
+static int default_cropcap(struct soc_camera_device *icd,
+ struct v4l2_cropcap *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, cropcap, a);
+}
+
+static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, g_crop, a);
+}
+
+static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, s_crop, a);
+}
+
int soc_camera_host_register(struct soc_camera_host *ici)
{
struct soc_camera_host *ix;
+ int ret;
if (!ici || !ici->ops ||
!ici->ops->try_fmt ||
!ici->ops->set_fmt ||
- !ici->ops->set_crop ||
!ici->ops->set_bus_param ||
!ici->ops->querycap ||
!ici->ops->init_videobuf ||
@@ -973,18 +1113,27 @@ int soc_camera_host_register(struct soc_camera_host *ici)
!ici->ops->add ||
!ici->ops->remove ||
!ici->ops->poll ||
- !ici->dev)
+ !ici->v4l2_dev.dev)
return -EINVAL;
+ if (!ici->ops->set_crop)
+ ici->ops->set_crop = default_s_crop;
+ if (!ici->ops->get_crop)
+ ici->ops->get_crop = default_g_crop;
+ if (!ici->ops->cropcap)
+ ici->ops->cropcap = default_cropcap;
+
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
if (ix->nr == ici->nr) {
- mutex_unlock(&list_lock);
- return -EBUSY;
+ ret = -EBUSY;
+ goto edevreg;
}
}
- dev_set_drvdata(ici->dev, ici);
+ ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
+ if (ret < 0)
+ goto edevreg;
list_add_tail(&ici->list, &hosts);
mutex_unlock(&list_lock);
@@ -992,6 +1141,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
scan_add_host(ici);
return 0;
+
+edevreg:
+ mutex_unlock(&list_lock);
+ return ret;
}
EXPORT_SYMBOL(soc_camera_host_register);
@@ -1005,42 +1158,34 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
list_del(&ici->list);
list_for_each_entry(icd, &devices, list) {
- if (icd->dev.parent == ici->dev) {
+ if (icd->iface == ici->nr) {
+ /* The bus->remove will be called */
device_unregister(&icd->dev);
/* Not before device_unregister(), .remove
* needs parent to call ici->ops->remove() */
icd->dev.parent = NULL;
+
+ /* If the host module is loaded again, device_register()
+ * would complain "already initialised" */
memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
}
}
mutex_unlock(&list_lock);
- dev_set_drvdata(ici->dev, NULL);
+ v4l2_device_unregister(&ici->v4l2_dev);
}
EXPORT_SYMBOL(soc_camera_host_unregister);
/* Image capture device */
-int soc_camera_device_register(struct soc_camera_device *icd)
+static int soc_camera_device_register(struct soc_camera_device *icd)
{
struct soc_camera_device *ix;
int num = -1, i;
- if (!icd || !icd->ops ||
- !icd->ops->probe ||
- !icd->ops->init ||
- !icd->ops->release ||
- !icd->ops->start_capture ||
- !icd->ops->stop_capture ||
- !icd->ops->set_crop ||
- !icd->ops->set_fmt ||
- !icd->ops->try_fmt ||
- !icd->ops->query_bus_param ||
- !icd->ops->set_bus_param)
- return -EINVAL;
-
for (i = 0; i < 256 && num < 0; i++) {
num = i;
+ /* Check if this index is available on this interface */
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
@@ -1062,21 +1207,15 @@ int soc_camera_device_register(struct soc_camera_device *icd)
icd->host_priv = NULL;
mutex_init(&icd->video_lock);
- return scan_add_device(icd);
+ list_add_tail(&icd->list, &devices);
+
+ return 0;
}
-EXPORT_SYMBOL(soc_camera_device_register);
-void soc_camera_device_unregister(struct soc_camera_device *icd)
+static void soc_camera_device_unregister(struct soc_camera_device *icd)
{
- mutex_lock(&list_lock);
list_del(&icd->list);
-
- /* The bus->remove will be eventually called */
- if (icd->dev.parent)
- device_unregister(&icd->dev);
- mutex_unlock(&list_lock);
}
-EXPORT_SYMBOL(soc_camera_device_unregister);
static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_querycap = soc_camera_querycap,
@@ -1107,23 +1246,13 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
#endif
};
-/*
- * Usually called from the struct soc_camera_ops .probe() method, i.e., from
- * soc_camera_probe() above with .video_lock held
- */
-int soc_camera_video_start(struct soc_camera_device *icd)
+static int video_dev_create(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int err = -ENOMEM;
- struct video_device *vdev;
+ struct video_device *vdev = video_device_alloc();
- if (!icd->dev.parent)
- return -ENODEV;
-
- vdev = video_device_alloc();
if (!vdev)
- goto evidallocd;
- dev_dbg(ici->dev, "Allocated video_device %p\n", vdev);
+ return -ENOMEM;
strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
@@ -1133,87 +1262,93 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->ioctl_ops = &soc_camera_ioctl_ops;
vdev->release = video_device_release;
vdev->minor = -1;
- vdev->tvnorms = V4L2_STD_UNKNOWN,
+ vdev->tvnorms = V4L2_STD_UNKNOWN;
- err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
- if (err < 0) {
- dev_err(vdev->parent, "video_register_device failed\n");
- goto evidregd;
- }
icd->vdev = vdev;
return 0;
-
-evidregd:
- video_device_release(vdev);
-evidallocd:
- return err;
}
-EXPORT_SYMBOL(soc_camera_video_start);
-/* Called from client .remove() methods with .video_lock held */
-void soc_camera_video_stop(struct soc_camera_device *icd)
+/*
+ * Called from soc_camera_probe() above (with .video_lock held???)
+ */
+static int soc_camera_video_start(struct soc_camera_device *icd)
{
- struct video_device *vdev = icd->vdev;
+ int ret;
- dev_dbg(&icd->dev, "%s\n", __func__);
+ if (!icd->dev.parent)
+ return -ENODEV;
- if (!icd->dev.parent || !vdev)
- return;
+ if (!icd->ops ||
+ !icd->ops->query_bus_param ||
+ !icd->ops->set_bus_param)
+ return -EINVAL;
+
+ ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER,
+ icd->vdev->minor);
+ if (ret < 0) {
+ dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
+ return ret;
+ }
- video_unregister_device(vdev);
- icd->vdev = NULL;
+ return 0;
}
-EXPORT_SYMBOL(soc_camera_video_stop);
static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
{
struct soc_camera_link *icl = pdev->dev.platform_data;
- struct i2c_adapter *adap;
- struct i2c_client *client;
+ struct soc_camera_device *icd;
+ int ret;
if (!icl)
return -EINVAL;
- adap = i2c_get_adapter(icl->i2c_adapter_id);
- if (!adap) {
- dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n",
- icl->i2c_adapter_id);
- /* -ENODEV and -ENXIO do not produce an error on probe()... */
- return -ENOENT;
- }
-
- icl->board_info->platform_data = icl;
- client = i2c_new_device(adap, icl->board_info);
- if (!client) {
- i2c_put_adapter(adap);
+ icd = kzalloc(sizeof(*icd), GFP_KERNEL);
+ if (!icd)
return -ENOMEM;
- }
- platform_set_drvdata(pdev, client);
+ icd->iface = icl->bus_id;
+ icd->pdev = &pdev->dev;
+ platform_set_drvdata(pdev, icd);
+ icd->dev.platform_data = icl;
+
+ ret = soc_camera_device_register(icd);
+ if (ret < 0)
+ goto escdevreg;
+
+ icd->user_width = DEFAULT_WIDTH;
+ icd->user_height = DEFAULT_HEIGHT;
return 0;
+
+escdevreg:
+ kfree(icd);
+
+ return ret;
}
+/* Only called on rmmod for each platform device, since they are not
+ * hot-pluggable. Now we know, that all our users - hosts and devices have
+ * been unloaded already */
static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
{
- struct i2c_client *client = platform_get_drvdata(pdev);
+ struct soc_camera_device *icd = platform_get_drvdata(pdev);
- if (!client)
- return -ENODEV;
+ if (!icd)
+ return -EINVAL;
- i2c_unregister_device(client);
- i2c_put_adapter(client->adapter);
+ soc_camera_device_unregister(icd);
+
+ kfree(icd);
return 0;
}
static struct platform_driver __refdata soc_camera_pdrv = {
- .probe = soc_camera_pdrv_probe,
- .remove = __devexit_p(soc_camera_pdrv_remove),
- .driver = {
- .name = "soc-camera-pdrv",
- .owner = THIS_MODULE,
+ .remove = __devexit_p(soc_camera_pdrv_remove),
+ .driver = {
+ .name = "soc-camera-pdrv",
+ .owner = THIS_MODULE,
},
};
@@ -1226,7 +1361,7 @@ static int __init soc_camera_init(void)
if (ret)
goto edrvr;
- ret = platform_driver_register(&soc_camera_pdrv);
+ ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
if (ret)
goto epdr;
diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c
index c48676356..b6a575ce5 100644
--- a/linux/drivers/media/video/soc_camera_platform.c
+++ b/linux/drivers/media/video/soc_camera_platform.c
@@ -16,54 +16,32 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
struct soc_camera_platform_priv {
- struct soc_camera_platform_info *info;
- struct soc_camera_device icd;
+ struct v4l2_subdev subdev;
struct soc_camera_data_format format;
};
-static struct soc_camera_platform_info *
-soc_camera_platform_get_info(struct soc_camera_device *icd)
+static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
{
- struct soc_camera_platform_priv *priv;
- priv = container_of(icd, struct soc_camera_platform_priv, icd);
- return priv->info;
-}
-
-static int soc_camera_platform_init(struct soc_camera_device *icd)
-{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
-
- if (p->power)
- p->power(1);
-
- return 0;
-}
-
-static int soc_camera_platform_release(struct soc_camera_device *icd)
-{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
-
- if (p->power)
- p->power(0);
-
- return 0;
+ struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+ return container_of(subdev, struct soc_camera_platform_priv, subdev);
}
-static int soc_camera_platform_start_capture(struct soc_camera_device *icd)
+static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd)
{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
- return p->set_capture(p, 1);
+ struct platform_device *pdev =
+ to_platform_device(to_soc_camera_control(icd));
+ return pdev->dev.platform_data;
}
-static int soc_camera_platform_stop_capture(struct soc_camera_device *icd)
+static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
- return p->set_capture(p, 0);
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+ return p->set_capture(p, enable);
}
static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd,
@@ -75,26 +53,14 @@ static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd,
static unsigned long
soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+ struct soc_camera_platform_info *p = get_info(icd);
return p->bus_param;
}
-static int soc_camera_platform_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
-{
- return 0;
-}
-
-static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
struct v4l2_format *f)
{
- return 0;
-}
-
-static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->width = p->format.width;
@@ -102,82 +68,99 @@ static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int soc_camera_platform_video_probe(struct soc_camera_device *icd)
+static void soc_camera_platform_video_probe(struct soc_camera_device *icd,
+ struct platform_device *pdev)
{
- struct soc_camera_platform_priv *priv;
- priv = container_of(icd, struct soc_camera_platform_priv, icd);
+ struct soc_camera_platform_priv *priv = get_priv(pdev);
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
- priv->format.name = priv->info->format_name;
- priv->format.depth = priv->info->format_depth;
- priv->format.fourcc = priv->info->format.pixelformat;
- priv->format.colorspace = priv->info->format.colorspace;
+ priv->format.name = p->format_name;
+ priv->format.depth = p->format_depth;
+ priv->format.fourcc = p->format.pixelformat;
+ priv->format.colorspace = p->format.colorspace;
icd->formats = &priv->format;
icd->num_formats = 1;
-
- return soc_camera_video_start(icd);
}
-static void soc_camera_platform_video_remove(struct soc_camera_device *icd)
-{
- soc_camera_video_stop(icd);
-}
+static struct v4l2_subdev_core_ops platform_subdev_core_ops;
+
+static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
+ .s_stream = soc_camera_platform_s_stream,
+ .try_fmt = soc_camera_platform_try_fmt,
+};
+
+static struct v4l2_subdev_ops platform_subdev_ops = {
+ .core = &platform_subdev_core_ops,
+ .video = &platform_subdev_video_ops,
+};
static struct soc_camera_ops soc_camera_platform_ops = {
- .owner = THIS_MODULE,
- .probe = soc_camera_platform_video_probe,
- .remove = soc_camera_platform_video_remove,
- .init = soc_camera_platform_init,
- .release = soc_camera_platform_release,
- .start_capture = soc_camera_platform_start_capture,
- .stop_capture = soc_camera_platform_stop_capture,
- .set_crop = soc_camera_platform_set_crop,
- .set_fmt = soc_camera_platform_set_fmt,
- .try_fmt = soc_camera_platform_try_fmt,
.set_bus_param = soc_camera_platform_set_bus_param,
.query_bus_param = soc_camera_platform_query_bus_param,
};
static int soc_camera_platform_probe(struct platform_device *pdev)
{
+ struct soc_camera_host *ici;
struct soc_camera_platform_priv *priv;
- struct soc_camera_platform_info *p;
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
struct soc_camera_device *icd;
int ret;
- p = pdev->dev.platform_data;
if (!p)
return -EINVAL;
+ if (!p->dev) {
+ dev_err(&pdev->dev,
+ "Platform has not set soc_camera_device pointer!\n");
+ return -EINVAL;
+ }
+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->info = p;
- platform_set_drvdata(pdev, priv);
+ icd = to_soc_camera_dev(p->dev);
+
+ /* soc-camera convention: control's drvdata points to the subdev */
+ platform_set_drvdata(pdev, &priv->subdev);
+ /* Set the control device reference */
+ dev_set_drvdata(&icd->dev, &pdev->dev);
+
+ icd->y_skip_top = 0;
+ icd->ops = &soc_camera_platform_ops;
+
+ ici = to_soc_camera_host(icd->dev.parent);
- icd = &priv->icd;
- icd->ops = &soc_camera_platform_ops;
- icd->control = &pdev->dev;
- icd->width_min = 0;
- icd->width_max = priv->info->format.width;
- icd->height_min = 0;
- icd->height_max = priv->info->format.height;
- icd->y_skip_top = 0;
- icd->iface = priv->info->iface;
+ soc_camera_platform_video_probe(icd, pdev);
- ret = soc_camera_device_register(icd);
+ v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
+ v4l2_set_subdevdata(&priv->subdev, p);
+ strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
+
+ ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
if (ret)
- kfree(priv);
+ goto evdrs;
+
+ return ret;
+evdrs:
+ icd->ops = NULL;
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
return ret;
}
static int soc_camera_platform_remove(struct platform_device *pdev)
{
- struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+ struct soc_camera_platform_priv *priv = get_priv(pdev);
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
+ struct soc_camera_device *icd = to_soc_camera_dev(p->dev);
- soc_camera_device_unregister(&priv->icd);
+ v4l2_device_unregister_subdev(&priv->subdev);
+ icd->ops = NULL;
+ platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;
}
@@ -185,6 +168,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
static struct platform_driver soc_camera_platform_driver = {
.driver = {
.name = "soc_camera_platform",
+ .owner = THIS_MODULE,
},
.probe = soc_camera_platform_probe,
.remove = soc_camera_platform_remove,
@@ -206,3 +190,4 @@ module_exit(soc_camera_platform_module_exit);
MODULE_DESCRIPTION("SoC Camera Platform driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:soc_camera_platform");
diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c
index aaeee8319..3034a31a5 100644
--- a/linux/drivers/media/video/stk-webcam.c
+++ b/linux/drivers/media/video/stk-webcam.c
@@ -1401,7 +1401,6 @@ static int stk_camera_probe(struct usb_interface *interface,
}
stk_create_sysfs_files(&dev->vdev);
- usb_autopm_enable(dev->interface);
return 0;
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 85b133df4..a4f6c19b7 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -842,8 +842,8 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
- (abs_freq * 2 + 125/2) / 125 :
- (abs_freq + 62500/2) / 62500;
+ DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
+ DIV_ROUND_CLOSEST(abs_freq, 62500);
return 0;
}
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c
index 5e3c9f4e2..085b869f5 100644
--- a/linux/drivers/media/video/tveeprom.c
+++ b/linux/drivers/media/video/tveeprom.c
@@ -647,14 +647,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->has_radio = 1;
}
- if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+ if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) {
tvee->tuner_type = hauppauge_tuner[tuner1].id;
t_name1 = hauppauge_tuner[tuner1].name;
} else {
t_name1 = "unknown";
}
- if (tuner2 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+ if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) {
tvee->tuner2_type = hauppauge_tuner[tuner2].id;
t_name2 = hauppauge_tuner[tuner2].name;
} else {
diff --git a/linux/drivers/media/video/tw9910.c b/linux/drivers/media/video/tw9910.c
index f75787594..db56ae683 100644
--- a/linux/drivers/media/video/tw9910.c
+++ b/linux/drivers/media/video/tw9910.c
@@ -24,7 +24,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/tw9910.h>
@@ -223,9 +223,8 @@ struct tw9910_hsync_ctrl {
};
struct tw9910_priv {
+ struct v4l2_subdev subdev;
struct tw9910_video_info *info;
- struct i2c_client *client;
- struct soc_camera_device icd;
const struct tw9910_scale_ctrl *scale;
};
@@ -356,6 +355,12 @@ static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = {
/*
* general function
*/
+static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct tw9910_priv,
+ subdev);
+}
+
static int tw9910_set_scale(struct i2c_client *client,
const struct tw9910_scale_ctrl *scale)
{
@@ -509,44 +514,20 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
/*
* soc_camera_ops function
*/
-static int tw9910_init(struct soc_camera_device *icd)
-{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
- int ret = 0;
-
- if (priv->info->link.power) {
- ret = priv->info->link.power(&priv->client->dev, 1);
- if (ret < 0)
- return ret;
- }
-
- if (priv->info->link.reset)
- ret = priv->info->link.reset(&priv->client->dev);
-
- return ret;
-}
-
-static int tw9910_release(struct soc_camera_device *icd)
+static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
- int ret = 0;
-
- if (priv->info->link.power)
- ret = priv->info->link.power(&priv->client->dev, 0);
-
- return ret;
-}
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
-static int tw9910_start_capture(struct soc_camera_device *icd)
-{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ if (!enable)
+ return 0;
if (!priv->scale) {
- dev_err(&icd->dev, "norm select error\n");
+ dev_err(&client->dev, "norm select error\n");
return -EPERM;
}
- dev_dbg(&icd->dev, "%s %dx%d\n",
+ dev_dbg(&client->dev, "%s %dx%d\n",
priv->scale->name,
priv->scale->width,
priv->scale->height);
@@ -554,11 +535,6 @@ static int tw9910_start_capture(struct soc_camera_device *icd)
return 0;
}
-static int tw9910_stop_capture(struct soc_camera_device *icd)
-{
- return 0;
-}
-
static int tw9910_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
@@ -567,8 +543,9 @@ static int tw9910_set_bus_param(struct soc_camera_device *icd,
static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
- struct soc_camera_link *icl = priv->client->dev.platform_data;
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
@@ -576,21 +553,11 @@ static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, flags);
}
-static int tw9910_get_chip_id(struct soc_camera_device *icd,
- struct v4l2_dbg_chip_ident *id)
-{
- id->ident = V4L2_IDENT_TW9910;
- id->revision = 0;
-
- return 0;
-}
-
-static int tw9910_set_std(struct soc_camera_device *icd,
- v4l2_std_id *a)
+static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
{
int ret = -EINVAL;
- if (*a & (V4L2_STD_NTSC | V4L2_STD_PAL))
+ if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL))
ret = 0;
return ret;
@@ -606,17 +573,26 @@ static int tw9910_enum_input(struct soc_camera_device *icd,
return 0;
}
+static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ id->ident = V4L2_IDENT_TW9910;
+ id->revision = 0;
+
+ return 0;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int tw9910_get_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int tw9910_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct i2c_client *client = sd->priv;
int ret;
if (reg->reg > 0xff)
return -EINVAL;
- ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
if (ret < 0)
return ret;
@@ -628,23 +604,25 @@ static int tw9910_get_register(struct soc_camera_device *icd,
return 0;
}
-static int tw9910_set_register(struct soc_camera_device *icd,
- struct v4l2_dbg_register *reg)
+static int tw9910_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct i2c_client *client = sd->priv;
if (reg->reg > 0xff ||
reg->val > 0xff)
return -EINVAL;
- return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
}
#endif
-static int tw9910_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
+static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct v4l2_rect *rect = &a->c;
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
int ret = -EINVAL;
u8 val;
@@ -658,8 +636,8 @@ static int tw9910_set_crop(struct soc_camera_device *icd,
/*
* reset hardware
*/
- tw9910_reset(priv->client);
- ret = tw9910_write_array(priv->client, tw9910_default_regs);
+ tw9910_reset(client);
+ ret = tw9910_write_array(client, tw9910_default_regs);
if (ret < 0)
goto tw9910_set_fmt_error;
@@ -670,7 +648,7 @@ static int tw9910_set_crop(struct soc_camera_device *icd,
if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
val = LEN;
- ret = tw9910_mask_set(priv->client, OPFORM, LEN, val);
+ ret = tw9910_mask_set(client, OPFORM, LEN, val);
if (ret < 0)
goto tw9910_set_fmt_error;
@@ -698,52 +676,139 @@ static int tw9910_set_crop(struct soc_camera_device *icd,
val = 0;
}
- ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val);
+ ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
if (ret < 0)
goto tw9910_set_fmt_error;
/*
* set scale
*/
- ret = tw9910_set_scale(priv->client, priv->scale);
+ ret = tw9910_set_scale(client, priv->scale);
if (ret < 0)
goto tw9910_set_fmt_error;
/*
* set cropping
*/
- ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl);
+ ret = tw9910_set_cropping(client, &tw9910_cropping_ctrl);
if (ret < 0)
goto tw9910_set_fmt_error;
/*
* set hsync
*/
- ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl);
+ ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl);
if (ret < 0)
goto tw9910_set_fmt_error;
+ rect->width = priv->scale->width;
+ rect->height = priv->scale->height;
+ rect->left = 0;
+ rect->top = 0;
+
return ret;
tw9910_set_fmt_error:
- tw9910_reset(priv->client);
+ tw9910_reset(client);
priv->scale = NULL;
return ret;
}
-static int tw9910_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ if (!priv->scale) {
+ int ret;
+ struct v4l2_crop crop = {
+ .c = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ };
+ ret = tw9910_s_crop(sd, &crop);
+ if (ret < 0)
+ return ret;
+ }
+
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = priv->scale->width;
+ a->c.height = priv->scale->height;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = 768;
+ a->bounds.height = 576;
+ a->defrect.left = 0;
+ a->defrect.top = 0;
+ a->defrect.width = 640;
+ a->defrect.height = 480;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (!priv->scale) {
+ int ret;
+ struct v4l2_crop crop = {
+ .c = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ };
+ ret = tw9910_s_crop(sd, &crop);
+ if (ret < 0)
+ return ret;
+ }
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ pix->width = priv->scale->width;
+ pix->height = priv->scale->height;
+ pix->pixelformat = V4L2_PIX_FMT_VYUY;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->field = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct i2c_client *client = sd->priv;
+ struct tw9910_priv *priv = to_tw9910(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
- .width = pix->width,
- .height = pix->height,
+ /* See tw9910_s_crop() - no proper cropping support */
+ struct v4l2_crop a = {
+ .c = {
+ .left = 0,
+ .top = 0,
+ .width = pix->width,
+ .height = pix->height,
+ },
};
- int i;
+ int i, ret;
/*
* check color format
@@ -755,19 +820,25 @@ static int tw9910_set_fmt(struct soc_camera_device *icd,
if (i == ARRAY_SIZE(tw9910_color_fmt))
return -EINVAL;
- return tw9910_set_crop(icd, &rect);
+ ret = tw9910_s_crop(sd, &a);
+ if (!ret) {
+ pix->width = priv->scale->width;
+ pix->height = priv->scale->height;
+ }
+ return ret;
}
-static int tw9910_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
+static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
{
+ struct i2c_client *client = sd->priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct tw9910_scale_ctrl *scale;
if (V4L2_FIELD_ANY == pix->field) {
pix->field = V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != pix->field) {
- dev_err(&icd->dev, "Field type invalid.\n");
+ dev_err(&client->dev, "Field type invalid.\n");
return -EINVAL;
}
@@ -784,11 +855,11 @@ static int tw9910_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int tw9910_video_probe(struct soc_camera_device *icd)
+static int tw9910_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
{
- struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ struct tw9910_priv *priv = to_tw9910(client);
s32 val;
- int ret;
/*
* We must have a parent by now. And it cannot be a wrong one.
@@ -803,7 +874,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd)
*/
if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
- dev_err(&icd->dev, "bus width error\n");
+ dev_err(&client->dev, "bus width error\n");
return -ENODEV;
}
@@ -813,54 +884,54 @@ static int tw9910_video_probe(struct soc_camera_device *icd)
/*
* check and show Product ID
*/
- val = i2c_smbus_read_byte_data(priv->client, ID);
+ val = i2c_smbus_read_byte_data(client, ID);
+
if (0x0B != GET_ID(val) ||
0x00 != GET_ReV(val)) {
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"Product ID error %x:%x\n", GET_ID(val), GET_ReV(val));
return -ENODEV;
}
- dev_info(&icd->dev,
+ dev_info(&client->dev,
"tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val));
- ret = soc_camera_video_start(icd);
- if (ret < 0)
- return ret;
-
icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL;
icd->vdev->current_norm = V4L2_STD_NTSC;
- return ret;
-}
-
-static void tw9910_video_remove(struct soc_camera_device *icd)
-{
- soc_camera_video_stop(icd);
+ return 0;
}
static struct soc_camera_ops tw9910_ops = {
- .owner = THIS_MODULE,
- .probe = tw9910_video_probe,
- .remove = tw9910_video_remove,
- .init = tw9910_init,
- .release = tw9910_release,
- .start_capture = tw9910_start_capture,
- .stop_capture = tw9910_stop_capture,
- .set_crop = tw9910_set_crop,
- .set_fmt = tw9910_set_fmt,
- .try_fmt = tw9910_try_fmt,
.set_bus_param = tw9910_set_bus_param,
.query_bus_param = tw9910_query_bus_param,
- .get_chip_id = tw9910_get_chip_id,
- .set_std = tw9910_set_std,
.enum_input = tw9910_enum_input,
+};
+
+static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
+ .g_chip_ident = tw9910_g_chip_ident,
+ .s_std = tw9910_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = tw9910_get_register,
- .set_register = tw9910_set_register,
+ .g_register = tw9910_g_register,
+ .s_register = tw9910_s_register,
#endif
};
+static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+ .s_stream = tw9910_s_stream,
+ .g_fmt = tw9910_g_fmt,
+ .s_fmt = tw9910_s_fmt,
+ .try_fmt = tw9910_try_fmt,
+ .cropcap = tw9910_cropcap,
+ .g_crop = tw9910_g_crop,
+ .s_crop = tw9910_s_crop,
+};
+
+static struct v4l2_subdev_ops tw9910_subdev_ops = {
+ .core = &tw9910_subdev_core_ops,
+ .video = &tw9910_subdev_video_ops,
+};
+
/*
* i2c_driver function
*/
@@ -875,18 +946,24 @@ static int tw9910_probe(struct i2c_client *client,
{
struct tw9910_priv *priv;
struct tw9910_video_info *info;
- struct soc_camera_device *icd;
- const struct tw9910_scale_ctrl *scale;
- int i, ret;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct i2c_adapter *adapter =
+ to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
+ int ret;
+
+ if (!icd) {
+ dev_err(&client->dev, "TW9910: missing soc-camera data!\n");
+ return -EINVAL;
+ }
- if (!client->dev.platform_data)
+ icl = to_soc_camera_link(icd);
+ if (!icl)
return -EINVAL;
- info = container_of(client->dev.platform_data,
- struct tw9910_video_info, link);
+ info = container_of(icl, struct tw9910_video_info, link);
- if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
- I2C_FUNC_SMBUS_BYTE_DATA)) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
"I2C-Adapter doesn't support "
"I2C_FUNC_SMBUS_BYTE_DATA\n");
@@ -898,40 +975,15 @@ static int tw9910_probe(struct i2c_client *client,
return -ENOMEM;
priv->info = info;
- priv->client = client;
- i2c_set_clientdata(client, priv);
- icd = &priv->icd;
+ v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
+
icd->ops = &tw9910_ops;
- icd->control = &client->dev;
icd->iface = info->link.bus_id;
- /*
- * set width and height
- */
- icd->width_max = tw9910_ntsc_scales[0].width; /* set default */
- icd->width_min = tw9910_ntsc_scales[0].width;
- icd->height_max = tw9910_ntsc_scales[0].height;
- icd->height_min = tw9910_ntsc_scales[0].height;
-
- scale = tw9910_ntsc_scales;
- for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) {
- icd->width_max = max(scale[i].width, icd->width_max);
- icd->width_min = min(scale[i].width, icd->width_min);
- icd->height_max = max(scale[i].height, icd->height_max);
- icd->height_min = min(scale[i].height, icd->height_min);
- }
- scale = tw9910_pal_scales;
- for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) {
- icd->width_max = max(scale[i].width, icd->width_max);
- icd->width_min = min(scale[i].width, icd->width_min);
- icd->height_max = max(scale[i].height, icd->height_max);
- icd->height_min = min(scale[i].height, icd->height_min);
- }
-
- ret = soc_camera_device_register(icd);
-
+ ret = tw9910_video_probe(icd, client);
if (ret) {
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -941,9 +993,10 @@ static int tw9910_probe(struct i2c_client *client,
static int tw9910_remove(struct i2c_client *client)
{
- struct tw9910_priv *priv = i2c_get_clientdata(client);
+ struct tw9910_priv *priv = to_tw9910(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
- soc_camera_device_unregister(&priv->icd);
+ icd->ops = NULL;
i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c
index b74ada0c6..82c7d298d 100644
--- a/linux/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c
@@ -250,9 +250,9 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
switch (usbvision_device_data[usbvision->DevModel].Codec) {
case CODEC_SAA7113:
case CODEC_SAA7111:
- v4l2_i2c_new_probed_subdev(&usbvision->v4l2_dev,
+ v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
&usbvision->i2c_adap, "saa7115",
- "saa7115_auto", saa711x_addrs);
+ "saa7115_auto", 0, saa711x_addrs);
break;
}
if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
@@ -260,16 +260,16 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
enum v4l2_i2c_tuner_type type;
struct tuner_setup tun_setup;
- sd = v4l2_i2c_new_probed_subdev(&usbvision->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
&usbvision->i2c_adap, "tuner",
- "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
/* depending on whether we found a demod or not, select
the tuner type. */
type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
- sd = v4l2_i2c_new_probed_subdev(&usbvision->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
&usbvision->i2c_adap, "tuner",
- "tuner", v4l2_i2c_tuner_addrs(type));
+ "tuner", 0, v4l2_i2c_tuner_addrs(type));
if (usbvision->tuner_type != -1) {
tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
diff --git a/linux/drivers/media/video/v4l1-compat.c b/linux/drivers/media/video/v4l1-compat.c
index ee3991f2f..2225243ad 100644
--- a/linux/drivers/media/video/v4l1-compat.c
+++ b/linux/drivers/media/video/v4l1-compat.c
@@ -77,9 +77,8 @@ get_v4l_control(struct file *file,
dprintk("VIDIOC_G_CTRL: %d\n", err);
return 0;
}
- return ((ctrl2.value - qctrl2.minimum) * 65535
- + (qctrl2.maximum - qctrl2.minimum) / 2)
- / (qctrl2.maximum - qctrl2.minimum);
+ return DIV_ROUND_CLOSEST((ctrl2.value-qctrl2.minimum) * 65535,
+ qctrl2.maximum - qctrl2.minimum);
}
return 0;
}
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index 864ee0772..203945635 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -157,6 +157,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
return -EINVAL;
if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+ return 0;
if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
@@ -341,6 +343,12 @@ const char **v4l2_ctrl_get_menu(u32 id)
"Sepia",
NULL
};
+ static const char *tune_preemphasis[] = {
+ "No preemphasis",
+ "50 useconds",
+ "75 useconds",
+ NULL,
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -379,6 +387,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
return camera_exposure_auto;
case V4L2_CID_COLORFX:
return colorfx;
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ return tune_preemphasis;
default:
return NULL;
}
@@ -477,6 +487,28 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
case V4L2_CID_PRIVACY: return "Privacy";
+ /* FM Radio Modulator control */
+ case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
+ case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
+ case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
+ case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
+ case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
+ case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
+ case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+ case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
+ case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
+ case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
+ case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
+ case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
+
default:
return NULL;
}
@@ -509,6 +541,9 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
case V4L2_CID_FOCUS_AUTO:
case V4L2_CID_PRIVACY:
+ case V4L2_CID_AUDIO_LIMITER_ENABLED:
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+ case V4L2_CID_PILOT_TONE_ENABLED:
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
min = 0;
max = step = 1;
@@ -537,12 +572,18 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_MPEG_STREAM_VBI_FMT:
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_COLORFX:
+ case V4L2_CID_TUNE_PREEMPHASIS:
qctrl->type = V4L2_CTRL_TYPE_MENU;
step = 1;
break;
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ qctrl->type = V4L2_CTRL_TYPE_STRING;
+ break;
case V4L2_CID_USER_CLASS:
case V4L2_CID_CAMERA_CLASS:
case V4L2_CID_MPEG_CLASS:
+ case V4L2_CID_FM_TX_CLASS:
qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
min = max = step = def = 0;
@@ -571,6 +612,17 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_BLUE_BALANCE:
case V4L2_CID_GAMMA:
case V4L2_CID_SHARPNESS:
+ case V4L2_CID_RDS_TX_DEVIATION:
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ case V4L2_CID_PILOT_TONE_FREQUENCY:
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
break;
case V4L2_CID_PAN_RELATIVE:
@@ -819,163 +871,6 @@ static struct i2c_client *v4l2_i2c_legacy_find_client(struct i2c_adapter *adap,
/* Load an i2c sub-device. */
-struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type, u8 addr)
-{
- struct v4l2_subdev *sd = NULL;
- struct i2c_client *client;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- struct i2c_board_info info;
-#endif
-
- BUG_ON(!v4l2_dev);
-
- if (module_name)
- request_module(module_name);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- /* Setup the i2c board info with the device type and
- the device address. */
- memset(&info, 0, sizeof(info));
- strlcpy(info.type, client_type, sizeof(info.type));
- info.addr = addr;
-
- /* Create the i2c client */
- client = i2c_new_device(adapter, &info);
-#else
- /* Legacy code: loading the module automatically
- probes and creates the i2c_client on the adapter.
- Try to find the client by walking the adapter's client list. */
- client = v4l2_i2c_legacy_find_client(adapter, addr);
-#endif
- /* Note: it is possible in the future that
- c->driver is NULL if the driver is still being loaded.
- We need better support from the kernel so that we
- can easily wait for the load to finish. */
- if (client == NULL || client->driver == NULL)
- goto error;
-
- /* Lock the module so we can safely get the v4l2_subdev pointer */
- if (!try_module_get(client->driver->driver.owner))
- goto error;
- sd = i2c_get_clientdata(client);
-
- /* Register with the v4l2_device which increases the module's
- use count as well. */
- if (v4l2_device_register_subdev(v4l2_dev, sd))
- sd = NULL;
- /* Decrease the module use count to match the first try_module_get. */
- module_put(client->driver->driver.owner);
-
- if (sd) {
- /* We return errors from v4l2_subdev_call only if we have the
- callback as the .s_config is not mandatory */
- int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);
-
- if (err && err != -ENOIOCTLCMD) {
- v4l2_device_unregister_subdev(sd);
- sd = NULL;
- }
- }
-
-error:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- /* If we have a client but no subdev, then something went wrong and
- we must unregister the client. */
- if (client && sd == NULL)
- i2c_unregister_device(client);
-#endif
- return sd;
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
-
-/* Probe and load an i2c sub-device. */
-struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
- const unsigned short *addrs)
-{
- struct v4l2_subdev *sd = NULL;
- struct i2c_client *client = NULL;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- struct i2c_board_info info;
-#endif
-
- BUG_ON(!v4l2_dev);
-
- if (module_name)
- request_module(module_name);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- /* Setup the i2c board info with the device type and
- the device address. */
- memset(&info, 0, sizeof(info));
- strlcpy(info.type, client_type, sizeof(info.type));
-
- /* Probe and create the i2c client */
- client = i2c_new_probed_device(adapter, &info, addrs);
-#else
- /* Legacy code: loading the module should automatically
- probe and create the i2c_client on the adapter.
- Try to find the client by walking the adapter's client list
- for each of the possible addresses. */
- while (!client && *addrs != I2C_CLIENT_END)
- client = v4l2_i2c_legacy_find_client(adapter, *addrs++);
-#endif
- /* Note: it is possible in the future that
- c->driver is NULL if the driver is still being loaded.
- We need better support from the kernel so that we
- can easily wait for the load to finish. */
- if (client == NULL || client->driver == NULL)
- goto error;
-
- /* Lock the module so we can safely get the v4l2_subdev pointer */
- if (!try_module_get(client->driver->driver.owner))
- goto error;
- sd = i2c_get_clientdata(client);
-
- /* Register with the v4l2_device which increases the module's
- use count as well. */
- if (v4l2_device_register_subdev(v4l2_dev, sd))
- sd = NULL;
- /* Decrease the module use count to match the first try_module_get. */
- module_put(client->driver->driver.owner);
-
- if (sd) {
- /* We return errors from v4l2_subdev_call only if we have the
- callback as the .s_config is not mandatory */
- int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);
-
- if (err && err != -ENOIOCTLCMD) {
- v4l2_device_unregister_subdev(sd);
- sd = NULL;
- }
- }
-
-error:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
- /* If we have a client but no subdev, then something went wrong and
- we must unregister the client. */
- if (client && sd == NULL)
- i2c_unregister_device(client);
-#endif
- return sd;
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
-
-struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type, u8 addr)
-{
- unsigned short addrs[2] = { addr, I2C_CLIENT_END };
-
- return v4l2_i2c_new_probed_subdev(v4l2_dev, adapter,
- module_name, client_type, addrs);
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr);
-
-/* Load an i2c sub-device. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
diff --git a/linux/drivers/media/video/v4l2-compat-ioctl32.c b/linux/drivers/media/video/v4l2-compat-ioctl32.c
index d9cee38cd..3454e7c64 100644
--- a/linux/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/linux/drivers/media/video/v4l2-compat-ioctl32.c
@@ -605,9 +605,37 @@ struct v4l2_ext_controls32 {
compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
};
+struct v4l2_ext_control32 {
+ __u32 id;
+ __u32 size;
+ __u32 reserved2[1];
+ union {
+ __s32 value;
+ __s64 value64;
+ compat_caddr_t string; /* actually char * */
+ };
+} __attribute__ ((packed));
+
+/* The following function really belong in v4l2-common, but that causes
+ a circular dependency between modules. We need to think about this, but
+ for now this will do. */
+
+/* Return non-zero if this control is a pointer type. Currently only
+ type STRING is a pointer type. */
+static inline int ctrl_is_pointer(u32 id)
+{
+ switch (id) {
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols;
int n;
compat_caddr_t p;
@@ -631,15 +659,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
kp->controls = kcontrols;
while (--n >= 0) {
- if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
- return -EFAULT;
- if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
- return -EFAULT;
- /* Note: if the void * part of the union ever becomes relevant
- then we need to know the type of the control in order to do
- the right thing here. Luckily, that is not yet an issue. */
- if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
return -EFAULT;
+ if (ctrl_is_pointer(kcontrols->id)) {
+ void __user *s;
+
+ if (get_user(p, &ucontrols->string))
+ return -EFAULT;
+ s = compat_ptr(p);
+ if (put_user(s, &kcontrols->string))
+ return -EFAULT;
+ }
ucontrols++;
kcontrols++;
}
@@ -648,7 +678,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols = kp->controls;
int n = kp->count;
compat_caddr_t p;
@@ -669,15 +699,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
return -EFAULT;
while (--n >= 0) {
- if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
- return -EFAULT;
- if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
- sizeof(ucontrols->reserved2)))
- return -EFAULT;
- /* Note: if the void * part of the union ever becomes relevant
- then we need to know the type of the control in order to do
- the right thing here. Luckily, that is not yet an issue. */
- if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+ unsigned size = sizeof(*ucontrols);
+
+ /* Do not modify the pointer when copying a pointer control.
+ The contents of the pointer was changed, not the pointer
+ itself. */
+ if (ctrl_is_pointer(kcontrols->id))
+ size -= sizeof(ucontrols->value64);
+ if (copy_in_user(ucontrols, kcontrols, size))
return -EFAULT;
ucontrols++;
kcontrols++;
diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c
index 9969abb28..a6d761dec 100644
--- a/linux/drivers/media/video/v4l2-dev.c
+++ b/linux/drivers/media/video/v4l2-dev.c
@@ -86,7 +86,49 @@ static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
*/
static struct video_device *video_device[VIDEO_NUM_DEVICES];
static DEFINE_MUTEX(videodev_lock);
-static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
+static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
+
+/* Device node utility functions */
+
+/* Note: these utility functions all assume that vfl_type is in the range
+ [0, VFL_TYPE_MAX-1]. */
+
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+/* Return the bitmap corresponding to vfl_type. */
+static inline unsigned long *devnode_bits(int vfl_type)
+{
+ /* Any types not assigned to fixed minor ranges must be mapped to
+ one single bitmap for the purposes of finding a free node number
+ since all those unassigned types use the same minor range. */
+ int idx = (vfl_type > VFL_TYPE_VTX) ? VFL_TYPE_MAX - 1 : vfl_type;
+
+ return devnode_nums[idx];
+}
+#else
+/* Return the bitmap corresponding to vfl_type. */
+static inline unsigned long *devnode_bits(int vfl_type)
+{
+ return devnode_nums[vfl_type];
+}
+#endif
+
+/* Mark device node number vdev->num as used */
+static inline void devnode_set(struct video_device *vdev)
+{
+ set_bit(vdev->num, devnode_bits(vdev->vfl_type));
+}
+
+/* Mark device node number vdev->num as unused */
+static inline void devnode_clear(struct video_device *vdev)
+{
+ clear_bit(vdev->num, devnode_bits(vdev->vfl_type));
+}
+
+/* Try to find a free device node number in the range [from, to> */
+static inline int devnode_find(struct video_device *vdev, int from, int to)
+{
+ return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from);
+}
struct video_device *video_device_alloc(void)
{
@@ -151,8 +193,8 @@ static void v4l2_device_release(struct device *cd)
the release() callback. */
vdev->cdev = NULL;
- /* Mark minor as free */
- clear_bit(vdev->num, video_nums[vdev->vfl_type]);
+ /* Mark device node number as free */
+ devnode_clear(vdev);
mutex_unlock(&videodev_lock);
@@ -337,32 +379,28 @@ static const struct file_operations v4l2_fops = {
};
/**
- * get_index - assign stream number based on parent device
+ * get_index - assign stream index number based on parent device
* @vdev: video_device to assign index number to, vdev->parent should be assigned
- * @num: -1 if auto assign, requested number otherwise
*
* Note that when this is called the new device has not yet been registered
- * in the video_device array.
+ * in the video_device array, but it was able to obtain a minor number.
+ *
+ * This means that we can always obtain a free stream index number since
+ * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
+ * use of the video_device array.
*
- * Returns -ENFILE if num is already in use, a free index number if
- * successful.
+ * Returns a free index number.
*/
-static int get_index(struct video_device *vdev, int num)
+static int get_index(struct video_device *vdev)
{
/* This can be static since this function is called with the global
videodev_lock held. */
static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
int i;
- if (num >= VIDEO_NUM_DEVICES) {
- printk(KERN_ERR "videodev: %s num is too large\n", __func__);
- return -EINVAL;
- }
-
- /* Some drivers do not set the parent. In that case always return
- num or 0. */
+ /* Some drivers do not set the parent. In that case always return 0. */
if (vdev->parent == NULL)
- return num >= 0 ? num : 0;
+ return 0;
bitmap_zero(used, VIDEO_NUM_DEVICES);
@@ -373,35 +411,23 @@ static int get_index(struct video_device *vdev, int num)
}
}
- if (num >= 0) {
- if (test_bit(num, used))
- return -ENFILE;
- return num;
- }
-
- i = find_first_zero_bit(used, VIDEO_NUM_DEVICES);
- return i == VIDEO_NUM_DEVICES ? -ENFILE : i;
+ return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
}
-int video_register_device(struct video_device *vdev, int type, int nr)
-{
- return video_register_device_index(vdev, type, nr, -1);
-}
-EXPORT_SYMBOL(video_register_device);
-
/**
- * video_register_device_index - register video4linux devices
+ * video_register_device - register video4linux devices
* @vdev: video device structure we want to register
* @type: type of device to register
- * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
+ * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...
* -1 == first free)
- * @index: stream number based on parent device;
- * -1 if auto assign, requested number otherwise
+ * @warn_if_nr_in_use: warn if the desired device node number
+ * was already in use and another number was chosen instead.
*
- * The registration code assigns minor numbers based on the type
- * requested. -ENFILE is returned in all the device slots for this
- * category are full. If not then the minor field is set and the
- * driver initialize function is called (if non %NULL).
+ * The registration code assigns minor numbers and device node numbers
+ * based on the requested type and registers the new device node with
+ * the kernel.
+ * An error is returned if no free minor or device node number could be
+ * found, or if the registration of the device node failed.
*
* Zero is returned on success.
*
@@ -415,8 +441,8 @@ EXPORT_SYMBOL(video_register_device);
*
* %VFL_TYPE_RADIO - A radio card
*/
-int video_register_device_index(struct video_device *vdev, int type, int nr,
- int index)
+static int __video_register_device(struct video_device *vdev, int type, int nr,
+ int warn_if_nr_in_use)
{
int i = 0;
int ret;
@@ -459,7 +485,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
if (vdev->v4l2_dev && vdev->v4l2_dev->dev)
vdev->parent = vdev->v4l2_dev->dev;
- /* Part 2: find a free minor, kernel number and device index. */
+ /* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* Keep the ranges for the first four types for historical
* reasons.
@@ -490,21 +516,22 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
}
#endif
- /* Pick a minor number */
+ /* Pick a device node number */
mutex_lock(&videodev_lock);
- nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr);
+ nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
if (nr == minor_cnt)
- nr = find_first_zero_bit(video_nums[type], minor_cnt);
+ nr = devnode_find(vdev, 0, minor_cnt);
if (nr == minor_cnt) {
- printk(KERN_ERR "could not get a free kernel number\n");
+ printk(KERN_ERR "could not get a free device node number\n");
mutex_unlock(&videodev_lock);
return -ENFILE;
}
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
- /* 1-on-1 mapping of kernel number to minor number */
+ /* 1-on-1 mapping of device node number to minor number */
i = nr;
#else
- /* The kernel number and minor numbers are independent */
+ /* The device node number and minor numbers are independent, so
+ we just find the first free minor number. */
for (i = 0; i < VIDEO_NUM_DEVICES; i++)
if (video_device[i] == NULL)
break;
@@ -516,17 +543,13 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
#endif
vdev->minor = i + minor_offset;
vdev->num = nr;
- set_bit(nr, video_nums[type]);
+ devnode_set(vdev);
+
/* Should not happen since we thought this minor was free */
WARN_ON(video_device[vdev->minor] != NULL);
- ret = vdev->index = get_index(vdev, index);
+ vdev->index = get_index(vdev);
mutex_unlock(&videodev_lock);
- if (ret < 0) {
- printk(KERN_ERR "%s: get_index failed\n", __func__);
- goto cleanup;
- }
-
/* Part 3: Initialize the character device */
vdev->cdev = cdev_alloc();
if (vdev->cdev == NULL) {
@@ -563,12 +586,12 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
if (vdev->parent)
vdev->dev.dev = vdev->parent;
- sprintf(vdev->dev.class_id, "%s%d", name_base, nr);
+ sprintf(vdev->dev.class_id, "%s%d", name_base, vdev->num);
ret = class_device_register(&vdev->dev);
#else
if (vdev->parent)
vdev->dev.parent = vdev->parent;
- dev_set_name(&vdev->dev, "%s%d", name_base, nr);
+ dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
ret = device_register(&vdev->dev);
#endif
if (ret < 0) {
@@ -595,6 +618,10 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
reference to the device goes away. */
vdev->dev.release = v4l2_device_release;
+ if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
+ printk(KERN_WARNING "%s: requested %s%d, got %s%d\n",
+ __func__, name_base, nr, name_base, vdev->num);
+
/* Part 5: Activate this minor. The char device can now be used. */
mutex_lock(&videodev_lock);
video_device[vdev->minor] = vdev;
@@ -605,13 +632,24 @@ cleanup:
mutex_lock(&videodev_lock);
if (vdev->cdev)
cdev_del(vdev->cdev);
- clear_bit(vdev->num, video_nums[type]);
+ devnode_clear(vdev);
mutex_unlock(&videodev_lock);
/* Mark this video device as never having been registered. */
vdev->minor = -1;
return ret;
}
-EXPORT_SYMBOL(video_register_device_index);
+
+int video_register_device(struct video_device *vdev, int type, int nr)
+{
+ return __video_register_device(vdev, type, nr, 1);
+}
+EXPORT_SYMBOL(video_register_device);
+
+int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
+{
+ return __video_register_device(vdev, type, nr, 0);
+}
+EXPORT_SYMBOL(video_register_device_no_warn);
/**
* video_unregister_device - unregister a video4linux device
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index d746d9555..d40c7bb2d 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -514,11 +514,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
dbgarg(cmd, "");
printk(KERN_CONT "class=0x%x", c->ctrl_class);
for (i = 0; i < c->count; i++) {
- if (show_vals)
+ if (show_vals && !c->controls[i].size)
printk(KERN_CONT " id/val=0x%x/0x%x",
c->controls[i].id, c->controls[i].value);
else
- printk(KERN_CONT " id=0x%x", c->controls[i].id);
+ printk(KERN_CONT " id=0x%x,size=%u",
+ c->controls[i].id, c->controls[i].size);
}
printk(KERN_CONT "\n");
};
@@ -529,10 +530,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
/* zero the reserved fields */
c->reserved[0] = c->reserved[1] = 0;
- for (i = 0; i < c->count; i++) {
+ for (i = 0; i < c->count; i++)
c->controls[i].reserved2[0] = 0;
- c->controls[i].reserved2[1] = 0;
- }
+
/* V4L2_CID_PRIVATE_BASE cannot be used as control class
when using extended controls.
Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
diff --git a/linux/drivers/media/video/videobuf-dma-contig.c b/linux/drivers/media/video/videobuf-dma-contig.c
index 633a124cf..bd1b13e93 100644
--- a/linux/drivers/media/video/videobuf-dma-contig.c
+++ b/linux/drivers/media/video/videobuf-dma-contig.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
#include <media/videobuf-dma-contig.h>
#include "compat.h"
@@ -26,6 +27,7 @@ struct videobuf_dma_contig_memory {
void *vaddr;
dma_addr_t dma_handle;
unsigned long size;
+ int is_userptr;
};
#define MAGIC_DC_MEM 0x0733ac61
@@ -109,6 +111,82 @@ static struct vm_operations_struct videobuf_vm_ops = {
.close = videobuf_vm_close,
};
+/**
+ * videobuf_dma_contig_user_put() - reset pointer to user space buffer
+ * @mem: per-buffer private videobuf-dma-contig data
+ *
+ * This function resets the user space pointer
+ */
+static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
+{
+ mem->is_userptr = 0;
+ mem->dma_handle = 0;
+ mem->size = 0;
+}
+
+/**
+ * videobuf_dma_contig_user_get() - setup user space memory pointer
+ * @mem: per-buffer private videobuf-dma-contig data
+ * @vb: video buffer to map
+ *
+ * This function validates and sets up a pointer to user space memory.
+ * Only physically contiguous pfn-mapped memory is accepted.
+ *
+ * Returns 0 if successful.
+ */
+static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
+ struct videobuf_buffer *vb)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long prev_pfn, this_pfn;
+ unsigned long pages_done, user_address;
+ int ret;
+
+ mem->size = PAGE_ALIGN(vb->size);
+ mem->is_userptr = 0;
+ ret = -EINVAL;
+
+ down_read(&mm->mmap_sem);
+
+ vma = find_vma(mm, vb->baddr);
+ if (!vma)
+ goto out_up;
+
+ if ((vb->baddr + mem->size) > vma->vm_end)
+ goto out_up;
+
+ pages_done = 0;
+ prev_pfn = 0; /* kill warning */
+ user_address = vb->baddr;
+
+ while (pages_done < (mem->size >> PAGE_SHIFT)) {
+ ret = follow_pfn(vma, user_address, &this_pfn);
+ if (ret)
+ break;
+
+ if (pages_done == 0)
+ mem->dma_handle = this_pfn << PAGE_SHIFT;
+ else if (this_pfn != (prev_pfn + 1))
+ ret = -EFAULT;
+
+ if (ret)
+ break;
+
+ prev_pfn = this_pfn;
+ user_address += PAGE_SIZE;
+ pages_done++;
+ }
+
+ if (!ret)
+ mem->is_userptr = 1;
+
+ out_up:
+ up_read(&current->mm->mmap_sem);
+
+ return ret;
+}
+
static void *__videobuf_alloc(size_t size)
{
struct videobuf_dma_contig_memory *mem;
@@ -155,12 +233,11 @@ static int __videobuf_iolock(struct videobuf_queue *q,
case V4L2_MEMORY_USERPTR:
dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
- /* The only USERPTR currently supported is the one needed for
- read() method.
- */
+ /* handle pointer from user space */
if (vb->baddr)
- return -EINVAL;
+ return videobuf_dma_contig_user_get(mem, vb);
+ /* allocate memory for the read() method */
mem->size = PAGE_ALIGN(vb->size);
mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
&mem->dma_handle, GFP_KERNEL);
@@ -387,7 +464,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
So, it should free memory only if the memory were allocated for
read() operation.
*/
- if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
+ if (buf->memory != V4L2_MEMORY_USERPTR)
return;
if (!mem)
@@ -395,6 +472,13 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+ /* handle user space pointer case */
+ if (buf->baddr) {
+ videobuf_dma_contig_user_put(mem);
+ return;
+ }
+
+ /* read() method */
dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
mem->vaddr = NULL;
}
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index af03ec2d5..5a8dd5e19 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -50,6 +50,7 @@
#include <asm/sgi/ip22.h>
#include <asm/sgi/mc.h>
+#include "compat.h"
#include "vino.h"
#include "saa7191.h"
#include "indycam.h"
@@ -4337,11 +4338,11 @@ static int __init vino_module_init(void)
vino_init_stage++;
vino_drvdata->decoder =
- v4l2_i2c_new_probed_subdev_addr(&vino_drvdata->v4l2_dev,
- &vino_i2c_adapter, "saa7191", "saa7191", 0x45);
+ v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
+ "saa7191", "saa7191", 0, I2C_ADDRS(0x45));
vino_drvdata->camera =
- v4l2_i2c_new_probed_subdev_addr(&vino_drvdata->v4l2_dev,
- &vino_i2c_adapter, "indycam", "indycam", 0x2b);
+ v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
+ "indycam", "indycam", 0, I2C_ADDRS(0x2b));
dprintk("init complete!\n");
diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c
index 5324c092a..c52301762 100644
--- a/linux/drivers/media/video/w9968cf.c
+++ b/linux/drivers/media/video/w9968cf.c
@@ -3529,9 +3529,9 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
w9968cf_turn_on_led(cam);
w9968cf_i2c_init(cam);
- cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->v4l2_dev,
+ cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
&cam->i2c_adapter,
- "ovcamchip", "ovcamchip", addrs);
+ "ovcamchip", "ovcamchip", 0, addrs);
usb_set_intfdata(intf, cam);
mutex_unlock(&cam->dev_mutex);
diff --git a/linux/drivers/media/video/zoran/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c
index 375f158fd..ed1b04303 100644
--- a/linux/drivers/media/video/zoran/zoran_card.c
+++ b/linux/drivers/media/video/zoran/zoran_card.c
@@ -1358,15 +1358,15 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
goto zr_free_irq;
}
- zr->decoder = v4l2_i2c_new_probed_subdev(&zr->v4l2_dev,
+ zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
&zr->i2c_adapter, zr->card.mod_decoder, zr->card.i2c_decoder,
- zr->card.addrs_decoder);
+ 0, zr->card.addrs_decoder);
if (zr->card.mod_encoder)
- zr->encoder = v4l2_i2c_new_probed_subdev(&zr->v4l2_dev,
+ zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
&zr->i2c_adapter,
zr->card.mod_encoder, zr->card.i2c_encoder,
- zr->card.addrs_encoder);
+ 0, zr->card.addrs_encoder);
dprintk(2,
KERN_INFO "%s: Initializing videocodec bus...\n",