diff options
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-video.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 124 |
1 files changed, 73 insertions, 51 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index b43edc3fa23e..5b17ca9cad11 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -234,6 +234,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
234 | int minor = iminor(inode); | 234 | int minor = iminor(inode); |
235 | int errCode = 0; | 235 | int errCode = 0; |
236 | struct em28xx *h,*dev = NULL; | 236 | struct em28xx *h,*dev = NULL; |
237 | struct em28xx_fh *fh; | ||
237 | 238 | ||
238 | list_for_each_entry(h, &em28xx_devlist, devlist) { | 239 | list_for_each_entry(h, &em28xx_devlist, devlist) { |
239 | if (h->vdev->minor == minor) { | 240 | if (h->vdev->minor == minor) { |
@@ -251,19 +252,17 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
251 | em28xx_videodbg("open minor=%d type=%s users=%d\n", | 252 | em28xx_videodbg("open minor=%d type=%s users=%d\n", |
252 | minor,v4l2_type_names[dev->type],dev->users); | 253 | minor,v4l2_type_names[dev->type],dev->users); |
253 | 254 | ||
254 | mutex_lock(&dev->lock); | 255 | fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); |
255 | 256 | ||
256 | if (dev->users) { | 257 | if (!fh) { |
257 | em28xx_warn("this driver can be opened only once\n"); | 258 | em28xx_errdev("em28xx-video.c: Out of memory?!\n"); |
258 | mutex_unlock(&dev->lock); | 259 | return -ENOMEM; |
259 | return -EBUSY; | ||
260 | } | 260 | } |
261 | mutex_lock(&dev->lock); | ||
262 | fh->dev = dev; | ||
263 | filp->private_data = fh; | ||
261 | 264 | ||
262 | spin_lock_init(&dev->queue_lock); | 265 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { |
263 | init_waitqueue_head(&dev->wait_frame); | ||
264 | init_waitqueue_head(&dev->wait_stream); | ||
265 | |||
266 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
267 | em28xx_set_alternate(dev); | 266 | em28xx_set_alternate(dev); |
268 | 267 | ||
269 | dev->width = norm_maxw(dev); | 268 | dev->width = norm_maxw(dev); |
@@ -277,26 +276,16 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
277 | em28xx_capture_start(dev, 1); | 276 | em28xx_capture_start(dev, 1); |
278 | em28xx_resolution_set(dev); | 277 | em28xx_resolution_set(dev); |
279 | 278 | ||
280 | /* device needs to be initialized before isoc transfer */ | ||
281 | video_mux(dev, 0); | ||
282 | 279 | ||
283 | /* start the transfer */ | 280 | /* start the transfer */ |
284 | errCode = em28xx_init_isoc(dev); | 281 | errCode = em28xx_init_isoc(dev); |
285 | if (errCode) | 282 | if (errCode) |
286 | goto err; | 283 | goto err; |
287 | 284 | ||
285 | em28xx_empty_framequeues(dev); | ||
288 | } | 286 | } |
289 | 287 | ||
290 | dev->users++; | 288 | dev->users++; |
291 | filp->private_data = dev; | ||
292 | dev->io = IO_NONE; | ||
293 | dev->stream = STREAM_OFF; | ||
294 | dev->num_frames = 0; | ||
295 | |||
296 | /* prepare queues */ | ||
297 | em28xx_empty_framequeues(dev); | ||
298 | |||
299 | dev->state |= DEV_INITIALIZED; | ||
300 | 289 | ||
301 | err: | 290 | err: |
302 | mutex_unlock(&dev->lock); | 291 | mutex_unlock(&dev->lock); |
@@ -333,34 +322,41 @@ static void em28xx_release_resources(struct em28xx *dev) | |||
333 | */ | 322 | */ |
334 | static int em28xx_v4l2_close(struct inode *inode, struct file *filp) | 323 | static int em28xx_v4l2_close(struct inode *inode, struct file *filp) |
335 | { | 324 | { |
336 | int errCode; | 325 | struct em28xx_fh *fh = filp->private_data; |
337 | struct em28xx *dev=filp->private_data; | 326 | struct em28xx *dev = fh->dev; |
327 | int errCode; | ||
338 | 328 | ||
339 | em28xx_videodbg("users=%d\n", dev->users); | 329 | em28xx_videodbg("users=%d\n", dev->users); |
340 | 330 | ||
341 | mutex_lock(&dev->lock); | 331 | mutex_lock(&dev->lock); |
332 | if (fh->reader == 1) | ||
333 | fh->reader = 0; | ||
342 | 334 | ||
343 | em28xx_uninit_isoc(dev); | 335 | if (dev->users == 1) { |
336 | dev->reader = 0; | ||
344 | 337 | ||
345 | em28xx_release_buffers(dev); | 338 | em28xx_uninit_isoc(dev); |
339 | em28xx_release_buffers(dev); | ||
346 | 340 | ||
347 | /* the device is already disconnect, free the remaining resources */ | 341 | /* the device is already disconnect, |
348 | if (dev->state & DEV_DISCONNECTED) { | 342 | free the remaining resources */ |
349 | em28xx_release_resources(dev); | 343 | if (dev->state & DEV_DISCONNECTED) { |
350 | mutex_unlock(&dev->lock); | 344 | em28xx_release_resources(dev); |
351 | kfree(dev); | 345 | mutex_unlock(&dev->lock); |
352 | return 0; | 346 | kfree(dev); |
353 | } | 347 | return 0; |
348 | } | ||
354 | 349 | ||
355 | /* set alternate 0 */ | 350 | /* set alternate 0 */ |
356 | dev->alt = 0; | 351 | dev->alt = 0; |
357 | em28xx_videodbg("setting alternate 0\n"); | 352 | em28xx_videodbg("setting alternate 0\n"); |
358 | errCode = usb_set_interface(dev->udev, 0, 0); | 353 | errCode = usb_set_interface(dev->udev, 0, 0); |
359 | if (errCode < 0) { | 354 | if (errCode < 0) { |
360 | em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n", | 355 | em28xx_errdev("cannot change alternate number to " |
361 | errCode); | 356 | "0 (error=%i)\n", errCode); |
357 | } | ||
362 | } | 358 | } |
363 | 359 | kfree(fh); | |
364 | dev->users--; | 360 | dev->users--; |
365 | wake_up_interruptible_nr(&dev->open, 1); | 361 | wake_up_interruptible_nr(&dev->open, 1); |
366 | mutex_unlock(&dev->lock); | 362 | mutex_unlock(&dev->lock); |
@@ -378,13 +374,19 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
378 | struct em28xx_frame_t *f, *i; | 374 | struct em28xx_frame_t *f, *i; |
379 | unsigned long lock_flags; | 375 | unsigned long lock_flags; |
380 | int ret = 0; | 376 | int ret = 0; |
381 | struct em28xx *dev = filp->private_data; | 377 | struct em28xx_fh *fh = filp->private_data; |
378 | struct em28xx *dev = fh->dev; | ||
382 | 379 | ||
383 | mutex_lock(&dev->lock); | 380 | mutex_lock(&dev->lock); |
384 | 381 | ||
385 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 382 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
386 | em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); | 383 | em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); |
384 | |||
385 | if (dev->reader > 0 && fh->reader == 0) { | ||
386 | mutex_unlock(&dev->lock); | ||
387 | return -EBUSY; | ||
387 | } | 388 | } |
389 | |||
388 | if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 390 | if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
389 | em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); | 391 | em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); |
390 | em28xx_videodbg("not supported yet! ...\n"); | 392 | em28xx_videodbg("not supported yet! ...\n"); |
@@ -423,6 +425,9 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
423 | " the device again to choose the read method\n"); | 425 | " the device again to choose the read method\n"); |
424 | mutex_unlock(&dev->lock); | 426 | mutex_unlock(&dev->lock); |
425 | return -EINVAL; | 427 | return -EINVAL; |
428 | } else { | ||
429 | dev->reader = 1; | ||
430 | fh->reader = 1; | ||
426 | } | 431 | } |
427 | 432 | ||
428 | if (dev->io == IO_NONE) { | 433 | if (dev->io == IO_NONE) { |
@@ -491,7 +496,8 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
491 | static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) | 496 | static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) |
492 | { | 497 | { |
493 | unsigned int mask = 0; | 498 | unsigned int mask = 0; |
494 | struct em28xx *dev = filp->private_data; | 499 | struct em28xx_fh *fh = filp->private_data; |
500 | struct em28xx *dev = fh->dev; | ||
495 | 501 | ||
496 | mutex_lock(&dev->lock); | 502 | mutex_lock(&dev->lock); |
497 | 503 | ||
@@ -559,15 +565,23 @@ static struct vm_operations_struct em28xx_vm_ops = { | |||
559 | */ | 565 | */ |
560 | static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | 566 | static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) |
561 | { | 567 | { |
562 | unsigned long size = vma->vm_end - vma->vm_start, | 568 | struct em28xx_fh *fh = filp->private_data; |
563 | start = vma->vm_start; | 569 | struct em28xx *dev = fh->dev; |
564 | void *pos; | 570 | unsigned long size = vma->vm_end - vma->vm_start; |
565 | u32 i; | 571 | unsigned long start = vma->vm_start; |
566 | 572 | void *pos; | |
567 | struct em28xx *dev = filp->private_data; | 573 | u32 i; |
568 | 574 | ||
569 | mutex_lock(&dev->lock); | 575 | mutex_lock(&dev->lock); |
570 | 576 | ||
577 | if (dev->reader > 0 && fh->reader == 0) { | ||
578 | mutex_unlock(&dev->lock); | ||
579 | return -EBUSY; | ||
580 | } else { | ||
581 | dev->reader = 1; | ||
582 | fh->reader = 1; | ||
583 | } | ||
584 | |||
571 | if (dev->state & DEV_DISCONNECTED) { | 585 | if (dev->state & DEV_DISCONNECTED) { |
572 | em28xx_videodbg("mmap: device not present\n"); | 586 | em28xx_videodbg("mmap: device not present\n"); |
573 | mutex_unlock(&dev->lock); | 587 | mutex_unlock(&dev->lock); |
@@ -918,6 +932,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
918 | struct em28xx *dev, unsigned int cmd, void *arg, | 932 | struct em28xx *dev, unsigned int cmd, void *arg, |
919 | v4l2_kioctl driver_ioctl) | 933 | v4l2_kioctl driver_ioctl) |
920 | { | 934 | { |
935 | struct em28xx_fh *fh = filp->private_data; | ||
921 | int ret; | 936 | int ret; |
922 | 937 | ||
923 | switch (cmd) { | 938 | switch (cmd) { |
@@ -1227,6 +1242,8 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1227 | return ret; | 1242 | return ret; |
1228 | } | 1243 | } |
1229 | } | 1244 | } |
1245 | |||
1246 | fh->reader = 0; | ||
1230 | em28xx_empty_framequeues(dev); | 1247 | em28xx_empty_framequeues(dev); |
1231 | mutex_unlock(&dev->lock); | 1248 | mutex_unlock(&dev->lock); |
1232 | 1249 | ||
@@ -1248,7 +1265,8 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1248 | static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, | 1265 | static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, |
1249 | unsigned int cmd, void *arg) | 1266 | unsigned int cmd, void *arg) |
1250 | { | 1267 | { |
1251 | struct em28xx *dev = filp->private_data; | 1268 | struct em28xx_fh *fh = filp->private_data; |
1269 | struct em28xx *dev = fh->dev; | ||
1252 | 1270 | ||
1253 | if (!dev) | 1271 | if (!dev) |
1254 | return -ENODEV; | 1272 | return -ENODEV; |
@@ -1456,7 +1474,8 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, | |||
1456 | unsigned int cmd, unsigned long arg) | 1474 | unsigned int cmd, unsigned long arg) |
1457 | { | 1475 | { |
1458 | int ret = 0; | 1476 | int ret = 0; |
1459 | struct em28xx *dev = filp->private_data; | 1477 | struct em28xx_fh *fh = filp->private_data; |
1478 | struct em28xx *dev = fh->dev; | ||
1460 | 1479 | ||
1461 | if (dev->state & DEV_DISCONNECTED) { | 1480 | if (dev->state & DEV_DISCONNECTED) { |
1462 | em28xx_errdev("v4l2 ioctl: device not present\n"); | 1481 | em28xx_errdev("v4l2 ioctl: device not present\n"); |
@@ -1503,7 +1522,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1503 | 1522 | ||
1504 | dev->udev = udev; | 1523 | dev->udev = udev; |
1505 | mutex_init(&dev->lock); | 1524 | mutex_init(&dev->lock); |
1525 | spin_lock_init(&dev->queue_lock); | ||
1506 | init_waitqueue_head(&dev->open); | 1526 | init_waitqueue_head(&dev->open); |
1527 | init_waitqueue_head(&dev->wait_frame); | ||
1528 | init_waitqueue_head(&dev->wait_stream); | ||
1507 | 1529 | ||
1508 | dev->em28xx_write_regs = em28xx_write_regs; | 1530 | dev->em28xx_write_regs = em28xx_write_regs; |
1509 | dev->em28xx_read_reg = em28xx_read_reg; | 1531 | dev->em28xx_read_reg = em28xx_read_reg; |