Commit ff7e22df authored by Dean Anderson's avatar Dean Anderson Committed by Mauro Carvalho Chehab

V4L/DVB: s2255drv: cleanup of driver disconnect code

simplifies use of kref in driver
Signed-off-by: default avatarDean Anderson <dean@sensoray.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent f5e20c34
...@@ -226,7 +226,6 @@ struct s2255_fmt; /*forward declaration */ ...@@ -226,7 +226,6 @@ struct s2255_fmt; /*forward declaration */
struct s2255_dev { struct s2255_dev {
int frames; int frames;
int users[MAX_CHANNELS];
struct mutex lock; struct mutex lock;
struct mutex open_lock; struct mutex open_lock;
int resources[MAX_CHANNELS]; int resources[MAX_CHANNELS];
...@@ -367,7 +366,6 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, ...@@ -367,7 +366,6 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
struct s2255_mode *mode); struct s2255_mode *mode);
static int s2255_board_shutdown(struct s2255_dev *dev); static int s2255_board_shutdown(struct s2255_dev *dev);
static void s2255_exit_v4l(struct s2255_dev *dev);
static void s2255_fwload_start(struct s2255_dev *dev, int reset); static void s2255_fwload_start(struct s2255_dev *dev, int reset);
static void s2255_destroy(struct kref *kref); static void s2255_destroy(struct kref *kref);
static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
...@@ -606,7 +604,6 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize) ...@@ -606,7 +604,6 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
return 0; return 0;
} }
static const struct s2255_fmt *format_by_fourcc(int fourcc) static const struct s2255_fmt *format_by_fourcc(int fourcc)
{ {
unsigned int i; unsigned int i;
...@@ -620,9 +617,6 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc) ...@@ -620,9 +617,6 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
return NULL; return NULL;
} }
/* video buffer vmalloc implementation based partly on VIVI driver which is /* video buffer vmalloc implementation based partly on VIVI driver which is
* Copyright (c) 2006 by * Copyright (c) 2006 by
* Mauro Carvalho Chehab <mchehab--a.t--infradead.org> * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
...@@ -849,7 +843,6 @@ static int vidioc_querymenu(struct file *file, void *priv, ...@@ -849,7 +843,6 @@ static int vidioc_querymenu(struct file *file, void *priv,
return v4l2_ctrl_query_menu(qmenu, NULL, NULL); return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
} }
static int vidioc_querycap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap) struct v4l2_capability *cap)
{ {
...@@ -1759,31 +1752,26 @@ static int s2255_open(struct file *file) ...@@ -1759,31 +1752,26 @@ static int s2255_open(struct file *file)
int i = 0; int i = 0;
int cur_channel = -1; int cur_channel = -1;
int state; int state;
dprintk(1, "s2255: open called (dev=%s)\n", dprintk(1, "s2255: open called (dev=%s)\n",
video_device_node_name(vdev)); video_device_node_name(vdev));
lock_kernel(); lock_kernel();
for (i = 0; i < MAX_CHANNELS; i++)
for (i = 0; i < MAX_CHANNELS; i++) {
if (dev->vdev[i] == vdev) { if (dev->vdev[i] == vdev) {
cur_channel = i; cur_channel = i;
break; break;
} }
} /*
* open lock necessary to prevent multiple instances
if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) { * of v4l-conf (or other programs) from simultaneously
* reloading firmware.
*/
mutex_lock(&dev->open_lock);
state = atomic_read(&dev->fw_data->fw_state);
switch (state) {
case S2255_FW_DISCONNECTING:
mutex_unlock(&dev->open_lock);
unlock_kernel(); unlock_kernel();
printk(KERN_INFO "disconnecting\n");
return -ENODEV; return -ENODEV;
}
kref_get(&dev->kref);
mutex_lock(&dev->open_lock);
dev->users[cur_channel]++;
dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]);
switch (atomic_read(&dev->fw_data->fw_state)) {
case S2255_FW_FAILED: case S2255_FW_FAILED:
s2255_dev_err(&dev->udev->dev, s2255_dev_err(&dev->udev->dev,
"firmware load failed. retrying.\n"); "firmware load failed. retrying.\n");
...@@ -1794,6 +1782,8 @@ static int s2255_open(struct file *file) ...@@ -1794,6 +1782,8 @@ static int s2255_open(struct file *file)
(atomic_read(&dev->fw_data->fw_state) (atomic_read(&dev->fw_data->fw_state)
== S2255_FW_DISCONNECTING)), == S2255_FW_DISCONNECTING)),
msecs_to_jiffies(S2255_LOAD_TIMEOUT)); msecs_to_jiffies(S2255_LOAD_TIMEOUT));
/* state may have changed, re-read */
state = atomic_read(&dev->fw_data->fw_state);
break; break;
case S2255_FW_NOTLOADED: case S2255_FW_NOTLOADED:
case S2255_FW_LOADED_DSPWAIT: case S2255_FW_LOADED_DSPWAIT:
...@@ -1806,52 +1796,44 @@ static int s2255_open(struct file *file) ...@@ -1806,52 +1796,44 @@ static int s2255_open(struct file *file)
(atomic_read(&dev->fw_data->fw_state) (atomic_read(&dev->fw_data->fw_state)
== S2255_FW_DISCONNECTING)), == S2255_FW_DISCONNECTING)),
msecs_to_jiffies(S2255_LOAD_TIMEOUT)); msecs_to_jiffies(S2255_LOAD_TIMEOUT));
/* state may have changed, re-read */
state = atomic_read(&dev->fw_data->fw_state);
break; break;
case S2255_FW_SUCCESS: case S2255_FW_SUCCESS:
default: default:
break; break;
} }
state = atomic_read(&dev->fw_data->fw_state); mutex_unlock(&dev->open_lock);
if (state != S2255_FW_SUCCESS) { /* state may have changed in above switch statement */
int rc;
switch (state) { switch (state) {
case S2255_FW_FAILED: case S2255_FW_SUCCESS:
printk(KERN_INFO "2255 FW load failed. %d\n", state);
rc = -ENODEV;
break; break;
case S2255_FW_FAILED:
printk(KERN_INFO "2255 firmware load failed.\n");
unlock_kernel();
return -ENODEV;
case S2255_FW_DISCONNECTING: case S2255_FW_DISCONNECTING:
printk(KERN_INFO "%s: disconnecting\n", __func__); printk(KERN_INFO "%s: disconnecting\n", __func__);
rc = -ENODEV; unlock_kernel();
break; return -ENODEV;
case S2255_FW_LOADED_DSPWAIT: case S2255_FW_LOADED_DSPWAIT:
case S2255_FW_NOTLOADED: case S2255_FW_NOTLOADED:
printk(KERN_INFO "%s: firmware not loaded yet" printk(KERN_INFO "%s: firmware not loaded yet"
"please try again later\n", "please try again later\n",
__func__); __func__);
rc = -EAGAIN; unlock_kernel();
break; return -EAGAIN;
default: default:
printk(KERN_INFO "%s: unknown state\n", __func__); printk(KERN_INFO "%s: unknown state\n", __func__);
rc = -EFAULT;
break;
}
dev->users[cur_channel]--;
mutex_unlock(&dev->open_lock);
kref_put(&dev->kref, s2255_destroy);
unlock_kernel(); unlock_kernel();
return rc; return -EFAULT;
} }
/* allocate + initialize per filehandle data */ /* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL); fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh) { if (NULL == fh) {
dev->users[cur_channel]--;
mutex_unlock(&dev->open_lock);
kref_put(&dev->kref, s2255_destroy);
unlock_kernel(); unlock_kernel();
return -ENOMEM; return -ENOMEM;
} }
file->private_data = fh; file->private_data = fh;
fh->dev = dev; fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
...@@ -1866,9 +1848,8 @@ static int s2255_open(struct file *file) ...@@ -1866,9 +1848,8 @@ static int s2255_open(struct file *file)
s2255_set_mode(dev, cur_channel, &fh->mode); s2255_set_mode(dev, cur_channel, &fh->mode);
dev->chn_configured[cur_channel] = 1; dev->chn_configured[cur_channel] = 1;
} }
dprintk(1, "s2255drv: open dev=%s type=%s users=%d\n", dprintk(1, "s2255drv: open dev=%s type=%s\n",
video_device_node_name(vdev), v4l2_type_names[type], video_device_node_name(vdev), v4l2_type_names[type]);
dev->users[cur_channel]);
dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n",
(unsigned long)fh, (unsigned long)dev, (unsigned long)fh, (unsigned long)dev,
(unsigned long)&dev->vidq[cur_channel]); (unsigned long)&dev->vidq[cur_channel]);
...@@ -1880,8 +1861,6 @@ static int s2255_open(struct file *file) ...@@ -1880,8 +1861,6 @@ static int s2255_open(struct file *file)
fh->type, fh->type,
V4L2_FIELD_INTERLACED, V4L2_FIELD_INTERLACED,
sizeof(struct s2255_buffer), fh); sizeof(struct s2255_buffer), fh);
mutex_unlock(&dev->open_lock);
unlock_kernel(); unlock_kernel();
return 0; return 0;
} }
...@@ -1904,28 +1883,10 @@ static unsigned int s2255_poll(struct file *file, ...@@ -1904,28 +1883,10 @@ static unsigned int s2255_poll(struct file *file,
static void s2255_destroy(struct kref *kref) static void s2255_destroy(struct kref *kref)
{ {
struct s2255_dev *dev = to_s2255_dev(kref); struct s2255_dev *dev = to_s2255_dev(kref);
int i;
if (!dev) {
printk(KERN_ERR "s2255drv: kref problem\n");
return;
}
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
dev->setmode_ready[i] = 1;
wake_up(&dev->wait_setmode[i]);
dev->vidstatus_ready[i] = 1;
wake_up(&dev->wait_vidstatus[i]);
}
mutex_lock(&dev->open_lock);
/* reset the DSP so firmware can be reload next time */
s2255_reset_dsppower(dev);
s2255_exit_v4l(dev);
/* board shutdown stops the read pipe if it is running */ /* board shutdown stops the read pipe if it is running */
s2255_board_shutdown(dev); s2255_board_shutdown(dev);
/* make sure firmware still not trying to load */ /* make sure firmware still not trying to load */
del_timer(&dev->timer); /* only started in .probe and .open */ del_timer(&dev->timer); /* only started in .probe and .open */
if (dev->fw_data->fw_urb) { if (dev->fw_data->fw_urb) {
dprintk(2, "kill fw_urb\n"); dprintk(2, "kill fw_urb\n");
usb_kill_urb(dev->fw_data->fw_urb); usb_kill_urb(dev->fw_data->fw_urb);
...@@ -1936,24 +1897,22 @@ static void s2255_destroy(struct kref *kref) ...@@ -1936,24 +1897,22 @@ static void s2255_destroy(struct kref *kref)
release_firmware(dev->fw_data->fw); release_firmware(dev->fw_data->fw);
kfree(dev->fw_data->pfw_data); kfree(dev->fw_data->pfw_data);
kfree(dev->fw_data); kfree(dev->fw_data);
/* reset the DSP so firmware can be reloaded next time */
s2255_reset_dsppower(dev);
mutex_destroy(&dev->open_lock);
mutex_destroy(&dev->lock);
usb_put_dev(dev->udev); usb_put_dev(dev->udev);
dprintk(1, "%s", __func__); dprintk(1, "%s", __func__);
mutex_unlock(&dev->open_lock);
kfree(dev); kfree(dev);
} }
static int s2255_close(struct file *file) static int s2255_release(struct file *file)
{ {
struct s2255_fh *fh = file->private_data; struct s2255_fh *fh = file->private_data;
struct s2255_dev *dev = fh->dev; struct s2255_dev *dev = fh->dev;
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
mutex_lock(&dev->open_lock);
/* turn off stream */ /* turn off stream */
if (res_check(fh)) { if (res_check(fh)) {
if (dev->b_acquire[fh->channel]) if (dev->b_acquire[fh->channel])
...@@ -1961,15 +1920,8 @@ static int s2255_close(struct file *file) ...@@ -1961,15 +1920,8 @@ static int s2255_close(struct file *file)
videobuf_streamoff(&fh->vb_vidq); videobuf_streamoff(&fh->vb_vidq);
res_free(dev, fh); res_free(dev, fh);
} }
videobuf_mmap_free(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq);
dev->users[fh->channel]--; dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
mutex_unlock(&dev->open_lock);
kref_put(&dev->kref, s2255_destroy);
dprintk(1, "s2255: close called (dev=%s, users=%d)\n",
video_device_node_name(vdev), dev->users[fh->channel]);
kfree(fh); kfree(fh);
return 0; return 0;
} }
...@@ -1995,7 +1947,7 @@ static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma) ...@@ -1995,7 +1947,7 @@ static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
static const struct v4l2_file_operations s2255_fops_v4l = { static const struct v4l2_file_operations s2255_fops_v4l = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = s2255_open, .open = s2255_open,
.release = s2255_close, .release = s2255_release,
.poll = s2255_poll, .poll = s2255_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = s2255_mmap_v4l, .mmap = s2255_mmap_v4l,
...@@ -2031,11 +1983,19 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { ...@@ -2031,11 +1983,19 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
.vidioc_enum_frameintervals = vidioc_enum_frameintervals, .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
}; };
static void s2255_video_device_release(struct video_device *vdev)
{
struct s2255_dev *dev = video_get_drvdata(vdev);
video_device_release(vdev);
kref_put(&dev->kref, s2255_destroy);
return;
}
static struct video_device template = { static struct video_device template = {
.name = "s2255v", .name = "s2255v",
.fops = &s2255_fops_v4l, .fops = &s2255_fops_v4l,
.ioctl_ops = &s2255_ioctl_ops, .ioctl_ops = &s2255_ioctl_ops,
.release = video_device_release, .release = s2255_video_device_release,
.tvnorms = S2255_NORMS, .tvnorms = S2255_NORMS,
.current_norm = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M,
}; };
...@@ -2079,21 +2039,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) ...@@ -2079,21 +2039,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
return ret; return ret;
} }
static void s2255_exit_v4l(struct s2255_dev *dev)
{
int i;
for (i = 0; i < MAX_CHANNELS; i++) {
if (video_is_registered(dev->vdev[i])) {
video_unregister_device(dev->vdev[i]);
printk(KERN_INFO "s2255 unregistered\n");
} else {
video_device_release(dev->vdev[i]);
printk(KERN_INFO "s2255 released\n");
}
}
}
/* this function moves the usb stream read pipe data /* this function moves the usb stream read pipe data
* into the system buffers. * into the system buffers.
* returns 0 on success, EAGAIN if more data to process( call this * returns 0 on success, EAGAIN if more data to process( call this
...@@ -2408,9 +2353,7 @@ static int s2255_board_init(struct s2255_dev *dev) ...@@ -2408,9 +2353,7 @@ static int s2255_board_init(struct s2255_dev *dev)
dprintk(1, "out of memory!\n"); dprintk(1, "out of memory!\n");
return -ENOMEM; return -ENOMEM;
} }
} }
/* query the firmware */ /* query the firmware */
fw_ver = s2255_get_fx2fw(dev); fw_ver = s2255_get_fx2fw(dev);
...@@ -2447,7 +2390,6 @@ static int s2255_board_init(struct s2255_dev *dev) ...@@ -2447,7 +2390,6 @@ static int s2255_board_init(struct s2255_dev *dev)
static int s2255_board_shutdown(struct s2255_dev *dev) static int s2255_board_shutdown(struct s2255_dev *dev)
{ {
u32 i; u32 i;
dprintk(1, "S2255: board shutdown: %p", dev); dprintk(1, "S2255: board shutdown: %p", dev);
for (i = 0; i < MAX_CHANNELS; i++) { for (i = 0; i < MAX_CHANNELS; i++) {
...@@ -2640,7 +2582,6 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn) ...@@ -2640,7 +2582,6 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
static void s2255_stop_readpipe(struct s2255_dev *dev) static void s2255_stop_readpipe(struct s2255_dev *dev)
{ {
int j; int j;
if (dev == NULL) { if (dev == NULL) {
s2255_dev_err(&dev->udev->dev, "invalid device\n"); s2255_dev_err(&dev->udev->dev, "invalid device\n");
return; return;
...@@ -2654,7 +2595,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) ...@@ -2654,7 +2595,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
pipe_info->state = 0; pipe_info->state = 0;
} }
} }
for (j = 0; j < MAX_PIPE_BUFFERS; j++) { for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
struct s2255_pipeinfo *pipe_info = &dev->pipes[j]; struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
if (pipe_info->stream_urb) { if (pipe_info->stream_urb) {
...@@ -2703,24 +2643,22 @@ static int s2255_probe(struct usb_interface *interface, ...@@ -2703,24 +2643,22 @@ static int s2255_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
if (dev == NULL) { if (dev == NULL) {
s2255_dev_err(&interface->dev, "out of memory\n"); s2255_dev_err(&interface->dev, "out of memory\n");
goto error; return -ENOMEM;
} }
kref_init(&dev->kref);
dev->pid = id->idProduct; dev->pid = id->idProduct;
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data) if (!dev->fw_data)
goto error; goto errorFWDATA1;
mutex_init(&dev->lock); mutex_init(&dev->lock);
mutex_init(&dev->open_lock); mutex_init(&dev->open_lock);
/* grab usb_device and save it */ /* grab usb_device and save it */
dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->udev = usb_get_dev(interface_to_usbdev(interface));
if (dev->udev == NULL) { if (dev->udev == NULL) {
dev_err(&interface->dev, "null usb device\n"); dev_err(&interface->dev, "null usb device\n");
retval = -ENODEV; retval = -ENODEV;
goto error; goto errorUDEV;
} }
kref_init(&dev->kref);
dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref, dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref,
dev->udev, interface); dev->udev, interface);
dev->interface = interface; dev->interface = interface;
...@@ -2737,14 +2675,11 @@ static int s2255_probe(struct usb_interface *interface, ...@@ -2737,14 +2675,11 @@ static int s2255_probe(struct usb_interface *interface,
if (!dev->read_endpoint) { if (!dev->read_endpoint) {
dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
goto error; goto errorEP;
} }
/* set intfdata */ /* set intfdata */
usb_set_intfdata(interface, dev); usb_set_intfdata(interface, dev);
dprintk(100, "after intfdata %p\n", dev); dprintk(100, "after intfdata %p\n", dev);
init_timer(&dev->timer); init_timer(&dev->timer);
dev->timer.function = s2255_timer; dev->timer.function = s2255_timer;
dev->timer.data = (unsigned long)dev->fw_data; dev->timer.data = (unsigned long)dev->fw_data;
...@@ -2756,21 +2691,21 @@ static int s2255_probe(struct usb_interface *interface, ...@@ -2756,21 +2691,21 @@ static int s2255_probe(struct usb_interface *interface,
} }
dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->fw_data->fw_urb) { if (!dev->fw_data->fw_urb) {
dev_err(&interface->dev, "out of memory!\n"); dev_err(&interface->dev, "out of memory!\n");
goto error; goto errorFWURB;
} }
dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
if (!dev->fw_data->pfw_data) { if (!dev->fw_data->pfw_data) {
dev_err(&interface->dev, "out of memory!\n"); dev_err(&interface->dev, "out of memory!\n");
goto error; goto errorFWDATA2;
} }
/* load the first chunk */ /* load the first chunk */
if (request_firmware(&dev->fw_data->fw, if (request_firmware(&dev->fw_data->fw,
FIRMWARE_FILE_NAME, &dev->udev->dev)) { FIRMWARE_FILE_NAME, &dev->udev->dev)) {
printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
goto error; goto errorREQFW;
} }
/* check the firmware is valid */ /* check the firmware is valid */
fw_size = dev->fw_data->fw->size; fw_size = dev->fw_data->fw->size;
...@@ -2779,7 +2714,7 @@ static int s2255_probe(struct usb_interface *interface, ...@@ -2779,7 +2714,7 @@ static int s2255_probe(struct usb_interface *interface,
if (*pdata != S2255_FW_MARKER) { if (*pdata != S2255_FW_MARKER) {
printk(KERN_INFO "Firmware invalid.\n"); printk(KERN_INFO "Firmware invalid.\n");
retval = -ENODEV; retval = -ENODEV;
goto error; goto errorFWMARKER;
} else { } else {
/* make sure firmware is the latest */ /* make sure firmware is the latest */
__le32 *pRel; __le32 *pRel;
...@@ -2789,26 +2724,53 @@ static int s2255_probe(struct usb_interface *interface, ...@@ -2789,26 +2724,53 @@ static int s2255_probe(struct usb_interface *interface,
if (*pRel < S2255_CUR_DSP_FWVER) if (*pRel < S2255_CUR_DSP_FWVER)
printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER) if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
printk(KERN_WARNING "s2255: 2257 requires firmware 8 or above.\n"); printk(KERN_WARNING "s2255: 2257 requires firmware %d"
"or above.\n", S2255_MIN_DSP_COLORFILTER);
} }
/* loads v4l specific */
s2255_probe_v4l(dev);
usb_reset_device(dev->udev); usb_reset_device(dev->udev);
/* load 2255 board specific */ /* load 2255 board specific */
retval = s2255_board_init(dev); retval = s2255_board_init(dev);
if (retval) if (retval)
goto error; goto errorBOARDINIT;
dprintk(4, "before probe done %p\n", dev); dprintk(4, "before probe done %p\n", dev);
spin_lock_init(&dev->slock); spin_lock_init(&dev->slock);
s2255_fwload_start(dev, 0); s2255_fwload_start(dev, 0);
/* kref for each vdev. Released on video_device_release callback */
for (i = 0; i < MAX_CHANNELS; i++)
kref_get(&dev->kref);
/* loads v4l specific */
retval = s2255_probe_v4l(dev);
if (retval)
goto errorV4L;
dev_info(&interface->dev, "Sensoray 2255 detected\n"); dev_info(&interface->dev, "Sensoray 2255 detected\n");
return 0; return 0;
error: errorV4L:
for (i = 0; i < MAX_CHANNELS; i++)
if (dev->vdev[i] && video_is_registered(dev->vdev[i]))
video_unregister_device(dev->vdev[i]);
errorBOARDINIT:
s2255_board_shutdown(dev);
errorFWMARKER:
release_firmware(dev->fw_data->fw);
errorREQFW:
kfree(dev->fw_data->pfw_data);
errorFWDATA2:
usb_free_urb(dev->fw_data->fw_urb);
errorFWURB:
del_timer(&dev->timer);
errorEP:
usb_put_dev(dev->udev);
errorUDEV:
kfree(dev->fw_data);
mutex_destroy(&dev->open_lock);
mutex_destroy(&dev->lock);
errorFWDATA1:
kfree(dev);
printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
return retval; return retval;
} }
/* disconnect routine. when board is removed physically or with rmmod */ /* disconnect routine. when board is removed physically or with rmmod */
static void s2255_disconnect(struct usb_interface *interface) static void s2255_disconnect(struct usb_interface *interface)
{ {
...@@ -2816,11 +2778,11 @@ static void s2255_disconnect(struct usb_interface *interface) ...@@ -2816,11 +2778,11 @@ static void s2255_disconnect(struct usb_interface *interface)
int i; int i;
dprintk(1, "s2255: disconnect interface %p\n", interface); dprintk(1, "s2255: disconnect interface %p\n", interface);
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
/* unregister each video device. */
/* for (i = 0; i < MAX_CHANNELS; i++)
* wake up any of the timers to allow open_lock to be if (video_is_registered(dev->vdev[i]))
* acquired sooner video_unregister_device(dev->vdev[i]);
*/ /* wake up any of our timers */
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw); wake_up(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) { for (i = 0; i < MAX_CHANNELS; i++) {
...@@ -2829,16 +2791,9 @@ static void s2255_disconnect(struct usb_interface *interface) ...@@ -2829,16 +2791,9 @@ static void s2255_disconnect(struct usb_interface *interface)
dev->vidstatus_ready[i] = 1; dev->vidstatus_ready[i] = 1;
wake_up(&dev->wait_vidstatus[i]); wake_up(&dev->wait_vidstatus[i]);
} }
mutex_lock(&dev->open_lock);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
mutex_unlock(&dev->open_lock);
if (dev) {
kref_put(&dev->kref, s2255_destroy); kref_put(&dev->kref, s2255_destroy);
dprintk(1, "s2255drv: disconnect\n"); dev_info(&interface->dev, "%s\n", __func__);
dev_info(&interface->dev, "s2255usb now disconnected\n");
}
} }
static struct usb_driver s2255_driver = { static struct usb_driver s2255_driver = {
...@@ -2851,15 +2806,12 @@ static struct usb_driver s2255_driver = { ...@@ -2851,15 +2806,12 @@ static struct usb_driver s2255_driver = {
static int __init usb_s2255_init(void) static int __init usb_s2255_init(void)
{ {
int result; int result;
/* register this driver with the USB subsystem */ /* register this driver with the USB subsystem */
result = usb_register(&s2255_driver); result = usb_register(&s2255_driver);
if (result) if (result)
pr_err(KBUILD_MODNAME pr_err(KBUILD_MODNAME
": usb_register failed. Error number %d\n", result); ": usb_register failed. Error number %d\n", result);
dprintk(2, "%s\n", __func__);
dprintk(2, "s2255_init: done\n");
return result; return result;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment