Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S262031AbVBAO5D (ORCPT ); Tue, 1 Feb 2005 09:57:03 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S262026AbVBAOzu (ORCPT ); Tue, 1 Feb 2005 09:55:50 -0500 Received: from adsl-67-64-210-234.dsl.stlsmo.swbell.net ([67.64.210.234]:55711 "EHLO SpacedOut.fries.net") by vger.kernel.org with ESMTP id S262031AbVBAOxN (ORCPT ); Tue, 1 Feb 2005 09:53:13 -0500 Date: Tue, 1 Feb 2005 08:52:15 -0600 From: David Fries To: Vojtech Pavlik Cc: Linus Torvalds , trivial@rustcorp.com.au, linux-kernel@vger.kernel.org Subject: [PATCH] Linux joydev joystick disconnect patch 2.6.11-rc2 Message-ID: <20050201145215.GA29942@spacedout.fries.net> References: <20041123212813.GA3196@spacedout.fries.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="Q68bSM7Ycu6FN28Q" Content-Disposition: inline In-Reply-To: <20041123212813.GA3196@spacedout.fries.net> User-Agent: Mutt/1.5.4i Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6749 Lines: 284 --Q68bSM7Ycu6FN28Q Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Currently a blocking read, select, or poll call will not return if a joystick device is unplugged. This patch allows them to return. This patch adds a wake_up_interruptible call to the joydev_disconnect to interrupt both a blocking read and a blocking poll call. The read routine was already setup to handle this situation, just nothing was waking it up. The poll routine required only minimal changes to report the error condition. It is important to find out when the joystick has been disconnected instead of blocking forever. I tested it with a USB joystick, or rather I keep on getting the following messages and my application needed to know when the joystick was removed to close the port and re-open it when the USB system has completed rediscovering it. hub 4-0:1.0: port 1 enable change, status 00000101 hub 4-0:1.0: port 1 disabled by hub (EMI?), re-enabling... hub 4-0:1.0: port 1, status 0101, change 0002, 12 Mb/s usb 4-1: USB disconnect, address 39 usb 4-1: usb_disable_device nuking all URBs I can reliably enough reproduce the problem by standing up as the static on my cloth chair followed by a discharge to the chair is enough to cause the joystick to be disabled by the USB HUB even if I'm only touching the chair and floor! The kernel then removes the old joystick and redetects it as a new joystick. I've also included a test program to verify that a blocking select, poll, and read call will return if the joystick is unplugged. -- David Fries http://fries.net/~david/pgpkey.txt Signed-off-by: David Fries --- drivers/input/joydev.c.orig Tue Feb 1 08:39:52 2005 +++ drivers/input/joydev.c Tue Feb 1 08:40:15 2005 @@ -279,11 +279,14 @@ static ssize_t joydev_read(struct file * /* No kernel lock - fine */ static unsigned int joydev_poll(struct file *file, poll_table *wait) { + int mask = 0; struct joydev_list *list = file->private_data; poll_wait(file, &list->joydev->wait, wait); - if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) - return POLLIN | POLLRDNORM; - return 0; + if(!list->joydev->exist) + mask |= POLLERR; + if(list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) + mask |= POLLIN | POLLRDNORM; + return mask; } static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -469,9 +472,14 @@ static void joydev_disconnect(struct inp joydev->exist = 0; if (joydev->open) + { input_close_device(handle); + wake_up_interruptible(&joydev->wait); + } else + { joydev_free(joydev); + } } static struct input_device_id joydev_blacklist[] = { --Q68bSM7Ycu6FN28Q Content-Type: text/x-csrc; charset=us-ascii Content-Disposition: attachment; filename="joystick_select.c" #include #include #include #include #include #include #include #include #include #include #include //#define UFDS_COUNT 10 #define UFDS_COUNT 1 void select_call(const char *device) { int result, fd; fd_set tmpfds, readfds, writefds, exceptfds; fd = open(device, O_RDONLY | O_NONBLOCK); if(fd == -1) { fprintf(stderr, "Error opening %s: %s\n", device, strerror(errno)); exit(1); } FD_ZERO(&tmpfds); FD_SET(fd, &tmpfds); for(;;) { writefds = exceptfds = readfds = tmpfds; result = select(fd+1, &readfds, &writefds, &exceptfds, NULL); if(result == -1) { perror("Select error"); exit(1); } if(FD_ISSET(fd, &readfds)) { struct js_event event; int size; printf("%s readable\n", __FUNCTION__); size = read(fd, &event, sizeof(event)); if(size == -1) { fprintf(stderr, "%s Error reading data\n", __FUNCTION__); if(errno == ENODEV) exit(1); } } if(FD_ISSET(fd, &writefds)) { printf("%s writable\n", __FUNCTION__); } if(FD_ISSET(fd, &exceptfds)) { printf("%s exception\n", __FUNCTION__); break; } } } void poll_call(const char *device) { int i, result, fd; struct pollfd ufds[UFDS_COUNT]; fd = open(device, O_RDONLY | O_NONBLOCK); if(fd == -1) { fprintf(stderr, "Error opening %s: %s\n", device, strerror(errno)); exit(1); } for(i=0; i