mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (11423): gspca - m5602-ov9650: Add a disconnect hook, setup a ctrl cache ctrl.
Reading and writing to a register doesn't always work reliably. Add a cache and ensure that it is deallocated properly upon module disconnect. Signed-off-by: Erik Andr?n <erik.andren@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
1a3dd5d91a
commit
d9c700d415
|
@ -117,6 +117,9 @@ struct sd {
|
||||||
|
|
||||||
struct sd_desc *desc;
|
struct sd_desc *desc;
|
||||||
|
|
||||||
|
/* Sensor private data */
|
||||||
|
void *sensor_priv;
|
||||||
|
|
||||||
/* The current frame's id, used to detect frame boundaries */
|
/* The current frame's id, used to detect frame boundaries */
|
||||||
u8 frame_id;
|
u8 frame_id;
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,17 @@ static int m5602_probe(struct usb_interface *intf,
|
||||||
THIS_MODULE);
|
THIS_MODULE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void m5602_disconnect(struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
|
||||||
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
|
|
||||||
|
if (sd->sensor->disconnect)
|
||||||
|
sd->sensor->disconnect(sd);
|
||||||
|
|
||||||
|
gspca_disconnect(intf);
|
||||||
|
}
|
||||||
|
|
||||||
static struct usb_driver sd_driver = {
|
static struct usb_driver sd_driver = {
|
||||||
.name = MODULE_NAME,
|
.name = MODULE_NAME,
|
||||||
.id_table = m5602_table,
|
.id_table = m5602_table,
|
||||||
|
@ -370,7 +381,7 @@ static struct usb_driver sd_driver = {
|
||||||
.suspend = gspca_suspend,
|
.suspend = gspca_suspend,
|
||||||
.resume = gspca_resume,
|
.resume = gspca_resume,
|
||||||
#endif
|
#endif
|
||||||
.disconnect = gspca_disconnect
|
.disconnect = m5602_disconnect
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -- module insert / remove -- */
|
/* -- module insert / remove -- */
|
||||||
|
|
|
@ -220,6 +220,7 @@ int ov9650_probe(struct sd *sd)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 prod_id = 0, ver_id = 0, i;
|
u8 prod_id = 0, ver_id = 0, i;
|
||||||
|
s32 *sensor_settings;
|
||||||
|
|
||||||
if (force_sensor) {
|
if (force_sensor) {
|
||||||
if (force_sensor == OV9650_SENSOR) {
|
if (force_sensor == OV9650_SENSOR) {
|
||||||
|
@ -238,9 +239,10 @@ int ov9650_probe(struct sd *sd)
|
||||||
u8 data = preinit_ov9650[i][2];
|
u8 data = preinit_ov9650[i][2];
|
||||||
if (preinit_ov9650[i][0] == SENSOR)
|
if (preinit_ov9650[i][0] == SENSOR)
|
||||||
err = m5602_write_sensor(sd,
|
err = m5602_write_sensor(sd,
|
||||||
preinit_ov9650[i][1], &data, 1);
|
preinit_ov9650[i][1], &data, 1);
|
||||||
else
|
else
|
||||||
err = m5602_write_bridge(sd, preinit_ov9650[i][1], data);
|
err = m5602_write_bridge(sd,
|
||||||
|
preinit_ov9650[i][1], data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -260,10 +262,21 @@ int ov9650_probe(struct sd *sd)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
sensor_found:
|
sensor_found:
|
||||||
|
|
||||||
|
sensor_settings = kmalloc(
|
||||||
|
ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
|
||||||
|
if (!sensor_settings)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
sd->gspca_dev.cam.cam_mode = ov9650_modes;
|
sd->gspca_dev.cam.cam_mode = ov9650_modes;
|
||||||
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
|
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
|
||||||
sd->desc->ctrls = ov9650_ctrls;
|
sd->desc->ctrls = ov9650_ctrls;
|
||||||
sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
|
sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
|
||||||
|
sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
|
||||||
|
sd->sensor_priv = sensor_settings;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +337,8 @@ int ov9650_start(struct sd *sd)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, ((ver_offs >> 8) & 0xff));
|
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
|
||||||
|
((ver_offs >> 8) & 0xff));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -344,13 +358,13 @@ int ov9650_start(struct sd *sd)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
for (i = 0; i < 2 && !err; i++) {
|
for (i = 0; i < 2 && !err; i++)
|
||||||
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
|
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
|
||||||
}
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (hor_offs >> 8) & 0xff);
|
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
|
||||||
|
(hor_offs >> 8) & 0xff);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -358,11 +372,13 @@ int ov9650_start(struct sd *sd)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, ((width + hor_offs) >> 8) & 0xff);
|
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
|
||||||
|
((width + hor_offs) >> 8) & 0xff);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, ((width + hor_offs) & 0xff));
|
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
|
||||||
|
((width + hor_offs) & 0xff));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -431,6 +447,16 @@ int ov9650_power_down(struct sd *sd)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ov9650_disconnect(struct sd *sd)
|
||||||
|
{
|
||||||
|
ov9650_stop(sd);
|
||||||
|
ov9650_power_down(sd);
|
||||||
|
|
||||||
|
sd->sensor = NULL;
|
||||||
|
|
||||||
|
kfree(sd->sensor_priv);
|
||||||
|
}
|
||||||
|
|
||||||
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
|
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
|
|
|
@ -138,6 +138,7 @@ int ov9650_init(struct sd *sd);
|
||||||
int ov9650_start(struct sd *sd);
|
int ov9650_start(struct sd *sd);
|
||||||
int ov9650_stop(struct sd *sd);
|
int ov9650_stop(struct sd *sd);
|
||||||
int ov9650_power_down(struct sd *sd);
|
int ov9650_power_down(struct sd *sd);
|
||||||
|
void ov9650_disconnect(struct sd *sd);
|
||||||
|
|
||||||
int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
|
int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
|
||||||
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
|
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
|
||||||
|
@ -167,6 +168,7 @@ const static struct m5602_sensor ov9650 = {
|
||||||
.start = ov9650_start,
|
.start = ov9650_start,
|
||||||
.stop = ov9650_stop,
|
.stop = ov9650_stop,
|
||||||
.power_down = ov9650_power_down,
|
.power_down = ov9650_power_down,
|
||||||
|
.disconnect = ov9650_disconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char preinit_ov9650[][3] =
|
static const unsigned char preinit_ov9650[][3] =
|
||||||
|
|
|
@ -59,6 +59,9 @@ struct m5602_sensor {
|
||||||
/* Executed when the camera ends to send data */
|
/* Executed when the camera ends to send data */
|
||||||
int (*stop)(struct sd *sd);
|
int (*stop)(struct sd *sd);
|
||||||
|
|
||||||
|
/* Executed when the device is disconnected */
|
||||||
|
void (*disconnect)(struct sd *sd);
|
||||||
|
|
||||||
/* Performs a power down sequence */
|
/* Performs a power down sequence */
|
||||||
int (*power_down)(struct sd *sd);
|
int (*power_down)(struct sd *sd);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue