patch-2.3.17 linux/drivers/usb/mouse.c
Next file: linux/drivers/usb/ohci.c
Previous file: linux/drivers/usb/inits.h
Back to the patch index
Back to the overall index
- Lines: 162
- Date:
Wed Sep 1 16:24:19 1999
- Orig file:
v2.3.16/linux/drivers/usb/mouse.c
- Orig date:
Thu Aug 26 13:05:39 1999
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
@@ -4,6 +4,12 @@
*
* Brad Keryan 4/3/1999
*
+ * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse
+ * disconnect and suspend/resume. Added module parameter "force=1"
+ * to allow opening of the mouse driver before mouse has been plugged
+ * in (enables consistent XF86Config settings). Fixed module use count.
+ * Documented missing blocking/non-blocking read handling (not fixed).
+ *
* version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
* correctly. Events are added together, not queued, to keep the rodent sober.
*
@@ -49,6 +55,7 @@
int present; /* this mouse is plugged in */
int active; /* someone is has this mouse's device open */
int ready; /* the mouse has changed state since the last read */
+ int suspended; /* mouse disconnected */
wait_queue_head_t wait; /* for polling */
struct fasync_struct *fasync;
/* later, add a list here to support multiple mice */
@@ -65,12 +72,38 @@
spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
+static int force=0; /* allow the USB mouse to be opened even if not there (yet) */
+MODULE_PARM(force,"i");
+
static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
{
signed char *data = __buffer;
/* finding the mouse is easy when there's only one */
struct mouse_state *mouse = &static_mouse_state;
+ if (state)
+ printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d, dp %p\n",
+ __FILE__, __LINE__, state, __buffer, len, dev_id);
+
+ /*
+ * USB_ST_NOERROR is the normal case.
+ * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume
+ * USB_ST_INTERNALERROR occurs if system suspended then mouse removed
+ * followed by resume. On UHCI could then occur every second
+ * In both cases, suspend the mouse
+ * On other states, ignore
+ */
+ switch (state) {
+ case USB_ST_REMOVED:
+ case USB_ST_INTERNALERROR:
+ printk(KERN_DEBUG "%s(%d): Suspending\n",
+ __FILE__, __LINE__);
+ mouse->suspended = 1;
+ return 0; /* disable */
+ case USB_ST_NOERROR: break;
+ default: return 1; /* ignore */
+ }
+
/* if a mouse moves with no one listening, do we care? no */
if(!mouse->active)
return 1;
@@ -110,9 +143,11 @@
fasync_mouse(-1, file, 0);
+ printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__);
MOD_DEC_USE_COUNT;
if (--mouse->active == 0) {
+ mouse->suspended = 0;
/* stop polling the mouse while its not in use */
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
@@ -126,15 +161,38 @@
{
struct mouse_state *mouse = &static_mouse_state;
+ printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__);
+ /*
+ * First open may fail since mouse_probe() may get called after this
+ * if module load is in response to the open
+ * mouse_probe() sets mouse->present. This open can be delayed by
+ * specifying force=1 in module load
+ * This helps if you want to insert the USB mouse after starting X
+ */
if (!mouse->present)
- return -EINVAL;
+ {
+ if (force) /* always load the driver even if no mouse (yet) */
+ {
+ printk(KERN_DEBUG "%s(%d): forced open\n",
+ __FILE__, __LINE__);
+ mouse->suspended = 1;
+ }
+ else
+ return -EINVAL;
+ }
+
+ /* prevent the driver from being unloaded while its in use */
+ printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__);
+ /* Increment use count even if already active */
+ MOD_INC_USE_COUNT;
+
if (mouse->active++)
return 0;
/* flush state */
mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
- /* prevent the driver from being unloaded while its in use */
- MOD_INC_USE_COUNT;
+ if (!mouse->present) /* only get here if force == 1 */
+ return 0;
/* start the usb controller's polling of the mouse */
mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
@@ -160,6 +218,10 @@
static int state = 0;
struct mouse_state *mouse = &static_mouse_state;
+ /*
+ * FIXME - Other mouse drivers handle blocking and nonblocking reads
+ * differently here...
+ */
if (count) {
mouse->ready = 0;
switch (state) {
@@ -304,6 +366,19 @@
mouse->bInterval = endpoint->bInterval;
mouse->present = 1;
+
+ /* This appears to let USB mouse survive disconnection and */
+ /* APM suspend/resume */
+ if (mouse->suspended)
+ {
+ printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__);
+ /* restart the usb controller's polling of the mouse */
+ mouse->irq_handle = usb_request_irq(mouse->dev,
+ usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
+ mouse_irq, mouse->bInterval, NULL);
+ mouse->suspended = 0;
+ }
+
return 0;
}
@@ -315,7 +390,6 @@
if (mouse->present) {
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
- mouse->irq_handle = NULL;
}
mouse->irq_handle = NULL;
@@ -336,7 +410,7 @@
{
struct mouse_state *mouse = &static_mouse_state;
- mouse->present = mouse->active = 0;
+ mouse->present = mouse->active = mouse->suspended = 0;
mouse->irq_handle = NULL;
init_waitqueue_head(&mouse->wait);
mouse->fasync = NULL;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)