summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-16 23:00:36 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-16 23:00:36 +0000
commit14dd2ec093cfabda3ae7efeeaf0e23c66ebaccc0 (patch)
tree9a9ce5cff6ef92faa6e07a82785b9a6d6838f7e4 /drivers/usb
parent847290510f811c572cc2aa80c1f02a04721410b1 (diff)
Merge with 2.4.0-test1.
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/audio.c165
-rw-r--r--drivers/usb/ibmcam.c80
-rw-r--r--drivers/usb/ov511.c424
3 files changed, 436 insertions, 233 deletions
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 40903a9c2..ad94fef55 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -52,14 +52,17 @@
* decent headphones!
* "Let's make things better" -> but please Philips start with your
* own stuff!!!!
- * 1999-11-02: It takes the Philips boxes several seconds to acquire synchronisation
+ * 1999-11-02: Thomas Sailer
+ * It takes the Philips boxes several seconds to acquire synchronisation
* that means they won't play short sounds. Should probably maintain
* the ISO datastream even if there's nothing to play.
* Fix counting the total_bytes counter, RealPlayer G2 depends on it.
- * 1999-12-20: Fix bad bug in conversion to per interface probing.
+ * 1999-12-20: Thomas Sailer
+ * Fix bad bug in conversion to per interface probing.
* disconnect was called multiple times for the audio device,
* leading to a premature freeing of the audio structures
- * 2000-05-13: I don't remember who changed the find_format routine,
+ * 2000-05-13: Thomas Sailer
+ * I don't remember who changed the find_format routine,
* but the change was completely broken for the Dallas
* chip. Anyway taking sampling rate into account in find_format
* is bad and should not be done unless there are devices with
@@ -72,8 +75,20 @@
* for the Dallas chip.
* Also fix a rather long standing problem with applications that
* use "small" writes producing no sound at all.
- * 2000-05-15: My fears came true, the Philips camera indeed has pretty stupid
+ * 2000-05-15: Thomas Sailer
+ * My fears came true, the Philips camera indeed has pretty stupid
* audio descriptors.
+ * 2000-05-17: Thomas Sailer
+ * Nemsoft spotted my stupid last minute change, thanks
+ * 2000-05-19: Thomas Sailer
+ * Fixed FEATURE_UNIT thinkos found thanks to the KC Technology
+ * Xtend device. Basically the driver treated FEATURE_UNIT's sourced
+ * by mono terminals as stereo.
+ * 2000-05-20: Thomas Sailer
+ * SELECTOR support (and thus selecting record channels from the mixer).
+ * Somewhat peculiar due to OSS interface limitations. Only works
+ * for channels where a "slider" is already in front of it (i.e.
+ * a MIXER unit or a FEATURE unit with volume capability).
*
*/
@@ -211,6 +226,7 @@ struct mixerchannel {
__u16 value;
__u16 osschannel; /* number of the OSS channel */
__s16 minval, maxval;
+ __u16 slctunitid;
__u8 unitid;
__u8 selector;
__u8 chnum;
@@ -988,7 +1004,7 @@ static int usbin_start(struct usb_audiodev *as)
}
spin_lock_irqsave(&as->lock, flags);
}
- if (u->dma.count <= 0 && !u->dma.mapped)
+ if (u->dma.count >= u->dma.dmasize && !u->dma.mapped)
return 0;
u->flags |= FLG_RUNNING;
if (!(u->flags & FLG_URB0RUNNING)) {
@@ -1719,7 +1735,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
goto err;
- if (ch->chnum == 0)
+ if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2;
data[1] = v2 >> 8;
@@ -1735,7 +1751,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
goto err;
- if (ch->chnum == 0)
+ if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
@@ -1754,6 +1770,89 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
return -1;
}
+static int get_rec_src(struct usb_mixerdev *ms)
+{
+ struct usb_device *dev = ms->state->usbdev;
+ unsigned int mask = 0, retmask = 0;
+ unsigned int i, j;
+ unsigned char buf;
+ int err = 0;
+
+ for (i = 0; i < ms->numch; i++) {
+ if (!ms->ch[i].slctunitid || (mask & (1 << i)))
+ continue;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+ err = -EIO;
+ printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
+ dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
+ continue;
+ }
+ for (j = i; j < ms->numch; i++) {
+ if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+ continue;
+ mask |= 1 << j;
+ if (buf == (ms->ch[j].slctunitid >> 8))
+ retmask |= 1 << ms->ch[j].osschannel;
+ }
+ }
+ if (err)
+ return -EIO;
+ return retmask;
+}
+
+static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
+{
+ struct usb_device *dev = ms->state->usbdev;
+ unsigned int mask = 0, smask, bmask;
+ unsigned int i, j;
+ unsigned char buf;
+ int err = 0;
+
+ for (i = 0; i < ms->numch; i++) {
+ if (!ms->ch[i].slctunitid || (mask & (1 << i)))
+ continue;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+ err = -EIO;
+ printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
+ dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
+ continue;
+ }
+ /* first generate smask */
+ smask = bmask = 0;
+ for (j = i; j < ms->numch; i++) {
+ if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+ continue;
+ smask |= 1 << ms->ch[j].osschannel;
+ if (buf == (ms->ch[j].slctunitid >> 8))
+ bmask |= 1 << ms->ch[j].osschannel;
+ mask |= 1 << j;
+ }
+ /* check for multiple set sources */
+ j = hweight32(srcmask & smask);
+ if (j == 0)
+ continue;
+ if (j > 1)
+ srcmask &= ~bmask;
+ for (j = i; j < ms->numch; i++) {
+ if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+ continue;
+ if (!(srcmask & (1 << ms->ch[j].osschannel)))
+ continue;
+ buf = ms->ch[j].slctunitid >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ 0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) {
+ err = -EIO;
+ printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n",
+ dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
+ continue;
+ }
+ }
+ }
+ return err ? -EIO : 0;
+}
+
/* --------------------------------------------------------------------- */
/*
@@ -1886,8 +1985,10 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
if (_IOC_DIR(cmd) == _IOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- /* don't know how to handle this yet */
- return put_user(0, (int *)arg);
+ val = get_rec_src(ms);
+ if (val < 0)
+ return val;
+ return put_user(val, (int *)arg);
case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
for (val = i = 0; i < ms->numch; i++)
@@ -1895,9 +1996,11 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
return put_user(val, (int *)arg);
case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- /* don't know how to handle this yet */
- return put_user(0, (int *)arg);
-
+ for (val = i = 0; i < ms->numch; i++)
+ if (ms->ch[i].slctunitid)
+ val |= 1 << ms->ch[i].osschannel;
+ return put_user(val, (int *)arg);
+
case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
for (val = i = 0; i < ms->numch; i++)
if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
@@ -1905,7 +2008,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
return put_user(val, (int *)arg);
case SOUND_MIXER_CAPS:
- return put_user(0, (int *)arg);
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
default:
i = _IOC_NR(cmd);
@@ -1925,8 +2028,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
get_user_ret(val, (int *)arg, -EFAULT);
- /* set recording source: val */
- return 0;
+ return set_rec_src(ms, val);
default:
i = _IOC_NR(cmd);
@@ -2852,7 +2954,7 @@ static unsigned int getvolchannel(struct consmixstate *state)
{
unsigned int u;
- if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME))
+ if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME))
return SOUND_MIXER_VOLUME;
if ((state->termtype & 0xff00) == 0x0100) {
if (state->mixchmask & SOUND_MASK_PCM)
@@ -2864,8 +2966,6 @@ static unsigned int getvolchannel(struct consmixstate *state)
return SOUND_MIXER_MIC;
if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
return SOUND_MIXER_SPEAKER;
- if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
- return SOUND_MIXER_SPEAKER;
if ((state->termtype & 0xff00) == 0x0500) {
if (state->mixchmask & SOUND_MASK_PHONEIN)
return SOUND_MIXER_PHONEIN;
@@ -2950,7 +3050,7 @@ static void prepmixch(struct consmixstate *state)
if (v3 > 100)
v3 = 100;
ch->value = v3;
- if (ch->chnum != 0) {
+ if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
(ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
goto err;
@@ -2986,7 +3086,7 @@ static void prepmixch(struct consmixstate *state)
if (v3 > 100)
v3 = 100;
ch->value = v3;
- if (ch->chnum != 0) {
+ if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
(ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
goto err;
@@ -3095,15 +3195,24 @@ static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer
static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
{
- unsigned int chnum, i;
+ unsigned int chnum, i, mixch;
+ struct mixerchannel *mch;
if (!selector[4]) {
printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
return;
}
+ mixch = state->nrmixch;
usb_audio_recurseunit(state, selector[5]);
+ if (state->nrmixch != mixch) {
+ mch = &state->mixch[state->nrmixch-1];
+ mch->slctunitid = selector[5] | (1 << 8);
+ } else {
+ printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]);
+ }
chnum = state->nrchannels;
for (i = 1; i < selector[4]; i++) {
+ mixch = state->nrmixch;
usb_audio_recurseunit(state, selector[5+i]);
if (chnum != state->nrchannels) {
printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
@@ -3112,6 +3221,12 @@ static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *se
state->nrchannels = 0;
return;
}
+ if (state->nrmixch != mixch) {
+ mch = &state->mixch[state->nrmixch-1];
+ mch->slctunitid = selector[5] | ((i + 1) << 8);
+ } else {
+ printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1);
+ }
}
state->termtype = 0;
state->chconfig = 0;
@@ -3167,7 +3282,7 @@ static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr
ch->unitid = ftr[3];
ch->selector = VOLUME_CONTROL;
ch->chnum = 1;
- ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
prepmixch(state);
}
} else if (mchftr & 2) {
@@ -3187,7 +3302,7 @@ static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr
ch->unitid = ftr[3];
ch->selector = BASS_CONTROL;
ch->chnum = 1;
- ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
prepmixch(state);
}
} else if (mchftr & 4) {
@@ -3207,7 +3322,7 @@ static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr
ch->unitid = ftr[3];
ch->selector = TREBLE_CONTROL;
ch->chnum = 1;
- ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
prepmixch(state);
}
} else if (mchftr & 16) {
@@ -3239,7 +3354,7 @@ static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unit
unsigned int i, j;
if (test_and_set_bit(unitid, &state->unitbitmap)) {
- printk(KERN_ERR "usbaudio: mixer path recursion detected, unit %d!\n", unitid);
+ printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
return;
}
p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
index 2deab03fa..f643dee47 100644
--- a/drivers/usb/ibmcam.c
+++ b/drivers/usb/ibmcam.c
@@ -7,6 +7,22 @@
*
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
+ *
+ * 5/24/00 Removed optional (and unnecessary) locking of the driver while
+ * the device remains plugged in. Corrected race conditions in ibmcam_open
+ * and ibmcam_probe() routines using this as a guideline:
+ *
+ * (2) The big kernel lock is automatically released when a process sleeps
+ * in the kernel and is automatically reacquired on reschedule if the
+ * process had the lock originally. Any code that can be compiled as
+ * a module and is entered with the big kernel lock held *MUST*
+ * increment the use count to activate the indirect module protection
+ * before doing anything that might sleep.
+ *
+ * In practice, this means that all routines that live in modules and
+ * are invoked under the big kernel lock should do MOD_INC_USE_COUNT
+ * as their very first action. And all failure paths from that
+ * routine must do MOD_DEC_USE_COUNT before returning.
*/
#include <linux/kernel.h>
@@ -26,21 +42,6 @@
#include "ibmcam.h"
-/*
- * IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED: This symbol controls
- * the locking of the driver. If non-zero, the driver counts the
- * probe() call as usage and increments module usage counter; this
- * effectively prevents removal of the module (with rmmod) until the
- * device is unplugged (then disconnect() callback reduces the module
- * usage counter back, and module can be removed).
- *
- * This behavior may be useful if you prefer to lock the driver in
- * memory until device is unplugged. However you can't reload the
- * driver if you want to alter some parameters - you'd need to unplug
- * the camera first. Therefore, I recommend setting 0.
- */
-#define IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED 0
-
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
static int debug = 0;
@@ -242,7 +243,7 @@ static void *rvmalloc(unsigned long size)
size += (PAGE_SIZE - 1);
size &= ~(PAGE_SIZE - 1);
- mem = vmalloc(size);
+ mem = vmalloc_32(size);
if (!mem)
return NULL;
@@ -2346,6 +2347,7 @@ static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
* camera is also initialized here (once per connect), at
* expense of V4L client (it waits on open() call).
* 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers.
+ * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
*/
static int ibmcam_open(struct video_device *dev, int flags)
{
@@ -2353,6 +2355,7 @@ static int ibmcam_open(struct video_device *dev, int flags)
const int sb_size = FRAMES_PER_DESC * ibmcam->iso_packet_len;
int i, err = 0;
+ MOD_INC_USE_COUNT;
down(&ibmcam->lock);
if (ibmcam->user)
@@ -2425,14 +2428,13 @@ static int ibmcam_open(struct video_device *dev, int flags)
else
err = -EBUSY;
}
- if (!err) {
+ if (!err)
ibmcam->user++;
- MOD_INC_USE_COUNT;
- }
}
}
-
up(&ibmcam->lock);
+ if (err)
+ MOD_DEC_USE_COUNT;
return err;
}
@@ -2446,6 +2448,7 @@ static int ibmcam_open(struct video_device *dev, int flags)
* History:
* 1/22/00 Moved scratch buffer deallocation here.
* 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers.
+ * 5/24/00 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
*/
static void ibmcam_close(struct video_device *dev)
{
@@ -2462,13 +2465,13 @@ static void ibmcam_close(struct video_device *dev)
kfree(ibmcam->sbuf[i].data);
ibmcam->user--;
- MOD_DEC_USE_COUNT;
if (ibmcam->remove_pending) {
printk(KERN_INFO "ibmcam_close: Final disconnect.\n");
usb_ibmcam_release(ibmcam);
}
up(&ibmcam->lock);
+ MOD_DEC_USE_COUNT;
}
static int ibmcam_init_done(struct video_device *dev)
@@ -2891,7 +2894,7 @@ static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam)
}
/*
- * usb_ibmcam_release()
+ * ibmcam_find_struct()
*
* This code searches the array of preallocated (static) structures
* and returns index of the first one that isn't in use. Returns -1
@@ -2929,6 +2932,7 @@ static int ibmcam_find_struct(void)
* History:
* 1/22/00 Moved camera init code to ibmcam_open()
* 1/27/00 Changed to use static structures, added locking.
+ * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
*/
static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
{
@@ -2994,10 +2998,14 @@ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
RESTRICT_TO_RANGE(videosize, VIDEOSIZE_176x144, VIDEOSIZE_352x240);
}
+ /* Code below may sleep, need to lock module while we are here */
+ MOD_INC_USE_COUNT;
+
devnum = ibmcam_find_struct();
if (devnum == -1) {
printk(KERN_INFO "IBM USB camera driver: Too many devices!\n");
- return NULL;
+ ibmcam = NULL; /* Do not free, it's preallocated */
+ goto probe_done;
}
ibmcam = &cams[devnum];
@@ -3017,17 +3025,14 @@ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
usb_ibmcam_configure_video(ibmcam);
up (&ibmcam->lock);
-#if IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED
- MOD_INC_USE_COUNT;
-#endif
-
if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) {
printk(KERN_ERR "video_register_device failed\n");
- return NULL;
+ ibmcam = NULL; /* Do not free, it's preallocated */
}
if (debug > 1)
printk(KERN_DEBUG "video_register_device() successful\n");
-
+probe_done:
+ MOD_DEC_USE_COUNT;
return ibmcam;
}
@@ -3055,17 +3060,26 @@ static void usb_ibmcam_release(struct usb_ibmcam *ibmcam)
* structure (pointed by 'ptr') and after that driver should be removable
* with no ill consequences.
*
- * TODO: This code behaves badly on surprise removal!
+ * This code handles surprise removal. The ibmcam->user is a counter which
+ * increments on open() and decrements on close(). If we see here that
+ * this counter is not 0 then we have a client who still has us opened.
+ * We set ibmcam->remove_pending flag as early as possible, and after that
+ * all access to the camera will gracefully fail. These failures should
+ * prompt client to (eventually) close the video device, and then - in
+ * ibmcam_close() - we decrement ibmcam->ibmcam_used and usage counter.
*
* History:
* 1/22/00 Added polling of MOD_IN_USE to delay removal until all users gone.
* 1/27/00 Reworked to allow pending disconnects; see ibmcam_close()
+ * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
*/
static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr)
{
static const char proc[] = "usb_ibmcam_disconnect";
struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr;
+ MOD_INC_USE_COUNT;
+
if (debug > 0)
printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr);
@@ -3077,16 +3091,14 @@ static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr)
ibmcam->dev = NULL; /* USB device is no more */
-#if IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED
- MOD_DEC_USE_COUNT;
-#endif
if (ibmcam->user)
printk(KERN_INFO "%s: In use, disconnect pending.\n", proc);
else
usb_ibmcam_release(ibmcam);
up(&ibmcam->lock);
-
printk(KERN_INFO "IBM USB camera disconnected.\n");
+
+ MOD_DEC_USE_COUNT;
}
static struct usb_driver ibmcam_driver = {
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index e97410c32..3ffb6f8eb 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -30,7 +30,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-static const char version[] = "1.14";
+static const char version[] = "1.15";
#define __NO_VERSION__
@@ -216,7 +216,7 @@ static void *rvmalloc(unsigned long size)
size += (PAGE_SIZE - 1);
size &= ~(PAGE_SIZE - 1);
- mem = vmalloc(size);
+ mem = vmalloc_32(size);
if (!mem)
return NULL;
@@ -263,9 +263,10 @@ static void rvfree(void *mem, unsigned long size)
* Based on the CPiA driver version 0.7.4 -claudio
**********************************************************************/
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
static struct proc_dir_entry *ov511_proc_entry = NULL;
-static struct proc_dir_entry *video_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
#define YES_NO(x) ((x) ? "yes" : "no")
@@ -343,6 +344,7 @@ static int ov511_read_proc(char *page, char **start, off_t off,
len = count;
*start = page + off;
+
return len;
}
@@ -357,12 +359,11 @@ static void create_proc_ov511_cam (struct usb_ov511 *ov511)
char name[7];
struct proc_dir_entry *ent;
- PDEBUG (4, "creating /proc/video/ov511/videoX entry");
if (!ov511_proc_entry || !ov511)
return;
sprintf(name, "video%d", ov511->vdev.minor);
- PDEBUG (4, "creating %s", name);
+ PDEBUG (4, "creating /proc/video/ov511/%s", name);
ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_entry);
@@ -372,7 +373,6 @@ static void create_proc_ov511_cam (struct usb_ov511 *ov511)
ent->data = ov511;
ent->read_proc = ov511_read_proc;
ent->write_proc = ov511_write_proc;
- ent->size = 3626; /* FIXME */
ov511->proc_entry = ent;
}
@@ -391,22 +391,13 @@ static void destroy_proc_ov511_cam (struct usb_ov511 *ov511)
static void proc_ov511_create(void)
{
- struct proc_dir_entry *p = NULL;
-
/* No current standard here. Alan prefers /proc/video/ as it keeps
* /proc "less cluttered than /proc/randomcardifoundintheshed/"
* -claudio
*/
- PDEBUG (3, "creating /proc/video");
- video_proc_entry = proc_mkdir("video", p);
- if (!video_proc_entry) {
- if (!p) {
- err("Unable to initialise /proc/video\n");
- return;
- } else { /* FIXME - this doesn't work */
- PDEBUG (3, "/proc/video already exists");
- video_proc_entry = p;
- }
+ if (video_proc_entry == NULL) {
+ err("Unable to initialise /proc/video/ov511");
+ return;
}
ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry);
@@ -414,16 +405,19 @@ static void proc_ov511_create(void)
if (ov511_proc_entry)
ov511_proc_entry->owner = THIS_MODULE;
else
- err("Unable to initialise /proc/video/ov511\n");
+ err("Unable to initialise /proc/ov511");
}
static void proc_ov511_destroy(void)
{
PDEBUG (3, "removing /proc/video/ov511");
+
+ if (ov511_proc_entry == NULL)
+ return;
+
remove_proc_entry("ov511", video_proc_entry);
- remove_proc_entry("video", NULL);
}
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
/**********************************************************************
@@ -852,7 +846,7 @@ ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
return 0;
}
-/* FIXME: add 176x144, 160x140 */
+/* FIXME: add 400x300, 176x144, 160x140 */
static struct mode_list mlist[] = {
{ 640, 480, VIDEO_PALETTE_GREY, 0x4f, 0x3d, 0x00, 0x00,
0x4f, 0x3d, 0x00, 0x00, 0x04, 0x03, 0x24, 0x04, 0x9e },
@@ -866,6 +860,14 @@ static struct mode_list mlist[] = {
0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
{ 352, 288, VIDEO_PALETTE_RGB24,0x2b, 0x25, 0x00, 0x00,
0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ { 384, 288, VIDEO_PALETTE_GREY, 0x2f, 0x25, 0x00, 0x00,
+ 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ { 384, 288, VIDEO_PALETTE_RGB24,0x2f, 0x25, 0x00, 0x00,
+ 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ { 448, 336, VIDEO_PALETTE_GREY, 0x37, 0x29, 0x00, 0x00,
+ 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ { 448, 336, VIDEO_PALETTE_RGB24,0x37, 0x29, 0x00, 0x00,
+ 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
{ 0, 0 }
};
@@ -1302,158 +1304,190 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
int i, totlen = 0;
int aPackNum[10];
struct ov511_frame *frame;
+ unsigned char *pData;
+ int iPix;
- PDEBUG(4, "ov511_move_data");
+ PDEBUG (4, "Moving %d packets", urb->number_of_packets);
for (i = 0; i < urb->number_of_packets; i++) {
int n = urb->iso_frame_desc[i].actual_length;
int st = urb->iso_frame_desc[i].status;
+
urb->iso_frame_desc[i].actual_length = 0;
urb->iso_frame_desc[i].status = 0;
+
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
- if (!n || ov511->curframe == -1) continue;
+ if (!n || ov511->curframe == -1)
+ continue;
if (st)
PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
frame = &ov511->frame[ov511->curframe];
- /* Can we find a frame end */
+ /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+ * byte non-zero. The EOF packet has image width/height in the
+ * 10th and 11th packets. The 9th bit is given as follows:
+ *
+ * bit 7: EOF
+ * 6: compression enabled
+ * 5: 422/420/400 modes
+ * 4: 422/420/400 modes
+ * 3: 1
+ * 2: snapshot bottom on
+ * 1: snapshot frame
+ * 0: even/odd field
+ */
+
+ /* Check for SOF/EOF packet */
if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
- cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
- (cdata[8] & 8) && (cdata[8] & 0x80)) {
+ cdata[4] | cdata[5] | cdata[6] | cdata[7]) ||
+ (~cdata[8] & 0x08))
+ goto check_middle;
+
+ /* Frame end */
+ if (cdata[8] & 0x80) {
+#if 0
+ struct timeval *ts;
+
+ ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE);
+ do_gettimeofday (ts);
+#endif
- struct timeval *ts;
- ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE);
- do_gettimeofday(ts);
+ PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d",
+ ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
+ (int)(cdata[9]), (int)(cdata[10]));
- PDEBUG(4, "Frame End, curframe = %d, packnum=%d, hw=%d, vw=%d",
- ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
- (int)(cdata[9]), (int)(cdata[10]));
+ if (frame->scanstate == STATE_LINES) {
+ int iFrameNext;
- if (frame->scanstate == STATE_LINES) {
- int iFrameNext;
if (fix_rgb_offset)
fixFrameRGBoffset(frame);
frame->grabstate = FRAME_DONE;
- if (waitqueue_active(&frame->wq)) {
- frame->grabstate = FRAME_DONE;
- wake_up_interruptible(&frame->wq);
+
+ if (waitqueue_active(&frame->wq)) {
+ frame->grabstate = FRAME_DONE;
+ wake_up_interruptible(&frame->wq);
}
- /* If next frame is ready or grabbing, point to it */
+
+ /* If next frame is ready or grabbing,
+ * point to it */
iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES;
- if (ov511->frame[iFrameNext].grabstate== FRAME_READY ||
- ov511->frame[iFrameNext].grabstate== FRAME_GRABBING) {
- ov511->curframe = iFrameNext;
- ov511->frame[iFrameNext].scanstate = STATE_SCANNING;
+ if (ov511->frame[iFrameNext].grabstate == FRAME_READY
+ || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) {
+ ov511->curframe = iFrameNext;
+ ov511->frame[iFrameNext].scanstate = STATE_SCANNING;
} else {
-
- PDEBUG(4, "Frame not ready? state = %d",
- ov511->frame[iFrameNext].grabstate);
-
- ov511->curframe = -1;
+ if (frame->grabstate == FRAME_DONE) {
+ PDEBUG(4, "Frame done! congratulations");
+ } else {
+ PDEBUG(4, "Frame not ready? state = %d",
+ ov511->frame[iFrameNext].grabstate);
+ }
+
+ ov511->curframe = -1;
}
- }
- }
-
- /* Can we find a frame start */
- else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
- cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
- (cdata[8] & 8)) {
-
- PDEBUG(4, "ov511: Found Frame Start!, framenum = %d",
- ov511->curframe);
+ }
+ /* Image corruption caused by misplaced frame->segment = 0
+ * fixed by carlosf@conectiva.com.br
+ */
+ } else {
+ /* Frame start */
+ PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);
/* Check to see if it's a snapshot frame */
/* FIXME?? Should the snapshot reset go here? Performance? */
if (cdata[8] & 0x02) {
frame->snapshot = 1;
- PDEBUG(3, "ov511_move_data: snapshot detected");
+ PDEBUG(3, "snapshot detected");
}
frame->scanstate = STATE_LINES;
frame->segment = 0;
}
+check_middle:
/* Are we in a frame? */
- if (frame->scanstate == STATE_LINES) {
- unsigned char * pData;
- int iPix;
-
- /* Deal with leftover from last segment, if any */
- if (frame->segment) {
- pData = ov511->scratch;
- iPix = - ov511->scratchlen;
- memmove(pData + ov511->scratchlen, cdata,
- iPix+frame->segsize);
- } else {
- pData = &cdata[iPix = 9];
- }
-
- /* Parse the segments */
- while(iPix <= (ov511->packet_size - 1) - frame->segsize &&
- frame->segment < frame->width * frame->height / 256) {
- int iSegY;
- int iSegUV;
- int iY, jY, iUV, jUV;
- int iOutY, iOutUV;
- unsigned char * pOut;
-
- iSegY = iSegUV = frame->segment;
- pOut = frame->data;
-
- frame->segment++;
- iPix += frame->segsize;
-
- if (frame->sub_flag) {
- int iSeg1;
- iSeg1 = iSegY / (ov511->subw / 32);
- iSeg1 *= frame->width / 32;
- iSegY = iSeg1 + (iSegY % (ov511->subw / 32));
- if (iSegY >= frame->width * ov511->subh / 256)
- break;
-
- iSeg1 = iSegUV / (ov511->subw / 16);
- iSeg1 *= frame->width / 16;
- iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16));
-
- pOut += (ov511->subx +
- ov511->suby * frame->width) * frame->depth;
- }
-
- iY = iSegY / (frame->width / WDIV);
- jY = iSegY - iY * (frame->width / WDIV);
- iOutY = (iY*HDIV*frame->width + jY*WDIV) * frame->depth;
- iUV = iSegUV / (frame->width / WDIV * 2);
- jUV = iSegUV - iUV * (frame->width / WDIV * 2);
- iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * frame->depth;
-
- if (frame->format == VIDEO_PALETTE_GREY) {
- ov511_parse_data_grey(pData, pOut, iOutY, frame->width);
- } else if (frame->format == VIDEO_PALETTE_RGB24) {
- ov511_parse_data_rgb24(pData, pOut, iOutY, iOutUV, iY & 1,
- frame->width);
- }
- pData = &cdata[iPix];
- }
+ if (frame->scanstate != STATE_LINES)
+ continue;
- /* Save extra data for next time */
- if (frame->segment < frame->width * frame->height / 256) {
- ov511->scratchlen = (ov511->packet_size - 1) - iPix;
- if (ov511->scratchlen < frame->segsize) {
- memmove(ov511->scratch, pData, ov511->scratchlen);
- } else {
- ov511->scratchlen = 0;
- }
+ /* Deal with leftover from last segment, if any */
+ if (frame->segment) {
+ pData = ov511->scratch;
+ iPix = -ov511->scratchlen;
+ memmove(pData + ov511->scratchlen, cdata,
+ iPix+frame->segsize);
+ } else {
+ pData = &cdata[iPix = 9];
+ }
+
+ /* Parse the segments */
+ while (iPix <= (ov511->packet_size - 1) - frame->segsize &&
+ frame->segment < frame->width * frame->height / 256) {
+ int iSegY, iSegUV;
+ int iY, jY, iUV, jUV;
+ int iOutY, iOutUV;
+ unsigned char *pOut;
+
+ iSegY = iSegUV = frame->segment;
+ pOut = frame->data;
+ frame->segment++;
+ iPix += frame->segsize;
+
+ /* Handle subwindow */
+ if (frame->sub_flag) {
+ int iSeg1;
+
+ iSeg1 = iSegY / (ov511->subw / 32);
+ iSeg1 *= frame->width / 32;
+ iSegY = iSeg1 + (iSegY % (ov511->subw / 32));
+ if (iSegY >= frame->width * ov511->subh / 256)
+ break;
+
+ iSeg1 = iSegUV / (ov511->subw / 16);
+ iSeg1 *= frame->width / 16;
+ iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16));
+
+ pOut += (ov511->subx + ov511->suby * frame->width) *
+ (frame->depth >> 3);
}
+
+ /*
+ * iY counts segment lines
+ * jY counts segment columns
+ * iOutY is the offset (in bytes) of the segment upper left corner
+ */
+ iY = iSegY / (frame->width / WDIV);
+ jY = iSegY - iY * (frame->width / WDIV);
+ iOutY = (iY*HDIV*frame->width + jY*WDIV) * (frame->depth >> 3);
+ iUV = iSegUV / (frame->width / WDIV * 2);
+ jUV = iSegUV - iUV * (frame->width / WDIV * 2);
+ iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * (frame->depth >> 3);
+
+ if (frame->format == VIDEO_PALETTE_GREY)
+ ov511_parse_data_grey (pData, pOut, iOutY, frame->width);
+ else if (frame->format == VIDEO_PALETTE_RGB24)
+ ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV,
+ iY & 1, frame->width);
+
+ pData = &cdata[iPix];
}
- }
+ /* Save extra data for next time */
+ if (frame->segment < frame->width * frame->height / 256) {
+ ov511->scratchlen = (ov511->packet_size - 1) - iPix;
+ if (ov511->scratchlen < frame->segsize)
+ memmove(ov511->scratch, pData,
+ ov511->scratchlen);
+ else
+ ov511->scratchlen = 0;
+ }
+ }
- PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d\n",
+ PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
@@ -1472,8 +1506,6 @@ static void ov511_isoc_irq(struct urb *urb)
if (!ov511->streaming) {
PDEBUG(2, "hmmm... not streaming, but got interrupt");
return;
- } else {
- PDEBUG(5, "streaming. got interrupt");
}
sbuf = &ov511->sbuf[ov511->cursbuf];
@@ -1723,7 +1755,7 @@ static void ov511_close(struct video_device *dev)
static int ov511_init_done(struct video_device *dev)
{
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
create_proc_ov511_cam((struct usb_ov511 *)dev);
#endif
@@ -1749,6 +1781,8 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
struct video_capability b;
+ PDEBUG (4, "VIDIOCGCAP");
+
strcpy(b.name, "OV511 USB Camera");
b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
b.channels = 1;
@@ -1798,6 +1832,8 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
struct video_picture p;
+ PDEBUG (4, "VIDIOCGPICT");
+
if (ov7610_get_picture(ov511, &p))
return -EIO;
@@ -1809,18 +1845,33 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
case VIDIOCSPICT:
{
struct video_picture p;
+ int i;
+
+ PDEBUG (4, "VIDIOCSPICT");
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
-
+
if (ov7610_set_picture(ov511, &p))
return -EIO;
+ /* FIXME: check validity */
+
+ PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
+ for (i = 0; i < OV511_NUMFRAMES; i++) {
+ ov511->frame[i].depth = p.depth;
+ ov511->frame[i].format = p.palette;
+ ov511->frame[i].segsize = GET_SEGSIZE(p.palette);
+ }
+
return 0;
}
case VIDIOCGCAPTURE:
{
int vf;
+
+ PDEBUG (4, "VIDIOCGCAPTURE");
+
if (copy_from_user(&vf, arg, sizeof(vf)))
return -EFAULT;
ov511->sub_flag = vf;
@@ -1836,16 +1887,25 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
return -EINVAL;
if (vc.decimation)
return -EINVAL;
+#if 0
vc.x /= 4;
vc.x *= 4;
vc.y /= 2;
vc.y *= 2;
vc.width /= 32;
vc.width *= 32;
- if (vc.width == 0) vc.width = 32;
+#else
+ vc.x &= ~3L;
+ vc.y &= ~1L;
+ vc.y &= ~31L;
+#endif
+ if (vc.width == 0)
+ vc.width = 32;
+
vc.height /= 16;
vc.height *= 16;
- if (vc.height == 0) vc.height = 16;
+ if (vc.height == 0)
+ vc.height = 16;
ov511->subx = vc.x;
ov511->suby = vc.y;
@@ -1857,9 +1917,15 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
case VIDIOCSWIN:
{
struct video_window vw;
+ int i, result;
if (copy_from_user(&vw, arg, sizeof(vw)))
return -EFAULT;
+
+ PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d",
+ vw.width, vw.height);
+
+#if 0
if (vw.flags)
return -EINVAL;
if (vw.clipcount)
@@ -1868,8 +1934,22 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
return -EINVAL;
if (vw.width != DEFAULT_WIDTH)
return -EINVAL;
+#endif
+
+ /* If we're collecting previous frame wait
+ before changing modes */
+ interruptible_sleep_on(&ov511->wq);
+ if (signal_pending(current)) return -EINTR;
- ov511->compress = 0;
+ result = ov511_mode_init_regs(ov511, vw.width, vw.height,
+ ov511->frame[0].format, ov511->sub_flag);
+ if (result < 0)
+ return result;
+
+ for (i = 0; i < OV511_NUMFRAMES; i++) {
+ ov511->frame[i].width = vw.width;
+ ov511->frame[i].height = vw.height;
+ }
return 0;
}
@@ -1877,13 +1957,15 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
struct video_window vw;
- vw.x = 0;
+ vw.x = 0; /* FIXME */
vw.y = 0;
- vw.width = DEFAULT_WIDTH;
- vw.height = DEFAULT_HEIGHT;
+ vw.width = ov511->frame[0].width;
+ vw.height = ov511->frame[0].height;
vw.chromakey = 0;
vw.flags = 30;
+ PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
+
if (copy_to_user(arg, &vw, sizeof(vw)))
return -EFAULT;
@@ -1935,19 +2017,16 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
before changing modes */
interruptible_sleep_on(&ov511->wq);
if (signal_pending(current)) return -EINTR;
- ov511_mode_init_regs(ov511,
- vm.width, vm.height,
- vm.format, ov511->sub_flag);
+ ov511_mode_init_regs(ov511, vm.width, vm.height,
+ vm.format, ov511->sub_flag);
}
ov511->frame[vm.frame].width = vm.width;
ov511->frame[vm.frame].height = vm.height;
ov511->frame[vm.frame].format = vm.format;
ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
- ov511->frame[vm.frame].segsize =
- vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256;
- ov511->frame[vm.frame].depth =
- vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1;
+ ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format);
+ ov511->frame[vm.frame].depth = GET_DEPTH(vm.format);
/* Mark it as ready */
ov511->frame[vm.frame].grabstate = FRAME_READY;
@@ -1965,11 +2044,11 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
ov511->frame[frame].grabstate);
switch (ov511->frame[frame].grabstate) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- case FRAME_ERROR:
+ case FRAME_UNUSED:
+ return -EINVAL;
+ case FRAME_READY:
+ case FRAME_GRABBING:
+ case FRAME_ERROR:
redo:
if (!ov511->dev)
return -EIO;
@@ -1989,23 +2068,21 @@ redo:
if ((ret = ov511_new_frame(ov511, frame)) < 0)
return ret;
goto redo;
- }
- case FRAME_DONE:
- ov511->frame[frame].grabstate = FRAME_UNUSED;
- break;
- }
-
- ov511->frame[frame].grabstate = FRAME_UNUSED;
-
- /* Reset the hardware snapshot button */
- /* FIXME - Is this the best place for this? */
- if ((ov511->snap_enabled) &&
- (ov511->frame[frame].snapshot)) {
- ov511->frame[frame].snapshot = 0;
- ov511_reg_write(ov511->dev, 0x52, 0x01);
- ov511_reg_write(ov511->dev, 0x52, 0x03);
- ov511_reg_write(ov511->dev, 0x52, 0x01);
- }
+ }
+ case FRAME_DONE:
+ ov511->frame[frame].grabstate = FRAME_UNUSED;
+
+ /* Reset the hardware snapshot button */
+ /* FIXME - Is this the best place for this? */
+ if ((ov511->snap_enabled) &&
+ (ov511->frame[frame].snapshot)) {
+ ov511->frame[frame].snapshot = 0;
+ ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+ ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03);
+ ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+ }
+ break;
+ } /* end switch */
return 0;
}
@@ -2038,7 +2115,7 @@ redo:
return -EINVAL;
default:
return -ENOIOCTLCMD;
- } /* End switch(cmd) */
+ } /* end switch */
return 0;
}
@@ -2610,7 +2687,7 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
ov511->sbuf[0].urb = NULL;
}
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
destroy_proc_ov511_cam(ov511);
#endif
@@ -2637,8 +2714,7 @@ static struct usb_driver ov511_driver = {
static int __init usb_ov511_init(void)
{
-#ifdef CONFIG_PROC_FS
- PDEBUG(3, "creating /proc/ov511");
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
proc_ov511_create();
#endif
@@ -2655,7 +2731,7 @@ static void __exit usb_ov511_exit(void)
usb_deregister(&ov511_driver);
info("ov511 driver deregistered");
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
proc_ov511_destroy();
#endif
}