Commit ae59dad4 authored by Mike Thomas's avatar Mike Thomas Committed by Greg Kroah-Hartman

staging/easycap: Eliminate BKL

No locking is required for normal operation of the driver, but locking
is needed to prevent an Oops during some hot-unplugging scenarios.  The
BKL is replaced here by mutex locks together with traps to detect null
pointers following asynchronous device disconnection.
Signed-off-by: default avatarMike Thomas <rmthomas@sciolus.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2a87a0b9
config EASYCAP config EASYCAP
tristate "EasyCAP USB ID 05e1:0408 support" tristate "EasyCAP USB ID 05e1:0408 support"
depends on USB && VIDEO_DEV depends on USB && VIDEO_DEV
depends on BKL # please fix
---help--- ---help---
This is an integrated audio/video driver for EasyCAP cards with This is an integrated audio/video driver for EasyCAP cards with
......
...@@ -10,4 +10,5 @@ ccflags-y := -Wall ...@@ -10,4 +10,5 @@ ccflags-y := -Wall
ccflags-y += -DEASYCAP_IS_VIDEODEV_CLIENT ccflags-y += -DEASYCAP_IS_VIDEODEV_CLIENT
ccflags-y += -DEASYCAP_NEEDS_V4L2_DEVICE_H ccflags-y += -DEASYCAP_NEEDS_V4L2_DEVICE_H
ccflags-y += -DEASYCAP_NEEDS_V4L2_FOPS ccflags-y += -DEASYCAP_NEEDS_V4L2_FOPS
ccflags-y += -DEASYCAP_NEEDS_UNLOCKED_IOCTL
...@@ -251,6 +251,12 @@ INTERLACE_MANY ...@@ -251,6 +251,12 @@ INTERLACE_MANY
* STRUCTURE DEFINITIONS * STRUCTURE DEFINITIONS
*/ */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
struct easycap_dongle {
struct easycap *peasycap;
struct mutex mutex_video;
struct mutex mutex_audio;
};
/*---------------------------------------------------------------------------*/
struct data_buffer { struct data_buffer {
struct list_head list_head; struct list_head list_head;
void *pgo; void *pgo;
...@@ -491,7 +497,10 @@ struct data_buffer audio_buffer[]; ...@@ -491,7 +497,10 @@ struct data_buffer audio_buffer[];
void easycap_complete(struct urb *); void easycap_complete(struct urb *);
int easycap_open(struct inode *, struct file *); int easycap_open(struct inode *, struct file *);
int easycap_release(struct inode *, struct file *); int easycap_release(struct inode *, struct file *);
long easycap_ioctl(struct file *, unsigned int, unsigned long); long easycap_ioctl_noinode(struct file *, unsigned int, \
unsigned long);
int easycap_ioctl(struct inode *, struct file *, unsigned int, \
unsigned long);
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT) #if defined(EASYCAP_IS_VIDEODEV_CLIENT)
...@@ -538,7 +547,10 @@ void easysnd_complete(struct urb *); ...@@ -538,7 +547,10 @@ void easysnd_complete(struct urb *);
ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *); ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *);
int easysnd_open(struct inode *, struct file *); int easysnd_open(struct inode *, struct file *);
int easysnd_release(struct inode *, struct file *); int easysnd_release(struct inode *, struct file *);
long easysnd_ioctl(struct file *, unsigned int, unsigned long); long easysnd_ioctl_noinode(struct file *, unsigned int, \
unsigned long);
int easysnd_ioctl(struct inode *, struct file *, unsigned int, \
unsigned long);
unsigned int easysnd_poll(struct file *, poll_table *); unsigned int easysnd_poll(struct file *, poll_table *);
void easysnd_delete(struct kref *); void easysnd_delete(struct kref *);
int submit_audio_urbs(struct easycap *); int submit_audio_urbs(struct easycap *);
......
...@@ -26,3 +26,4 @@ ...@@ -26,3 +26,4 @@
/*****************************************************************************/ /*****************************************************************************/
extern int debug; extern int debug;
extern int gain; extern int gain;
extern struct easycap_dongle easycap_dongle[];
This diff is collapsed.
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
*/ */
/****************************************************************************/ /****************************************************************************/
#include "easycap_debug.h"
#include "easycap.h" #include "easycap.h"
#include "easycap_debug.h"
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
const struct stk1160config { int reg; int set; } stk1160configPAL[256] = { const struct stk1160config { int reg; int set; } stk1160configPAL[256] = {
...@@ -248,6 +248,9 @@ int ...@@ -248,6 +248,9 @@ int
confirm_resolution(struct usb_device *p) confirm_resolution(struct usb_device *p)
{ {
__u8 get0, get1, get2, get3, get4, get5, get6, get7; __u8 get0, get1, get2, get3, get4, get5, get6, get7;
if (NULL == p)
return -ENODEV;
GET(p, 0x0110, &get0); GET(p, 0x0110, &get0);
GET(p, 0x0111, &get1); GET(p, 0x0111, &get1);
GET(p, 0x0112, &get2); GET(p, 0x0112, &get2);
...@@ -288,6 +291,8 @@ confirm_stream(struct usb_device *p) ...@@ -288,6 +291,8 @@ confirm_stream(struct usb_device *p)
__u16 get2; __u16 get2;
__u8 igot; __u8 igot;
if (NULL == p)
return -ENODEV;
GET(p, 0x0100, &igot); get2 = 0x80 & igot; GET(p, 0x0100, &igot); get2 = 0x80 & igot;
if (0x80 == get2) if (0x80 == get2)
JOT(8, "confirm_stream: OK\n"); JOT(8, "confirm_stream: OK\n");
...@@ -301,6 +306,8 @@ setup_stk(struct usb_device *p, bool ntsc) ...@@ -301,6 +306,8 @@ setup_stk(struct usb_device *p, bool ntsc)
{ {
int i0; int i0;
if (NULL == p)
return -ENODEV;
i0 = 0; i0 = 0;
if (true == ntsc) { if (true == ntsc) {
while (0xFFF != stk1160configNTSC[i0].reg) { while (0xFFF != stk1160configNTSC[i0].reg) {
...@@ -324,6 +331,8 @@ setup_saa(struct usb_device *p, bool ntsc) ...@@ -324,6 +331,8 @@ setup_saa(struct usb_device *p, bool ntsc)
{ {
int i0, ir; int i0, ir;
if (NULL == p)
return -ENODEV;
i0 = 0; i0 = 0;
if (true == ntsc) { if (true == ntsc) {
while (0xFF != saa7113configNTSC[i0].reg) { while (0xFF != saa7113configNTSC[i0].reg) {
...@@ -346,6 +355,8 @@ write_000(struct usb_device *p, __u16 set2, __u16 set0) ...@@ -346,6 +355,8 @@ write_000(struct usb_device *p, __u16 set2, __u16 set0)
{ {
__u8 igot0, igot2; __u8 igot0, igot2;
if (NULL == p)
return -ENODEV;
GET(p, 0x0002, &igot2); GET(p, 0x0002, &igot2);
GET(p, 0x0000, &igot0); GET(p, 0x0000, &igot0);
SET(p, 0x0002, set2); SET(p, 0x0002, set2);
...@@ -356,6 +367,8 @@ return 0; ...@@ -356,6 +367,8 @@ return 0;
int int
write_saa(struct usb_device *p, __u16 reg0, __u16 set0) write_saa(struct usb_device *p, __u16 reg0, __u16 set0)
{ {
if (NULL == p)
return -ENODEV;
SET(p, 0x200, 0x00); SET(p, 0x200, 0x00);
SET(p, 0x204, reg0); SET(p, 0x204, reg0);
SET(p, 0x205, set0); SET(p, 0x205, set0);
...@@ -379,6 +392,8 @@ __u8 igot; ...@@ -379,6 +392,8 @@ __u8 igot;
__u16 got502, got503; __u16 got502, got503;
__u16 set502, set503; __u16 set502, set503;
if (NULL == p)
return -ENODEV;
SET(p, 0x0504, reg0); SET(p, 0x0504, reg0);
SET(p, 0x0500, 0x008B); SET(p, 0x0500, 0x008B);
...@@ -414,6 +429,8 @@ read_vt(struct usb_device *p, __u16 reg0) ...@@ -414,6 +429,8 @@ read_vt(struct usb_device *p, __u16 reg0)
__u8 igot; __u8 igot;
__u16 got502, got503; __u16 got502, got503;
if (NULL == p)
return -ENODEV;
SET(p, 0x0504, reg0); SET(p, 0x0504, reg0);
SET(p, 0x0500, 0x008B); SET(p, 0x0500, 0x008B);
...@@ -433,6 +450,8 @@ return (got503 << 8) | got502; ...@@ -433,6 +450,8 @@ return (got503 << 8) | got502;
int int
write_300(struct usb_device *p) write_300(struct usb_device *p)
{ {
if (NULL == p)
return -ENODEV;
SET(p, 0x300, 0x0012); SET(p, 0x300, 0x0012);
SET(p, 0x350, 0x002D); SET(p, 0x350, 0x002D);
SET(p, 0x351, 0x0001); SET(p, 0x351, 0x0001);
...@@ -453,6 +472,8 @@ check_saa(struct usb_device *p, bool ntsc) ...@@ -453,6 +472,8 @@ check_saa(struct usb_device *p, bool ntsc)
{ {
int i0, ir, rc; int i0, ir, rc;
if (NULL == p)
return -ENODEV;
i0 = 0; i0 = 0;
rc = 0; rc = 0;
if (true == ntsc) { if (true == ntsc) {
...@@ -501,6 +522,8 @@ merit_saa(struct usb_device *p) ...@@ -501,6 +522,8 @@ merit_saa(struct usb_device *p)
{ {
int rc; int rc;
if (NULL == p)
return -ENODEV;
rc = read_saa(p, 0x1F); rc = read_saa(p, 0x1F);
if ((0 > rc) || (0x02 & rc)) if ((0 > rc) || (0x02 & rc))
return 1 ; return 1 ;
...@@ -521,6 +544,8 @@ const int max = 5, marktime = PATIENCE/5; ...@@ -521,6 +544,8 @@ const int max = 5, marktime = PATIENCE/5;
* 3 FOR NON-INTERLACED 60 Hz * 3 FOR NON-INTERLACED 60 Hz
*/ */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
if (NULL == p)
return -ENODEV;
j = 0; j = 0;
while (max > j) { while (max > j) {
rc = read_saa(p, 0x1F); rc = read_saa(p, 0x1F);
...@@ -565,6 +590,8 @@ check_stk(struct usb_device *p, bool ntsc) ...@@ -565,6 +590,8 @@ check_stk(struct usb_device *p, bool ntsc)
{ {
int i0, ir; int i0, ir;
if (NULL == p)
return -ENODEV;
i0 = 0; i0 = 0;
if (true == ntsc) { if (true == ntsc) {
while (0xFFF != stk1160configNTSC[i0].reg) { while (0xFFF != stk1160configNTSC[i0].reg) {
...@@ -637,6 +664,8 @@ read_saa(struct usb_device *p, __u16 reg0) ...@@ -637,6 +664,8 @@ read_saa(struct usb_device *p, __u16 reg0)
{ {
__u8 igot; __u8 igot;
if (NULL == p)
return -ENODEV;
SET(p, 0x208, reg0); SET(p, 0x208, reg0);
SET(p, 0x200, 0x20); SET(p, 0x200, 0x20);
if (0 != wait_i2c(p)) if (0 != wait_i2c(p))
...@@ -651,6 +680,8 @@ read_stk(struct usb_device *p, __u32 reg0) ...@@ -651,6 +680,8 @@ read_stk(struct usb_device *p, __u32 reg0)
{ {
__u8 igot; __u8 igot;
if (NULL == p)
return -ENODEV;
igot = 0; igot = 0;
GET(p, reg0, &igot); GET(p, reg0, &igot);
return igot; return igot;
...@@ -679,6 +710,8 @@ select_input(struct usb_device *p, int input, int mode) ...@@ -679,6 +710,8 @@ select_input(struct usb_device *p, int input, int mode)
{ {
int ir; int ir;
if (NULL == p)
return -ENODEV;
stop_100(p); stop_100(p);
switch (input) { switch (input) {
case 0: case 0:
...@@ -781,6 +814,8 @@ set_resolution(struct usb_device *p, \ ...@@ -781,6 +814,8 @@ set_resolution(struct usb_device *p, \
{ {
__u16 u0x0111, u0x0113, u0x0115, u0x0117; __u16 u0x0111, u0x0113, u0x0115, u0x0117;
if (NULL == p)
return -ENODEV;
u0x0111 = ((0xFF00 & set0) >> 8); u0x0111 = ((0xFF00 & set0) >> 8);
u0x0113 = ((0xFF00 & set1) >> 8); u0x0113 = ((0xFF00 & set1) >> 8);
u0x0115 = ((0xFF00 & set2) >> 8); u0x0115 = ((0xFF00 & set2) >> 8);
...@@ -804,6 +839,8 @@ start_100(struct usb_device *p) ...@@ -804,6 +839,8 @@ start_100(struct usb_device *p)
__u16 get116, get117, get0; __u16 get116, get117, get0;
__u8 igot116, igot117, igot; __u8 igot116, igot117, igot;
if (NULL == p)
return -ENODEV;
GET(p, 0x0116, &igot116); GET(p, 0x0116, &igot116);
get116 = igot116; get116 = igot116;
GET(p, 0x0117, &igot117); GET(p, 0x0117, &igot117);
...@@ -827,6 +864,8 @@ stop_100(struct usb_device *p) ...@@ -827,6 +864,8 @@ stop_100(struct usb_device *p)
__u16 get0; __u16 get0;
__u8 igot; __u8 igot;
if (NULL == p)
return -ENODEV;
GET(p, 0x0100, &igot); GET(p, 0x0100, &igot);
get0 = igot; get0 = igot;
SET(p, 0x0100, (0x7F & get0)); SET(p, 0x0100, (0x7F & get0));
...@@ -846,6 +885,8 @@ __u8 igot; ...@@ -846,6 +885,8 @@ __u8 igot;
const int max = 2; const int max = 2;
int k; int k;
if (NULL == p)
return -ENODEV;
for (k = 0; k < max; k++) { for (k = 0; k < max; k++) {
GET(p, 0x0201, &igot); get0 = igot; GET(p, 0x0201, &igot); get0 = igot;
switch (get0) { switch (get0) {
...@@ -872,8 +913,7 @@ __u16 igot; ...@@ -872,8 +913,7 @@ __u16 igot;
int rc0, rc1; int rc0, rc1;
if (!pusb_device) if (!pusb_device)
return -EFAULT; return -ENODEV;
rc1 = 0; igot = 0; rc1 = 0; igot = 0;
rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(__u8)0x01, \ (__u8)0x01, \
...@@ -936,8 +976,7 @@ regget(struct usb_device *pusb_device, __u16 index, void *pvoid) ...@@ -936,8 +976,7 @@ regget(struct usb_device *pusb_device, __u16 index, void *pvoid)
int ir; int ir;
if (!pusb_device) if (!pusb_device)
return -EFAULT; return -ENODEV;
ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \ ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
(__u8)0x00, \ (__u8)0x00, \
(__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \ (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
...@@ -952,6 +991,8 @@ return 0xFF & ir; ...@@ -952,6 +991,8 @@ return 0xFF & ir;
int int
wakeup_device(struct usb_device *pusb_device) wakeup_device(struct usb_device *pusb_device)
{ {
if (!pusb_device)
return -ENODEV;
return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(__u8)USB_REQ_SET_FEATURE, \ (__u8)USB_REQ_SET_FEATURE, \
(__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \ (__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \
...@@ -1056,6 +1097,8 @@ check_vt(struct usb_device *pusb_device) ...@@ -1056,6 +1097,8 @@ check_vt(struct usb_device *pusb_device)
{ {
int igot; int igot;
if (!pusb_device)
return -ENODEV;
igot = read_vt(pusb_device, 0x0002); igot = read_vt(pusb_device, 0x0002);
if (0 > igot) if (0 > igot)
SAY("ERROR: failed to read VT1612A register 0x02\n"); SAY("ERROR: failed to read VT1612A register 0x02\n");
...@@ -1128,7 +1171,7 @@ int igot; ...@@ -1128,7 +1171,7 @@ int igot;
__u8 u8; __u8 u8;
__u16 mute; __u16 mute;
if ((struct usb_device *)NULL == pusb_device) if (NULL == pusb_device)
return -ENODEV; return -ENODEV;
if (0 > loud) if (0 > loud)
loud = 0; loud = 0;
......
This diff is collapsed.
...@@ -636,7 +636,7 @@ else ...@@ -636,7 +636,7 @@ else
if ((struct usb_device *)NULL == peasycap->pusb_device) { if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device has become NULL\n"); SAM("ERROR: peasycap->pusb_device has become NULL\n");
return -EFAULT; return -ENODEV;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
if ((struct usb_device *)NULL == peasycap->pusb_device) { if ((struct usb_device *)NULL == peasycap->pusb_device) {
...@@ -695,7 +695,7 @@ long long int above, below, mean; ...@@ -695,7 +695,7 @@ long long int above, below, mean;
struct signed_div_result sdr; struct signed_div_result sdr;
unsigned char *p0; unsigned char *p0;
long int kount1, more, rc, l0, lm; long int kount1, more, rc, l0, lm;
int fragment; int fragment, kd;
struct easycap *peasycap; struct easycap *peasycap;
struct data_buffer *pdata_buffer; struct data_buffer *pdata_buffer;
size_t szret; size_t szret;
...@@ -713,20 +713,76 @@ size_t szret; ...@@ -713,20 +713,76 @@ size_t szret;
JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff)); JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
peasycap = (struct easycap *)(file->private_data); if (NULL == file) {
SAY("ERROR: file is NULL\n");
return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) { if (NULL == peasycap) {
SAY("ERROR in easysnd_read(): peasycap is NULL\n"); SAY("ERROR in easysnd_read(): peasycap is NULL\n");
return -EFAULT; return -EFAULT;
} }
if (NULL == peasycap->pusb_device) {
SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n");
return -EFAULT;
}
kd = isdongle(peasycap);
if (0 <= kd && DONGLE_MANY > kd) {
if (mutex_lock_interruptible(&(easycap_dongle[kd].mutex_audio))) {
SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
return -ERESTARTSYS;
}
JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
/*---------------------------------------------------------------------------*/
/*
* MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
* IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
* IF NECESSARY, BAIL OUT.
*/
/*---------------------------------------------------------------------------*/
if (kd != isdongle(peasycap))
return -ERESTARTSYS;
if (NULL == file) {
SAY("ERROR: file is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
} else {
/*---------------------------------------------------------------------------*/
/*
* IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
* ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
*/
/*---------------------------------------------------------------------------*/
return -ERESTARTSYS;
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
if (file->f_flags & O_NONBLOCK)
JOT(16, "NONBLOCK kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
else
JOT(8, "BLOCKING kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
if ((0 > peasycap->audio_read) || \ if ((0 > peasycap->audio_read) || \
(peasycap->audio_buffer_page_many <= peasycap->audio_read)) { (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
SAM("ERROR: peasycap->audio_read out of range\n"); SAM("ERROR: peasycap->audio_read out of range\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read]; pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) { if ((struct data_buffer *)NULL == pdata_buffer) {
SAM("ERROR: pdata_buffer is NULL\n"); SAM("ERROR: pdata_buffer is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
JOM(12, "before wait, %i=frag read %i=frag fill\n", \ JOM(12, "before wait, %i=frag read %i=frag fill\n", \
...@@ -738,6 +794,7 @@ while ((fragment == (peasycap->audio_fill / \ ...@@ -738,6 +794,7 @@ while ((fragment == (peasycap->audio_fill / \
(0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) { (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
if (file->f_flags & O_NONBLOCK) { if (file->f_flags & O_NONBLOCK) {
JOM(16, "returning -EAGAIN as instructed\n"); JOM(16, "returning -EAGAIN as instructed\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EAGAIN; return -EAGAIN;
} }
rc = wait_event_interruptible(peasycap->wq_audio, \ rc = wait_event_interruptible(peasycap->wq_audio, \
...@@ -747,21 +804,25 @@ while ((fragment == (peasycap->audio_fill / \ ...@@ -747,21 +804,25 @@ while ((fragment == (peasycap->audio_fill / \
(0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))))); (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
if (0 != rc) { if (0 != rc) {
SAM("aborted by signal\n"); SAM("aborted by signal\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
if (peasycap->audio_eof) { if (peasycap->audio_eof) {
JOM(8, "returning 0 because %i=audio_eof\n", \ JOM(8, "returning 0 because %i=audio_eof\n", \
peasycap->audio_eof); peasycap->audio_eof);
kill_audio_urbs(peasycap); kill_audio_urbs(peasycap);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0; return 0;
} }
if (peasycap->audio_idle) { if (peasycap->audio_idle) {
JOM(16, "returning 0 because %i=audio_idle\n", \ JOM(16, "returning 0 because %i=audio_idle\n", \
peasycap->audio_idle); peasycap->audio_idle);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0; return 0;
} }
if (!peasycap->audio_isoc_streaming) { if (!peasycap->audio_isoc_streaming) {
JOM(16, "returning 0 because audio urbs not streaming\n"); JOM(16, "returning 0 because audio urbs not streaming\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0; return 0;
} }
} }
...@@ -773,15 +834,18 @@ while (fragment == (peasycap->audio_read / \ ...@@ -773,15 +834,18 @@ while (fragment == (peasycap->audio_read / \
peasycap->audio_pages_per_fragment)) { peasycap->audio_pages_per_fragment)) {
if (NULL == pdata_buffer->pgo) { if (NULL == pdata_buffer->pgo) {
SAM("ERROR: pdata_buffer->pgo is NULL\n"); SAM("ERROR: pdata_buffer->pgo is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
if (NULL == pdata_buffer->pto) { if (NULL == pdata_buffer->pto) {
SAM("ERROR: pdata_buffer->pto is NULL\n"); SAM("ERROR: pdata_buffer->pto is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo); kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
if (0 > kount1) { if (0 > kount1) {
SAM("easysnd_read: MISTAKE: kount1 is negative\n"); SAM("easysnd_read: MISTAKE: kount1 is negative\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
if (!kount1) { if (!kount1) {
...@@ -799,19 +863,23 @@ while (fragment == (peasycap->audio_read / \ ...@@ -799,19 +863,23 @@ while (fragment == (peasycap->audio_read / \
(peasycap->audio_buffer_page_many <= \ (peasycap->audio_buffer_page_many <= \
peasycap->audio_read)) { peasycap->audio_read)) {
SAM("ERROR: peasycap->audio_read out of range\n"); SAM("ERROR: peasycap->audio_read out of range\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read]; pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) { if ((struct data_buffer *)NULL == pdata_buffer) {
SAM("ERROR: pdata_buffer is NULL\n"); SAM("ERROR: pdata_buffer is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
if (NULL == pdata_buffer->pgo) { if (NULL == pdata_buffer->pgo) {
SAM("ERROR: pdata_buffer->pgo is NULL\n"); SAM("ERROR: pdata_buffer->pgo is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
if (NULL == pdata_buffer->pto) { if (NULL == pdata_buffer->pto) {
SAM("ERROR: pdata_buffer->pto is NULL\n"); SAM("ERROR: pdata_buffer->pto is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo); kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
...@@ -840,6 +908,7 @@ while (fragment == (peasycap->audio_read / \ ...@@ -840,6 +908,7 @@ while (fragment == (peasycap->audio_read / \
rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more); rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
if (0 != rc) { if (0 != rc) {
SAM("ERROR: copy_to_user() returned %li\n", rc); SAM("ERROR: copy_to_user() returned %li\n", rc);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT; return -EFAULT;
} }
*poff += (loff_t)more; *poff += (loff_t)more;
...@@ -902,6 +971,7 @@ JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient); ...@@ -902,6 +971,7 @@ JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
peasycap->dnbydt = sdr.quotient; peasycap->dnbydt = sdr.quotient;
JOM(8, "returning %li\n", (long int)szret); JOM(8, "returning %li\n", (long int)szret);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return szret; return szret;
} }
/*****************************************************************************/ /*****************************************************************************/
......
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