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: Mike Thomas <rmthomas@sciolus.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
2a87a0b922
commit
ae59dad4fe
@@ -1,7 +1,6 @@
|
|||||||
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
|
|||||||
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
|
|||||||
* 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[];
|
|||||||
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 *);
|
|||||||
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 @@
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
extern int debug;
|
extern int debug;
|
||||||
extern int gain;
|
extern int gain;
|
||||||
|
extern struct easycap_dongle easycap_dongle[];
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -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
|
|||||||
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)
|
|||||||
__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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
__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;
|
|||||||
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;
|
|||||||
__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)
|
|||||||
__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;
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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;
|
|||||||
* 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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
__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)
|
|||||||
{
|
{
|
||||||
__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)
|
|||||||
{
|
{
|
||||||
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, \
|
|||||||
{
|
{
|
||||||
__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)
|
|||||||
__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)
|
|||||||
__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;
|
|||||||
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;
|
|||||||
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)
|
|||||||
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;
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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;
|
|||||||
__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;
|
||||||
|
@@ -45,11 +45,14 @@ module_param(gain, int, S_IRUGO | S_IWUSR);
|
|||||||
* IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap
|
* IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap
|
||||||
* ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN
|
* ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN
|
||||||
* PROBING INTERFACES 1 AND 2.
|
* PROBING INTERFACES 1 AND 2.
|
||||||
|
*
|
||||||
|
* IOCTL LOCKING IS DONE AT MODULE LEVEL, NOT DEVICE LEVEL.
|
||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
struct easycap *peasycap_dongle[DONGLE_MANY];
|
struct easycap_dongle easycap_dongle[DONGLE_MANY];
|
||||||
static int dongle_this;
|
static int dongle_this;
|
||||||
|
static int dongle_done;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
@@ -80,7 +83,11 @@ const struct file_operations easycap_fops = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = easycap_open,
|
.open = easycap_open,
|
||||||
.release = easycap_release,
|
.release = easycap_release,
|
||||||
.unlocked_ioctl = easycap_ioctl,
|
#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
|
||||||
|
.unlocked_ioctl = easycap_ioctl_noinode,
|
||||||
|
#else
|
||||||
|
.ioctl = easycap_ioctl,
|
||||||
|
#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
|
||||||
.poll = easycap_poll,
|
.poll = easycap_poll,
|
||||||
.mmap = easycap_mmap,
|
.mmap = easycap_mmap,
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
@@ -103,7 +110,11 @@ const struct v4l2_file_operations v4l2_fops = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = easycap_open_noinode,
|
.open = easycap_open_noinode,
|
||||||
.release = easycap_release_noinode,
|
.release = easycap_release_noinode,
|
||||||
.unlocked_ioctl = easycap_ioctl,
|
#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
|
||||||
|
.unlocked_ioctl = easycap_ioctl_noinode,
|
||||||
|
#else
|
||||||
|
.ioctl = easycap_ioctl,
|
||||||
|
#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
|
||||||
.poll = easycap_poll,
|
.poll = easycap_poll,
|
||||||
.mmap = easycap_mmap,
|
.mmap = easycap_mmap,
|
||||||
};
|
};
|
||||||
@@ -120,7 +131,11 @@ const struct file_operations easysnd_fops = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = easysnd_open,
|
.open = easysnd_open,
|
||||||
.release = easysnd_release,
|
.release = easysnd_release,
|
||||||
.unlocked_ioctl = easysnd_ioctl,
|
#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
|
||||||
|
.unlocked_ioctl = easysnd_ioctl_noinode,
|
||||||
|
#else
|
||||||
|
.ioctl = easysnd_ioctl,
|
||||||
|
#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
|
||||||
.read = easysnd_read,
|
.read = easysnd_read,
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
};
|
};
|
||||||
@@ -139,10 +154,10 @@ int
|
|||||||
isdongle(struct easycap *peasycap)
|
isdongle(struct easycap *peasycap)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
if ((struct easycap *)NULL == peasycap)
|
if (NULL == peasycap)
|
||||||
return -2;
|
return -2;
|
||||||
for (k = 0; k < DONGLE_MANY; k++) {
|
for (k = 0; k < DONGLE_MANY; k++) {
|
||||||
if (peasycap_dongle[k] == peasycap) {
|
if (easycap_dongle[k].peasycap == peasycap) {
|
||||||
peasycap->isdongle = k;
|
peasycap->isdongle = k;
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
@@ -196,11 +211,10 @@ if ((struct video_device *)NULL == pvideo_device) {
|
|||||||
peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
|
peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
|
||||||
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
|
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
|
||||||
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
file->private_data = peasycap;
|
|
||||||
if (NULL == peasycap->pusb_device) {
|
if (NULL == peasycap->pusb_device) {
|
||||||
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
@@ -208,6 +222,7 @@ if (NULL == peasycap->pusb_device) {
|
|||||||
JOM(16, "0x%08lX=peasycap->pusb_device\n", \
|
JOM(16, "0x%08lX=peasycap->pusb_device\n", \
|
||||||
(long int)peasycap->pusb_device);
|
(long int)peasycap->pusb_device);
|
||||||
}
|
}
|
||||||
|
file->private_data = peasycap;
|
||||||
rc = wakeup_device(peasycap->pusb_device);
|
rc = wakeup_device(peasycap->pusb_device);
|
||||||
if (0 == rc)
|
if (0 == rc)
|
||||||
JOM(8, "wakeup_device() OK\n");
|
JOM(8, "wakeup_device() OK\n");
|
||||||
@@ -243,7 +258,7 @@ struct easycap_standard const *peasycap_standard;
|
|||||||
int i, rc, input, rate;
|
int i, rc, input, rate;
|
||||||
bool ntsc, other;
|
bool ntsc, other;
|
||||||
|
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
@@ -251,7 +266,7 @@ input = peasycap->input;
|
|||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* IF THE SAA7113H HAS ALREADY ACQUIRED LOCK, USE ITS HARDWARE-DETECTED
|
* IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
|
||||||
* FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR
|
* FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR
|
||||||
* gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
|
* gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
|
||||||
* A SWITCH BETWEEN PAL AND NTSC.
|
* A SWITCH BETWEEN PAL AND NTSC.
|
||||||
@@ -447,7 +462,7 @@ if (NULL == peasycap) {
|
|||||||
}
|
}
|
||||||
JOM(8, "%i=input sought\n", input);
|
JOM(8, "%i=input sought\n", input);
|
||||||
|
|
||||||
if ((0 > input) &&(INPUT_MANY <= input))
|
if (0 > input && INPUT_MANY <= input)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
inputnow = peasycap->input;
|
inputnow = peasycap->input;
|
||||||
if (input == inputnow)
|
if (input == inputnow)
|
||||||
@@ -581,7 +596,7 @@ if (input == peasycap->inputset[input].input) {
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
if ((struct usb_device *)NULL == peasycap->pusb_device) {
|
if (NULL == peasycap->pusb_device) {
|
||||||
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -617,16 +632,16 @@ struct list_head *plist_head;
|
|||||||
int j, isbad, nospc, m, rc;
|
int j, isbad, nospc, m, rc;
|
||||||
int isbuf;
|
int isbuf;
|
||||||
|
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((struct list_head *)NULL == peasycap->purb_video_head) {
|
if (NULL == peasycap->purb_video_head) {
|
||||||
SAY("ERROR: peasycap->urb_video_head uninitialized\n");
|
SAY("ERROR: peasycap->urb_video_head uninitialized\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
if ((struct usb_device *)NULL == peasycap->pusb_device) {
|
if (NULL == peasycap->pusb_device) {
|
||||||
SAY("ERROR: peasycap->pusb_device is NULL\n");
|
SAY("ERROR: peasycap->pusb_device is NULL\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -768,7 +783,7 @@ int m;
|
|||||||
struct list_head *plist_head;
|
struct list_head *plist_head;
|
||||||
struct data_urb *pdata_urb;
|
struct data_urb *pdata_urb;
|
||||||
|
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
@@ -780,8 +795,8 @@ if (peasycap->video_isoc_streaming) {
|
|||||||
list_for_each(plist_head, (peasycap->purb_video_head)) {
|
list_for_each(plist_head, (peasycap->purb_video_head)) {
|
||||||
pdata_urb = list_entry(plist_head, struct data_urb, \
|
pdata_urb = list_entry(plist_head, struct data_urb, \
|
||||||
list_head);
|
list_head);
|
||||||
if ((struct data_urb *)NULL != pdata_urb) {
|
if (NULL != pdata_urb) {
|
||||||
if ((struct urb *)NULL != pdata_urb->purb) {
|
if (NULL != pdata_urb->purb) {
|
||||||
usb_kill_urb(pdata_urb->purb);
|
usb_kill_urb(pdata_urb->purb);
|
||||||
m++;
|
m++;
|
||||||
}
|
}
|
||||||
@@ -864,15 +879,17 @@ return 0;
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect().
|
* THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
|
||||||
* BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED.
|
* PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
|
||||||
* peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL.
|
*
|
||||||
|
* BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
|
||||||
|
* peasycap->pusb_device IS NO LONGER VALID.
|
||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
easycap_delete(struct kref *pkref)
|
easycap_delete(struct kref *pkref)
|
||||||
{
|
{
|
||||||
int k, m, gone;
|
int k, m, gone, kd;
|
||||||
int allocation_video_urb, allocation_video_page, allocation_video_struct;
|
int allocation_video_urb, allocation_video_page, allocation_video_struct;
|
||||||
int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
|
int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
|
||||||
int registered_video, registered_audio;
|
int registered_video, registered_audio;
|
||||||
@@ -883,10 +900,11 @@ struct list_head *plist_head, *plist_next;
|
|||||||
JOT(4, "\n");
|
JOT(4, "\n");
|
||||||
|
|
||||||
peasycap = container_of(pkref, struct easycap, kref);
|
peasycap = container_of(pkref, struct easycap, kref);
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
|
SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
kd = isdongle(peasycap);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* FREE VIDEO.
|
* FREE VIDEO.
|
||||||
@@ -925,8 +943,6 @@ if ((struct list_head *)NULL != peasycap->purb_video_head) {
|
|||||||
JOM(4, "%i video data_urb structures freed\n", m);
|
JOM(4, "%i video data_urb structures freed\n", m);
|
||||||
JOM(4, "setting peasycap->purb_video_head=NULL\n");
|
JOM(4, "setting peasycap->purb_video_head=NULL\n");
|
||||||
peasycap->purb_video_head = (struct list_head *)NULL;
|
peasycap->purb_video_head = (struct list_head *)NULL;
|
||||||
} else {
|
|
||||||
JOM(4, "peasycap->purb_video_head is NULL\n");
|
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
JOM(4, "freeing video isoc buffers.\n");
|
JOM(4, "freeing video isoc buffers.\n");
|
||||||
@@ -1051,15 +1067,16 @@ allocation_audio_urb = peasycap->allocation_audio_urb;
|
|||||||
allocation_audio_page = peasycap->allocation_audio_page;
|
allocation_audio_page = peasycap->allocation_audio_page;
|
||||||
allocation_audio_struct = peasycap->allocation_audio_struct;
|
allocation_audio_struct = peasycap->allocation_audio_struct;
|
||||||
registered_audio = peasycap->registered_audio;
|
registered_audio = peasycap->registered_audio;
|
||||||
m = 0;
|
|
||||||
if ((struct easycap *)NULL != peasycap) {
|
|
||||||
kfree(peasycap); peasycap = (struct easycap *)NULL;
|
|
||||||
allocation_video_struct -= sizeof(struct easycap);
|
|
||||||
m++;
|
|
||||||
}
|
|
||||||
JOT(4, "%i easycap structure freed\n", m);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
kfree(peasycap);
|
||||||
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
easycap_dongle[kd].peasycap = (struct easycap *)NULL;
|
||||||
|
JOT(4, " null-->easycap_dongle[%i].peasycap\n", kd);
|
||||||
|
allocation_video_struct -= sizeof(struct easycap);
|
||||||
|
} else {
|
||||||
|
SAY("ERROR: cannot purge easycap_dongle[].peasycap");
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
SAY("%8i= video urbs after all deletions\n", allocation_video_urb);
|
SAY("%8i= video urbs after all deletions\n", allocation_video_urb);
|
||||||
SAY("%8i= video pages after all deletions\n", allocation_video_page);
|
SAY("%8i= video pages after all deletions\n", allocation_video_page);
|
||||||
SAY("%8i= video structs after all deletions\n", allocation_video_struct);
|
SAY("%8i= video structs after all deletions\n", allocation_video_struct);
|
||||||
@@ -1076,27 +1093,75 @@ return;
|
|||||||
unsigned int easycap_poll(struct file *file, poll_table *wait)
|
unsigned int easycap_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct easycap *peasycap;
|
struct easycap *peasycap;
|
||||||
|
int rc, kd;
|
||||||
|
|
||||||
JOT(8, "\n");
|
JOT(8, "\n");
|
||||||
|
|
||||||
if (NULL == ((poll_table *)wait))
|
if (NULL == ((poll_table *)wait))
|
||||||
JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
|
JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
|
||||||
if (NULL == ((struct file *)file)) {
|
if ((struct file *)NULL == file) {
|
||||||
SAY("ERROR: file pointer is NULL\n");
|
SAY("ERROR: file pointer is NULL\n");
|
||||||
return -EFAULT;
|
return -ERESTARTSYS;
|
||||||
}
|
}
|
||||||
peasycap = file->private_data;
|
peasycap = file->private_data;
|
||||||
if (NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
if (NULL == peasycap->pusb_device) {
|
||||||
|
SAY("ERROR: 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_video)) {
|
||||||
|
SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
}
|
||||||
|
JOM(4, "locked easycap_dongle[%i].mutex_video\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_video);
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
}
|
||||||
|
peasycap = file->private_data;
|
||||||
|
if (NULL == peasycap) {
|
||||||
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
|
mutex_unlock(&easycap_dongle[kd].mutex_video);
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
}
|
||||||
|
if (NULL == peasycap->pusb_device) {
|
||||||
|
SAM("ERROR: peasycap->pusb_device is NULL\n");
|
||||||
|
mutex_unlock(&easycap_dongle[kd].mutex_video);
|
||||||
|
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;
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
rc = easycap_dqbuf(peasycap, 0);
|
||||||
peasycap->polled = 1;
|
peasycap->polled = 1;
|
||||||
|
mutex_unlock(&easycap_dongle[kd].mutex_video);
|
||||||
if (0 == easycap_dqbuf(peasycap, 0))
|
if (0 == rc)
|
||||||
return POLLIN | POLLRDNORM;
|
return POLLIN | POLLRDNORM;
|
||||||
else
|
else
|
||||||
return POLLERR;
|
return POLLERR;
|
||||||
|
|
||||||
}
|
}
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@@ -1115,6 +1180,10 @@ if (NULL == peasycap) {
|
|||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
if (NULL == peasycap->pusb_device) {
|
||||||
|
SAY("ERROR: peasycap->pusb_device is NULL\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
ifield = 0;
|
ifield = 0;
|
||||||
JOM(8, "%i=ifield\n", ifield);
|
JOM(8, "%i=ifield\n", ifield);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@@ -1122,9 +1191,9 @@ JOM(8, "%i=ifield\n", ifield);
|
|||||||
* CHECK FOR LOST INPUT SIGNAL.
|
* CHECK FOR LOST INPUT SIGNAL.
|
||||||
*
|
*
|
||||||
* FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
|
* FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
|
||||||
* IF INPUT 0 IS PRESENT AND LOCKED, UNPLUGGING INPUT 4 DOES NOT RESULT IN
|
* IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
|
||||||
* SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE IS FLYWHEELING
|
* RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
|
||||||
* ON INPUT 0. THE UPSHOT IS:
|
* IS FLYWHEELING ON INPUT 0. THE UPSHOT IS:
|
||||||
*
|
*
|
||||||
* INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK
|
* INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK
|
||||||
* INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK
|
* INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK
|
||||||
@@ -1342,7 +1411,7 @@ int rc, bytesperpixel, multiplier, much, more, over, rump, caches, input;
|
|||||||
__u8 mask, margin;
|
__u8 mask, margin;
|
||||||
bool odd, isuy, decimatepixel, offerfields, badinput;
|
bool odd, isuy, decimatepixel, offerfields, badinput;
|
||||||
|
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if (NULL == peasycap) {
|
||||||
SAY("ERROR: peasycap is NULL\n");
|
SAY("ERROR: peasycap is NULL\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
@@ -1447,13 +1516,11 @@ while (cz < wz) {
|
|||||||
much) / 2;
|
much) / 2;
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
if (1 < bytesperpixel) {
|
if (1 < bytesperpixel) {
|
||||||
if ((rad * \
|
if (rad * 2 < much * bytesperpixel) {
|
||||||
2) < (much * \
|
|
||||||
bytesperpixel)) {
|
|
||||||
/*
|
/*
|
||||||
** INJUDICIOUS ALTERATION OF THIS
|
** INJUDICIOUS ALTERATION OF THIS
|
||||||
** BLOCK WILL CAUSE BREAKAGE.
|
** STATEMENT BLOCK WILL CAUSE
|
||||||
** BEWARE.
|
** BREAKAGE. BEWARE.
|
||||||
**/
|
**/
|
||||||
rad2 = rad + bytesperpixel - 1;
|
rad2 = rad + bytesperpixel - 1;
|
||||||
much = ((((2 * \
|
much = ((((2 * \
|
||||||
@@ -1483,7 +1550,6 @@ while (cz < wz) {
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
if (rump)
|
if (rump)
|
||||||
caches++;
|
caches++;
|
||||||
|
|
||||||
if (true == badinput) {
|
if (true == badinput) {
|
||||||
JOM(8, "ERROR: 0x%02X=->field_buffer" \
|
JOM(8, "ERROR: 0x%02X=->field_buffer" \
|
||||||
"[%i][%i].input, " \
|
"[%i][%i].input, " \
|
||||||
@@ -1492,7 +1558,6 @@ while (cz < wz) {
|
|||||||
[kex][mex].input, kex, mex, \
|
[kex][mex].input, kex, mex, \
|
||||||
(0x08|peasycap->input));
|
(0x08|peasycap->input));
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = redaub(peasycap, pad, pex, much, more, \
|
rc = redaub(peasycap, pad, pex, much, more, \
|
||||||
mask, margin, isuy);
|
mask, margin, isuy);
|
||||||
if (0 > rc) {
|
if (0 > rc) {
|
||||||
@@ -1575,12 +1640,11 @@ while (cz < wz) {
|
|||||||
much) / 4;
|
much) / 4;
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
if (1 < bytesperpixel) {
|
if (1 < bytesperpixel) {
|
||||||
if ((rad * 4) < (much * \
|
if (rad * 4 < much * bytesperpixel) {
|
||||||
bytesperpixel)) {
|
|
||||||
/*
|
/*
|
||||||
** INJUDICIOUS ALTERATION OF THIS
|
** INJUDICIOUS ALTERATION OF THIS
|
||||||
** BLOCK WILL CAUSE BREAKAGE.
|
** STATEMENT BLOCK WILL CAUSE
|
||||||
** BEWARE.
|
** BREAKAGE. BEWARE.
|
||||||
**/
|
**/
|
||||||
rad2 = rad + bytesperpixel - 1;
|
rad2 = rad + bytesperpixel - 1;
|
||||||
much = ((((2 * rad2)/bytesperpixel)/2)\
|
much = ((((2 * rad2)/bytesperpixel)/2)\
|
||||||
@@ -1620,7 +1684,6 @@ while (cz < wz) {
|
|||||||
[kex][mex].input, kex, mex, \
|
[kex][mex].input, kex, mex, \
|
||||||
(0x08|peasycap->input));
|
(0x08|peasycap->input));
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = redaub(peasycap, pad, pex, much, more, \
|
rc = redaub(peasycap, pad, pex, much, more, \
|
||||||
mask, margin, isuy);
|
mask, margin, isuy);
|
||||||
if (0 > rc) {
|
if (0 > rc) {
|
||||||
@@ -3297,8 +3360,8 @@ return;
|
|||||||
* FIXME
|
* FIXME
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS
|
* THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE EasyCAP
|
||||||
* PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
|
* IS PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
|
||||||
* IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
|
* IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
|
||||||
*
|
*
|
||||||
* THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
|
* THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
|
||||||
@@ -3338,6 +3401,16 @@ __s32 value;
|
|||||||
struct easycap_format *peasycap_format;
|
struct easycap_format *peasycap_format;
|
||||||
|
|
||||||
JOT(4, "\n");
|
JOT(4, "\n");
|
||||||
|
|
||||||
|
if (!dongle_done) {
|
||||||
|
dongle_done = 1;
|
||||||
|
for (k = 0; k < DONGLE_MANY; k++) {
|
||||||
|
easycap_dongle[k].peasycap = (struct easycap *)NULL;
|
||||||
|
mutex_init(&easycap_dongle[k].mutex_video);
|
||||||
|
mutex_init(&easycap_dongle[k].mutex_audio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
peasycap = (struct easycap *)NULL;
|
peasycap = (struct easycap *)NULL;
|
||||||
|
|
||||||
if ((struct usb_interface *)NULL == pusb_interface) {
|
if ((struct usb_interface *)NULL == pusb_interface) {
|
||||||
@@ -3481,12 +3554,20 @@ if (0 == bInterfaceNumber) {
|
|||||||
init_waitqueue_head(&peasycap->wq_audio);
|
init_waitqueue_head(&peasycap->wq_audio);
|
||||||
|
|
||||||
for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) {
|
for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) {
|
||||||
if ((struct easycap *)NULL == peasycap_dongle[dongle_this]) {
|
if (NULL == easycap_dongle[dongle_this].peasycap) {
|
||||||
peasycap_dongle[dongle_this] = peasycap;
|
if (0 == mutex_is_locked(&easycap_dongle\
|
||||||
JOM(8, "intf[%i]: peasycap-->easycap" \
|
[dongle_this].mutex_video)) {
|
||||||
|
if (0 == mutex_is_locked(&easycap_dongle\
|
||||||
|
[dongle_this].mutex_audio)) {
|
||||||
|
easycap_dongle\
|
||||||
|
[dongle_this].peasycap = \
|
||||||
|
peasycap;
|
||||||
|
JOM(8, "intf[%i]: peasycap-->easycap" \
|
||||||
"_dongle[%i].peasycap\n", \
|
"_dongle[%i].peasycap\n", \
|
||||||
bInterfaceNumber, dongle_this);
|
bInterfaceNumber, dongle_this);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DONGLE_MANY <= dongle_this) {
|
if (DONGLE_MANY <= dongle_this) {
|
||||||
@@ -3665,15 +3746,15 @@ if (0 == bInterfaceNumber) {
|
|||||||
* FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING
|
* FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING
|
||||||
* THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF
|
* THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF
|
||||||
* THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN
|
* THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN
|
||||||
* SIMULTANEOUSLY, THERE WILL BE VERY SERIOUS TROUBLE.
|
* SIMULTANEOUSLY, THERE WILL BE SERIOUS TROUBLE.
|
||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) {
|
if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) {
|
||||||
SAY("ERROR: bad dongle count\n");
|
SAY("ERROR: bad dongle count\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
peasycap = peasycap_dongle[dongle_this];
|
peasycap = easycap_dongle[dongle_this].peasycap;
|
||||||
JOT(8, "intf[%i]: peasycap_dongle[%i]-->peasycap\n", \
|
JOT(8, "intf[%i]: easycap_dongle[%i].peasycap-->peasycap\n", \
|
||||||
bInterfaceNumber, dongle_this);
|
bInterfaceNumber, dongle_this);
|
||||||
|
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if ((struct easycap *)NULL == peasycap) {
|
||||||
@@ -3721,6 +3802,7 @@ if ((USB_CLASS_VIDEO == bInterfaceClass) || \
|
|||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
isokalt = 0;
|
isokalt = 0;
|
||||||
|
|
||||||
for (i = 0; i < pusb_interface->num_altsetting; i++) {
|
for (i = 0; i < pusb_interface->num_altsetting; i++) {
|
||||||
pusb_host_interface = &(pusb_interface->altsetting[i]);
|
pusb_host_interface = &(pusb_interface->altsetting[i]);
|
||||||
if ((struct usb_host_interface *)NULL == pusb_host_interface) {
|
if ((struct usb_host_interface *)NULL == pusb_host_interface) {
|
||||||
@@ -4245,6 +4327,9 @@ case 0: {
|
|||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
*
|
||||||
* THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
|
* THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
|
||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@@ -4587,9 +4672,8 @@ return 0;
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY
|
* WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
|
||||||
* UNPLUGGED.
|
* UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
|
||||||
* HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL.
|
|
||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
@@ -4602,7 +4686,7 @@ struct easycap *peasycap;
|
|||||||
|
|
||||||
struct list_head *plist_head;
|
struct list_head *plist_head;
|
||||||
struct data_urb *pdata_urb;
|
struct data_urb *pdata_urb;
|
||||||
int minor, m;
|
int minor, m, kd;
|
||||||
|
|
||||||
JOT(4, "\n");
|
JOT(4, "\n");
|
||||||
|
|
||||||
@@ -4691,49 +4775,75 @@ default:
|
|||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* DEREGISTER
|
* DEREGISTER
|
||||||
|
*
|
||||||
|
* THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
|
||||||
|
* IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
|
||||||
|
* AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE.
|
||||||
*/
|
*/
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
kd = isdongle(peasycap);
|
||||||
switch (bInterfaceNumber) {
|
switch (bInterfaceNumber) {
|
||||||
case 0: {
|
case 0: {
|
||||||
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
wake_up_interruptible(&peasycap->wq_video);
|
||||||
|
JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
if (mutex_lock_interruptible(&easycap_dongle[kd].\
|
||||||
|
mutex_video)) {
|
||||||
|
SAY("ERROR: cannot lock easycap_dongle[%i]." \
|
||||||
|
"mutex_video\n", kd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
} else
|
||||||
|
SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
|
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
if ((struct easycap *)NULL == peasycap) {
|
||||||
SAM("ERROR: peasycap has become NULL\n");
|
SAM("ERROR: peasycap has become NULL\n");
|
||||||
} else {
|
} else {
|
||||||
lock_kernel();
|
|
||||||
usb_deregister_dev(pusb_interface, &easycap_class);
|
usb_deregister_dev(pusb_interface, &easycap_class);
|
||||||
(peasycap->registered_video)--;
|
(peasycap->registered_video)--;
|
||||||
|
|
||||||
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
|
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
|
||||||
unlock_kernel();
|
|
||||||
SAM("easycap detached from minor #%d\n", minor);
|
SAM("easycap detached from minor #%d\n", minor);
|
||||||
}
|
}
|
||||||
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
||||||
#else
|
#else
|
||||||
if ((struct easycap *)NULL == peasycap)
|
video_unregister_device(&peasycap->video_device);
|
||||||
SAM("ERROR: peasycap has become NULL\n");
|
JOM(4, "unregistered with videodev: %i=minor\n", \
|
||||||
else {
|
|
||||||
lock_kernel();
|
|
||||||
video_unregister_device(&peasycap->video_device);
|
|
||||||
(peasycap->registered_video)--;
|
|
||||||
unlock_kernel();
|
|
||||||
JOM(4, "unregistered with videodev: %i=minor\n", \
|
|
||||||
peasycap->video_device.minor);
|
peasycap->video_device.minor);
|
||||||
}
|
(peasycap->registered_video)--;
|
||||||
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
||||||
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
|
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
|
||||||
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
mutex_unlock(&easycap_dongle[kd].mutex_video);
|
||||||
|
JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
lock_kernel();
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
wake_up_interruptible(&peasycap->wq_audio);
|
||||||
|
JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
if (mutex_lock_interruptible(&easycap_dongle[kd].\
|
||||||
|
mutex_audio)) {
|
||||||
|
SAY("ERROR: cannot lock easycap_dongle[%i]." \
|
||||||
|
"mutex_audio\n", kd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
} else
|
||||||
|
SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
|
||||||
|
|
||||||
usb_deregister_dev(pusb_interface, &easysnd_class);
|
usb_deregister_dev(pusb_interface, &easysnd_class);
|
||||||
if ((struct easycap *)NULL != peasycap)
|
(peasycap->registered_audio)--;
|
||||||
(peasycap->registered_audio)--;
|
|
||||||
|
|
||||||
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
|
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
|
||||||
unlock_kernel();
|
|
||||||
|
|
||||||
SAM("easysnd detached from minor #%d\n", minor);
|
SAM("easysnd detached from minor #%d\n", minor);
|
||||||
|
|
||||||
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
mutex_unlock(&easycap_dongle[kd].mutex_audio);
|
||||||
|
JOM(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -4744,24 +4854,41 @@ default:
|
|||||||
* CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
|
* CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
|
||||||
*/
|
*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
if ((struct easycap *)NULL == peasycap) {
|
|
||||||
SAM("ERROR: peasycap has become NULL\n");
|
|
||||||
SAM("cannot call kref_put()\n");
|
|
||||||
SAM("ending unsuccessfully: may cause memory leak\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!peasycap->kref.refcount.counter) {
|
if (!peasycap->kref.refcount.counter) {
|
||||||
SAM("ERROR: peasycap->kref.refcount.counter is zero " \
|
SAM("ERROR: peasycap->kref.refcount.counter is zero "
|
||||||
"so cannot call kref_put()\n");
|
"so cannot call kref_put()\n");
|
||||||
SAM("ending unsuccessfully: may cause memory leak\n");
|
SAM("ending unsuccessfully: may cause memory leak\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
JOM(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
|
||||||
|
SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
SAM("ending unsuccessfully: may cause memory leak\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
|
||||||
|
SAY("ERROR: cannot down easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
mutex_unlock(&(easycap_dongle[kd].mutex_video));
|
||||||
|
JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
SAM("ending unsuccessfully: may cause memory leak\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
}
|
||||||
|
JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n", \
|
||||||
bInterfaceNumber, (int)peasycap->kref.refcount.counter);
|
bInterfaceNumber, (int)peasycap->kref.refcount.counter);
|
||||||
kref_put(&peasycap->kref, easycap_delete);
|
kref_put(&peasycap->kref, easycap_delete);
|
||||||
JOM(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
|
JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
|
||||||
|
if (0 <= kd && DONGLE_MANY > kd) {
|
||||||
|
mutex_unlock(&(easycap_dongle[kd].mutex_audio));
|
||||||
|
JOT(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
|
||||||
|
mutex_unlock(&easycap_dongle[kd].mutex_video);
|
||||||
|
JOT(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
|
||||||
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
JOM(4, "ends\n");
|
JOM(4, "ends\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
|||||||
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;
|
|||||||
|
|
||||||
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 / \
|
|||||||
(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 / \
|
|||||||
(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 / \
|
|||||||
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 / \
|
|||||||
(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 / \
|
|||||||
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);
|
|||||||
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;
|
||||||
}
|
}
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
Reference in New Issue
Block a user