From: Luca Risolia Date: Sat, 25 Feb 2006 06:54:18 +0000 (+0000) Subject: [PATCH] USB: ET61X[12]51 driver updates X-Git-Tag: v2.6.17-rc1~1176^2~25 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ccad7789d5e557644d1c866b018394872af0ec5b;p=linux-2.6 [PATCH] USB: ET61X[12]51 driver updates USB: ET61X[12]51 driver updates Changes: + new, - removed, * cleanup, @ bugfix @ Fix stream_interrupt() @ Fix vidioc_enum_input() and split vidioc_gs_input() @ Need usb_get|put_dev() when disconnecting, if the device is open * Use wait_event_interruptible_timeout() instead of wait_event_interruptible() when waiting for video frames * replace wake_up_interruptible(&wait_stream) with wake_up(&wait_stream) * Cleanups and updates in the documentation * Use mutexes instead of semaphores + Use per-device sensor structures + Add support for PAS202BCA image sensors + Add frame_timeout module parameter Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- diff --git a/Documentation/usb/et61x251.txt b/Documentation/usb/et61x251.txt index b44dda407c..29340282ab 100644 --- a/Documentation/usb/et61x251.txt +++ b/Documentation/usb/et61x251.txt @@ -176,6 +176,14 @@ Description: Force the application to unmap previously mapped buffer memory 1 = force memory unmapping (save memory) Default: 0 ------------------------------------------------------------------------------- +Name: frame_timeout +Type: uint array (min = 0, max = 64) +Syntax: +Description: Timeout for a video frame in seconds. This parameter is + specific for each detected camera. This parameter can be + changed at runtime thanks to the /sys filesystem interface. +Default: 2 +------------------------------------------------------------------------------- Name: debug Type: ushort Syntax: @@ -266,7 +274,7 @@ the V4L2 interface. 10. Notes for V4L2 application developers -======================================== +========================================= This driver follows the V4L2 API specifications. In particular, it enforces two rules: diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h index 652238f329..eee8afc9be 100644 --- a/drivers/usb/media/et61x251.h +++ b/drivers/usb/media/et61x251.h @@ -33,7 +33,9 @@ #include #include #include -#include +#include +#include +#include #include "et61x251_sensor.h" @@ -51,6 +53,7 @@ #define ET61X251_ALTERNATE_SETTING 13 #define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) #define ET61X251_CTRL_TIMEOUT 100 +#define ET61X251_FRAME_TIMEOUT 2 /*****************************************************************************/ @@ -127,15 +130,16 @@ struct et61x251_sysfs_attr { struct et61x251_module_param { u8 force_munmap; + u16 frame_timeout; }; -static DECLARE_MUTEX(et61x251_sysfs_lock); +static DEFINE_MUTEX(et61x251_sysfs_lock); static DECLARE_RWSEM(et61x251_disconnect); struct et61x251_device { struct video_device* v4ldev; - struct et61x251_sensor* sensor; + struct et61x251_sensor sensor; struct usb_device* usbdev; struct urb* urb[ET61X251_URBS]; @@ -157,19 +161,28 @@ struct et61x251_device { enum et61x251_dev_state state; u8 users; - struct semaphore dev_sem, fileop_sem; + struct mutex dev_mutex, fileop_mutex; spinlock_t queue_lock; wait_queue_head_t open, wait_frame, wait_stream; }; /*****************************************************************************/ +struct et61x251_device* +et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) +{ + if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) + return cam; + + return NULL; +} + + void et61x251_attach_sensor(struct et61x251_device* cam, struct et61x251_sensor* sensor) { - cam->sensor = sensor; - cam->sensor->usbdev = cam->usbdev; + memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); } /*****************************************************************************/ @@ -212,7 +225,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c index 2c0171a5ad..7cc01b828b 100644 --- a/drivers/usb/media/et61x251_core.c +++ b/drivers/usb/media/et61x251_core.c @@ -25,11 +25,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -50,8 +48,8 @@ #define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia" #define ET61X251_AUTHOR_EMAIL "" #define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.01" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) +#define ET61X251_MODULE_VERSION "1:1.02" +#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) /*****************************************************************************/ @@ -90,6 +88,16 @@ MODULE_PARM_DESC(force_munmap, "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." "\n"); +static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = + ET61X251_FRAME_TIMEOUT}; +module_param_array(frame_timeout, uint, NULL, 0644); +MODULE_PARM_DESC(frame_timeout, + "\n Timeout for a video frame in seconds." + "\nThis parameter is specific for each detected camera." + "\nDefault value is " + __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." + "\n"); + #ifdef ET61X251_DEBUG static unsigned short debug = ET61X251_DEBUG_LEVEL; module_param(debug, ushort, 0644); @@ -111,8 +119,8 @@ static u32 et61x251_request_buffers(struct et61x251_device* cam, u32 count, enum et61x251_io_method io) { - struct v4l2_pix_format* p = &(cam->sensor->pix_format); - struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); + struct v4l2_pix_format* p = &(cam->sensor.pix_format); + struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); const size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? (p->width * p->height * p->priv) / 8 : @@ -268,8 +276,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam, int err = 0, res; data[0] = address; - data[1] = cam->sensor->i2c_slave_id; - data[2] = cam->sensor->rsta | 0x10; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x10; data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); @@ -301,8 +309,8 @@ et61x251_i2c_try_write(struct et61x251_device* cam, int err = 0, res; data[0] = address; - data[1] = cam->sensor->i2c_slave_id; - data[2] = cam->sensor->rsta | 0x12; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x12; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); if (res < 0) @@ -334,9 +342,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, u8* data = cam->control_buffer; int err = 0, res; - if (!cam->sensor) - return -1; - data[0] = data2; data[1] = data3; data[2] = data4; @@ -350,8 +355,8 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, err += res; data[0] = address; - data[1] = cam->sensor->i2c_slave_id; - data[2] = cam->sensor->rsta | 0x02 | (n << 4); + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x02 | (n << 4); res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); if (res < 0) @@ -364,11 +369,11 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, if (res < 0) err += res; - err += et61x251_i2c_wait(cam, cam->sensor); + err += et61x251_i2c_wait(cam, &cam->sensor); if (err) DBG(3, "I2C raw write failed for %s image sensor", - cam->sensor->name); + cam->sensor.name); PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," @@ -382,19 +387,13 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, int et61x251_i2c_read(struct et61x251_device* cam, u8 address) { - if (!cam->sensor) - return -1; - - return et61x251_i2c_try_read(cam, cam->sensor, address); + return et61x251_i2c_try_read(cam, &cam->sensor, address); } int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) { - if (!cam->sensor) - return -1; - - return et61x251_i2c_try_write(cam, cam->sensor, address, value); + return et61x251_i2c_try_write(cam, &cam->sensor, address, value); } /*****************************************************************************/ @@ -417,7 +416,7 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) if ((*f)) (*f)->state = F_QUEUED; DBG(3, "Stream interrupted"); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); } if (cam->state & DEV_DISCONNECTED) @@ -435,9 +434,9 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, frame); - imagesize = (cam->sensor->pix_format.width * - cam->sensor->pix_format.height * - cam->sensor->pix_format.priv) / 8; + imagesize = (cam->sensor.pix_format.width * + cam->sensor.pix_format.height * + cam->sensor.pix_format.priv) / 8; for (i = 0; i < urb->number_of_packets; i++) { unsigned int len, status; @@ -476,7 +475,7 @@ start_of_frame: if ((*f)->state == F_GRABBING) { if (sof && (*f)->buf.bytesused) { - if (cam->sensor->pix_format.pixelformat == + if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) goto end_of_frame; else { @@ -521,7 +520,7 @@ end_of_frame: goto resubmit_urb; if (sof && - cam->sensor->pix_format.pixelformat == + cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) goto start_of_frame; } @@ -650,21 +649,21 @@ static int et61x251_stop_transfer(struct et61x251_device* cam) static int et61x251_stream_interrupt(struct et61x251_device* cam) { - int err = 0; + long timeout; cam->stream = STREAM_INTERRUPT; - err = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - ET61X251_URB_TIMEOUT); + timeout = wait_event_timeout(cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED), + ET61X251_URB_TIMEOUT); if (cam->state & DEV_DISCONNECTED) return -ENODEV; - else if (err) { + else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " "use it, close and open /dev/video%d again.", cam->v4ldev->minor); - return err; + return -EIO; } return 0; @@ -709,18 +708,18 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) struct et61x251_device* cam; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } count = sprintf(buf, "%u\n", cam->sysfs.reg); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -733,18 +732,18 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) u8 index; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } index = et61x251_strtou8(buf, len, &count); if (index > 0x8e || !count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } @@ -753,7 +752,7 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -765,17 +764,17 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) ssize_t count; int val; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -783,7 +782,7 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -797,24 +796,24 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) ssize_t count; int err; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } value = et61x251_strtou8(buf, len, &count); if (!count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } err = et61x251_write_reg(cam, value, cam->sysfs.reg); if (err) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -822,7 +821,7 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) cam->sysfs.reg, value); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -833,12 +832,12 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) struct et61x251_device* cam; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } @@ -846,7 +845,7 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -859,18 +858,18 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) u8 index; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } index = et61x251_strtou8(buf, len, &count); if (!count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } @@ -879,7 +878,7 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -891,22 +890,22 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) ssize_t count; int val; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } - if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) { - up(&et61x251_sysfs_lock); + if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { + mutex_unlock(&et61x251_sysfs_lock); return -ENOSYS; } if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -914,7 +913,7 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -928,29 +927,29 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) ssize_t count; int err; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } - if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) { - up(&et61x251_sysfs_lock); + if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { + mutex_unlock(&et61x251_sysfs_lock); return -ENOSYS; } value = et61x251_strtou8(buf, len, &count); if (!count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); if (err) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -958,7 +957,7 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) cam->sysfs.i2c_reg, value); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -980,7 +979,7 @@ static void et61x251_create_sysfs(struct et61x251_device* cam) video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); - if (cam->sensor && cam->sensor->sysfs_ops) { + if (cam->sensor.sysfs_ops) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); video_device_create_file(v4ldev, &class_device_attr_i2c_val); } @@ -1048,7 +1047,7 @@ static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) static int et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + s->active_pixel.left), fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + @@ -1076,7 +1075,7 @@ et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) static int et61x251_init(struct et61x251_device* cam) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_control ctrl; struct v4l2_queryctrl *qctrl; struct v4l2_rect* rect; @@ -1143,7 +1142,7 @@ static int et61x251_init(struct et61x251_device* cam) } if (!(cam->state & DEV_INITIALIZED)) { - init_MUTEX(&cam->fileop_sem); + mutex_init(&cam->fileop_mutex); spin_lock_init(&cam->queue_lock); init_waitqueue_head(&cam->wait_frame); init_waitqueue_head(&cam->wait_stream); @@ -1161,13 +1160,15 @@ static int et61x251_init(struct et61x251_device* cam) static void et61x251_release_resources(struct et61x251_device* cam) { - down(&et61x251_sysfs_lock); + mutex_lock(&et61x251_sysfs_lock); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); - up(&et61x251_sysfs_lock); + usb_put_dev(cam->usbdev); + + mutex_unlock(&et61x251_sysfs_lock); kfree(cam->control_buffer); } @@ -1188,7 +1189,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) cam = video_get_drvdata(video_devdata(filp)); - if (down_interruptible(&cam->dev_sem)) { + if (mutex_lock_interruptible(&cam->dev_mutex)) { up_read(&et61x251_disconnect); return -ERESTARTSYS; } @@ -1200,7 +1201,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) err = -EWOULDBLOCK; goto out; } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); err = wait_event_interruptible_exclusive(cam->open, cam->state & DEV_DISCONNECTED || !cam->users); @@ -1212,7 +1213,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) up_read(&et61x251_disconnect); return -ENODEV; } - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); } @@ -1240,7 +1241,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); out: - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&et61x251_disconnect); return err; } @@ -1250,7 +1251,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) { struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - down(&cam->dev_sem); /* prevent disconnect() to be called */ + mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ et61x251_stop_transfer(cam); @@ -1258,7 +1259,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) if (cam->state & DEV_DISCONNECTED) { et61x251_release_resources(cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; } @@ -1268,7 +1269,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; } @@ -1281,28 +1282,29 @@ et61x251_read(struct file* filp, char __user * buf, struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); struct et61x251_frame_t* f, * i; unsigned long lock_flags; + long timeout; int err = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io == IO_MMAP) { DBG(3, "Close and open the device again to choose the read " "method"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1310,7 +1312,7 @@ et61x251_read(struct file* filp, char __user * buf, if (!et61x251_request_buffers(cam, cam->nreadbuffers, IO_READ)) { DBG(1, "read() failed, not enough memory"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENOMEM; } cam->io = IO_READ; @@ -1324,30 +1326,32 @@ et61x251_read(struct file* filp, char __user * buf, } if (!count) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return 0; } if (list_empty(&cam->outqueue)) { if (filp->f_flags & O_NONBLOCK) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) { - up(&cam->fileop_sem); - return err; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) { + mutex_unlock(&cam->fileop_mutex); + return timeout; } if (cam->state & DEV_DISCONNECTED) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } - if (cam->state & DEV_MISCONFIGURED) { - up(&cam->fileop_sem); + if (!timeout || (cam->state & DEV_MISCONFIGURED)) { + mutex_unlock(&cam->fileop_mutex); return -EIO; } } @@ -1375,7 +1379,7 @@ exit: PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index, count); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err ? err : count; } @@ -1388,7 +1392,7 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait) unsigned long lock_flags; unsigned int mask = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return POLLERR; if (cam->state & DEV_DISCONNECTED) { @@ -1426,12 +1430,12 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait) if (!list_empty(&cam->outqueue)) mask |= POLLIN | POLLRDNORM; - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return mask; error: - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return POLLERR; } @@ -1465,25 +1469,25 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) void *pos; u32 i; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(cam->frame[0].buf.length)) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1492,7 +1496,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) break; } if (i == cam->nbuffers) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1502,7 +1506,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) pos = cam->frame[i].bufmem; while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } start += PAGE_SIZE; @@ -1515,7 +1519,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) et61x251_vm_open(vma); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return 0; } @@ -1557,6 +1561,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) memset(&i, 0, sizeof(i)); strcpy(i.name, "Camera"); + i.type = V4L2_INPUT_TYPE_CAMERA; if (copy_to_user(arg, &i, sizeof(i))) return -EFAULT; @@ -1566,7 +1571,19 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) static int -et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg) +et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) +{ + int index = 0; + + if (copy_to_user(arg, &index, sizeof(index))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) { int index; @@ -1583,7 +1600,7 @@ et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_queryctrl qc; u8 i; @@ -1605,7 +1622,7 @@ et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_control ctrl; int err = 0; u8 i; @@ -1637,7 +1654,7 @@ exit: static int et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_control ctrl; u8 i; int err = 0; @@ -1650,6 +1667,8 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) if (ctrl.id == s->qctrl[i].id) { + if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) + return -EINVAL; if (ctrl.value < s->qctrl[i].minimum || ctrl.value > s->qctrl[i].maximum) return -ERANGE; @@ -1669,7 +1688,7 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) { - struct v4l2_cropcap* cc = &(cam->sensor->cropcap); + struct v4l2_cropcap* cc = &(cam->sensor.cropcap); cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cc->pixelaspect.numerator = 1; @@ -1685,7 +1704,7 @@ et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_crop crop = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, }; @@ -1702,7 +1721,7 @@ et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_crop crop; struct v4l2_rect* rect; struct v4l2_rect* bounds = &(s->cropcap.bounds); @@ -1843,7 +1862,7 @@ static int et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) { struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); + struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); if (copy_from_user(&format, arg, sizeof(format))) return -EFAULT; @@ -1868,7 +1887,7 @@ static int et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_format format; struct v4l2_pix_format* pix; struct v4l2_pix_format* pfmt = &(s->pix_format); @@ -2155,7 +2174,7 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, struct v4l2_buffer b; struct et61x251_frame_t *f; unsigned long lock_flags; - int err = 0; + long timeout; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; @@ -2168,16 +2187,18 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, return -EINVAL; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) - return err; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) + return timeout; if (cam->state & DEV_DISCONNECTED) return -ENODEV; - if (cam->state & DEV_MISCONFIGURED) + if (!timeout || (cam->state & DEV_MISCONFIGURED)) return -EIO; } @@ -2309,8 +2330,10 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, return et61x251_vidioc_enuminput(cam, arg); case VIDIOC_G_INPUT: + return et61x251_vidioc_g_input(cam, arg); + case VIDIOC_S_INPUT: - return et61x251_vidioc_gs_input(cam, arg); + return et61x251_vidioc_s_input(cam, arg); case VIDIOC_QUERYCTRL: return et61x251_vidioc_query_ctrl(cam, arg); @@ -2393,19 +2416,19 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp, struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); int err = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } @@ -2413,7 +2436,7 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp, err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err; } @@ -2459,7 +2482,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - init_MUTEX(&cam->dev_sem); + mutex_init(&cam->dev_mutex); DBG(2, "ET61X[12]51 PC Camera Controller detected " "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); @@ -2470,8 +2493,8 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) break; } - if (!err && cam->sensor) - DBG(2, "%s image sensor detected", cam->sensor->name); + if (!err) + DBG(2, "%s image sensor detected", cam->sensor.name); else { DBG(1, "No supported image sensor detected"); err = -ENODEV; @@ -2492,7 +2515,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); @@ -2502,13 +2525,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "Free /dev/videoX node not found"); video_nr[dev_nr] = -1; dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); goto fail; } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); cam->module_param.force_munmap = force_munmap[dev_nr]; + cam->module_param.frame_timeout = frame_timeout[dev_nr]; dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; @@ -2519,7 +2543,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) usb_set_intfdata(intf, cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; @@ -2543,7 +2567,7 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) down_write(&et61x251_disconnect); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); DBG(2, "Disconnecting %s...", cam->v4ldev->name); @@ -2557,13 +2581,14 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) et61x251_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); + usb_get_dev(cam->usbdev); } else { cam->state |= DEV_DISCONNECTED; et61x251_release_resources(cam); } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); if (!cam->users) kfree(cam); diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h index b9df91062f..56841ae8a2 100644 --- a/drivers/usb/media/et61x251_sensor.h +++ b/drivers/usb/media/et61x251_sensor.h @@ -42,6 +42,9 @@ static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ NULL, \ }; +extern struct et61x251_device* +et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); + extern void et61x251_attach_sensor(struct et61x251_device* cam, struct et61x251_sensor* sensor); @@ -105,8 +108,6 @@ struct et61x251_sensor { int (*set_pix_format)(struct et61x251_device* cam, const struct v4l2_pix_format* pix); - const struct usb_device* usbdev; - /* Private */ struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; struct v4l2_rect _rect; diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c index 65f1ae9cf2..3998d76a30 100644 --- a/drivers/usb/media/et61x251_tas5130d1b.c +++ b/drivers/usb/media/et61x251_tas5130d1b.c @@ -126,12 +126,16 @@ static struct et61x251_sensor tas5130d1b = { int et61x251_probe_tas5130d1b(struct et61x251_device* cam) { - /* This sensor has no identifiers, so let's attach it anyway */ - et61x251_attach_sensor(cam, &tas5130d1b); + const struct usb_device_id tas5130d1b_id_table[] = { + { USB_DEVICE(0x102c, 0x6251), }, + { } + }; /* Sensor detection is based on USB pid/vid */ - if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251) + if (!et61x251_match_id(cam, tas5130d1b_id_table)) return -ENODEV; + et61x251_attach_sensor(cam, &tas5130d1b); + return 0; }