You can subscribe to this list here.
2002 |
Jan
(53) |
Feb
(14) |
Mar
(2) |
Apr
(2) |
May
(3) |
Jun
|
Jul
(1) |
Aug
(28) |
Sep
(4) |
Oct
(11) |
Nov
(2) |
Dec
(1) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(49) |
Feb
(15) |
Mar
|
Apr
(4) |
May
(26) |
Jun
(7) |
Jul
(1) |
Aug
(9) |
Sep
(1) |
Oct
|
Nov
|
Dec
(3) |
2004 |
Jan
(5) |
Feb
(2) |
Mar
(22) |
Apr
(7) |
May
(2) |
Jun
(2) |
Jul
(5) |
Aug
(3) |
Sep
(2) |
Oct
|
Nov
|
Dec
|
From: Alexander S. <a.s...@ne...> - 2004-09-18 19:28:22
|
Hello all, I encountered some probems by using the legousbtower driver and would need some assistance. I am using Kernel Version 2.6.5 and was lucky to see that the legousbdriver is already a part of it but every time I try to communicate by programs from the LeJOS package with the tower I receive an error message "nbread: error exit !" and the kernel log contains a message "Couldn't submit interrupt_in_urb". After searching for a solution on the net I found that the driver is broken. Now my problem. Where can I find a Version which is not broken. The one from CVS seems to be for the wrong kernel version. The source code from this mail archive seems to be truncated and don't work. The diffs I found are truncated, too, or result in many errors when applying them. Many thanks in advance for help Alex |
From: Juergen S. <ju...@js...> - 2004-08-10 08:33:22
|
Hi Stewart, Stewart Heitmann wrote: > > since I have very little to do with this project these days, > and it is unlikley that situation will change soon, I feel its time I > signed-off from the project and bid you all farewell. >=20 > I am going back to Uni to study Psychology, as well as doing > part-time work as an embedded Linux developer, so my time is very full. >=20 > All the best for the future driver development, and maybe I'll see you > on-line. tanks, and many thanks to you for your work on the driver, I know it wasn't easy under 2.4. > Project admins, can one of you please remove from the > developer list - thanks. Ok, done. Good luck and success with your studies and whatever you're doing J=FCrgen --=20 J=FCrgen Stuber <ju...@js...> http://www.jstuber.net/ gnupg key fingerprint =3D 2767 CA3C 5680 58BA 9A91 23D9 BED6 9A7A AF9E 6= 8B4 |
From: Stewart H. <she...@us...> - 2004-08-09 23:03:17
|
legousb dev team, since I have very little to do with this project these days, and it is unlikley that situation will change soon, I feel its time I signed-off from the project and bid you all farewell. I am going back to Uni to study Psychology, as well as doing part-time work as an embedded Linux developer, so my time is very full. All the best for the future driver development, and maybe I'll see you on-line. Project admins, can one of you please remove from the developer list - thanks. -- Stewart Heitmann <she...@us...> |
From: Greg KH <gr...@kr...> - 2004-08-05 21:57:21
|
On Wed, Aug 04, 2004 at 08:48:38PM +0200, Juergen Stuber wrote: > The following message is a courtesy copy of an article > that has been posted to gmane.linux.usb.devel as well. > > Hi, > > the following patch reduces the amount of garbage data sent by > the device after open (must be the heat here causing trouble). > > Please apply. Applied, thanks. greg k-h |
From: Juergen S. <st...@lo...> - 2004-04-30 21:44:03
|
The following message is a courtesy copy of an article that has been posted to gmane.linux.usb.devel as well. Hi, here is the latest version 0.95 of the LEGO USB Tower driver against 2.6.= 6-rc3 which corrects a lot of problems in the version currently in the kernel, most notably sleeping in interrupt context and improper locking. Please apply. It has been thoroughly tested with UHCI, OHCI and EHCI host controllers using Lejos and NQC. Firmware and program download, and with proper modifications all communication protocols supported by Lejos work, as well as firmware and program download and datalog upload in NQC. Notes to application maintainers/protocol designers: - Small modifications are needed in communication protocols because the tower tends to discard the first byte of transmissions. So for example LNP needs to send an extra byte like 0xff before the packet, and F7 handlers needs to cope with a lost 0x55. - I suggest /dev/usb/legousbtower0 etc. as the standard device names. This puts it in the same place as the other USB devices and makes clear which driver is responsible for these devices. diff -uprN -X dontdiff linux-2.6.6-rc3/MAINTAINERS linux-2.6.6-rc3-legous= btower-0.95/MAINTAINERS --- linux-2.6.6-rc3/MAINTAINERS 2004-04-28 03:36:02.000000000 +0200 +++ linux-2.6.6-rc3-legousbtower-0.95/MAINTAINERS 2004-04-30 17:30:25.000= 000000 +0200 @@ -1228,6 +1228,13 @@ M: James.Bottomley@HansenPartnership.com L: lin...@vg... S: Maintained =20 +LEGO USB Tower driver +P: Juergen Stuber +M: sta...@us... +L: leg...@li... +W: http://legousb.sourceforge.net/ +S: Maintained + LINUX FOR IBM pSERIES (RS/6000) P: Paul Mackerras M: pa...@au... diff -uprN -X dontdiff linux-2.6.6-rc3/drivers/usb/misc/legousbtower.c li= nux-2.6.6-rc3-legousbtower-0.95/drivers/usb/misc/legousbtower.c --- linux-2.6.6-rc3/drivers/usb/misc/legousbtower.c 2004-04-28 03:35:46.0= 00000000 +0200 +++ linux-2.6.6-rc3-legousbtower-0.95/drivers/usb/misc/legousbtower.c 200= 4-04-30 21:44:31.000000000 +0200 @@ -1,8 +1,8 @@ /* * LEGO USB Tower driver * - * Copyright (C) 2003 David Glance <dav...@so...>=20 - * 2001 Juergen Stuber <st...@lo...> + * Copyright (C) 2003 David Glance <dav...@so...> + * 2001-2004 Juergen Stuber <sta...@us...= t> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,14 +33,44 @@ * - changed to use lego0 rather than tower0 * - changed dbg() to use __func__ rather than deprecated __FUNCTION__ * 2003-01-12 - 0.53 david (da...@cs...) - * - changed read and write to write everything or timeout (from a pat= ch by Chris Riesen and=20 - * Brett Thaeler driver) + * - changed read and write to write everything or + * timeout (from a patch by Chris Riesen and Brett Thaeler driver) * - added ioctl functionality to set timeouts - * 2003-07-18 - 0.54 davidgsf (da...@cs...)=20 + * 2003-07-18 - 0.54 davidgsf (da...@cs...) * - initial import into LegoUSB project * - merge of existing LegoUSB.c driver - * 2003-07-18 - 0.56 davidgsf (da...@cs...)=20 + * 2003-07-18 - 0.56 davidgsf (da...@cs...) * - port to 2.6 style driver + * 2004-02-29 - 0.6 Juergen Stuber <sta...@us...> + * - fix locking + * - unlink read URBs which are no longer needed + * - allow increased buffer size, eliminates need for timeout on write + * - have read URB running continuously + * - added poll + * - forbid seeking + * - added nonblocking I/O + * - changed back __func__ to __FUNCTION__ + * - read and log tower firmware version + * - reset tower on probe, avoids failure of first write + * 2004-03-09 - 0.7 Juergen Stuber <sta...@us...> + * - timeout read now only after inactivity, shorten default according= ly + * 2004-03-11 - 0.8 Juergen Stuber <sta...@us...> + * - log major, minor instead of possibly confusing device filename + * - whitespace cleanup + * 2004-03-12 - 0.9 Juergen Stuber <sta...@us...> + * - normalize whitespace in debug messages + * - take care about endianness in control message responses + * 2004-03-13 - 0.91 Juergen Stuber <sta...@us...> + * - make default intervals longer to accommodate current EHCI driver + * 2004-03-19 - 0.92 Juergen Stuber <sta...@us...> + * - replaced atomic_t by memory barriers + * 2004-04-21 - 0.93 Juergen Stuber <sta...@us...> + * - wait for completion of write urb in release (needed for remotecon= trol) + * - corrected poll for write direction (missing negation) + * 2004-04-22 - 0.94 Juergen Stuber <sta...@us...> + * - make device locking interruptible + * 2004-04-30 - 0.95 Juergen Stuber <sta...@us...> + * - check for valid udev on resubmitting and unlinking urbs */ =20 #include <linux/config.h> @@ -53,33 +83,113 @@ #include <linux/completion.h> #include <asm/uaccess.h> #include <linux/usb.h> +#include <linux/poll.h> =20 =20 #ifdef CONFIG_USB_DEBUG static int debug =3D 4; #else - static int debug =3D 1; + static int debug =3D 0; #endif =20 /* Use our own dbg macro */ #undef dbg -#define dbg(lvl, format, arg...) do { if (debug >=3D lvl) printk(KERN_DE= BUG __FILE__ " : " format " \n", ## arg); } while (0) +#define dbg(lvl, format, arg...) do { if (debug >=3D lvl) printk(KERN_DE= BUG __FILE__ ": " format "\n", ## arg); } while (0) =20 =20 /* Version Information */ -#define DRIVER_VERSION "v0.56" -#define DRIVER_AUTHOR "David Glance, dav...@so..." +#define DRIVER_VERSION "v0.95" +#define DRIVER_AUTHOR "Juergen Stuber <sta...@so...>" #define DRIVER_DESC "LEGO USB Tower Driver" =20 -/* Module paramaters */ +/* Module parameters */ MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); =20 +/* The defaults are chosen to work with the latest versions of leJOS and= NQC. + */ + +/* Some legacy software likes to receive packets in one piece. + * In this case read_buffer_size should exceed the maximal packet length + * (417 for datalog uploads), and packet_timeout should be set. + */ +static size_t read_buffer_size =3D 480; +MODULE_PARM(read_buffer_size, "i"); +MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); + +/* Some legacy software likes to send packets in one piece. + * In this case write_buffer_size should exceed the maximal packet lengt= h + * (417 for firmware and program downloads). + * A problem with long writes is that the following read may time out + * if the software is not prepared to wait long enough. + */ +static size_t write_buffer_size =3D 480; +MODULE_PARM(write_buffer_size, "i"); +MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); + +/* Some legacy software expects reads to contain whole LASM packets. + * To achieve this, characters which arrive before a packet timeout + * occurs will be returned in a single read operation. + * A problem with long reads is that the software may time out + * if it is not prepared to wait long enough. + * The packet timeout should be greater than the time between the + * reception of subsequent characters, which should arrive about + * every 5ms for the standard 2400 baud. + * Set it to 0 to disable. + */ +static int packet_timeout =3D 50; +MODULE_PARM(packet_timeout, "i"); +MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); + +/* Some legacy software expects blocking reads to time out. + * Timeout occurs after the specified time of read and write inactivity. + * Set it to 0 to disable. + */ +static int read_timeout =3D 200; +MODULE_PARM(read_timeout, "i"); +MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); + +/* As of kernel version 2.6.4 ehci-hcd uses an + * "only one interrupt transfer per frame" shortcut + * to simplify the scheduling of periodic transfers. + * This conflicts with our standard 1ms intervals for in and out URBs. + * We use default intervals of 2ms for in and 8ms for out transfers, + * which is fast enough for 2400 baud and allows a small additional load= . + * Increase the interval to allow more devices that do interrupt transfe= rs, + * or set to 0 to use the standard interval from the endpoint descriptor= s. + */ +static int interrupt_in_interval =3D 2; +MODULE_PARM(interrupt_in_interval, "i"); +MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms"); + +static int interrupt_out_interval =3D 8; +MODULE_PARM(interrupt_out_interval, "i"); +MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms")= ; =20 /* Define these values to match your device */ #define LEGO_USB_TOWER_VENDOR_ID 0x0694 #define LEGO_USB_TOWER_PRODUCT_ID 0x0001 =20 +/* Vendor requests */ +#define LEGO_USB_TOWER_REQUEST_RESET 0x04 +#define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD + +struct tower_reset_reply { + __u16 size; /* little-endian */ + __u8 err_code; + __u8 spare; +} __attribute__ ((packed)); + +struct tower_get_version_reply { + __u16 size; /* little-endian */ + __u8 err_code; + __u8 spare; + __u8 major; + __u8 minor; + __u16 build_no; /* little-endian */ +} __attribute__ ((packed)); + + /* table of devices that work with this driver */ static struct usb_device_id tower_table [] =3D { { USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) }, @@ -90,22 +200,21 @@ MODULE_DEVICE_TABLE (usb, tower_table); =20 #define LEGO_USB_TOWER_MINOR_BASE 160 =20 -/* we can have up to this number of device plugged in at once */ -#define MAX_DEVICES 16 - -#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ =20 /* Structure to hold all of our device specific stuff */ struct lego_usb_tower { struct semaphore sem; /* locks this structure */ - struct usb_device* udev; /* save off the usb device pointer */ - struct usb_interface* interface; + struct usb_device* udev; /* save off the usb device pointer */ unsigned char minor; /* the starting minor number for this device */ =20 int open_count; /* number of times this port has been opened */ =20 char* read_buffer; - int read_buffer_length; + size_t read_buffer_length; /* this much came in */ + size_t read_packet_length; /* this much will be returned on read */ + spinlock_t read_buffer_lock; + int packet_timeout_jiffies; + unsigned long read_last_arrival; =20 wait_queue_head_t read_wait; wait_queue_head_t write_wait; @@ -113,18 +222,18 @@ struct lego_usb_tower { char* interrupt_in_buffer; struct usb_endpoint_descriptor* interrupt_in_endpoint; struct urb* interrupt_in_urb; + int interrupt_in_interval; + int interrupt_in_running; + int interrupt_in_done; =20 char* interrupt_out_buffer; struct usb_endpoint_descriptor* interrupt_out_endpoint; struct urb* interrupt_out_urb; + int interrupt_out_interval; + int interrupt_out_busy; =20 }; =20 -/* Note that no locking is needed: - * read_buffer is arbitrated by read_buffer_length =3D=3D 0 - * interrupt_out_buffer is arbitrated by interrupt_out_urb->status =3D=3D= -EINPROGRESS - * interrupt_in_buffer belongs to urb alone and is overwritten on overfl= ow - */ =20 /* local function prototypes */ static ssize_t tower_read (struct file *file, char *buffer, size_t count= , loff_t *ppos); @@ -132,8 +241,11 @@ static ssize_t tower_write (struct file=20 static inline void tower_delete (struct lego_usb_tower *dev); static int tower_open (struct inode *inode, struct file *file); static int tower_release (struct inode *inode, struct file *file); -static int tower_release_internal (struct lego_usb_tower *dev); +static unsigned int tower_poll (struct file *file, poll_table *wait); +static loff_t tower_llseek (struct file *file, loff_t off, int whence); + static void tower_abort_transfers (struct lego_usb_tower *dev); +static void tower_check_for_read_packet (struct lego_usb_tower *dev); static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs= *regs); static void tower_interrupt_out_callback (struct urb *urb, struct pt_reg= s *regs); =20 @@ -146,14 +258,16 @@ static DECLARE_MUTEX (disconnect_sem); =20 /* file operations needed when we register this driver */ static struct file_operations tower_fops =3D { - .owner =3D THIS_MODULE, - .read =3D tower_read, + .owner =3D THIS_MODULE, + .read =3D tower_read, .write =3D tower_write, .open =3D tower_open, - .release =3D tower_release, + .release =3D tower_release, + .poll =3D tower_poll, + .llseek =3D tower_llseek, }; =20 -/*=20 +/* * usb class driver info in order to get a minor number from the usb cor= e, * and to have the device registered with devfs and the driver core */ @@ -167,11 +281,11 @@ static struct usb_class_driver tower_cla =20 /* usb specific object needed to register this driver with the usb subsy= stem */ static struct usb_driver tower_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "legousbtower", - .probe =3D tower_probe, - .disconnect =3D tower_disconnect, - .id_table =3D tower_table, + .owner =3D THIS_MODULE, + .name =3D "legousbtower", + .probe =3D tower_probe, + .disconnect =3D tower_disconnect, + .id_table =3D tower_table, }; =20 =20 @@ -183,8 +297,8 @@ static inline void lego_usb_tower_debug_ int i; =20 if (debug < level) - return;=20 -=09 + return; + printk (KERN_DEBUG __FILE__": %s - length =3D %d, data =3D ", function,= size); for (i =3D 0; i < size; ++i) { printk ("%.2x ", data[i]); @@ -198,7 +312,7 @@ static inline void lego_usb_tower_debug_ */ static inline void tower_delete (struct lego_usb_tower *dev) { - dbg(2, "%s enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 tower_abort_transfers (dev); =20 @@ -214,7 +328,7 @@ static inline void tower_delete (struct=20 kfree (dev->interrupt_out_buffer); kfree (dev); =20 - dbg(2, "%s : leave", __func__); + dbg(2, "%s: leave", __FUNCTION__); } =20 =20 @@ -228,7 +342,7 @@ static int tower_open (struct inode *ino int retval =3D 0; struct usb_interface *interface; =20 - dbg(2,"%s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 subminor =3D iminor(inode); =20 @@ -240,37 +354,63 @@ static int tower_open (struct inode *ino err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval =3D -ENODEV; - goto exit_no_device; + goto unlock_disconnect_exit; } =20 dev =3D usb_get_intfdata(interface); =20 if (!dev) { retval =3D -ENODEV; - goto exit_no_device; + goto unlock_disconnect_exit; } =20 /* lock this device */ - down (&dev->sem); - -=09 - /* increment our usage count for the device */ - ++dev->open_count; - - /* save device in the file's private structure */ - file->private_data =3D dev; + if (down_interruptible (&dev->sem)) { + retval =3D -ERESTARTSYS; + goto unlock_disconnect_exit; + } =20 + /* allow opening only once */ + if (dev->open_count) { + retval =3D -EBUSY; + goto unlock_exit; + } + dev->open_count =3D 1; =20 /* initialize in direction */ dev->read_buffer_length =3D 0; + dev->read_packet_length =3D 0; + usb_fill_int_urb (dev->interrupt_in_urb, + dev->udev, + usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddr= ess), + dev->interrupt_in_buffer, + dev->interrupt_in_endpoint->wMaxPacketSize, + tower_interrupt_in_callback, + dev, + dev->interrupt_in_interval); + + dev->interrupt_in_running =3D 1; + dev->interrupt_in_done =3D 0; + mb(); =20 - up (&dev->sem); + retval =3D usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); + if (retval) { + err("Couldn't submit interrupt_in_urb %d", retval); + dev->interrupt_in_running =3D 0; + dev->open_count =3D 0; + goto unlock_exit; + } =20 -exit_no_device: + /* save device in the file's private structure */ + file->private_data =3D dev; + +unlock_exit: + up (&dev->sem); =20 +unlock_disconnect_exit: up (&disconnect_sem); =20 - dbg(2,"%s : leave, return value %d ", __func__, retval); + dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval); =20 return retval; } @@ -283,87 +423,137 @@ static int tower_release (struct inode * struct lego_usb_tower *dev; int retval =3D 0; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 dev =3D (struct lego_usb_tower *)file->private_data; =20 if (dev =3D=3D NULL) { - dbg(1," %s : object is NULL", __func__); + dbg(1, "%s: object is NULL", __FUNCTION__); retval =3D -ENODEV; goto exit; } =20 + if (down_interruptible (&dev->sem)) { + retval =3D -ERESTARTSYS; + goto exit; + } =20 - /* lock our device */ - down (&dev->sem); - - if (dev->open_count <=3D 0) { - dbg(1," %s : device not opened", __func__); + if (dev->open_count !=3D 1) { + dbg(1, "%s: device not opened exactly once", __FUNCTION__); retval =3D -ENODEV; + goto unlock_exit; + } + if (dev->udev =3D=3D NULL) { + /* the device was unplugged before the file was released */ + up (&dev->sem); /* unlock here as tower_delete frees dev */ + tower_delete (dev); goto exit; } =20 - /* do the work */ - retval =3D tower_release_internal (dev); + /* wait until write transfer is finished */ + if (dev->interrupt_out_busy) { + wait_event_interruptible_timeout (dev->write_wait, !dev->interrupt_out= _busy, 2 * HZ); + } + tower_abort_transfers (dev); + dev->open_count =3D 0; + +unlock_exit: + up (&dev->sem); =20 exit: - up (&dev->sem); - dbg(2," %s : leave, return value %d", __func__, retval); + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); return retval; } =20 =20 /** - * tower_release_internal + * tower_abort_transfers + * aborts transfers and frees associated data structures */ -static int tower_release_internal (struct lego_usb_tower *dev) +static void tower_abort_transfers (struct lego_usb_tower *dev) { - int retval =3D 0; - - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 - if (dev->udev =3D=3D NULL) { - /* the device was unplugged before the file was released */ - tower_delete (dev); + if (dev =3D=3D NULL) { + dbg(1, "%s: dev is null", __FUNCTION__); goto exit; } =20 - /* decrement our usage count for the device */ - --dev->open_count; - if (dev->open_count <=3D 0) { - tower_abort_transfers (dev); - dev->open_count =3D 0; + /* shutdown transfer */ + if (dev->interrupt_in_running) { + dev->interrupt_in_running =3D 0; + mb(); + if (dev->interrupt_in_urb !=3D NULL && dev->udev) { + usb_unlink_urb (dev->interrupt_in_urb); + } + } + if (dev->interrupt_out_busy) { + if (dev->interrupt_out_urb !=3D NULL && dev->udev) { + usb_unlink_urb (dev->interrupt_out_urb); + } } =20 exit: - dbg(2," %s : leave", __func__); - return retval; + dbg(2, "%s: leave", __FUNCTION__); } =20 =20 /** - * tower_abort_transfers - * aborts transfers and frees associated data structures + * tower_check_for_read_packet + * + * To get correct semantics for signals and non-blocking I/O + * with packetizing we pretend not to see any data in the read buff= er + * until it has been there unchanged for at least + * dev->packet_timeout_jiffies, or until the buffer is full. */ -static void tower_abort_transfers (struct lego_usb_tower *dev) +static void tower_check_for_read_packet (struct lego_usb_tower *dev) { - dbg(2," %s : enter", __func__); - - if (dev =3D=3D NULL) { - dbg(1," %s : dev is null", __func__); - goto exit; + spin_lock_irq (&dev->read_buffer_lock); + if (!packet_timeout + || time_after(jiffies, dev->read_last_arrival + dev->packet_timeout= _jiffies) + || dev->read_buffer_length =3D=3D read_buffer_size) { + dev->read_packet_length =3D dev->read_buffer_length; } + dev->interrupt_in_done =3D 0; + spin_unlock_irq (&dev->read_buffer_lock); +} =20 - /* shutdown transfer */ - if (dev->interrupt_in_urb !=3D NULL) { - usb_unlink_urb (dev->interrupt_in_urb); + +/** + * tower_poll + */ +static unsigned int tower_poll (struct file *file, poll_table *wait) +{ + struct lego_usb_tower *dev; + unsigned int mask =3D 0; + + dbg(2, "%s: enter", __FUNCTION__); + + dev =3D file->private_data; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + tower_check_for_read_packet(dev); + if (dev->read_packet_length > 0) { + mask |=3D POLLIN | POLLRDNORM; } - if (dev->interrupt_out_urb !=3D NULL) { - usb_unlink_urb (dev->interrupt_out_urb); + if (!dev->interrupt_out_busy) { + mask |=3D POLLOUT | POLLWRNORM; } =20 -exit: - dbg(2," %s : leave", __func__); + dbg(2, "%s: leave, mask =3D %d", __FUNCTION__, mask); + + return mask; +} + + +/** + * tower_llseek + */ +static loff_t tower_llseek (struct file *file, loff_t off, int whence) +{ + return -ESPIPE; /* unseekable */ } =20 =20 @@ -373,96 +563,87 @@ exit: static ssize_t tower_read (struct file *file, char *buffer, size_t count= , loff_t *ppos) { struct lego_usb_tower *dev; - size_t bytes_read =3D 0; size_t bytes_to_read; int i; int retval =3D 0; - int timeout =3D 0; + unsigned long timeout =3D 0; =20 - dbg(2," %s : enter, count =3D %Zd", __func__, count); + dbg(2, "%s: enter, count =3D %Zd", __FUNCTION__, count); =20 dev =3D (struct lego_usb_tower *)file->private_data; -=09 + /* lock this object */ - down (&dev->sem); + if (down_interruptible (&dev->sem)) { + retval =3D -ERESTARTSYS; + goto exit; + } =20 /* verify that the device wasn't unplugged */ if (dev->udev =3D=3D NULL) { retval =3D -ENODEV; err("No device or device unplugged %d", retval); - goto exit; + goto unlock_exit; } =20 /* verify that we actually have some data to read */ if (count =3D=3D 0) { - dbg(1," %s : read request of 0 bytes", __func__); - goto exit; + dbg(1, "%s: read request of 0 bytes", __FUNCTION__); + goto unlock_exit; } =20 + if (read_timeout) { + timeout =3D jiffies + read_timeout * HZ / 1000; + } + + /* wait for data */ + tower_check_for_read_packet (dev); + while (dev->read_packet_length =3D=3D 0) { + if (file->f_flags & O_NONBLOCK) { + retval =3D -EAGAIN; + goto unlock_exit; + } + retval =3D wait_event_interruptible_timeout(dev->read_wait, dev->inter= rupt_in_done, dev->packet_timeout_jiffies); + if (retval < 0) { + goto unlock_exit; + } =20 - timeout =3D COMMAND_TIMEOUT; + /* reset read timeout during read or write activity */ + if (read_timeout + && (dev->read_buffer_length || dev->interrupt_out_busy)) { + timeout =3D jiffies + read_timeout * HZ / 1000; + } + /* check for read timeout */ + if (read_timeout && time_after (jiffies, timeout)) { + retval =3D -ETIMEDOUT; + goto unlock_exit; + } + tower_check_for_read_packet (dev); + } =20 - while (1) { - if (dev->read_buffer_length =3D=3D 0) { + /* copy the data from read_buffer into userspace */ + bytes_to_read =3D min(count, dev->read_packet_length); =20 - /* start reading */ - usb_fill_int_urb (dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAd= dress), - dev->interrupt_in_buffer, - dev->interrupt_in_endpoint->wMaxPacketSize, - tower_interrupt_in_callback, - dev, - dev->interrupt_in_endpoint->bInterval); - =09 - retval =3D usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); - =09 - if (retval < 0) { - err("Couldn't submit interrupt_in_urb"); - goto exit; - } - - if (timeout <=3D 0) { - retval =3D -ETIMEDOUT; - goto exit; - } - - if (signal_pending(current)) { - retval =3D -EINTR; - goto exit; - } - - up (&dev->sem); - timeout =3D interruptible_sleep_on_timeout (&dev->read_wait, timeout)= ; - down (&dev->sem); + if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) { + retval =3D -EFAULT; + goto unlock_exit; + } =20 - } else { - /* copy the data from read_buffer into userspace */ - bytes_to_read =3D count > dev->read_buffer_length ? dev->read_buffer_= length : count; - if (copy_to_user (buffer, dev->read_buffer, bytes_to_read) !=3D 0) { - retval =3D -EFAULT; - goto exit; - } - dev->read_buffer_length -=3D bytes_to_read; - for (i=3D0; i<dev->read_buffer_length; i++) { - dev->read_buffer[i] =3D dev->read_buffer[i+bytes_to_read]; - } - - buffer +=3D bytes_to_read; - count -=3D bytes_to_read; - bytes_read +=3D bytes_to_read; - if (count =3D=3D 0) { - break; - } - } + spin_lock_irq (&dev->read_buffer_lock); + dev->read_buffer_length -=3D bytes_to_read; + dev->read_packet_length -=3D bytes_to_read; + for (i=3D0; i<dev->read_buffer_length; i++) { + dev->read_buffer[i] =3D dev->read_buffer[i+bytes_to_read]; } + spin_unlock_irq (&dev->read_buffer_lock); =20 - retval =3D bytes_read; + retval =3D bytes_to_read; =20 -exit: +unlock_exit: /* unlock the device */ up (&dev->sem); =20 - dbg(2," %s : leave, return value %d", __func__, retval); +exit: + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); return retval; } =20 @@ -473,107 +654,80 @@ exit: static ssize_t tower_write (struct file *file, const char *buffer, size_= t count, loff_t *ppos) { struct lego_usb_tower *dev; - size_t bytes_written =3D 0; size_t bytes_to_write; - size_t buffer_size; int retval =3D 0; - int timeout =3D 0; =20 - dbg(2," %s : enter, count =3D %Zd", __func__, count); + dbg(2, "%s: enter, count =3D %Zd", __FUNCTION__, count); =20 dev =3D (struct lego_usb_tower *)file->private_data; =20 /* lock this object */ - down (&dev->sem); + if (down_interruptible (&dev->sem)) { + retval =3D -ERESTARTSYS; + goto exit; + } =20 /* verify that the device wasn't unplugged */ if (dev->udev =3D=3D NULL) { retval =3D -ENODEV; err("No device or device unplugged %d", retval); - goto exit; + goto unlock_exit; } =20 /* verify that we actually have some data to write */ if (count =3D=3D 0) { - dbg(1," %s : write request of 0 bytes", __func__); - goto exit; + dbg(1, "%s: write request of 0 bytes", __FUNCTION__); + goto unlock_exit; } =20 + /* wait until previous transfer is finished */ + while (dev->interrupt_out_busy) { + if (file->f_flags & O_NONBLOCK) { + retval =3D -EAGAIN; + goto unlock_exit; + } + retval =3D wait_event_interruptible (dev->write_wait, !dev->interrupt_= out_busy); + if (retval) { + goto unlock_exit; + } + } =20 - while (count > 0) { - if (dev->interrupt_out_urb->status =3D=3D -EINPROGRESS) { - timeout =3D COMMAND_TIMEOUT; - - while (timeout > 0) { - if (signal_pending(current)) { - dbg(1," %s : interrupted", __func__); - retval =3D -EINTR; - goto exit; - } - up (&dev->sem); - timeout =3D interruptible_sleep_on_timeout (&dev->write_wait, timeou= t); - down (&dev->sem); - if (timeout > 0) { - break; - } - dbg(1," %s : interrupted timeout: %d", __func__, timeout); - } - - - dbg(1," %s : final timeout: %d", __func__, timeout); - - if (timeout =3D=3D 0) { - dbg(1, "%s - command timed out.", __func__); - retval =3D -ETIMEDOUT; - goto exit; - } - - dbg(4," %s : in progress, count =3D %Zd", __func__, count); - } else { - dbg(4," %s : sending, count =3D %Zd", __func__, count); - - /* write the data into interrupt_out_buffer from userspace */ - buffer_size =3D dev->interrupt_out_endpoint->wMaxPacketSize; - bytes_to_write =3D count > buffer_size ? buffer_size : count; - dbg(4," %s : buffer_size =3D %Zd, count =3D %Zd, bytes_to_write =3D %= Zd", __func__, buffer_size, count, bytes_to_write); - - if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write= ) !=3D 0) { - retval =3D -EFAULT; - goto exit; - } - - /* send off the urb */ - usb_fill_int_urb(dev->interrupt_out_urb, - dev->udev,=20 - usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAdd= ress), - dev->interrupt_out_buffer, - bytes_to_write, - tower_interrupt_out_callback, - dev, - dev->interrupt_in_endpoint->bInterval); - - dev->interrupt_out_urb->actual_length =3D bytes_to_write; - retval =3D usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); - - if (retval < 0) { - err("Couldn't submit interrupt_out_urb %d", retval); - goto exit; - } + /* write the data into interrupt_out_buffer from userspace */ + bytes_to_write =3D min(count, write_buffer_size); + dbg(4, "%s: count =3D %Zd, bytes_to_write =3D %Zd", __FUNCTION__, count= , bytes_to_write); + + if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write))= { + retval =3D -EFAULT; + goto unlock_exit; + } + + /* send off the urb */ + usb_fill_int_urb(dev->interrupt_out_urb, + dev->udev, + usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddr= ess), + dev->interrupt_out_buffer, + bytes_to_write, + tower_interrupt_out_callback, + dev, + dev->interrupt_out_interval); =20 - buffer +=3D bytes_to_write; - count -=3D bytes_to_write; + dev->interrupt_out_busy =3D 1; + wmb(); =20 - bytes_written +=3D bytes_to_write; - } + retval =3D usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); + if (retval) { + dev->interrupt_out_busy =3D 0; + err("Couldn't submit interrupt_out_urb %d", retval); + goto unlock_exit; } + retval =3D bytes_to_write; =20 - retval =3D bytes_written; - -exit: +unlock_exit: /* unlock the device */ up (&dev->sem); =20 - dbg(2," %s : leave, return value %d", __func__, retval); +exit: + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); =20 return retval; } @@ -585,39 +739,53 @@ exit: static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs= *regs) { struct lego_usb_tower *dev =3D (struct lego_usb_tower *)urb->context; + int retval; =20 - dbg(4," %s : enter, status %d", __func__, urb->status); + dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); =20 - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); =20 - if (urb->status !=3D 0) { - if ((urb->status !=3D -ENOENT) && (urb->status !=3D -ECONNRESET)) { - dbg(1," %s : nonzero status received: %d", __func__, urb->status); + if (urb->status) { + if (urb->status =3D=3D -ENOENT || + urb->status =3D=3D -ECONNRESET || + urb->status =3D=3D -ESHUTDOWN) { + goto exit; + } else { + dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status); + goto resubmit; /* maybe we can recover */ } - goto exit; } =20 - down (&dev->sem); - if (urb->actual_length > 0) { - if (dev->read_buffer_length < (4 * dev->interrupt_in_endpoint->wMaxPac= ketSize) - (urb->actual_length)) { - - memcpy (dev->read_buffer+dev->read_buffer_length, dev->interrupt_in_b= uffer, urb->actual_length); - + spin_lock (&dev->read_buffer_lock); + if (dev->read_buffer_length + urb->actual_length < read_buffer_size) { + memcpy (dev->read_buffer + dev->read_buffer_length, + dev->interrupt_in_buffer, + urb->actual_length); dev->read_buffer_length +=3D urb->actual_length; - dbg(1," %s reading %d ", __func__, urb->actual_length); - wake_up_interruptible (&dev->read_wait); - + dev->read_last_arrival =3D jiffies; + dbg(3, "%s: received %d bytes", __FUNCTION__, urb->actual_length); } else { - dbg(1," %s : read_buffer overflow", __func__); + printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __F= UNCTION__, urb->actual_length); } + spin_unlock (&dev->read_buffer_lock); } =20 - up (&dev->sem); +resubmit: + /* resubmit if we're still running */ + if (dev->interrupt_in_running && dev->udev) { + retval =3D usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); + if (retval) { + err("%s: usb_submit_urb failed (%d)", __FUNCTION__, retval); + } + } =20 exit: - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); - dbg(4," %s : leave, status %d", __func__, urb->status); + dev->interrupt_in_done =3D 1; + wake_up_interruptible (&dev->read_wait); + + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); + dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status); } =20 =20 @@ -628,22 +796,22 @@ static void tower_interrupt_out_callback { struct lego_usb_tower *dev =3D (struct lego_usb_tower *)urb->context; =20 - dbg(4," %s : enter, status %d", __func__, urb->status); - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); + dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); =20 - if (urb->status !=3D 0) { - if ((urb->status !=3D -ENOENT) &&=20 - (urb->status !=3D -ECONNRESET)) { - dbg(1, " %s :nonzero status received: %d", __func__, urb->status); - } - goto exit; - } =20 + /* sync/async unlink faults aren't errors */ + if (urb->status && !(urb->status =3D=3D -ENOENT || + urb->status =3D=3D -ECONNRESET || + urb->status =3D=3D -ESHUTDOWN)) { + dbg(1, "%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); + } =20 + dev->interrupt_out_busy =3D 0; wake_up_interruptible(&dev->write_wait); -exit: =20 - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); - dbg(4," %s : leave, status %d", __func__, urb->status); + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); + dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status); } =20 =20 @@ -659,15 +827,18 @@ static int tower_probe (struct usb_inter struct lego_usb_tower *dev =3D NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor* endpoint; + struct tower_reset_reply reset_reply; + struct tower_get_version_reply get_version_reply; int i; int retval =3D -ENOMEM; + int result; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 if (udev =3D=3D NULL) { info ("udev is NULL."); } -=09 + /* See if the device offered us matches what we can accept */ if ((udev->descriptor.idVendor !=3D LEGO_USB_TOWER_VENDOR_ID) || (udev->descriptor.idProduct !=3D LEGO_USB_TOWER_PRODUCT_ID)) { @@ -691,6 +862,10 @@ static int tower_probe (struct usb_inter =20 dev->read_buffer =3D NULL; dev->read_buffer_length =3D 0; + dev->read_packet_length =3D 0; + spin_lock_init (&dev->read_buffer_lock); + dev->packet_timeout_jiffies =3D packet_timeout * HZ / 1000; + dev->read_last_arrival =3D jiffies; =20 init_waitqueue_head (&dev->read_wait); init_waitqueue_head (&dev->write_wait); @@ -698,11 +873,13 @@ static int tower_probe (struct usb_inter dev->interrupt_in_buffer =3D NULL; dev->interrupt_in_endpoint =3D NULL; dev->interrupt_in_urb =3D NULL; + dev->interrupt_in_running =3D 0; + dev->interrupt_in_done =3D 0; =20 dev->interrupt_out_buffer =3D NULL; dev->interrupt_out_endpoint =3D NULL; dev->interrupt_out_urb =3D NULL; - + dev->interrupt_out_busy =3D 0; =20 iface_desc =3D &interface->altsetting[0]; =20 @@ -714,7 +891,7 @@ static int tower_probe (struct usb_inter ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) =3D=3D USB_= ENDPOINT_XFER_INT)) { dev->interrupt_in_endpoint =3D endpoint; } - =09 + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) =3D=3D USB_D= IR_OUT) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) =3D=3D USB_= ENDPOINT_XFER_INT)) { dev->interrupt_out_endpoint =3D endpoint; @@ -729,7 +906,7 @@ static int tower_probe (struct usb_inter goto error; } =20 - dev->read_buffer =3D kmalloc ((4*dev->interrupt_in_endpoint->wMaxPacket= Size), GFP_KERNEL); + dev->read_buffer =3D kmalloc (read_buffer_size, GFP_KERNEL); if (!dev->read_buffer) { err("Couldn't allocate read_buffer"); goto error; @@ -744,7 +921,7 @@ static int tower_probe (struct usb_inter err("Couldn't allocate interrupt_in_urb"); goto error; } - dev->interrupt_out_buffer =3D kmalloc (dev->interrupt_out_endpoint->wMa= xPacketSize, GFP_KERNEL); + dev->interrupt_out_buffer =3D kmalloc (write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { err("Couldn't allocate interrupt_out_buffer"); goto error; @@ -753,7 +930,9 @@ static int tower_probe (struct usb_inter if (!dev->interrupt_out_urb) { err("Couldn't allocate interrupt_out_urb"); goto error; - } =20 + } + dev->interrupt_in_interval =3D interrupt_in_interval ? interrupt_in_int= erval : dev->interrupt_in_endpoint->bInterval; + dev->interrupt_out_interval =3D interrupt_out_interval ? interrupt_out_= interval : dev->interrupt_out_endpoint->bInterval; =20 /* we can register the device now, as it is ready */ usb_set_intfdata (interface, dev); @@ -766,16 +945,50 @@ static int tower_probe (struct usb_inter usb_set_intfdata (interface, NULL); goto error; } - dev->minor =3D interface->minor; =20 /* let the user know what node this device is now attached to */ - info ("LEGO USB Tower device now attached to /dev/usb/lego%d", (dev->mi= nor - LEGO_USB_TOWER_MINOR_BASE)); + info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->min= or - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor); =20 + /* reset the tower */ + result =3D usb_control_msg (udev, + usb_rcvctrlpipe(udev, 0), + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &reset_reply, + sizeof(reset_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower reset control request failed"); + retval =3D result; + goto error; + } + + /* get the firmware version and log it */ + result =3D usb_control_msg (udev, + usb_rcvctrlpipe(udev, 0), + LEGO_USB_TOWER_REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &get_version_reply, + sizeof(get_version_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower get version control request failed"); + retval =3D result; + goto error; + } + info("LEGO USB Tower firmware version is %d.%d build %d", + get_version_reply.major, + get_version_reply.minor, + le16_to_cpu(get_version_reply.build_no)); =20 =20 exit: - dbg(2," %s : leave, return value 0x%.8lx (dev)", __func__, (long) dev); + dbg(2, "%s: leave, return value 0x%.8lx (dev)", __FUNCTION__, (long) de= v); =20 return retval; =20 @@ -795,7 +1008,7 @@ static void tower_disconnect (struct usb struct lego_usb_tower *dev; int minor; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 down (&disconnect_sem); =20 @@ -823,7 +1036,7 @@ static void tower_disconnect (struct usb =20 info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MIN= OR_BASE)); =20 - dbg(2," %s : leave", __func__); + dbg(2, "%s: leave", __FUNCTION__); } =20 =20 @@ -836,7 +1049,7 @@ static int __init lego_usb_tower_init(vo int result; int retval =3D 0; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 /* register this driver with the USB subsystem */ result =3D usb_register(&tower_driver); @@ -849,7 +1062,7 @@ static int __init lego_usb_tower_init(vo info(DRIVER_DESC " " DRIVER_VERSION); =20 exit: - dbg(2," %s : leave, return value %d", __func__, retval); + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); =20 return retval; } @@ -860,12 +1073,12 @@ exit: */ static void __exit lego_usb_tower_exit(void) { - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 /* deregister this driver with the USB subsystem */ usb_deregister (&tower_driver); =20 - dbg(2," %s : leave", __func__); + dbg(2, "%s: leave", __FUNCTION__); } =20 module_init (lego_usb_tower_init); J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ gnupg key fingerprint =3D 2767 CA3C 5680 58BA 9A91 23D9 BED6 9A7A AF9E 6= 8B4 Please always send email as plain text. Email sent as HTML will be filtered and read later, or may get lost in sp= am. |
From: Juergen S. <st...@lo...> - 2004-04-14 09:09:43
|
Hi Andreas, Andreas Tille wrote: > On Thu, 8 Apr 2004, Juergen Stuber wrote: >=20 > > I don't think libusb has anything to do with it, > > as far as I know it has never been used with the tower. > > > > Seems like the current Debian version of nqc (2.5.r3-2) > > uses /dev/usb/legousbtower0 as the name of the device. > > If I create that one then downloading the same firmware works > > with my latest working version of the driver. > To be sure I did a symlink to /dev/usb/lego0 which worked before on thi= s > box but this did not changed anything. be careful with the name, /dev/usb/legousbtower0 !=3D /dev/usb/lego0 . Personally I like /dev/usb/legousbtower0 best. BTW, you can use strace to find out which files a program is accessing. > Could you please send me your major and minor device numbers which > are successful for you. When I started with legousb I had to try > some different drivers with different device numbers. May be the > new module in 2.6.5 kernel has changed the device numbers again. Yes, this changed as in 2.6 we got official minor numbers starting at 160= . The new driver announces the major and minor number for each device in the system log, like this: LEGO USB Tower #0 now attached to major 180 minor 160 Hope this helps J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ gnupg key fingerprint =3D 2767 CA3C 5680 58BA 9A91 23D9 BED6 9A7A AF9E 6= 8B4 Please always send email as plain text. Email sent as HTML will be filtered and read later, or may get lost in sp= am. |
From: Andreas T. <ti...@rk...> - 2004-04-14 08:41:08
|
On Thu, 8 Apr 2004, Juergen Stuber wrote: > I don't think libusb has anything to do with it, > as far as I know it has never been used with the tower. > > Seems like the current Debian version of nqc (2.5.r3-2) > uses /dev/usb/legousbtower0 as the name of the device. > If I create that one then downloading the same firmware works > with my latest working version of the driver. To be sure I did a symlink to /dev/usb/lego0 which worked before on this box but this did not changed anything. Could you please send me your major and minor device numbers which are successful for you. When I started with legousb I had to try some different drivers with different device numbers. May be the new module in 2.6.5 kernel has changed the device numbers again. Kind regards Andreas. |
From: Carl T. <ca...@th...> - 2004-04-09 08:00:15
|
Hi all. I just joined this list, after realizing that there was activity on it (the project otherwise looks rather dead, with no CVS activity going on). In particular, I spotted Jürgen's mails about the new version of the driver, which is great news. The old driver would only work on one of my two machines, and then only with lejos (not brickos), and it would make the machine crash (or reboot spontaneously) once in a while. Last weekend, before I saw the mails about the new driver version, I tried to get 0.56 working, and once I had it stable (though not very pretty - it's my first attempt at this sort of thing), I tried to get it to work with the 2.4 kernel (since that's what I'm still using), and it seems to have worked. So if someone else has problems with 0.54 crashing, I have a version that might work. But anyhow, Jürgen, what I was going to ask is if there's somewhere I can download the new driver version, or if you could mail it to me. (It seems like a bad idea to try to salvage the patch from the HTML of the mailing list archive.) I'd like to see if I can backport it to 2.4. //Carl -- Carl Troein - ca...@th... http://www.thep.lu.se/~carl/ BASE developer - http://base.thep.lu.se/ |
From: Juergen S. <st...@lo...> - 2004-04-08 15:02:32
|
Hi Andreas, Andreas Tille wrote: >=20 > I'm using Debian GNU/Linux and just reportet the bug to the place where > I consider it relevant (libusb) package. I don't think libusb has anything to do with it, as far as I know it has never been used with the tower. Seems like the current Debian version of nqc (2.5.r3-2) uses /dev/usb/legousbtower0 as the name of the device. If I create that one then downloading the same firmware works with my latest working version of the driver. J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ gnupg key fingerprint =3D 2767 CA3C 5680 58BA 9A91 23D9 BED6 9A7A AF9E 6= 8B4 Please always send email as plain text. Email sent as HTML will be filtered and read later, or may get lost in sp= am. |
From: Andreas T. <ti...@rk...> - 2004-04-08 14:26:20
|
Hi, I'm using Debian GNU/Linux and just reportet the bug to the place where I consider it relevant (libusb) package. Any way I hope that somebody here might give a hint which might be the reason when downloading any file or firmware via nqc gets the response: Could not open serial port or USB device This is the case since I updated libusb on all boxes which worked before. For the complete bug report please see http://bugs.debian.org/242627 Thanks for your attention Andreas. |
From: Juergen S. <st...@lo...> - 2004-03-29 15:55:21
|
Thanks Stewart, looks like it works also for you. (Would be a surprise if not, I also had it working on OHCI with a P133.) J=FCrgen Stewart Heitmann wrote: > Juergen, > here are my test results for legousbtower v0.7. > It works fine for me. >=20 > These tests were done using linux 2.6.2 on a PII (Cyrixinstead M II 3.5= x=20 > Core/Bus Clock 233Mhz) with Silicon Integrated Systems [SiS] USB 1.0=20 > Controller >=20 > $cat /var/log/messages > kernel: usb-ohci.c: USB OHCI at membase 0xc4818000, IRQ 11 > kernel: usb-ohci.c: usb-00:01.2, Silicon Integrated Systems [SiS] USB 1= .0=20 > Controller > kernel: usb.c: new USB bus registered, assigned bus number 1 > kernel: hub.c: USB hub found > kernel: hub.c: 2 ports detected > kernel: hub.c: new USB device 00:01.2-2, assigned address 2 > kernel: usb.c: USB device 2 (vend/prod 0x694/0x1) is not claimed by any= active=20 > driver. >=20 > $modprobe legousbtower > kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower #0 now disconne= cted > kernel: drivers/usb/core/usb.c: deregistering driver legousbtower > kernel: drivers/usb/core/usb.c: registered new driver legousbtower > kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower Driver v0.7 >=20 > $dmesg > drivers/usb/misc/legousbtower.c : lego_usb_tower_init: enter > drivers/usb/core/usb.c: registered new driver legousbtower > drivers/usb/misc/legousbtower.c: LEGO USB Tower Driver v0.7 > drivers/usb/misc/legousbtower.c : lego_usb_tower_init: leave, return v= alue 0 >=20 > <connect the usb tower> >=20 > $dmesg > drivers/usb/core/usb.c: usb_hotplug > ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] =3D 0x00020300 = PESC LSDA=20 > PPS > hub 1-0:1.0: port 2 enable change, status 300 > ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] =3D 0x00010301 = CSC LSDA=20 > PPS CCS > hub 1-0:1.0: port 2, status 301, change 1, 1.5 Mb/s > hub 1-0:1.0: debounce: port 2: delay 100ms stable 4 status 0x301 > ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] =3D 0x00100303 = PRSC LSDA=20 > PPS PES CCS > hub 1-0:1.0: new USB device on port 2, assigned address 8 > usb 1-2: new device strings: Mfr=3D4, Product=3D26, SerialNumber=3D0 > drivers/usb/core/message.c: USB device number 8 default language ID 0x4= 09 > usb 1-2: Product: LEGO USB Tower > usb 1-2: Manufacturer: LEGO Group > drivers/usb/core/usb.c: usb_hotplug > usb 1-2: configuration #1 chosen from 4 choices > usb 1-2: registering 1-2:1.0 (config #1, interface 0) > drivers/usb/core/usb.c: usb_hotplug > legousbtower 1-2:1.0: usb_probe_interface > legousbtower 1-2:1.0: usb_probe_interface - got id > drivers/usb/misc/legousbtower.c : tower_probe: enter > drivers/usb/core/file.c: looking for a minor, starting at 160 > drivers/usb/misc/legousbtower.c: LEGO USB Tower device now attached=20 > to /dev/usb/lego0 > drivers/usb/misc/legousbtower.c: LEGO USB Tower firmware version is 1.0= build=20 > 134 > drivers/usb/misc/legousbtower.c : tower_probe: leave, return value 0xc= 0da8de0=20 > (dev) >=20 > <upload firmware> (using my own hacked version of lejosfirmdl) >=20 > $dmesg > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: receive= d 1=20 > bytes > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: leave, = status=20 > -115 > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: enter, = status=20 > 0 > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: receive= d 1=20 > bytes > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: leave, = status=20 > -115 > drivers/usb/misc/legousbtower.c : tower_read: leave, return value 9 > drivers/usb/misc/legousbtower.c : tower_write: enter, count =3D 417 > drivers/usb/misc/legousbtower.c : tower_write: count =3D 417, bytes_to= _write =3D=20 > 417 > drivers/usb/misc/legousbtower.c : tower_write: leave, return value 417 > drivers/usb/misc/legousbtower.c : tower_read: enter, count =3D 9 > drivers/usb/misc/legousbtower.c : tower_interrupt_out_callback: enter,= status=20 > 0 > drivers/usb/misc/legousbtower.c : tower_interrupt_out_callback: leave,= status=20 > 0 > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: enter, = status=20 > 0 > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: receive= d 1=20 > bytes > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: leave, = status=20 > -115 > drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: enter, = status=20 > 0 >=20 > ...ad nauseum... >=20 > <at this point firmware download was succesful> >=20 >=20 > <disconnect the tower> >=20 > $dmesg > ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] =3D 0x00030300 = PESC CSC=20 > LSDA PPS > hub 1-0:1.0: port 2, status 300, change 3, 1.5 Mb/s > usb 1-2: USB disconnect, address 8 > usb 1-2: usb_disable_device nuking all URBs > usb 1-2: unregistering interface 1-2:1.0 > drivers/usb/misc/legousbtower.c : tower_disconnect: enter > drivers/usb/core/file.c: removing 160 minor > drivers/usb/core/file.c: release_usb_class_dev - legousbtower0 > drivers/usb/misc/legousbtower.c : tower_delete: enter > drivers/usb/misc/legousbtower.c : tower_abort_transfers: enter > drivers/usb/misc/legousbtower.c : tower_abort_transfers: leave > drivers/usb/misc/legousbtower.c : tower_delete: leave > drivers/usb/misc/legousbtower.c: LEGO USB Tower #0 now disconnected > drivers/usb/misc/legousbtower.c : tower_disconnect: leave > drivers/usb/core/usb.c: usb_hotplug > usb 1-2: unregistering device > drivers/usb/core/usb.c: usb_hotplug > ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] =3D 0x00020300 = PESC LSDA=20 > PPS > hub 1-0:1.0: port 2 enable change, status 300 >=20 >=20 > $rmmod legousbtower > kernel: usb 1-2: USB disconnect, address 8 > kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower #0 now disconne= cted > kernel: drivers/usb/core/usb.c: deregistering driver legousbtower >=20 > hope this is useful > --=20 > Stewart Heitmann <st...@he...> >=20 >=20 >=20 > ------------------------------------------------------- > This SF.Net email is sponsored by: IBM Linux Tutorials > Free Linux tutorial presented by Daniel Robbins, President and CEO of > GenToo technologies. Learn everything from fundamentals to system > administration.http://ads.osdn.com/?ad_id=3D1470&alloc_id=3D3638&op=3Dc= lick > _______________________________________________ > Legousb-devel mailing list > Leg...@li... > https://lists.sourceforge.net/lists/listinfo/legousb-devel --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ gnupg key fingerprint =3D 2767 CA3C 5680 58BA 9A91 23D9 BED6 9A7A AF9E 6= 8B4 Please always send email as plain text. Email sent as HTML will be filtered and read later, or get lost in spam. |
From: Stewart H. <st...@he...> - 2004-03-28 07:04:28
|
Juergen, here are my test results for legousbtower v0.7. It works fine for me. These tests were done using linux 2.6.2 on a PII (Cyrixinstead M II 3.5x Core/Bus Clock 233Mhz) with Silicon Integrated Systems [SiS] USB 1.0 Controller $cat /var/log/messages kernel: usb-ohci.c: USB OHCI at membase 0xc4818000, IRQ 11 kernel: usb-ohci.c: usb-00:01.2, Silicon Integrated Systems [SiS] USB 1.0 Controller kernel: usb.c: new USB bus registered, assigned bus number 1 kernel: hub.c: USB hub found kernel: hub.c: 2 ports detected kernel: hub.c: new USB device 00:01.2-2, assigned address 2 kernel: usb.c: USB device 2 (vend/prod 0x694/0x1) is not claimed by any active driver. $modprobe legousbtower kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower #0 now disconnected kernel: drivers/usb/core/usb.c: deregistering driver legousbtower kernel: drivers/usb/core/usb.c: registered new driver legousbtower kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower Driver v0.7 $dmesg drivers/usb/misc/legousbtower.c : lego_usb_tower_init: enter drivers/usb/core/usb.c: registered new driver legousbtower drivers/usb/misc/legousbtower.c: LEGO USB Tower Driver v0.7 drivers/usb/misc/legousbtower.c : lego_usb_tower_init: leave, return value 0 <connect the usb tower> $dmesg drivers/usb/core/usb.c: usb_hotplug ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] = 0x00020300 PESC LSDA PPS hub 1-0:1.0: port 2 enable change, status 300 ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] = 0x00010301 CSC LSDA PPS CCS hub 1-0:1.0: port 2, status 301, change 1, 1.5 Mb/s hub 1-0:1.0: debounce: port 2: delay 100ms stable 4 status 0x301 ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] = 0x00100303 PRSC LSDA PPS PES CCS hub 1-0:1.0: new USB device on port 2, assigned address 8 usb 1-2: new device strings: Mfr=4, Product=26, SerialNumber=0 drivers/usb/core/message.c: USB device number 8 default language ID 0x409 usb 1-2: Product: LEGO USB Tower usb 1-2: Manufacturer: LEGO Group drivers/usb/core/usb.c: usb_hotplug usb 1-2: configuration #1 chosen from 4 choices usb 1-2: registering 1-2:1.0 (config #1, interface 0) drivers/usb/core/usb.c: usb_hotplug legousbtower 1-2:1.0: usb_probe_interface legousbtower 1-2:1.0: usb_probe_interface - got id drivers/usb/misc/legousbtower.c : tower_probe: enter drivers/usb/core/file.c: looking for a minor, starting at 160 drivers/usb/misc/legousbtower.c: LEGO USB Tower device now attached to /dev/usb/lego0 drivers/usb/misc/legousbtower.c: LEGO USB Tower firmware version is 1.0 build 134 drivers/usb/misc/legousbtower.c : tower_probe: leave, return value 0xc0da8de0 (dev) <upload firmware> (using my own hacked version of lejosfirmdl) $dmesg drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: received 1 bytes drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: leave, status -115 drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: enter, status 0 drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: received 1 bytes drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: leave, status -115 drivers/usb/misc/legousbtower.c : tower_read: leave, return value 9 drivers/usb/misc/legousbtower.c : tower_write: enter, count = 417 drivers/usb/misc/legousbtower.c : tower_write: count = 417, bytes_to_write = 417 drivers/usb/misc/legousbtower.c : tower_write: leave, return value 417 drivers/usb/misc/legousbtower.c : tower_read: enter, count = 9 drivers/usb/misc/legousbtower.c : tower_interrupt_out_callback: enter, status 0 drivers/usb/misc/legousbtower.c : tower_interrupt_out_callback: leave, status 0 drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: enter, status 0 drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: received 1 bytes drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: leave, status -115 drivers/usb/misc/legousbtower.c : tower_interrupt_in_callback: enter, status 0 ...ad nauseum... <at this point firmware download was succesful> <disconnect the tower> $dmesg ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] = 0x00030300 PESC CSC LSDA PPS hub 1-0:1.0: port 2, status 300, change 3, 1.5 Mb/s usb 1-2: USB disconnect, address 8 usb 1-2: usb_disable_device nuking all URBs usb 1-2: unregistering interface 1-2:1.0 drivers/usb/misc/legousbtower.c : tower_disconnect: enter drivers/usb/core/file.c: removing 160 minor drivers/usb/core/file.c: release_usb_class_dev - legousbtower0 drivers/usb/misc/legousbtower.c : tower_delete: enter drivers/usb/misc/legousbtower.c : tower_abort_transfers: enter drivers/usb/misc/legousbtower.c : tower_abort_transfers: leave drivers/usb/misc/legousbtower.c : tower_delete: leave drivers/usb/misc/legousbtower.c: LEGO USB Tower #0 now disconnected drivers/usb/misc/legousbtower.c : tower_disconnect: leave drivers/usb/core/usb.c: usb_hotplug usb 1-2: unregistering device drivers/usb/core/usb.c: usb_hotplug ohci_hcd 0000:00:01.2: GetStatus roothub.portstatus [2] = 0x00020300 PESC LSDA PPS hub 1-0:1.0: port 2 enable change, status 300 $rmmod legousbtower kernel: usb 1-2: USB disconnect, address 8 kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower #0 now disconnected kernel: drivers/usb/core/usb.c: deregistering driver legousbtower hope this is useful -- Stewart Heitmann <st...@he...> |
From: Stewart H. <st...@he...> - 2004-03-16 10:21:27
|
> it uses the usbfs (former usbdevfs, typically mounted at /proc/bus/usb) > to access USB devices. For each device there is a file there, and > you can do ioctls on these to do USB transfers etc. > Another option is to use usbfs directly, but libusb should be more > portable. Oh, that makes more sense. So, presumably libusb doesnt do this properly yet? -- Stewart Heitmann <st...@he...> |
From: Juergen S. <st...@lo...> - 2004-03-16 09:44:06
|
Hi Stewart, Stewart Heitmann wrote: > > > How does libusb help? > > > > Then a kernel driver would no longer be needed, > > and one wouldn't need to add a bunch of nasty ioctls > > for all those extra functions. >=20 > Or is there some special USB way of doing things like > that???? For instance, can I guess that the USB control > channel allows a device to receive special command > sequences that it interprets in the same way as ioctl > calls???? it uses the usbfs (former usbdevfs, typically mounted at /proc/bus/usb) to access USB devices. For each device there is a file there, and you can do ioctls on these to do USB transfers etc. Another option is to use usbfs directly, but libusb should be more portab= le. > If so, then we would need those "special command sequences" from LEGO. Yes, they are called vendor control requests in USB jargon, and documented in "LEGO USB Tower Interface Reference.pdf" in the SDK. > > The legal issue was that the file vendreq.h from the SDK > > was used verbatim in the driver. > > I think if we just use the information from the docs and > > write our own code that should be ok. > agreed J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ |
From: Stewart H. <st...@he...> - 2004-03-16 09:20:13
|
> > How does libusb help? > > Then a kernel driver would no longer be needed, > and one wouldn't need to add a bunch of nasty ioctls > for all those extra functions. I still dont understand. How can libusb do in userspace what the driver must do with ioctl calls? For example, how can libusb tell the LEGO Tower to go into high power mode just by using normal I/O writes to /dev/legousb? Or is there some special USB way of doing things like that???? For instance, can I guess that the USB control channel allows a device to receive special command sequences that it interprets in the same way as ioctl calls???? If so, then we would need those "special command sequences" from LEGO. (this is all wild speculation on my part, please correct any foolish notions) > The legal issue was that the file vendreq.h from the SDK > was used verbatim in the driver. > I think if we just use the information from the docs and > write our own code that should be ok. agreed -- Stewart Heitmann <st...@he...> |
From: Juergen S. <st...@lo...> - 2004-03-14 12:15:57
|
Hi Stewart, Stewart Heitmann wrote: > > > > It would be nice to have a common low level library for all the tower > > packet communications (both serial and USB), and then add a version > > that uses libusb to more completely support the capabilities of > > the USB tower like higher speeds higher power, VLL, ... >=20 > I am confused, probably because I dont know anything about libusb. with libusb you can access any USB device from user space without the need of a special kernal driver. The main problem is that only control and interrupt transfers seem to be working currently. > How does libusb help? Then a kernel driver would no longer be needed, and one wouldn't need to add a bunch of nasty ioctls for all those extra functions. > I thought the only way to access the USB tower features like high power= , > VLL, and so on was to send the tower ioctl calls via the legousb driver= , > and that was not implemented so as to avoid legal issues with LEGO > with respect to the propriety ioctl codes. The legal issue was that the file vendreq.h from the SDK was used verbatim in the driver. I think if we just use the information from the docs and write our own code that should be ok. There is nothing in copyright law that forbids it, and they don't claim that it is a trade secret. > BTW, I think it would not only be nice to have a common lib for all tow= er=20 > comms, but a common firmdl for all of BrickOS/NQC/Lejosapplications too= . Sure, one of the main benefits would be to get the faster download speed also for USB towers. > It seems that everyone is doing their own thing with regard to firmdl > and it gets a bit confusing. Yes, I also noticed that when I wrote the driver. J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ |
From: Oliver N. <ol...@ne...> - 2004-03-13 12:32:30
|
Hi, [..] > + atomic_t interrupt_in_running; > + atomic_t interrupt_in_done; what use are these atomic declarations? [..] > @@ -628,22 +740,23 @@ static void tower_interrupt_out_callback > { > struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context; > > - dbg(4," %s : enter, status %d", __func__, urb->status); > - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer); > + dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); > + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); > > if (urb->status != 0) { > - if ((urb->status != -ENOENT) && > + if ((urb->status != -ENOENT) && You should also check for ESHUTDOWN. [..] > + dev->read_buffer_lock = SPIN_LOCK_UNLOCKED; Please use the macro. Regards Oliver |
From: Juergen S. <st...@lo...> - 2004-03-13 09:20:22
|
Hi David, David Brownell wrote: > Juergen Stuber wrote: > > It works flawlessly except for proper EHCI over a 2.0 hub, > > which gives me a -ENOSPC on submitting the first interrupt in URB. > > This needs to be investigated, but may take some time because I need > > to learn how USB 2.0 works.=20 >=20 > What's the period on that transfer? If it's 1 msec, try > increasing it, yes, the period is 1ms, as specified in the device descriptor. With interval increased to at least 2ms for the in direction and 4ms for out it works. I'll send an updated patch later today. > and/or having fewer devices connected. It's the only one on EHCI, there's another USB mouse on UHCI. > Likely it's the "only one interrupt transfer per frame" > shortcut, and you can watch > /sys/class/usb_host/usb*periodic (given CONFIG_USB_DEBUG) > filling up that schedule. Ok, I can see that, looks like you are right. > The latest EHCI code (with experimental "full speed ISO") > finally has most of the infrastructure (microframe scheduler) > needed to solve that problem. I'll dust off the patch that > does the rest, and see if it still works. I'd like to try it, if you could send it or point me to it. Maybe I should also mention that this is a low-speed device? Thanks J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ |
From: David B. <da...@pa...> - 2004-03-13 02:52:50
|
Juergen Stuber wrote: > It works flawlessly except for proper EHCI over a 2.0 hub, > which gives me a -ENOSPC on submitting the first interrupt in URB. > This needs to be investigated, but may take some time because I need > to learn how USB 2.0 works. What's the period on that transfer? If it's 1 msec, try increasing it, and/or having fewer devices connected. Likely it's the "only one interrupt transfer per frame" shortcut, and you can watch /sys/class/usb_host/usb*periodic (given CONFIG_USB_DEBUG) filling up that schedule. The latest EHCI code (with experimental "full speed ISO") finally has most of the infrastructure (microframe scheduler) needed to solve that problem. I'll dust off the patch that does the rest, and see if it still works. - Dave |
From: Stewart H. <st...@he...> - 2004-03-12 23:42:13
|
> didn't you have a non-x86 machine? No, I have a Pentium 4. > Can you try the new driver I sent? > I would be really interested whether it works for you, and > to iron out any problems. I'll try it anyway (next week sometime hopefully) > Sorry to rain on your parade, but lejosfirmdl is now obsolete, in CVS > it has been replaced by firmdl, a script that runs a Java program. > Its back end is the rcxcomm code of Lawrie Griffiths. Oh well, I figured something like that would happen. > It would be nice to have a common low level library for all the tower > packet communications (both serial and USB), and then add a version > that uses libusb to more completely support the capabilities of > the USB tower like higher speeds higher power, VLL, ... I am confused, probably because I dont know anything about libusb. How does libusb help? I thought the only way to access the USB tower features like high power, VLL, and so on was to send the tower ioctl calls via the legousb driver, and that was not implemented so as to avoid legal issues with LEGO with respect to the propriety ioctl codes. BTW, I think it would not only be nice to have a common lib for all tower comms, but a common firmdl for all of BrickOS/NQC/Lejosapplications too. It seems that everyone is doing their own thing with regard to firmdl and it gets a bit confusing. -- Stewart Heitmann <st...@he...> |
From: Juergen S. <st...@lo...> - 2004-03-12 21:17:22
|
Hi Stewart, didn't you have a non-x86 machine? Can you try the new driver I sent? I would be really interested whether it works for you, and to iron out any problems. Stewart Heitmann wrote: > > FYI the legousb driver (version 0.56) shipped in the 2.6.2 kernel works= fine=20 > for me on my OHCI USB hardware. > [...] > However lejosfirmdl (from lejos-2-1-0 distrib) does not work with it. Sorry to rain on your parade, but lejosfirmdl is now obsolete, in CVS it has been replaced by firmdl, a script that runs a Java program. Its back end is the rcxcomm code of Lawrie Griffiths. > I suspected the complicated timing code in the lejosfirmdl code was the= =20 > problem, Probably that was part of it, but the timout code in the driver was also not nice. It is now much cleaner in the new driver, it uses separate timeouts for grouping bytes into packets and for timing out reads. They are configurable by module parameters, though in most cases the defaults should be ok, and close to previous behaviour. Most software seems to just work fine. > and since the firmdl code has become such a mess of #ifdefs > from years of being hacked I ended up finding it easier to write my own > version of it from scratch...and yes it works very well. > So I find the driver itself to be ok. It may have worked in some circumstances, but it was really messy in various ways. For example it did blatantly wrong things like using semaphores in the completion handler, and didn't do proper locking (spinlocks), so on SMP machines you could get into trouble. It would be nice to have a common low level library for all the tower packet communications (both serial and USB), and then add a version that uses libusb to more completely support the capabilities of the USB tower like higher speeds higher power, VLL, ... Cheers J=FCrgen --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ |
From: Juergen S. <st...@lo...> - 2004-03-12 20:50:42
|
The following message is a courtesy copy of an article that has been posted to gmane.linux.usb.devel as well. Hi, here is a patch against 2.6.4 that corrects problems in the LEGO USB Tower driver, in particular the locking and sleeping in interrupt context, and generally overhauls and cleans it up. I have tested it with UHCI, OHCI and EHCI with and without hubs on x86 machines. It works flawlessly except for proper EHCI over a 2.0 hub, which gives me a -ENOSPC on submitting the first interrupt in URB. This needs to be investigated, but may take some time because I need to learn how USB 2.0 works. As for applications it works for me for Lejos and NQC with firmware and program download and datalog upload, and I have a report that it also works with a suitably patched brickos. I'll maintain this driver from now on, David Glance who has worked on it until now has agreed to that. Please apply. J=FCrgen diff -uprN -X dontdiff linux-2.6.4/MAINTAINERS linux-2.6.4-legousbtower-0= .9/MAINTAINERS --- linux-2.6.4/MAINTAINERS 2004-03-11 03:55:33.000000000 +0100 +++ linux-2.6.4-legousbtower-0.9/MAINTAINERS 2004-03-12 14:10:22.00000000= 0 +0100 @@ -1212,6 +1212,13 @@ M: James.Bottomley@HansenPartnership.com L: lin...@vg... S: Maintained =20 +LEGO USB Tower driver +P: Juergen Stuber +M: sta...@us... +L: leg...@li... +W: http://legousb.sourceforge.net/ +S: Maintained + LINUX FOR IBM pSERIES (RS/6000) P: Paul Mackerras M: pa...@au... diff -uprN -X dontdiff linux-2.6.4/drivers/usb/misc/legousbtower.c linux-= 2.6.4-legousbtower-0.9/drivers/usb/misc/legousbtower.c --- linux-2.6.4/drivers/usb/misc/legousbtower.c 2004-03-11 03:55:27.00000= 0000 +0100 +++ linux-2.6.4-legousbtower-0.9/drivers/usb/misc/legousbtower.c 2004-03-= 12 14:10:22.000000000 +0100 @@ -1,8 +1,8 @@ /* * LEGO USB Tower driver * - * Copyright (C) 2003 David Glance <dav...@so...>=20 - * 2001 Juergen Stuber <st...@lo...> + * Copyright (C) 2003 David Glance <dav...@so...> + * 2001-2004 Juergen Stuber <sta...@us...= t> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,14 +33,33 @@ * - changed to use lego0 rather than tower0 * - changed dbg() to use __func__ rather than deprecated __FUNCTION__ * 2003-01-12 - 0.53 david (da...@cs...) - * - changed read and write to write everything or timeout (from a pat= ch by Chris Riesen and=20 - * Brett Thaeler driver) + * - changed read and write to write everything or + * timeout (from a patch by Chris Riesen and Brett Thaeler driver) * - added ioctl functionality to set timeouts - * 2003-07-18 - 0.54 davidgsf (da...@cs...)=20 + * 2003-07-18 - 0.54 davidgsf (da...@cs...) * - initial import into LegoUSB project * - merge of existing LegoUSB.c driver - * 2003-07-18 - 0.56 davidgsf (da...@cs...)=20 + * 2003-07-18 - 0.56 davidgsf (da...@cs...) * - port to 2.6 style driver + * 2004-02-29 - 0.6 Juergen Stuber <sta...@us...> + * - fix locking + * - unlink read URBs which are no longer needed + * - allow increased buffer size, eliminates need for timeout on write + * - have read URB running continuously + * - added poll + * - forbid seeking + * - added nonblocking I/O + * - changed back __func__ to __FUNCTION__ + * - read and log tower firmware version + * - reset tower on probe, avoids failure of first write + * 2004-03-09 - 0.7 Juergen Stuber <sta...@us...> + * - timeout read now only after inactivity, shorten default according= ly + * 2004-03-11 - 0.8 Juergen Stuber <sta...@us...> + * - log major, minor instead of possibly confusing device filename + * - whitespace cleanup + * 2004-03-12 - 0.9 Juergen Stuber <sta...@us...> + * - normalize whitespace in debug messages + * - take care about endianness in control message responses */ =20 #include <linux/config.h> @@ -53,33 +72,98 @@ #include <linux/completion.h> #include <asm/uaccess.h> #include <linux/usb.h> +#include <linux/poll.h> =20 =20 #ifdef CONFIG_USB_DEBUG static int debug =3D 4; #else - static int debug =3D 1; + static int debug =3D 0; #endif =20 /* Use our own dbg macro */ #undef dbg -#define dbg(lvl, format, arg...) do { if (debug >=3D lvl) printk(KERN_DE= BUG __FILE__ " : " format " \n", ## arg); } while (0) +#define dbg(lvl, format, arg...) do { if (debug >=3D lvl) printk(KERN_DE= BUG __FILE__ ": " format "\n", ## arg); } while (0) =20 =20 /* Version Information */ -#define DRIVER_VERSION "v0.56" -#define DRIVER_AUTHOR "David Glance, dav...@so..." +#define DRIVER_VERSION "v0.9" +#define DRIVER_AUTHOR "Juergen Stuber <sta...@so...>" #define DRIVER_DESC "LEGO USB Tower Driver" =20 -/* Module paramaters */ +/* Module parameters */ MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); =20 +/* The defaults are chosen to work with current versions of leJOS and NQ= C, + * and so that behaviour is close to older versions of the driver. + */ + +/* Some legacy software likes to receive packets in one piece. + * In this case read_buffer_size should exceed the maximal packet length + * (417 for datalog uploads), and packet_timeout should be set. + */ +static size_t read_buffer_size =3D 480; +MODULE_PARM(read_buffer_size, "i"); +MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); + +/* Some legacy software likes to send packets in one piece. + * In this case write_buffer_size should exceed the maximal packet lengt= h + * (417 for firmware and program downloads). + * A problem with long writes is that the following read may time out + * if the software is not prepared to wait long enough. + */ +static size_t write_buffer_size =3D 480; +MODULE_PARM(write_buffer_size, "i"); +MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); + +/* Some legacy software expects reads to contain whole LASM packets. + * To achieve this, characters which arrive before a packet timeout + * occurs will be returned in a single read operation. + * A problem with long reads is that the software may time out + * if it is not prepared to wait long enough. + * The packet timeout should be greater than the time between the + * reception of subsequent characters, which should arrive about + * every 5ms for the standard 2400 baud. + * Set it to 0 to disable. + */ +static int packet_timeout =3D 50; +MODULE_PARM(packet_timeout, "i"); +MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); + +/* Some legacy software expects blocking reads to time out. + * Timeout occurs after the specified time of read and write inactivity. + * Set it to 0 to disable. + */ +static int read_timeout =3D 200; +MODULE_PARM(read_timeout, "i"); +MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); + =20 /* Define these values to match your device */ #define LEGO_USB_TOWER_VENDOR_ID 0x0694 #define LEGO_USB_TOWER_PRODUCT_ID 0x0001 =20 +/* Vendor requests */ +#define LEGO_USB_TOWER_REQUEST_RESET 0x04 +#define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD + +struct tower_reset_reply { + __u16 size; /* little-endian */ + __u8 err_code; + __u8 spare; +} __attribute__ ((packed)); + +struct tower_get_version_reply { + __u16 size; /* little-endian */ + __u8 err_code; + __u8 spare; + __u8 major; + __u8 minor; + __u16 build_no; /* little-endian */ +} __attribute__ ((packed)); + + /* table of devices that work with this driver */ static struct usb_device_id tower_table [] =3D { { USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) }, @@ -90,22 +174,22 @@ MODULE_DEVICE_TABLE (usb, tower_table); =20 #define LEGO_USB_TOWER_MINOR_BASE 160 =20 -/* we can have up to this number of device plugged in at once */ -#define MAX_DEVICES 16 - -#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ =20 /* Structure to hold all of our device specific stuff */ struct lego_usb_tower { struct semaphore sem; /* locks this structure */ - struct usb_device* udev; /* save off the usb device pointer */ + struct usb_device* udev; /* save off the usb device pointer */ struct usb_interface* interface; unsigned char minor; /* the starting minor number for this device */ =20 int open_count; /* number of times this port has been opened */ =20 char* read_buffer; - int read_buffer_length; + size_t read_buffer_length; /* this much came in */ + size_t read_packet_length; /* this much will be returned on read */ + spinlock_t read_buffer_lock; + int packet_timeout_jiffies; + unsigned long read_last_arrival; =20 wait_queue_head_t read_wait; wait_queue_head_t write_wait; @@ -113,18 +197,16 @@ struct lego_usb_tower { char* interrupt_in_buffer; struct usb_endpoint_descriptor* interrupt_in_endpoint; struct urb* interrupt_in_urb; + atomic_t interrupt_in_running; + atomic_t interrupt_in_done; =20 char* interrupt_out_buffer; struct usb_endpoint_descriptor* interrupt_out_endpoint; struct urb* interrupt_out_urb; + atomic_t interrupt_out_busy; =20 }; =20 -/* Note that no locking is needed: - * read_buffer is arbitrated by read_buffer_length =3D=3D 0 - * interrupt_out_buffer is arbitrated by interrupt_out_urb->status =3D=3D= -EINPROGRESS - * interrupt_in_buffer belongs to urb alone and is overwritten on overfl= ow - */ =20 /* local function prototypes */ static ssize_t tower_read (struct file *file, char *buffer, size_t count= , loff_t *ppos); @@ -132,8 +214,11 @@ static ssize_t tower_write (struct file=20 static inline void tower_delete (struct lego_usb_tower *dev); static int tower_open (struct inode *inode, struct file *file); static int tower_release (struct inode *inode, struct file *file); -static int tower_release_internal (struct lego_usb_tower *dev); +static unsigned int tower_poll (struct file *file, poll_table *wait); +static loff_t tower_llseek (struct file *file, loff_t off, int whence); + static void tower_abort_transfers (struct lego_usb_tower *dev); +static void tower_check_for_read_packet (struct lego_usb_tower *dev); static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs= *regs); static void tower_interrupt_out_callback (struct urb *urb, struct pt_reg= s *regs); =20 @@ -146,14 +231,16 @@ static DECLARE_MUTEX (disconnect_sem); =20 /* file operations needed when we register this driver */ static struct file_operations tower_fops =3D { - .owner =3D THIS_MODULE, - .read =3D tower_read, + .owner =3D THIS_MODULE, + .read =3D tower_read, .write =3D tower_write, .open =3D tower_open, - .release =3D tower_release, + .release =3D tower_release, + .poll =3D tower_poll, + .llseek =3D tower_llseek, }; =20 -/*=20 +/* * usb class driver info in order to get a minor number from the usb cor= e, * and to have the device registered with devfs and the driver core */ @@ -167,11 +254,11 @@ static struct usb_class_driver tower_cla =20 /* usb specific object needed to register this driver with the usb subsy= stem */ static struct usb_driver tower_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "legousbtower", - .probe =3D tower_probe, - .disconnect =3D tower_disconnect, - .id_table =3D tower_table, + .owner =3D THIS_MODULE, + .name =3D "legousbtower", + .probe =3D tower_probe, + .disconnect =3D tower_disconnect, + .id_table =3D tower_table, }; =20 =20 @@ -183,8 +270,8 @@ static inline void lego_usb_tower_debug_ int i; =20 if (debug < level) - return;=20 -=09 + return; + printk (KERN_DEBUG __FILE__": %s - length =3D %d, data =3D ", function,= size); for (i =3D 0; i < size; ++i) { printk ("%.2x ", data[i]); @@ -198,7 +285,7 @@ static inline void lego_usb_tower_debug_ */ static inline void tower_delete (struct lego_usb_tower *dev) { - dbg(2, "%s enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 tower_abort_transfers (dev); =20 @@ -214,7 +301,7 @@ static inline void tower_delete (struct=20 kfree (dev->interrupt_out_buffer); kfree (dev); =20 - dbg(2, "%s : leave", __func__); + dbg(2, "%s: leave", __FUNCTION__); } =20 =20 @@ -228,7 +315,7 @@ static int tower_open (struct inode *ino int retval =3D 0; struct usb_interface *interface; =20 - dbg(2,"%s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 subminor =3D iminor(inode); =20 @@ -253,24 +340,44 @@ static int tower_open (struct inode *ino /* lock this device */ down (&dev->sem); =20 -=09 - /* increment our usage count for the device */ - ++dev->open_count; - - /* save device in the file's private structure */ - file->private_data =3D dev; - + /* allow opening only once */ + if (dev->open_count) { + retval =3D -EBUSY; + goto exit_unlock; + } + dev->open_count =3D 1; =20 /* initialize in direction */ dev->read_buffer_length =3D 0; + dev->read_packet_length =3D 0; + usb_fill_int_urb (dev->interrupt_in_urb, + dev->udev, + usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddr= ess), + dev->interrupt_in_buffer, + dev->interrupt_in_endpoint->wMaxPacketSize, + tower_interrupt_in_callback, + dev, + dev->interrupt_in_endpoint->bInterval); + atomic_set (&dev->interrupt_in_running, 1); + atomic_set (&dev->interrupt_in_done, 0); + retval =3D usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); + if (retval) { + err("Couldn't submit interrupt_in_urb %d", retval); + atomic_set (&dev->interrupt_in_running, 0); + dev->open_count =3D 0; + goto exit_unlock; + } =20 + /* save device in the file's private structure */ + file->private_data =3D dev; + +exit_unlock: up (&dev->sem); =20 exit_no_device: - up (&disconnect_sem); =20 - dbg(2,"%s : leave, return value %d ", __func__, retval); + dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval); =20 return retval; } @@ -283,87 +390,129 @@ static int tower_release (struct inode * struct lego_usb_tower *dev; int retval =3D 0; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 dev =3D (struct lego_usb_tower *)file->private_data; =20 if (dev =3D=3D NULL) { - dbg(1," %s : object is NULL", __func__); + dbg(1, "%s: object is NULL", __FUNCTION__); retval =3D -ENODEV; goto exit; } =20 - - /* lock our device */ down (&dev->sem); =20 - if (dev->open_count <=3D 0) { - dbg(1," %s : device not opened", __func__); + if (dev->open_count !=3D 1) { + dbg(1, "%s: device not opened exactly once", __FUNCTION__); retval =3D -ENODEV; + goto exit_unlock; + } + if (dev->udev =3D=3D NULL) { + /* the device was unplugged before the file was released */ + up (&dev->sem); /* unlock here as tower_delete frees dev */ + tower_delete (dev); goto exit; } + tower_abort_transfers (dev); + dev->open_count =3D 0; =20 - /* do the work */ - retval =3D tower_release_internal (dev); +exit_unlock: + up (&dev->sem); =20 exit: - up (&dev->sem); - dbg(2," %s : leave, return value %d", __func__, retval); + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); return retval; } =20 =20 /** - * tower_release_internal + * tower_abort_transfers + * aborts transfers and frees associated data structures */ -static int tower_release_internal (struct lego_usb_tower *dev) +static void tower_abort_transfers (struct lego_usb_tower *dev) { - int retval =3D 0; + dbg(2, "%s: enter", __FUNCTION__); =20 - dbg(2," %s : enter", __func__); - - if (dev->udev =3D=3D NULL) { - /* the device was unplugged before the file was released */ - tower_delete (dev); + if (dev =3D=3D NULL) { + dbg(1, "%s: dev is null", __FUNCTION__); goto exit; } =20 - /* decrement our usage count for the device */ - --dev->open_count; - if (dev->open_count <=3D 0) { - tower_abort_transfers (dev); - dev->open_count =3D 0; + /* shutdown transfer */ + if (atomic_read(&dev->interrupt_in_running)) { + atomic_set (&dev->interrupt_in_running, 0); + if (dev->interrupt_in_urb !=3D NULL) { + usb_unlink_urb (dev->interrupt_in_urb); + } + } + if (atomic_read(&dev->interrupt_out_busy)) { + atomic_set (&dev->interrupt_out_busy, 0); + if (dev->interrupt_out_urb !=3D NULL) { + usb_unlink_urb (dev->interrupt_out_urb); + } } =20 exit: - dbg(2," %s : leave", __func__); - return retval; + dbg(2, "%s: leave", __FUNCTION__); } =20 =20 /** - * tower_abort_transfers - * aborts transfers and frees associated data structures + * tower_check_for_read_packet + * + * To get correct semantics for signals and non-blocking I/O + * with packetizing we pretend not to see any data in the read buff= er + * until it has been there unchanged for at least + * dev->packet_timeout_jiffies, or until the buffer is full. */ -static void tower_abort_transfers (struct lego_usb_tower *dev) +static void tower_check_for_read_packet (struct lego_usb_tower *dev) { - dbg(2," %s : enter", __func__); - - if (dev =3D=3D NULL) { - dbg(1," %s : dev is null", __func__); - goto exit; + spin_lock_irq (&dev->read_buffer_lock); + if (!packet_timeout + || time_after(jiffies, dev->read_last_arrival + dev->packet_timeout= _jiffies) + || dev->read_buffer_length =3D=3D read_buffer_size) { + dev->read_packet_length =3D dev->read_buffer_length; } + atomic_set (&dev->interrupt_in_done, 0); + spin_unlock_irq (&dev->read_buffer_lock); +} =20 - /* shutdown transfer */ - if (dev->interrupt_in_urb !=3D NULL) { - usb_unlink_urb (dev->interrupt_in_urb); + +/** + * tower_poll + */ +static unsigned int tower_poll (struct file *file, poll_table *wait) +{ + struct lego_usb_tower *dev; + unsigned int mask =3D 0; + + dbg(2, "%s: enter", __FUNCTION__); + + dev =3D file->private_data; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + tower_check_for_read_packet(dev); + if (dev->read_packet_length > 0) { + mask |=3D POLLIN | POLLRDNORM; } - if (dev->interrupt_out_urb !=3D NULL) { - usb_unlink_urb (dev->interrupt_out_urb); + if (!atomic_read(&dev->interrupt_out_busy)) { + mask |=3D POLLOUT | POLLWRNORM; } =20 -exit: - dbg(2," %s : leave", __func__); + dbg(2, "%s: leave, mask =3D %d", __FUNCTION__, mask); + + return mask; +} + + +/** + * tower_llseek + */ +static loff_t tower_llseek (struct file *file, loff_t off, int whence) +{ + return -ESPIPE; /* unseekable */ } =20 =20 @@ -373,16 +522,15 @@ exit: static ssize_t tower_read (struct file *file, char *buffer, size_t count= , loff_t *ppos) { struct lego_usb_tower *dev; - size_t bytes_read =3D 0; size_t bytes_to_read; int i; int retval =3D 0; - int timeout =3D 0; + unsigned long timeout =3D 0; =20 - dbg(2," %s : enter, count =3D %Zd", __func__, count); + dbg(2, "%s: enter, count =3D %Zd", __FUNCTION__, count); =20 dev =3D (struct lego_usb_tower *)file->private_data; -=09 + /* lock this object */ down (&dev->sem); =20 @@ -395,74 +543,63 @@ static ssize_t tower_read (struct file * =20 /* verify that we actually have some data to read */ if (count =3D=3D 0) { - dbg(1," %s : read request of 0 bytes", __func__); + dbg(1, "%s: read request of 0 bytes", __FUNCTION__); goto exit; } =20 + if (read_timeout) { + timeout =3D jiffies + read_timeout * HZ / 1000; + } =20 - timeout =3D COMMAND_TIMEOUT; + /* wait for data */ + tower_check_for_read_packet (dev); + while (dev->read_packet_length =3D=3D 0) { + if (file->f_flags & O_NONBLOCK) { + retval =3D -EAGAIN; + goto exit; + } + retval =3D wait_event_interruptible_timeout (dev->read_wait, atomic_re= ad (&dev->interrupt_in_done), dev->packet_timeout_jiffies); + if (retval < 0) { + goto exit; + } =20 - while (1) { - if (dev->read_buffer_length =3D=3D 0) { - - /* start reading */ - usb_fill_int_urb (dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAd= dress), - dev->interrupt_in_buffer, - dev->interrupt_in_endpoint->wMaxPacketSize, - tower_interrupt_in_callback, - dev, - dev->interrupt_in_endpoint->bInterval); - =09 - retval =3D usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); - =09 - if (retval < 0) { - err("Couldn't submit interrupt_in_urb"); - goto exit; - } - - if (timeout <=3D 0) { - retval =3D -ETIMEDOUT; - goto exit; - } - - if (signal_pending(current)) { - retval =3D -EINTR; - goto exit; - } - - up (&dev->sem); - timeout =3D interruptible_sleep_on_timeout (&dev->read_wait, timeout)= ; - down (&dev->sem); - - } else { - /* copy the data from read_buffer into userspace */ - bytes_to_read =3D count > dev->read_buffer_length ? dev->read_buffer_= length : count; - if (copy_to_user (buffer, dev->read_buffer, bytes_to_read) !=3D 0) { - retval =3D -EFAULT; - goto exit; - } - dev->read_buffer_length -=3D bytes_to_read; - for (i=3D0; i<dev->read_buffer_length; i++) { - dev->read_buffer[i] =3D dev->read_buffer[i+bytes_to_read]; - } - - buffer +=3D bytes_to_read; - count -=3D bytes_to_read; - bytes_read +=3D bytes_to_read; - if (count =3D=3D 0) { - break; - } + /* reset read timeout during read or write activity */ + if (read_timeout + && (dev->read_packet_length !=3D dev->read_buffer_length + || atomic_read(&dev->interrupt_out_busy))) { + timeout =3D jiffies + read_timeout * HZ / 1000; + } + /* check for read timeout */ + if (read_timeout && time_after (jiffies, timeout)) { + retval =3D -ETIMEDOUT; + goto exit; } + tower_check_for_read_packet (dev); } =20 - retval =3D bytes_read; + /* copy the data from read_buffer into userspace */ + bytes_to_read =3D min(count, dev->read_packet_length); + + if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) { + retval =3D -EFAULT; + goto exit; + } + + spin_lock_irq (&dev->read_buffer_lock); + dev->read_buffer_length -=3D bytes_to_read; + dev->read_packet_length -=3D bytes_to_read; + for (i=3D0; i<dev->read_buffer_length; i++) { + dev->read_buffer[i] =3D dev->read_buffer[i+bytes_to_read]; + } + spin_unlock_irq (&dev->read_buffer_lock); + + retval =3D bytes_to_read; =20 exit: /* unlock the device */ up (&dev->sem); =20 - dbg(2," %s : leave, return value %d", __func__, retval); + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); return retval; } =20 @@ -473,13 +610,10 @@ exit: static ssize_t tower_write (struct file *file, const char *buffer, size_= t count, loff_t *ppos) { struct lego_usb_tower *dev; - size_t bytes_written =3D 0; size_t bytes_to_write; - size_t buffer_size; int retval =3D 0; - int timeout =3D 0; =20 - dbg(2," %s : enter, count =3D %Zd", __func__, count); + dbg(2, "%s: enter, count =3D %Zd", __FUNCTION__, count); =20 dev =3D (struct lego_usb_tower *)file->private_data; =20 @@ -495,85 +629,54 @@ static ssize_t tower_write (struct file=20 =20 /* verify that we actually have some data to write */ if (count =3D=3D 0) { - dbg(1," %s : write request of 0 bytes", __func__); + dbg(1, "%s: write request of 0 bytes", __FUNCTION__); goto exit; } =20 + /* wait until previous transfer is finished */ + while (atomic_read(&dev->interrupt_out_busy)) { + if (file->f_flags & O_NONBLOCK) { + retval =3D -EAGAIN; + goto exit; + } + retval =3D wait_event_interruptible (dev->write_wait, !atomic_read(&de= v->interrupt_out_busy)); + if (retval) { + goto exit; + } + } =20 - while (count > 0) { - if (dev->interrupt_out_urb->status =3D=3D -EINPROGRESS) { - timeout =3D COMMAND_TIMEOUT; - - while (timeout > 0) { - if (signal_pending(current)) { - dbg(1," %s : interrupted", __func__); - retval =3D -EINTR; - goto exit; - } - up (&dev->sem); - timeout =3D interruptible_sleep_on_timeout (&dev->write_wait, timeou= t); - down (&dev->sem); - if (timeout > 0) { - break; - } - dbg(1," %s : interrupted timeout: %d", __func__, timeout); - } - - - dbg(1," %s : final timeout: %d", __func__, timeout); - - if (timeout =3D=3D 0) { - dbg(1, "%s - command timed out.", __func__); - retval =3D -ETIMEDOUT; - goto exit; - } - - dbg(4," %s : in progress, count =3D %Zd", __func__, count); - } else { - dbg(4," %s : sending, count =3D %Zd", __func__, count); - - /* write the data into interrupt_out_buffer from userspace */ - buffer_size =3D dev->interrupt_out_endpoint->wMaxPacketSize; - bytes_to_write =3D count > buffer_size ? buffer_size : count; - dbg(4," %s : buffer_size =3D %Zd, count =3D %Zd, bytes_to_write =3D %= Zd", __func__, buffer_size, count, bytes_to_write); - - if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write= ) !=3D 0) { - retval =3D -EFAULT; - goto exit; - } - - /* send off the urb */ - usb_fill_int_urb(dev->interrupt_out_urb, - dev->udev,=20 - usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAdd= ress), - dev->interrupt_out_buffer, - bytes_to_write, - tower_interrupt_out_callback, - dev, - dev->interrupt_in_endpoint->bInterval); - - dev->interrupt_out_urb->actual_length =3D bytes_to_write; - retval =3D usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); - - if (retval < 0) { - err("Couldn't submit interrupt_out_urb %d", retval); - goto exit; - } - - buffer +=3D bytes_to_write; - count -=3D bytes_to_write; + /* write the data into interrupt_out_buffer from userspace */ + bytes_to_write =3D min(count, write_buffer_size); + dbg(4, "%s: count =3D %Zd, bytes_to_write =3D %Zd", __FUNCTION__, count= , bytes_to_write); =20 - bytes_written +=3D bytes_to_write; - } + if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write))= { + retval =3D -EFAULT; + goto exit; } =20 - retval =3D bytes_written; + /* send off the urb */ + usb_fill_int_urb(dev->interrupt_out_urb, + dev->udev, + usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddr= ess), + dev->interrupt_out_buffer, + bytes_to_write, + tower_interrupt_out_callback, + dev, + dev->interrupt_out_endpoint->bInterval); + atomic_set (&dev->interrupt_out_busy, 1); + retval =3D usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); + if (retval) { + atomic_set (&dev->interrupt_out_busy, 0); + err("Couldn't submit interrupt_out_urb %d", retval); + goto exit; + } + retval =3D bytes_to_write; =20 exit: /* unlock the device */ up (&dev->sem); =20 - dbg(2," %s : leave, return value %d", __func__, retval); + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); =20 return retval; } @@ -585,39 +688,48 @@ exit: static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs= *regs) { struct lego_usb_tower *dev =3D (struct lego_usb_tower *)urb->context; + int retval; =20 - dbg(4," %s : enter, status %d", __func__, urb->status); + dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); =20 - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); =20 if (urb->status !=3D 0) { if ((urb->status !=3D -ENOENT) && (urb->status !=3D -ECONNRESET)) { - dbg(1," %s : nonzero status received: %d", __func__, urb->status); + dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status); } goto exit; } =20 - down (&dev->sem); - if (urb->actual_length > 0) { - if (dev->read_buffer_length < (4 * dev->interrupt_in_endpoint->wMaxPac= ketSize) - (urb->actual_length)) { - - memcpy (dev->read_buffer+dev->read_buffer_length, dev->interrupt_in_b= uffer, urb->actual_length); - + spin_lock (&dev->read_buffer_lock); + if (dev->read_buffer_length + urb->actual_length < read_buffer_size) { + memcpy (dev->read_buffer + dev->read_buffer_length, + dev->interrupt_in_buffer, + urb->actual_length); dev->read_buffer_length +=3D urb->actual_length; - dbg(1," %s reading %d ", __func__, urb->actual_length); - wake_up_interruptible (&dev->read_wait); - - } else { - dbg(1," %s : read_buffer overflow", __func__); + dev->read_last_arrival =3D jiffies; + dbg(3, "%s: received %d bytes", __FUNCTION__, urb->actual_length); + } + else { + printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __F= UNCTION__, urb->actual_length); } + spin_unlock (&dev->read_buffer_lock); } =20 - up (&dev->sem); - exit: - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); - dbg(4," %s : leave, status %d", __func__, urb->status); + /* resubmit if we're still running */ + if (atomic_read (&dev->interrupt_in_running)) { + retval =3D usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); + if (retval) { + err("%s: usb_submit_urb failed (%d)", __FUNCTION__, retval); + } + } + atomic_set (&dev->interrupt_in_done, 1); + wake_up_interruptible (&dev->read_wait); + + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); + dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status); } =20 =20 @@ -628,22 +740,23 @@ static void tower_interrupt_out_callback { struct lego_usb_tower *dev =3D (struct lego_usb_tower *)urb->context; =20 - dbg(4," %s : enter, status %d", __func__, urb->status); - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); + dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); =20 if (urb->status !=3D 0) { - if ((urb->status !=3D -ENOENT) &&=20 + if ((urb->status !=3D -ENOENT) && (urb->status !=3D -ECONNRESET)) { - dbg(1, " %s :nonzero status received: %d", __func__, urb->status); + dbg(1, "%s:nonzero status received: %d", __FUNCTION__, urb->status); } goto exit; - } =20 + } =20 - wake_up_interruptible(&dev->write_wait); exit: + atomic_set (&dev->interrupt_out_busy, 0); + wake_up_interruptible(&dev->write_wait); =20 - lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer= _buffer); - dbg(4," %s : leave, status %d", __func__, urb->status); + lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->tra= nsfer_buffer); + dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status); } =20 =20 @@ -659,15 +772,18 @@ static int tower_probe (struct usb_inter struct lego_usb_tower *dev =3D NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor* endpoint; + struct tower_reset_reply reset_reply; + struct tower_get_version_reply get_version_reply; int i; int retval =3D -ENOMEM; + int result; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 if (udev =3D=3D NULL) { info ("udev is NULL."); } -=09 + /* See if the device offered us matches what we can accept */ if ((udev->descriptor.idVendor !=3D LEGO_USB_TOWER_VENDOR_ID) || (udev->descriptor.idProduct !=3D LEGO_USB_TOWER_PRODUCT_ID)) { @@ -691,6 +807,10 @@ static int tower_probe (struct usb_inter =20 dev->read_buffer =3D NULL; dev->read_buffer_length =3D 0; + dev->read_packet_length =3D 0; + dev->read_buffer_lock =3D SPIN_LOCK_UNLOCKED; + dev->packet_timeout_jiffies =3D packet_timeout * HZ / 1000; + dev->read_last_arrival =3D jiffies; =20 init_waitqueue_head (&dev->read_wait); init_waitqueue_head (&dev->write_wait); @@ -698,10 +818,12 @@ static int tower_probe (struct usb_inter dev->interrupt_in_buffer =3D NULL; dev->interrupt_in_endpoint =3D NULL; dev->interrupt_in_urb =3D NULL; + atomic_set (&dev->interrupt_in_done, 0); =20 dev->interrupt_out_buffer =3D NULL; dev->interrupt_out_endpoint =3D NULL; dev->interrupt_out_urb =3D NULL; + atomic_set (&dev->interrupt_out_busy, 0); =20 =20 iface_desc =3D &interface->altsetting[0]; @@ -714,7 +836,7 @@ static int tower_probe (struct usb_inter ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) =3D=3D USB_= ENDPOINT_XFER_INT)) { dev->interrupt_in_endpoint =3D endpoint; } - =09 + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) =3D=3D USB_D= IR_OUT) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) =3D=3D USB_= ENDPOINT_XFER_INT)) { dev->interrupt_out_endpoint =3D endpoint; @@ -729,7 +851,7 @@ static int tower_probe (struct usb_inter goto error; } =20 - dev->read_buffer =3D kmalloc ((4*dev->interrupt_in_endpoint->wMaxPacket= Size), GFP_KERNEL); + dev->read_buffer =3D kmalloc (read_buffer_size, GFP_KERNEL); if (!dev->read_buffer) { err("Couldn't allocate read_buffer"); goto error; @@ -744,7 +866,7 @@ static int tower_probe (struct usb_inter err("Couldn't allocate interrupt_in_urb"); goto error; } - dev->interrupt_out_buffer =3D kmalloc (dev->interrupt_out_endpoint->wMa= xPacketSize, GFP_KERNEL); + dev->interrupt_out_buffer =3D kmalloc (write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { err("Couldn't allocate interrupt_out_buffer"); goto error; @@ -753,7 +875,7 @@ static int tower_probe (struct usb_inter if (!dev->interrupt_out_urb) { err("Couldn't allocate interrupt_out_urb"); goto error; - } =20 + } =20 /* we can register the device now, as it is ready */ usb_set_intfdata (interface, dev); @@ -766,16 +888,50 @@ static int tower_probe (struct usb_inter usb_set_intfdata (interface, NULL); goto error; } - dev->minor =3D interface->minor; =20 /* let the user know what node this device is now attached to */ - info ("LEGO USB Tower device now attached to /dev/usb/lego%d", (dev->mi= nor - LEGO_USB_TOWER_MINOR_BASE)); + info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->min= or - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor); + + /* reset the tower */ + result =3D usb_control_msg (udev, + usb_rcvctrlpipe(udev, 0), + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &reset_reply, + sizeof(reset_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower reset control request failed"); + retval =3D result; + goto error; + } =20 + /* get the firmware version and log it */ + result =3D usb_control_msg (udev, + usb_rcvctrlpipe(udev, 0), + LEGO_USB_TOWER_REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &get_version_reply, + sizeof(get_version_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower get version control request failed"); + retval =3D result; + goto error; + } + info("LEGO USB Tower firmware version is %d.%d build %d", + get_version_reply.major, + get_version_reply.minor, + le16_to_cpu(get_version_reply.build_no)); =20 =20 exit: - dbg(2," %s : leave, return value 0x%.8lx (dev)", __func__, (long) dev); + dbg(2, "%s: leave, return value 0x%.8lx (dev)", __FUNCTION__, (long) de= v); =20 return retval; =20 @@ -795,7 +951,7 @@ static void tower_disconnect (struct usb struct lego_usb_tower *dev; int minor; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 down (&disconnect_sem); =20 @@ -823,7 +979,7 @@ static void tower_disconnect (struct usb =20 info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MIN= OR_BASE)); =20 - dbg(2," %s : leave", __func__); + dbg(2, "%s: leave", __FUNCTION__); } =20 =20 @@ -836,7 +992,7 @@ static int __init lego_usb_tower_init(vo int result; int retval =3D 0; =20 - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 /* register this driver with the USB subsystem */ result =3D usb_register(&tower_driver); @@ -849,7 +1005,7 @@ static int __init lego_usb_tower_init(vo info(DRIVER_DESC " " DRIVER_VERSION); =20 exit: - dbg(2," %s : leave, return value %d", __func__, retval); + dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); =20 return retval; } @@ -860,12 +1016,12 @@ exit: */ static void __exit lego_usb_tower_exit(void) { - dbg(2," %s : enter", __func__); + dbg(2, "%s: enter", __FUNCTION__); =20 /* deregister this driver with the USB subsystem */ usb_deregister (&tower_driver); =20 - dbg(2," %s : leave", __func__); + dbg(2, "%s: leave", __FUNCTION__); } =20 module_init (lego_usb_tower_init); --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ |
From: Matthew C. R. <tom...@ma...> - 2004-03-12 18:09:12
|
Thank you. I had a EHCI controller loaded a few days ago but removed it because I thought it would fix the errors. I got the same errors with UHCI which I posted here. Anyway. The patch worked for both NCQ 2.5 r3 and the latest brickos with the LegoUSB brickos patch. I have not tried the EHCI controller, but I can if you are interested in the results. Thank you again, Matt On Fri, 2004-03-12 at 04:25, Juergen Stuber wrote: > Hi Matthew, >=20 > the driver currently in the kernel is broken in various ways. > I'm in the process of preparing a patch for Linux 2.6.4 that > I hope will go out today. My current version is attached, > can you try if it works and tell me your version of NQC and > what machine and USB host controller and hub you use? >=20 > For me it works with Lejos, and nqc-3.0a2 once I get that compiled, > on UHCI and OHCI host controlers. Only if I run it on EHCI across > a USB 2.0 hub it doesn't, usb_submit_urb returns -ENOSPC. > If you use that USB 2.0 setup, can you try a different one? >=20 >=20 > Sincerely >=20 > J=FCrgen >=20 >=20 > Matthew C. Ruschmann wrote: > > When using NQC and the driver for kernel 2.6 I get the error, "No rep= ly > > from RCX" Apparently this is a problem with usb_submit_urb which > > returns -EINVAL > >=20 > > I get the following kernel messages: > >=20 > > Mar 11 20:20:14 [kernel] drivers/usb/misc/legousbtower.c: LEGO USB To= wer > > device now attached to=20 > > /dev/usb/lego0 > > Mar 11 20:20:14 [kernel] drivers/usb/core/usb.c: registered new drive= r > > legousbtower > > Mar 11 20:20:22 [kernel] drivers/usb/misc/legousbtower.c :=20 > > tower_interrupt_in_callback reading 1 > > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c: Couldn't > > submit interrupt_in_urb > > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_wri= te > > : final timeout: 1999 > > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_wri= te > > : final timeout: 1998 > > - Last output repeated 2 times - > > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_wri= te > > : final timeout: 1984 > > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_wri= te > > : final timeout: 1968 > > - Last output repeated twice - |
From: Stewart H. <st...@he...> - 2004-03-12 15:42:18
|
Jurgen, David, FYI the legousb driver (version 0.56) shipped in the 2.6.2 kernel works fine for me on my OHCI USB hardware. $modprobe legousbtower Feb 27 01:25:47 pequod kernel: drivers/usb/core/usb.c: registered new driver legousbtower Feb 27 01:25:47 pequod kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower Driver v0.56 Feb 27 01:07:46 pequod kernel: hub 1-0:1.0: new USB device on port 2, assiged address 5 Feb 27 01:07:47 pequod kernel: usb 1-2: Product: LEGO USB Tower Feb 27 01:07:47 pequod kernel: usb 1-2: Manufacturer: LEGO Group Feb 27 01:07:47 pequod kernel: usb 1-2: configuration #1 chosen from 4 choices Feb 27 01:07:47 pequod kernel: drivers/usb/misc/legousbtower.c: LEGO USB Tower device now attached to /dev/usb/lego0 However lejosfirmdl (from lejos-2-1-0 distrib) does not work with it. I suspected the complicated timing code in the lejosfirmdl code was the problem, and since the firmdl code has become such a mess of #ifdefs from years of being hacked I ended up finding it easier to write my own version of it from scratch...and yes it works very well. So I find the driver itself to be ok. My version of firmdl is quite different in that it uses blocking reads to wait for a reply from the RCX after writing a command to it. It seems to be a simple and effective approach. In fact I wonder why it wasnt done that way before, and I suspect the time out code in the current family of firmdl derived programs may be an artefact of the original serial tower and is probably not relevant to the USB tower. The legousb driver will handle a read timeout gracefully return an appropriate error code to the calling application, so the application doesnt need to worry about timeouts itself. ps: I am happy to release my firmdl code to anyone who wants it - though it is still a bit rough at the moment. -- Stewart Heitmann <st...@he...> |
From: Juergen S. <st...@lo...> - 2004-03-12 09:46:25
|
Hi Matthew, the driver currently in the kernel is broken in various ways. I'm in the process of preparing a patch for Linux 2.6.4 that I hope will go out today. My current version is attached, can you try if it works and tell me your version of NQC and what machine and USB host controller and hub you use? For me it works with Lejos, and nqc-3.0a2 once I get that compiled, on UHCI and OHCI host controlers. Only if I run it on EHCI across a USB 2.0 hub it doesn't, usb_submit_urb returns -ENOSPC. If you use that USB 2.0 setup, can you try a different one? Sincerely J=FCrgen Matthew C. Ruschmann wrote: > When using NQC and the driver for kernel 2.6 I get the error, "No reply > from RCX" Apparently this is a problem with usb_submit_urb which > returns -EINVAL >=20 > I get the following kernel messages: >=20 > Mar 11 20:20:14 [kernel] drivers/usb/misc/legousbtower.c: LEGO USB Towe= r > device now attached to=20 > /dev/usb/lego0 > Mar 11 20:20:14 [kernel] drivers/usb/core/usb.c: registered new driver > legousbtower > Mar 11 20:20:22 [kernel] drivers/usb/misc/legousbtower.c :=20 > tower_interrupt_in_callback reading 1 > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c: Couldn't > submit interrupt_in_urb > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_write > : final timeout: 1999 > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_write > : final timeout: 1998 > - Last output repeated 2 times - > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_write > : final timeout: 1984 > Mar 11 20:20:24 [kernel] drivers/usb/misc/legousbtower.c : tower_write > : final timeout: 1968 > - Last output repeated twice - --=20 J=FCrgen Stuber <st...@lo...> http://www.loria.fr/~stuber/ |