From 33cb89940082c54f348062db2f8bab6cf8fed816 Mon Sep 17 00:00:00 2001 From: Josef Sipek Date: Fri, 8 Dec 2006 02:37:46 -0800 Subject: [PATCH] struct path: convert usb Signed-off-by: Josef Sipek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/inode.c | 4 ++-- drivers/usb/gadget/file_storage.c | 16 ++++++++-------- drivers/usb/misc/sisusbvga/sisusb.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index b5d6a79af0b..11dad22da41 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -379,7 +379,7 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) { loff_t retval = -EINVAL; - mutex_lock(&file->f_dentry->d_inode->i_mutex); + mutex_lock(&file->f_path.dentry->d_inode->i_mutex); switch(orig) { case 0: if (offset > 0) { @@ -396,7 +396,7 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) default: break; } - mutex_unlock(&file->f_dentry->d_inode->i_mutex); + mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); return retval; } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index c98316ce838..a265e262a2e 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1909,10 +1909,10 @@ static int fsync_sub(struct lun *curlun) if (!filp->f_op->fsync) return -EINVAL; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; mutex_lock(&inode->i_mutex); rc = filemap_fdatawrite(inode->i_mapping); - err = filp->f_op->fsync(filp, filp->f_dentry, 1); + err = filp->f_op->fsync(filp, filp->f_path.dentry, 1); if (!rc) rc = err; err = filemap_fdatawait(inode->i_mapping); @@ -1950,7 +1950,7 @@ static int do_synchronize_cache(struct fsg_dev *fsg) static void invalidate_sub(struct lun *curlun) { struct file *filp = curlun->filp; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; unsigned long rc; rc = invalidate_inode_pages(inode->i_mapping); @@ -3526,8 +3526,8 @@ static int open_backing_file(struct lun *curlun, const char *filename) if (!(filp->f_mode & FMODE_WRITE)) ro = 1; - if (filp->f_dentry) - inode = filp->f_dentry->d_inode; + if (filp->f_path.dentry) + inode = filp->f_path.dentry->d_inode; if (inode && S_ISBLK(inode->i_mode)) { if (bdev_read_only(inode->i_bdev)) ro = 1; @@ -3606,7 +3606,7 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt, + p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); @@ -4030,8 +4030,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) if (backing_file_is_open(curlun)) { p = NULL; if (pathbuf) { - p = d_path(curlun->filp->f_dentry, - curlun->filp->f_vfsmnt, + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, pathbuf, PATH_MAX); if (IS_ERR(p)) p = NULL; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b99ca9c7982..0398908b15d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3168,7 +3168,7 @@ sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case SISUSB_GET_CONFIG: case SISUSB_COMMAND: lock_kernel(); - retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg); + retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg); unlock_kernel(); return retval; -- cgit v1.2.3 From 606d099cdd1080bbb50ea50dc52d98252f8f10a1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 8 Dec 2006 02:38:45 -0800 Subject: [PATCH] tty: switch to ktermios This is the grungy swap all the occurrences in the right places patch that goes with the updates. At this point we have the same functionality as before (except that sgttyb() returns speeds not zero) and are ready to begin turning new stuff on providing nobody reports lots of bugs If you are a tty driver author converting an out of tree driver the only impact should be termios->ktermios name changes for the speed/property setting functions from your upper layers. If you are implementing your own TCGETS function before then your driver was broken already and its about to get a whole lot more painful for you so please fix it 8) Also fill in c_ispeed/ospeed on init for most devices, although the current code will do this for you anyway but I'd like eventually to lose that extra paranoia [akpm@osdl.org: bluetooth fix] [mp3@de.ibm.com: sclp fix] [mp3@de.ibm.com: warning fix for tty3270] [hugh@veritas.com: fix tty_ioctl powerpc build] [jdike@addtoit.com: uml: fix ->set_termios declaration] Signed-off-by: Alan Cox Signed-off-by: Martin Peschke Acked-by: Peter Oberparleiter Cc: Cornelia Huck Signed-off-by: Hugh Dickins Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/class/cdc-acm.c | 4 ++-- drivers/usb/gadget/serial.c | 4 ++-- drivers/usb/serial/ark3116.c | 4 ++-- drivers/usb/serial/belkin_sa.c | 4 ++-- drivers/usb/serial/console.c | 2 +- drivers/usb/serial/cp2101.c | 4 ++-- drivers/usb/serial/cypress_m8.c | 10 +++++----- drivers/usb/serial/digi_acceleport.c | 6 +++--- drivers/usb/serial/empeg.c | 4 ++-- drivers/usb/serial/ftdi_sio.c | 4 ++-- drivers/usb/serial/io_edgeport.c | 8 ++++---- drivers/usb/serial/io_ti.c | 6 +++--- drivers/usb/serial/ir-usb.c | 4 ++-- drivers/usb/serial/keyspan.c | 2 +- drivers/usb/serial/keyspan.h | 2 +- drivers/usb/serial/keyspan_pda.c | 2 +- drivers/usb/serial/kl5kusb105.c | 6 +++--- drivers/usb/serial/kobil_sct.c | 10 +++++----- drivers/usb/serial/mct_u232.c | 4 ++-- drivers/usb/serial/mos7720.c | 4 ++-- drivers/usb/serial/mos7840.c | 4 ++-- drivers/usb/serial/option.c | 4 ++-- drivers/usb/serial/pl2303.c | 4 ++-- drivers/usb/serial/sierra.c | 2 +- drivers/usb/serial/ti_usb_3410_5052.c | 4 ++-- drivers/usb/serial/usb-serial.c | 2 +- drivers/usb/serial/visor.c | 4 ++-- drivers/usb/serial/whiteheat.c | 6 +++--- 28 files changed, 62 insertions(+), 62 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7f1fa956dcd..98199628e39 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -677,10 +677,10 @@ static const __u8 acm_tty_size[] = { 5, 6, 7, 8 }; -static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old) +static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { struct acm *acm = tty->driver_data; - struct termios *termios = tty->termios; + struct ktermios *termios = tty->termios; struct usb_cdc_line_coding newline; int newctrl = acm->ctrlout; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 208e55a667a..5516c59ed5e 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -200,7 +200,7 @@ static void gs_unthrottle(struct tty_struct * tty); static void gs_break(struct tty_struct *tty, int break_state); static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void gs_set_termios(struct tty_struct *tty, struct termios *old); +static void gs_set_termios(struct tty_struct *tty, struct ktermios *old); static int gs_send(struct gs_dev *dev); static int gs_send_packet(struct gs_dev *dev, char *packet, @@ -1077,7 +1077,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, /* * gs_set_termios */ -static void gs_set_termios(struct tty_struct *tty, struct termios *old) +static void gs_set_termios(struct tty_struct *tty, struct ktermios *old) { } diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 863966c1c5a..5261cd22ee6 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -156,7 +156,7 @@ cleanup: } static void ark3116_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); @@ -326,7 +326,7 @@ static void ark3116_set_termios(struct usb_serial_port *port, static int ark3116_open(struct usb_serial_port *port, struct file *filp) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; char *buf; int result = 0; diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 8835bb58ca9..38b4dae319e 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -92,7 +92,7 @@ static void belkin_sa_shutdown (struct usb_serial *serial); static int belkin_sa_open (struct usb_serial_port *port, struct file *filp); static void belkin_sa_close (struct usb_serial_port *port, struct file *filp); static void belkin_sa_read_int_callback (struct urb *urb); -static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old); +static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios * old); static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state ); static int belkin_sa_tiocmget (struct usb_serial_port *port, struct file *file); @@ -333,7 +333,7 @@ exit: __FUNCTION__, retval); } -static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct belkin_sa_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 7167728d764..9386e216d68 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -65,7 +65,7 @@ static int usb_console_setup(struct console *co, char *options) struct usb_serial_port *port; int retval = 0; struct tty_struct *tty; - struct termios *termios; + struct ktermios *termios; dbg ("%s", __FUNCTION__); diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index f95d42c0d16..2f9b7ac3266 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -41,7 +41,7 @@ static int cp2101_open(struct usb_serial_port*, struct file*); static void cp2101_cleanup(struct usb_serial_port*); static void cp2101_close(struct usb_serial_port*, struct file*); static void cp2101_get_termios(struct usb_serial_port*); -static void cp2101_set_termios(struct usb_serial_port*, struct termios*); +static void cp2101_set_termios(struct usb_serial_port*, struct ktermios*); static int cp2101_tiocmget (struct usb_serial_port *, struct file *); static int cp2101_tiocmset (struct usb_serial_port *, struct file *, unsigned int, unsigned int); @@ -506,7 +506,7 @@ static void cp2101_get_termios (struct usb_serial_port *port) } static void cp2101_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { unsigned int cflag, old_cflag=0; int baud=0, bits; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 093f303b318..a1fdb85b8c0 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -143,7 +143,7 @@ struct cypress_private { wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ char prev_status, diff_status; /* used for TIOCMIWAIT */ /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */ - struct termios tmp_termios; /* stores the old termios settings */ + struct ktermios tmp_termios; /* stores the old termios settings */ }; /* write buffer structure */ @@ -165,7 +165,7 @@ static int cypress_write (struct usb_serial_port *port, const unsigned char *b static void cypress_send (struct usb_serial_port *port); static int cypress_write_room (struct usb_serial_port *port); static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void cypress_set_termios (struct usb_serial_port *port, struct termios * old); +static void cypress_set_termios (struct usb_serial_port *port, struct ktermios * old); static int cypress_tiocmget (struct usb_serial_port *port, struct file *file); static int cypress_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static int cypress_chars_in_buffer (struct usb_serial_port *port); @@ -949,13 +949,13 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi switch (cmd) { case TIOCGSERIAL: - if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { + if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) { return -EFAULT; } return (0); break; case TIOCSSERIAL: - if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { + if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) { return -EFAULT; } /* here we need to call cypress_set_termios to invoke the new settings */ @@ -1019,7 +1019,7 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi static void cypress_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct cypress_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 83d0e21145b..9d9ea874639 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -449,7 +449,7 @@ static int digi_transmit_idle( struct usb_serial_port *port, static void digi_rx_throttle (struct usb_serial_port *port); static void digi_rx_unthrottle (struct usb_serial_port *port); static void digi_set_termios( struct usb_serial_port *port, - struct termios *old_termios ); + struct ktermios *old_termios ); static void digi_break_ctl( struct usb_serial_port *port, int break_state ); static int digi_ioctl( struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg ); @@ -976,7 +976,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); static void digi_set_termios( struct usb_serial_port *port, - struct termios *old_termios ) + struct ktermios *old_termios ) { struct digi_port *priv = usb_get_serial_port_data(port); @@ -1463,7 +1463,7 @@ static int digi_open( struct usb_serial_port *port, struct file *filp ) int ret; unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); - struct termios not_termios; + struct ktermios not_termios; unsigned long flags = 0; diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 4ce10a83195..92beeb19795 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -92,7 +92,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void empeg_write_bulk_callback (struct urb *urb); static void empeg_read_bulk_callback (struct urb *urb); @@ -442,7 +442,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign } -static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s - port %d", __FUNCTION__, port->number); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 72e4d48f51e..41b0ad2d56a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -595,7 +595,7 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port); static void ftdi_write_bulk_callback (struct urb *urb); static void ftdi_read_bulk_callback (struct urb *urb); static void ftdi_process_read (struct work_struct *work); -static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); +static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios * old); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); @@ -1880,7 +1880,7 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) * WARNING: set_termios calls this with old_termios in kernel space */ -static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { /* ftdi_termios */ struct usb_device *dev = port->serial->dev; unsigned int cflag = port->tty->termios->c_cflag; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index d06547a13f2..f623d58370a 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -229,7 +229,7 @@ static int edge_write_room (struct usb_serial_port *port); static int edge_chars_in_buffer (struct usb_serial_port *port); static void edge_throttle (struct usb_serial_port *port); static void edge_unthrottle (struct usb_serial_port *port); -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void edge_break (struct usb_serial_port *port, int break_state); static int edge_tiocmget (struct usb_serial_port *port, struct file *file); @@ -257,7 +257,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8 static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param); static int calc_baud_rate_divisor (int baud_rate, int *divisor); static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate); -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios); +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios); static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue); static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength); static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); @@ -1431,7 +1431,7 @@ static void edge_unthrottle (struct usb_serial_port *port) * SerialSetTermios * this function is called by the tty driver when it wants to change the termios structure *****************************************************************************/ -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; @@ -2412,7 +2412,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r #ifndef CMSPAR #define CMSPAR 0 #endif -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { struct tty_struct *tty; int baud; diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ee0c921e152..2da2684e080 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -238,7 +238,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c static void stop_read(struct edgeport_port *edge_port); static int restart_read(struct edgeport_port *edge_port); -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void edge_send(struct usb_serial_port *port); /* circular buffer */ @@ -2361,7 +2361,7 @@ static int restart_read(struct edgeport_port *edge_port) return status; } -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { struct ump_uart_config *config; struct tty_struct *tty; @@ -2512,7 +2512,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio return; } -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 331bf81556f..8fdf486e346 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -107,7 +107,7 @@ static void ir_close (struct usb_serial_port *port, struct file *filep); static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count); static void ir_write_bulk_callback (struct urb *urb); static void ir_read_bulk_callback (struct urb *urb); -static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static u8 ir_baud = 0; static u8 ir_xbof = 0; @@ -497,7 +497,7 @@ static void ir_read_bulk_callback (struct urb *urb) return; } -static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { unsigned char *transfer_buffer; unsigned int cflag; diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7639652cec4..9d2fdfd6865 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -264,7 +264,7 @@ static void keyspan_break_ctl (struct usb_serial_port *port, int break_state) static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int baud_rate, device_port; struct keyspan_port_private *p_priv; diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 7472ed6bf62..6413d73c139 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -59,7 +59,7 @@ static int keyspan_ioctl (struct usb_serial_port *port, unsigned int cmd, unsigned long arg); static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old); + struct ktermios *old); static void keyspan_break_ctl (struct usb_serial_port *port, int break_state); static int keyspan_tiocmget (struct usb_serial_port *port, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index e09a0bfe623..126b9703bba 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -365,7 +365,7 @@ static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state static void keyspan_pda_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; unsigned int cflag = port->tty->termios->c_cflag; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 17e205699c2..73d755df484 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -86,7 +86,7 @@ static int klsi_105_write_room (struct usb_serial_port *port); static void klsi_105_read_bulk_callback (struct urb *urb); static void klsi_105_set_termios (struct usb_serial_port *port, - struct termios * old); + struct ktermios *old); static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, @@ -164,7 +164,7 @@ struct klsi_105_port_settings { #define URB_TRANSFER_BUFFER_SIZE 64 struct klsi_105_private { struct klsi_105_port_settings cfg; - struct termios termios; + struct ktermios termios; unsigned long line_state; /* modem line settings */ /* write pool */ struct urb * write_urb_pool[NUM_URBS]; @@ -688,7 +688,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb) static void klsi_105_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned int iflag = port->tty->termios->c_iflag; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 237289920f0..e284d6c0fd3 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -136,7 +136,7 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct termios internal_termios; + struct ktermios internal_termios; }; @@ -624,11 +624,11 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, switch (cmd) { case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) { + if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } - if (kernel_termios_to_user_termios((struct termios __user *)arg, + if (kernel_termios_to_user_termios((struct ktermios __user *)arg, &priv->internal_termios)) return -EFAULT; return 0; @@ -638,12 +638,12 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); return -ENOTTY; } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) { + if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct termios __user *)arg)) + (struct ktermios __user *)arg)) return -EFAULT; settings = kzalloc(50, GFP_KERNEL); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a906e500a02..38b1d17e06e 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -98,7 +98,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp); static void mct_u232_read_int_callback (struct urb *urb); static void mct_u232_set_termios (struct usb_serial_port *port, - struct termios * old); + struct ktermios * old); static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, @@ -556,7 +556,7 @@ exit: } /* mct_u232_read_int_callback */ static void mct_u232_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 70f93b18292..e55f4ed81d7 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1014,7 +1014,7 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, * the specified new settings. */ static void change_port_settings(struct moschip_port *mos7720_port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial_port *port; struct usb_serial *serial; @@ -1203,7 +1203,7 @@ static void change_port_settings(struct moschip_port *mos7720_port, * termios structure. */ static void mos7720_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int status; unsigned int cflag; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 5432c634008..8cc728a49e4 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1931,7 +1931,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_change_port_settings(struct moschip_port *mos7840_port, - struct termios *old_termios) + struct ktermios *old_termios) { struct tty_struct *tty; int baud; @@ -2118,7 +2118,7 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int status; unsigned int cflag; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 130afbbd3fc..0ae4098718c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -59,7 +59,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port); static int option_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void option_set_termios(struct usb_serial_port *port, - struct termios *old); + struct ktermios *old); static void option_break_ctl(struct usb_serial_port *port, int break_state); static int option_tiocmget(struct usb_serial_port *port, struct file *file); static int option_tiocmset(struct usb_serial_port *port, struct file *file, @@ -230,7 +230,7 @@ static void option_break_ctl(struct usb_serial_port *port, int break_state) } static void option_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { dbg("%s", __FUNCTION__); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index bc800c8787a..d124d780e42 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -455,7 +455,7 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port) } static void pl2303_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -687,7 +687,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp) static int pl2303_open(struct usb_serial_port *port, struct file *filp) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *buf; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 4b5097fa48d..6d8e91e00ec 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -145,7 +145,7 @@ static void sierra_break_ctl(struct usb_serial_port *port, int break_state) } static void sierra_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { dbg("%s", __FUNCTION__); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ae98d8cbdbb..f42eb9ea640 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -161,7 +161,7 @@ static void ti_throttle(struct usb_serial_port *port); static void ti_unthrottle(struct usb_serial_port *port); static int ti_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void ti_set_termios(struct usb_serial_port *port, - struct termios *old_termios); + struct ktermios *old_termios); static int ti_tiocmget(struct usb_serial_port *port, struct file *file); static int ti_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); @@ -881,7 +881,7 @@ static int ti_ioctl(struct usb_serial_port *port, struct file *file, static void ti_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct ti_port *tport = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 3d5072f14b8..716f6806cc8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -397,7 +397,7 @@ exit: return retval; } -static void serial_set_termios (struct tty_struct *tty, struct termios * old) +static void serial_set_termios (struct tty_struct *tty, struct ktermios * old) { struct usb_serial_port *port = tty->driver_data; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index eef5eaa5fa0..b09f0609605 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,7 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -916,7 +916,7 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign /* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { unsigned int cflag; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 154c7d29059..dc45e58e2b8 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -145,7 +145,7 @@ static void whiteheat_close (struct usb_serial_port *port, struct file *filp); static int whiteheat_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int whiteheat_write_room (struct usb_serial_port *port); static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old); +static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios * old); static int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file); static int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state); @@ -597,7 +597,7 @@ static void whiteheat_shutdown (struct usb_serial *serial) static int whiteheat_open (struct usb_serial_port *port, struct file *filp) { int retval = 0; - struct termios old_term; + struct ktermios old_term; dbg("%s - port %d", __FUNCTION__, port->number); @@ -870,7 +870,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un } -static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s -port %d", __FUNCTION__, port->number); -- cgit v1.2.3 From 64bb67b1702958759f650adb64ab33496641e526 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:40:37 +0100 Subject: [PATCH] Generic HID layer - disable USB HID This patch is a part of generic HID layer introduction. USB HID is disabled, so that the code split and changes could be introduced in a way that is reviewable (i.e. separate patches), but not to break git bisect by uncompilable kernel throughout different stages of the code splitup and changes. The last patch of this series enables HID again. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 661af7aa623..9b075319ed5 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -6,7 +6,7 @@ comment "USB Input Devices" config USB_HID tristate "USB Human Interface Device (full HID) support" - depends on USB + depends on USB && BROKEN ---help--- Say Y here if you want full HID support to connect keyboards, mice, joysticks, graphic tablets, or any other HID based devices -- cgit v1.2.3 From dde5845a529ff753364a6d1aea61180946270bfa Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:40:44 +0100 Subject: [PATCH] Generic HID layer - code split The "big main" split of USB HID code into generic HID code and USB-transport specific HID handling. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 1039 ++++------------------------------------- drivers/usb/input/hid-debug.h | 757 ------------------------------ drivers/usb/input/hid-ff.c | 2 +- drivers/usb/input/hid-input.c | 844 +-------------------------------- drivers/usb/input/hid-lgff.c | 2 +- drivers/usb/input/hid-pidff.c | 4 +- drivers/usb/input/hid-tmff.c | 2 +- drivers/usb/input/hid-zpff.c | 2 +- drivers/usb/input/hid.h | 540 --------------------- drivers/usb/input/hiddev.c | 3 +- 10 files changed, 106 insertions(+), 3089 deletions(-) delete mode 100644 drivers/usb/input/hid-debug.h delete mode 100644 drivers/usb/input/hid.h (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 0811c39bd14..06e169b6a17 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -4,6 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006 Jiri Kosina */ /* @@ -32,7 +33,7 @@ #include -#include "hid.h" +#include #include /* @@ -54,887 +55,6 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -/* - * Register a new report for a device. - */ - -static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) -{ - struct hid_report_enum *report_enum = device->report_enum + type; - struct hid_report *report; - - if (report_enum->report_id_hash[id]) - return report_enum->report_id_hash[id]; - - if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) - return NULL; - - if (id != 0) - report_enum->numbered = 1; - - report->id = id; - report->type = type; - report->size = 0; - report->device = device; - report_enum->report_id_hash[id] = report; - - list_add_tail(&report->list, &report_enum->report_list); - - return report; -} - -/* - * Register a new field for this report. - */ - -static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) -{ - struct hid_field *field; - - if (report->maxfield == HID_MAX_FIELDS) { - dbg("too many fields in report"); - return NULL; - } - - if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned), GFP_KERNEL))) return NULL; - - field->index = report->maxfield++; - report->field[field->index] = field; - field->usage = (struct hid_usage *)(field + 1); - field->value = (unsigned *)(field->usage + usages); - field->report = report; - - return field; -} - -/* - * Open a collection. The type/usage is pushed on the stack. - */ - -static int open_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_collection *collection; - unsigned usage; - - usage = parser->local.usage[0]; - - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { - dbg("collection stack overflow"); - return -1; - } - - if (parser->device->maxcollection == parser->device->collection_size) { - collection = kmalloc(sizeof(struct hid_collection) * - parser->device->collection_size * 2, GFP_KERNEL); - if (collection == NULL) { - dbg("failed to reallocate collection array"); - return -1; - } - memcpy(collection, parser->device->collection, - sizeof(struct hid_collection) * - parser->device->collection_size); - memset(collection + parser->device->collection_size, 0, - sizeof(struct hid_collection) * - parser->device->collection_size); - kfree(parser->device->collection); - parser->device->collection = collection; - parser->device->collection_size *= 2; - } - - parser->collection_stack[parser->collection_stack_ptr++] = - parser->device->maxcollection; - - collection = parser->device->collection + - parser->device->maxcollection++; - collection->type = type; - collection->usage = usage; - collection->level = parser->collection_stack_ptr - 1; - - if (type == HID_COLLECTION_APPLICATION) - parser->device->maxapplication++; - - return 0; -} - -/* - * Close a collection. - */ - -static int close_collection(struct hid_parser *parser) -{ - if (!parser->collection_stack_ptr) { - dbg("collection stack underflow"); - return -1; - } - parser->collection_stack_ptr--; - return 0; -} - -/* - * Climb up the stack, search for the specified collection type - * and return the usage. - */ - -static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) -{ - int n; - for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->device->collection[parser->collection_stack[n]].type == type) - return parser->device->collection[parser->collection_stack[n]].usage; - return 0; /* we know nothing about this usage type */ -} - -/* - * Add a usage to the temporary parser table. - */ - -static int hid_add_usage(struct hid_parser *parser, unsigned usage) -{ - if (parser->local.usage_index >= HID_MAX_USAGES) { - dbg("usage index exceeded"); - return -1; - } - parser->local.usage[parser->local.usage_index] = usage; - parser->local.collection_index[parser->local.usage_index] = - parser->collection_stack_ptr ? - parser->collection_stack[parser->collection_stack_ptr - 1] : 0; - parser->local.usage_index++; - return 0; -} - -/* - * Register a new field for this report. - */ - -static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) -{ - struct hid_report *report; - struct hid_field *field; - int usages; - unsigned offset; - int i; - - if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { - dbg("hid_register_report failed"); - return -1; - } - - if (parser->global.logical_maximum < parser->global.logical_minimum) { - dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); - return -1; - } - - offset = report->size; - report->size += parser->global.report_size * parser->global.report_count; - - if (!parser->local.usage_index) /* Ignore padding fields */ - return 0; - - usages = max_t(int, parser->local.usage_index, parser->global.report_count); - - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) - return 0; - - field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); - field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); - field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - - for (i = 0; i < usages; i++) { - int j = i; - /* Duplicate the last usage we parsed if we have excess values */ - if (i >= parser->local.usage_index) - j = parser->local.usage_index - 1; - field->usage[i].hid = parser->local.usage[j]; - field->usage[i].collection_index = - parser->local.collection_index[j]; - } - - field->maxusage = usages; - field->flags = flags; - field->report_offset = offset; - field->report_type = report_type; - field->report_size = parser->global.report_size; - field->report_count = parser->global.report_count; - field->logical_minimum = parser->global.logical_minimum; - field->logical_maximum = parser->global.logical_maximum; - field->physical_minimum = parser->global.physical_minimum; - field->physical_maximum = parser->global.physical_maximum; - field->unit_exponent = parser->global.unit_exponent; - field->unit = parser->global.unit; - - return 0; -} - -/* - * Read data value from item. - */ - -static u32 item_udata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.u8; - case 2: return item->data.u16; - case 4: return item->data.u32; - } - return 0; -} - -static s32 item_sdata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.s8; - case 2: return item->data.s16; - case 4: return item->data.s32; - } - return 0; -} - -/* - * Process a global item. - */ - -static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) -{ - switch (item->tag) { - - case HID_GLOBAL_ITEM_TAG_PUSH: - - if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { - dbg("global enviroment stack overflow"); - return -1; - } - - memcpy(parser->global_stack + parser->global_stack_ptr++, - &parser->global, sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_POP: - - if (!parser->global_stack_ptr) { - dbg("global enviroment stack underflow"); - return -1; - } - - memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, - sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: - parser->global.usage_page = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: - parser->global.logical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - if (parser->global.logical_minimum < 0) - parser->global.logical_maximum = item_sdata(item); - else - parser->global.logical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: - parser->global.physical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - if (parser->global.physical_minimum < 0) - parser->global.physical_maximum = item_sdata(item); - else - parser->global.physical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - parser->global.unit_exponent = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT: - parser->global.unit = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: - if ((parser->global.report_size = item_udata(item)) > 32) { - dbg("invalid report_size %d", parser->global.report_size); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { - dbg("invalid report_count %d", parser->global.report_count); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_ID: - if ((parser->global.report_id = item_udata(item)) == 0) { - dbg("report_id 0 is invalid"); - return -1; - } - return 0; - - default: - dbg("unknown global tag 0x%x", item->tag); - return -1; - } -} - -/* - * Process a local item. - */ - -static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - unsigned n; - - if (item->size == 0) { - dbg("item data expected for local item"); - return -1; - } - - data = item_udata(item); - - switch (item->tag) { - - case HID_LOCAL_ITEM_TAG_DELIMITER: - - if (data) { - /* - * We treat items before the first delimiter - * as global to all usage sets (branch 0). - * In the moment we process only these global - * items and the first delimiter set. - */ - if (parser->local.delimiter_depth != 0) { - dbg("nested delimiters"); - return -1; - } - parser->local.delimiter_depth++; - parser->local.delimiter_branch++; - } else { - if (parser->local.delimiter_depth < 1) { - dbg("bogus close delimiter"); - return -1; - } - parser->local.delimiter_depth--; - } - return 1; - - case HID_LOCAL_ITEM_TAG_USAGE: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - return hid_add_usage(parser, data); - - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - parser->local.usage_minimum = data; - return 0; - - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - for (n = parser->local.usage_minimum; n <= data; n++) - if (hid_add_usage(parser, n)) { - dbg("hid_add_usage failed\n"); - return -1; - } - return 0; - - default: - - dbg("unknown local item tag 0x%x", item->tag); - return 0; - } - return 0; -} - -/* - * Process a main item. - */ - -static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - int ret; - - data = item_udata(item); - - switch (item->tag) { - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 0xff); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - ret = close_collection(parser); - break; - case HID_MAIN_ITEM_TAG_INPUT: - ret = hid_add_field(parser, HID_INPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_FEATURE: - ret = hid_add_field(parser, HID_FEATURE_REPORT, data); - break; - default: - dbg("unknown main item tag 0x%x", item->tag); - ret = 0; - } - - memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ - - return ret; -} - -/* - * Process a reserved item. - */ - -static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) -{ - dbg("reserved item type, tag 0x%x", item->tag); - return 0; -} - -/* - * Free a report and all registered fields. The field->usage and - * field->value table's are allocated behind the field, so we need - * only to free(field) itself. - */ - -static void hid_free_report(struct hid_report *report) -{ - unsigned n; - - for (n = 0; n < report->maxfield; n++) - kfree(report->field[n]); - kfree(report); -} - -/* - * Free a device structure, all reports, and all fields. - */ - -static void hid_free_device(struct hid_device *device) -{ - unsigned i,j; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - struct hid_report_enum *report_enum = device->report_enum + i; - - for (j = 0; j < 256; j++) { - struct hid_report *report = report_enum->report_id_hash[j]; - if (report) - hid_free_report(report); - } - } - - kfree(device->rdesc); - kfree(device); -} - -/* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. - */ - -static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) -{ - u8 b; - - if ((end - start) <= 0) - return NULL; - - b = *start++; - - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; - - if (item->tag == HID_ITEM_TAG_LONG) { - - item->format = HID_ITEM_FORMAT_LONG; - - if ((end - start) < 2) - return NULL; - - item->size = *start++; - item->tag = *start++; - - if ((end - start) < item->size) - return NULL; - - item->data.longdata = start; - start += item->size; - return start; - } - - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - - switch (item->size) { - - case 0: - return start; - - case 1: - if ((end - start) < 1) - return NULL; - item->data.u8 = *start++; - return start; - - case 2: - if ((end - start) < 2) - return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); - start = (__u8 *)((__le16 *)start + 1); - return start; - - case 3: - item->size++; - if ((end - start) < 4) - return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); - start = (__u8 *)((__le32 *)start + 1); - return start; - } - - return NULL; -} - -/* - * Parse a report description into a hid_device structure. Reports are - * enumerated, fields are attached to these reports. - */ - -static struct hid_device *hid_parse_report(__u8 *start, unsigned size) -{ - struct hid_device *device; - struct hid_parser *parser; - struct hid_item item; - __u8 *end; - unsigned i; - static int (*dispatch_type[])(struct hid_parser *parser, - struct hid_item *item) = { - hid_parser_main, - hid_parser_global, - hid_parser_local, - hid_parser_reserved - }; - - if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) - return NULL; - - if (!(device->collection = kzalloc(sizeof(struct hid_collection) * - HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { - kfree(device); - return NULL; - } - device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; - - for (i = 0; i < HID_REPORT_TYPES; i++) - INIT_LIST_HEAD(&device->report_enum[i].report_list); - - if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { - kfree(device->collection); - kfree(device); - return NULL; - } - memcpy(device->rdesc, start, size); - device->rsize = size; - - if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) { - kfree(device->rdesc); - kfree(device->collection); - kfree(device); - return NULL; - } - parser->device = device; - - end = start + size; - while ((start = fetch_item(start, end, &item)) != NULL) { - - if (item.format != HID_ITEM_FORMAT_SHORT) { - dbg("unexpected long global item"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (dispatch_type[item.type](parser, &item)) { - dbg("item %u %u %u %u parsing failed\n", - item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (start == end) { - if (parser->collection_stack_ptr) { - dbg("unbalanced collection at end of report description"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - if (parser->local.delimiter_depth) { - dbg("unbalanced delimiter at end of report description"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - kfree(parser); - return device; - } - } - - dbg("item fetching failed at offset %d\n", (int)(end - start)); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; -} - -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static s32 snto32(__u32 value, unsigned n) -{ - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (-1 << n) : value; -} - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static u32 s32ton(__s32 value, unsigned n) -{ - s32 a = value >> (n - 1); - if (a && a != -1) - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - -/* - * Extract/implement a data field from/to a little endian report (bit array). - * - * Code sort-of follows HID spec: - * http://www.usb.org/developers/devclass_docs/HID1_11.pdf - * - * While the USB HID spec allows unlimited length bit fields in "report - * descriptors", most devices never use more than 16 bits. - * One model of UPS is claimed to report "LINEV" as a 32-bit field. - * Search linux-kernel and linux-usb-devel archives for "hid-core extract". - */ - -static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) -{ - u64 x; - - WARN_ON(n > 32); - - report += offset >> 3; /* adjust byte index */ - offset &= 7; /* now only need bit offset into one byte */ - x = get_unaligned((u64 *) report); - x = le64_to_cpu(x); - x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ - return (u32) x; -} - -/* - * "implement" : set bits in a little endian bit stream. - * Same concepts as "extract" (see comments above). - * The data mangled in the bit stream remains in little endian - * order the whole time. It make more sense to talk about - * endianness of register values by considering a register - * a "cached" copy of the little endiad bit stream. - */ -static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) -{ - u64 x; - u64 m = (1ULL << n) - 1; - - WARN_ON(n > 32); - - WARN_ON(value > m); - value &= m; - - report += offset >> 3; - offset &= 7; - - x = get_unaligned((u64 *)report); - x &= cpu_to_le64(~(m << offset)); - x |= cpu_to_le64(((u64) value) << offset); - put_unaligned(x, (u64 *) report); -} - -/* - * Search an array for a value. - */ - -static __inline__ int search(__s32 *array, __s32 value, unsigned n) -{ - while (n--) { - if (*array++ == value) - return 0; - } - return -1; -} - -static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) -{ - hid_dump_input(usage, value); - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_hid_event(hid, field, usage, value); - if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) - hiddev_hid_event(hid, field, usage, value); -} - -/* - * Analyse a received field, and fetch the data from it. The field - * content is stored for next report processing (we do differential - * reporting to the layer). - */ - -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) -{ - unsigned n; - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - __s32 min = field->logical_minimum; - __s32 max = field->logical_maximum; - __s32 *value; - - if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) - return; - - for (n = 0; n < count; n++) { - - value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : - extract(data, offset + n * size, size); - - if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ - && value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - goto exit; - } - - for (n = 0; n < count; n++) { - - if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt); - continue; - } - - if (field->value[n] >= min && field->value[n] <= max - && field->usage[field->value[n] - min].hid - && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); - - if (value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid - && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); - } - - memcpy(field->value, value, count * sizeof(__s32)); -exit: - kfree(value); -} - -static int hid_input_report(int type, struct urb *urb, int interrupt) -{ - struct hid_device *hid = urb->context; - struct hid_report_enum *report_enum = hid->report_enum + type; - u8 *data = urb->transfer_buffer; - int len = urb->actual_length; - struct hid_report *report; - int n, size; - - if (!len) { - dbg("empty report"); - return -1; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); -#endif - - n = 0; /* Normally report number is 0 */ - if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ - n = *data++; - len--; - } - -#ifdef DEBUG_DATA - { - int i; - printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); - for (i = 0; i < len; i++) - printk(" %02x", data[i]); - printk("\n"); - } -#endif - - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); - return -1; - } - - size = ((report->size - 1) >> 3) + 1; - - if (len < size) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - memset(data + len, 0, size - len); - } - - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_report_event(hid, report); - - for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, interrupt); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_report_event(hid, report); - - return 0; -} - /* * Input submission and I/O error handler. */ @@ -1044,6 +164,65 @@ done: spin_unlock_irqrestore(&hid->inlock, flags); } + +static int hid_input_report(int type, struct urb *urb, int interrupt) +{ + struct hid_device *hid = urb->context; + struct hid_report_enum *report_enum = hid->report_enum + type; + u8 *data = urb->transfer_buffer; + int len = urb->actual_length; + struct hid_report *report; + int n, size; + + if (!len) { + dbg("empty report"); + return -1; + } + +#ifdef DEBUG_DATA + printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); +#endif + + n = 0; /* Normally report number is 0 */ + if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ + n = *data++; + len--; + } + +#ifdef DEBUG_DATA + { + int i; + printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); + for (i = 0; i < len; i++) + printk(" %02x", data[i]); + printk("\n"); + } +#endif + + if (!(report = report_enum->report_id_hash[n])) { + dbg("undefined report_id %d received", n); + return -1; + } + + size = ((report->size - 1) >> 3) + 1; + + if (len < size) { + dbg("report %d is too short, (%d < %d)", report->id, len, size); + memset(data + len, 0, size - len); + } + + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_report_event(hid, report); + + for (n = 0; n < report->maxfield; n++) + hid_input_field(hid, report->field[n], data, interrupt); + + if (hid->claimed & HID_CLAIMED_INPUT) + hidinput_report_event(hid, report); + + return 0; +} + /* * Input interrupt completion handler. */ @@ -1092,67 +271,6 @@ static void hid_irq_in(struct urb *urb) } } -/* - * Output the field into the report. - */ - -static void hid_output_field(struct hid_field *field, __u8 *data) -{ - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - unsigned n; - - for (n = 0; n < count; n++) { - if (field->logical_minimum < 0) /* signed values */ - implement(data, offset + n * size, size, s32ton(field->value[n], size)); - else /* unsigned values */ - implement(data, offset + n * size, size, field->value[n]); - } -} - -/* - * Create a report. - */ - -static void hid_output_report(struct hid_report *report, __u8 *data) -{ - unsigned n; - - if (report->id > 0) - *data++ = report->id; - - for (n = 0; n < report->maxfield; n++) - hid_output_field(report->field[n], data); -} - -/* - * Set a field value. The report this field belongs to has to be - * created and transferred to the device, to set this value in the - * device. - */ - -int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) -{ - unsigned size = field->report_size; - - hid_dump_input(field->usage + offset, value); - - if (offset >= field->report_count) { - dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); - hid_dump_field(field, 8); - return -1; - } - if (field->logical_minimum < 0) { - if (value != snto32(s32ton(value, size), size)) { - dbg("value %d is out of range", value); - return -1; - } - } - field->value[offset] = value; - return 0; -} - /* * Find a report field with a specified HID usage. */ @@ -1379,6 +497,29 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign spin_unlock_irqrestore(&hid->ctrllock, flags); } +static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct hid_device *hid = dev->private; + struct hid_field *field; + int offset; + + if (type == EV_FF) + return input_ff_event(dev, type, code, value); + + if (type != EV_LED) + return -1; + + if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { + warn("event field not found"); + return -1; + } + + hid_set_field(field, offset, value); + hid_submit_report(hid, field->report, USB_DIR_OUT); + + return 0; +} + int hid_wait_io(struct hid_device *hid) { if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) && @@ -1428,6 +569,18 @@ void hid_close(struct hid_device *hid) usb_kill_urb(hid->urbin); } +static int hidinput_open(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + return hid_open(hid); +} + +static void hidinput_close(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + hid_close(hid); +} + #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_TURBOX 0x062a diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h deleted file mode 100644 index f04d6d75c09..00000000000 --- a/drivers/usb/input/hid-debug.h +++ /dev/null @@ -1,757 +0,0 @@ -/* - * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ - * - * (c) 1999 Andreas Gal - * (c) 2000-2001 Vojtech Pavlik - * - * Some debug stuff for the HID parser. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include - -struct hid_usage_entry { - unsigned page; - unsigned usage; - char *description; -}; - -static const struct hid_usage_entry hid_usage_table[] = { - { 0, 0, "Undefined" }, - { 1, 0, "GenericDesktop" }, - {0, 0x01, "Pointer"}, - {0, 0x02, "Mouse"}, - {0, 0x04, "Joystick"}, - {0, 0x05, "GamePad"}, - {0, 0x06, "Keyboard"}, - {0, 0x07, "Keypad"}, - {0, 0x08, "MultiAxis"}, - {0, 0x30, "X"}, - {0, 0x31, "Y"}, - {0, 0x32, "Z"}, - {0, 0x33, "Rx"}, - {0, 0x34, "Ry"}, - {0, 0x35, "Rz"}, - {0, 0x36, "Slider"}, - {0, 0x37, "Dial"}, - {0, 0x38, "Wheel"}, - {0, 0x39, "HatSwitch"}, - {0, 0x3a, "CountedBuffer"}, - {0, 0x3b, "ByteCount"}, - {0, 0x3c, "MotionWakeup"}, - {0, 0x3d, "Start"}, - {0, 0x3e, "Select"}, - {0, 0x40, "Vx"}, - {0, 0x41, "Vy"}, - {0, 0x42, "Vz"}, - {0, 0x43, "Vbrx"}, - {0, 0x44, "Vbry"}, - {0, 0x45, "Vbrz"}, - {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, - {0, 0x81, "SystemPowerDown"}, - {0, 0x82, "SystemSleep"}, - {0, 0x83, "SystemWakeUp"}, - {0, 0x84, "SystemContextMenu"}, - {0, 0x85, "SystemMainMenu"}, - {0, 0x86, "SystemAppMenu"}, - {0, 0x87, "SystemMenuHelp"}, - {0, 0x88, "SystemMenuExit"}, - {0, 0x89, "SystemMenuSelect"}, - {0, 0x8a, "SystemMenuRight"}, - {0, 0x8b, "SystemMenuLeft"}, - {0, 0x8c, "SystemMenuUp"}, - {0, 0x8d, "SystemMenuDown"}, - {0, 0x90, "D-PadUp"}, - {0, 0x91, "D-PadDown"}, - {0, 0x92, "D-PadRight"}, - {0, 0x93, "D-PadLeft"}, - { 2, 0, "Simulation" }, - {0, 0xb0, "Aileron"}, - {0, 0xb1, "AileronTrim"}, - {0, 0xb2, "Anti-Torque"}, - {0, 0xb3, "Autopilot"}, - {0, 0xb4, "Chaff"}, - {0, 0xb5, "Collective"}, - {0, 0xb6, "DiveBrake"}, - {0, 0xb7, "ElectronicCountermeasures"}, - {0, 0xb8, "Elevator"}, - {0, 0xb9, "ElevatorTrim"}, - {0, 0xba, "Rudder"}, - {0, 0xbb, "Throttle"}, - {0, 0xbc, "FlightCommunications"}, - {0, 0xbd, "FlareRelease"}, - {0, 0xbe, "LandingGear"}, - {0, 0xbf, "ToeBrake"}, - { 7, 0, "Keyboard" }, - { 8, 0, "LED" }, - {0, 0x01, "NumLock"}, - {0, 0x02, "CapsLock"}, - {0, 0x03, "ScrollLock"}, - {0, 0x04, "Compose"}, - {0, 0x05, "Kana"}, - {0, 0x4b, "GenericIndicator"}, - { 9, 0, "Button" }, - { 10, 0, "Ordinal" }, - { 12, 0, "Consumer" }, - {0, 0x238, "HorizontalWheel"}, - { 13, 0, "Digitizers" }, - {0, 0x01, "Digitizer"}, - {0, 0x02, "Pen"}, - {0, 0x03, "LightPen"}, - {0, 0x04, "TouchScreen"}, - {0, 0x05, "TouchPad"}, - {0, 0x20, "Stylus"}, - {0, 0x21, "Puck"}, - {0, 0x22, "Finger"}, - {0, 0x30, "TipPressure"}, - {0, 0x31, "BarrelPressure"}, - {0, 0x32, "InRange"}, - {0, 0x33, "Touch"}, - {0, 0x34, "UnTouch"}, - {0, 0x35, "Tap"}, - {0, 0x39, "TabletFunctionKey"}, - {0, 0x3a, "ProgramChangeKey"}, - {0, 0x3c, "Invert"}, - {0, 0x42, "TipSwitch"}, - {0, 0x43, "SecondaryTipSwitch"}, - {0, 0x44, "BarrelSwitch"}, - {0, 0x45, "Eraser"}, - {0, 0x46, "TabletPick"}, - { 15, 0, "PhysicalInterfaceDevice" }, - {0, 0x00, "Undefined"}, - {0, 0x01, "Physical_Interface_Device"}, - {0, 0x20, "Normal"}, - {0, 0x21, "Set_Effect_Report"}, - {0, 0x22, "Effect_Block_Index"}, - {0, 0x23, "Parameter_Block_Offset"}, - {0, 0x24, "ROM_Flag"}, - {0, 0x25, "Effect_Type"}, - {0, 0x26, "ET_Constant_Force"}, - {0, 0x27, "ET_Ramp"}, - {0, 0x28, "ET_Custom_Force_Data"}, - {0, 0x30, "ET_Square"}, - {0, 0x31, "ET_Sine"}, - {0, 0x32, "ET_Triangle"}, - {0, 0x33, "ET_Sawtooth_Up"}, - {0, 0x34, "ET_Sawtooth_Down"}, - {0, 0x40, "ET_Spring"}, - {0, 0x41, "ET_Damper"}, - {0, 0x42, "ET_Inertia"}, - {0, 0x43, "ET_Friction"}, - {0, 0x50, "Duration"}, - {0, 0x51, "Sample_Period"}, - {0, 0x52, "Gain"}, - {0, 0x53, "Trigger_Button"}, - {0, 0x54, "Trigger_Repeat_Interval"}, - {0, 0x55, "Axes_Enable"}, - {0, 0x56, "Direction_Enable"}, - {0, 0x57, "Direction"}, - {0, 0x58, "Type_Specific_Block_Offset"}, - {0, 0x59, "Block_Type"}, - {0, 0x5A, "Set_Envelope_Report"}, - {0, 0x5B, "Attack_Level"}, - {0, 0x5C, "Attack_Time"}, - {0, 0x5D, "Fade_Level"}, - {0, 0x5E, "Fade_Time"}, - {0, 0x5F, "Set_Condition_Report"}, - {0, 0x60, "CP_Offset"}, - {0, 0x61, "Positive_Coefficient"}, - {0, 0x62, "Negative_Coefficient"}, - {0, 0x63, "Positive_Saturation"}, - {0, 0x64, "Negative_Saturation"}, - {0, 0x65, "Dead_Band"}, - {0, 0x66, "Download_Force_Sample"}, - {0, 0x67, "Isoch_Custom_Force_Enable"}, - {0, 0x68, "Custom_Force_Data_Report"}, - {0, 0x69, "Custom_Force_Data"}, - {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, - {0, 0x6B, "Set_Custom_Force_Report"}, - {0, 0x6C, "Custom_Force_Data_Offset"}, - {0, 0x6D, "Sample_Count"}, - {0, 0x6E, "Set_Periodic_Report"}, - {0, 0x6F, "Offset"}, - {0, 0x70, "Magnitude"}, - {0, 0x71, "Phase"}, - {0, 0x72, "Period"}, - {0, 0x73, "Set_Constant_Force_Report"}, - {0, 0x74, "Set_Ramp_Force_Report"}, - {0, 0x75, "Ramp_Start"}, - {0, 0x76, "Ramp_End"}, - {0, 0x77, "Effect_Operation_Report"}, - {0, 0x78, "Effect_Operation"}, - {0, 0x79, "Op_Effect_Start"}, - {0, 0x7A, "Op_Effect_Start_Solo"}, - {0, 0x7B, "Op_Effect_Stop"}, - {0, 0x7C, "Loop_Count"}, - {0, 0x7D, "Device_Gain_Report"}, - {0, 0x7E, "Device_Gain"}, - {0, 0x7F, "PID_Pool_Report"}, - {0, 0x80, "RAM_Pool_Size"}, - {0, 0x81, "ROM_Pool_Size"}, - {0, 0x82, "ROM_Effect_Block_Count"}, - {0, 0x83, "Simultaneous_Effects_Max"}, - {0, 0x84, "Pool_Alignment"}, - {0, 0x85, "PID_Pool_Move_Report"}, - {0, 0x86, "Move_Source"}, - {0, 0x87, "Move_Destination"}, - {0, 0x88, "Move_Length"}, - {0, 0x89, "PID_Block_Load_Report"}, - {0, 0x8B, "Block_Load_Status"}, - {0, 0x8C, "Block_Load_Success"}, - {0, 0x8D, "Block_Load_Full"}, - {0, 0x8E, "Block_Load_Error"}, - {0, 0x8F, "Block_Handle"}, - {0, 0x90, "PID_Block_Free_Report"}, - {0, 0x91, "Type_Specific_Block_Handle"}, - {0, 0x92, "PID_State_Report"}, - {0, 0x94, "Effect_Playing"}, - {0, 0x95, "PID_Device_Control_Report"}, - {0, 0x96, "PID_Device_Control"}, - {0, 0x97, "DC_Enable_Actuators"}, - {0, 0x98, "DC_Disable_Actuators"}, - {0, 0x99, "DC_Stop_All_Effects"}, - {0, 0x9A, "DC_Device_Reset"}, - {0, 0x9B, "DC_Device_Pause"}, - {0, 0x9C, "DC_Device_Continue"}, - {0, 0x9F, "Device_Paused"}, - {0, 0xA0, "Actuators_Enabled"}, - {0, 0xA4, "Safety_Switch"}, - {0, 0xA5, "Actuator_Override_Switch"}, - {0, 0xA6, "Actuator_Power"}, - {0, 0xA7, "Start_Delay"}, - {0, 0xA8, "Parameter_Block_Size"}, - {0, 0xA9, "Device_Managed_Pool"}, - {0, 0xAA, "Shared_Parameter_Blocks"}, - {0, 0xAB, "Create_New_Effect_Report"}, - {0, 0xAC, "RAM_Pool_Available"}, - { 0x84, 0, "Power Device" }, - { 0x84, 0x02, "PresentStatus" }, - { 0x84, 0x03, "ChangeStatus" }, - { 0x84, 0x04, "UPS" }, - { 0x84, 0x05, "PowerSupply" }, - { 0x84, 0x10, "BatterySystem" }, - { 0x84, 0x11, "BatterySystemID" }, - { 0x84, 0x12, "Battery" }, - { 0x84, 0x13, "BatteryID" }, - { 0x84, 0x14, "Charger" }, - { 0x84, 0x15, "ChargerID" }, - { 0x84, 0x16, "PowerConverter" }, - { 0x84, 0x17, "PowerConverterID" }, - { 0x84, 0x18, "OutletSystem" }, - { 0x84, 0x19, "OutletSystemID" }, - { 0x84, 0x1a, "Input" }, - { 0x84, 0x1b, "InputID" }, - { 0x84, 0x1c, "Output" }, - { 0x84, 0x1d, "OutputID" }, - { 0x84, 0x1e, "Flow" }, - { 0x84, 0x1f, "FlowID" }, - { 0x84, 0x20, "Outlet" }, - { 0x84, 0x21, "OutletID" }, - { 0x84, 0x22, "Gang" }, - { 0x84, 0x24, "PowerSummary" }, - { 0x84, 0x25, "PowerSummaryID" }, - { 0x84, 0x30, "Voltage" }, - { 0x84, 0x31, "Current" }, - { 0x84, 0x32, "Frequency" }, - { 0x84, 0x33, "ApparentPower" }, - { 0x84, 0x35, "PercentLoad" }, - { 0x84, 0x40, "ConfigVoltage" }, - { 0x84, 0x41, "ConfigCurrent" }, - { 0x84, 0x43, "ConfigApparentPower" }, - { 0x84, 0x53, "LowVoltageTransfer" }, - { 0x84, 0x54, "HighVoltageTransfer" }, - { 0x84, 0x56, "DelayBeforeStartup" }, - { 0x84, 0x57, "DelayBeforeShutdown" }, - { 0x84, 0x58, "Test" }, - { 0x84, 0x5a, "AudibleAlarmControl" }, - { 0x84, 0x60, "Present" }, - { 0x84, 0x61, "Good" }, - { 0x84, 0x62, "InternalFailure" }, - { 0x84, 0x65, "Overload" }, - { 0x84, 0x66, "OverCharged" }, - { 0x84, 0x67, "OverTemperature" }, - { 0x84, 0x68, "ShutdownRequested" }, - { 0x84, 0x69, "ShutdownImminent" }, - { 0x84, 0x6b, "SwitchOn/Off" }, - { 0x84, 0x6c, "Switchable" }, - { 0x84, 0x6d, "Used" }, - { 0x84, 0x6e, "Boost" }, - { 0x84, 0x73, "CommunicationLost" }, - { 0x84, 0xfd, "iManufacturer" }, - { 0x84, 0xfe, "iProduct" }, - { 0x84, 0xff, "iSerialNumber" }, - { 0x85, 0, "Battery System" }, - { 0x85, 0x01, "SMBBatteryMode" }, - { 0x85, 0x02, "SMBBatteryStatus" }, - { 0x85, 0x03, "SMBAlarmWarning" }, - { 0x85, 0x04, "SMBChargerMode" }, - { 0x85, 0x05, "SMBChargerStatus" }, - { 0x85, 0x06, "SMBChargerSpecInfo" }, - { 0x85, 0x07, "SMBSelectorState" }, - { 0x85, 0x08, "SMBSelectorPresets" }, - { 0x85, 0x09, "SMBSelectorInfo" }, - { 0x85, 0x29, "RemainingCapacityLimit" }, - { 0x85, 0x2c, "CapacityMode" }, - { 0x85, 0x42, "BelowRemainingCapacityLimit" }, - { 0x85, 0x44, "Charging" }, - { 0x85, 0x45, "Discharging" }, - { 0x85, 0x4b, "NeedReplacement" }, - { 0x85, 0x66, "RemainingCapacity" }, - { 0x85, 0x68, "RunTimeToEmpty" }, - { 0x85, 0x6a, "AverageTimeToFull" }, - { 0x85, 0x83, "DesignCapacity" }, - { 0x85, 0x85, "ManufacturerDate" }, - { 0x85, 0x89, "iDeviceChemistry" }, - { 0x85, 0x8b, "Rechargable" }, - { 0x85, 0x8f, "iOEMInformation" }, - { 0x85, 0x8d, "CapacityGranularity1" }, - { 0x85, 0xd0, "ACPresent" }, - /* pages 0xff00 to 0xffff are vendor-specific */ - { 0xffff, 0, "Vendor-specific-FF" }, - { 0, 0, NULL } -}; - -static void resolv_usage_page(unsigned page) { - const struct hid_usage_entry *p; - - for (p = hid_usage_table; p->description; p++) - if (p->page == page) { - printk("%s", p->description); - return; - } - printk("%04x", page); -} - -static void resolv_usage(unsigned usage) { - const struct hid_usage_entry *p; - - resolv_usage_page(usage >> 16); - printk("."); - for (p = hid_usage_table; p->description; p++) - if (p->page == (usage >> 16)) { - for(++p; p->description && p->usage != 0; p++) - if (p->usage == (usage & 0xffff)) { - printk("%s", p->description); - return; - } - break; - } - printk("%04x", usage & 0xffff); -} - -__inline__ static void tab(int n) { - while (n--) printk(" "); -} - -static void hid_dump_field(struct hid_field *field, int n) { - int j; - - if (field->physical) { - tab(n); - printk("Physical("); - resolv_usage(field->physical); printk(")\n"); - } - if (field->logical) { - tab(n); - printk("Logical("); - resolv_usage(field->logical); printk(")\n"); - } - tab(n); printk("Usage(%d)\n", field->maxusage); - for (j = 0; j < field->maxusage; j++) { - tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); - } - if (field->logical_minimum != field->logical_maximum) { - tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); - tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); - } - if (field->physical_minimum != field->physical_maximum) { - tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); - tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); - } - if (field->unit_exponent) { - tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); - } - if (field->unit) { - char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; - char *units[5][8] = { - { "None", "None", "None", "None", "None", "None", "None", "None" }, - { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, - { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } - }; - - int i; - int sys; - __u32 data = field->unit; - - /* First nibble tells us which system we're in. */ - sys = data & 0xf; - data >>= 4; - - if(sys > 4) { - tab(n); printk("Unit(Invalid)\n"); - } - else { - int earlier_unit = 0; - - tab(n); printk("Unit(%s : ", systems[sys]); - - for (i=1 ; i>= 4; - if (nibble != 0) { - if(earlier_unit++ > 0) - printk("*"); - printk("%s", units[sys][i]); - if(nibble != 1) { - /* This is a _signed_ nibble(!) */ - - int val = nibble & 0x7; - if(nibble & 0x08) - val = -((0x7 & ~val) +1); - printk("^%d", val); - } - } - } - printk(")\n"); - } - } - tab(n); printk("Report Size(%u)\n", field->report_size); - tab(n); printk("Report Count(%u)\n", field->report_count); - tab(n); printk("Report Offset(%u)\n", field->report_offset); - - tab(n); printk("Flags( "); - j = field->flags; - printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); - printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); - printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); - printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); - printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); - printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); - printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); - printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); - printk(")\n"); -} - -static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - unsigned i,k; - static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - report_enum = device->report_enum + i; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - tab(2); - printk("%s", table[i]); - if (report->id) - printk("(%d)", report->id); - printk("[%s]", table[report->type]); - printk("\n"); - for (k = 0; k < report->maxfield; k++) { - tab(4); - printk("Field(%d)\n", k); - hid_dump_field(report->field[k], 6); - } - list = list->next; - } - } -} - -static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) { - printk("hid-debug: input "); - resolv_usage(usage->hid); - printk(" = %d\n", value); -} - - -static char *events[EV_MAX + 1] = { - [EV_SYN] = "Sync", [EV_KEY] = "Key", - [EV_REL] = "Relative", [EV_ABS] = "Absolute", - [EV_MSC] = "Misc", [EV_LED] = "LED", - [EV_SND] = "Sound", [EV_REP] = "Repeat", - [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", - [EV_FF_STATUS] = "ForceFeedbackStatus", -}; - -static char *syncs[2] = { - [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", -}; -static char *keys[KEY_MAX + 1] = { - [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", - [KEY_1] = "1", [KEY_2] = "2", - [KEY_3] = "3", [KEY_4] = "4", - [KEY_5] = "5", [KEY_6] = "6", - [KEY_7] = "7", [KEY_8] = "8", - [KEY_9] = "9", [KEY_0] = "0", - [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", - [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", - [KEY_Q] = "Q", [KEY_W] = "W", - [KEY_E] = "E", [KEY_R] = "R", - [KEY_T] = "T", [KEY_Y] = "Y", - [KEY_U] = "U", [KEY_I] = "I", - [KEY_O] = "O", [KEY_P] = "P", - [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", - [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", - [KEY_A] = "A", [KEY_S] = "S", - [KEY_D] = "D", [KEY_F] = "F", - [KEY_G] = "G", [KEY_H] = "H", - [KEY_J] = "J", [KEY_K] = "K", - [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", - [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", - [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", - [KEY_Z] = "Z", [KEY_X] = "X", - [KEY_C] = "C", [KEY_V] = "V", - [KEY_B] = "B", [KEY_N] = "N", - [KEY_M] = "M", [KEY_COMMA] = "Comma", - [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", - [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", - [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", - [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", - [KEY_F2] = "F2", [KEY_F3] = "F3", - [KEY_F4] = "F4", [KEY_F5] = "F5", - [KEY_F6] = "F6", [KEY_F7] = "F7", - [KEY_F8] = "F8", [KEY_F9] = "F9", - [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", - [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", - [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", - [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", - [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", - [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", - [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", - [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", - [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", - [KEY_F11] = "F11", [KEY_F12] = "F12", - [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", - [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", - [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", - [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", - [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", - [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", - [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", - [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", - [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", - [KEY_END] = "End", [KEY_DOWN] = "Down", - [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", - [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", - [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", - [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", - [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", - [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", - [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", - [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", - [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", - [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", - [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", - [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", - [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", - [KEY_FIND] = "Find", [KEY_CUT] = "Cut", - [KEY_HELP] = "Help", [KEY_MENU] = "Menu", - [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", - [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", - [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", - [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", - [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", - [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", - [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", - [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", - [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", - [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", - [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", - [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", - [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", - [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", - [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", - [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", - [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", - [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", - [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", - [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", - [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", - [KEY_REDO] = "Redo", [KEY_F13] = "F13", - [KEY_F14] = "F14", [KEY_F15] = "F15", - [KEY_F16] = "F16", [KEY_F17] = "F17", - [KEY_F18] = "F18", [KEY_F19] = "F19", - [KEY_F20] = "F20", [KEY_F21] = "F21", - [KEY_F22] = "F22", [KEY_F23] = "F23", - [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", - [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", - [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", - [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", - [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", - [KEY_PRINT] = "Print", [KEY_HP] = "HP", - [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", - [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", - [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", - [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", - [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", - [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", - [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", - [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", - [BTN_0] = "Btn0", [BTN_1] = "Btn1", - [BTN_2] = "Btn2", [BTN_3] = "Btn3", - [BTN_4] = "Btn4", [BTN_5] = "Btn5", - [BTN_6] = "Btn6", [BTN_7] = "Btn7", - [BTN_8] = "Btn8", [BTN_9] = "Btn9", - [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", - [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", - [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", - [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", - [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", - [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", - [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", - [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", - [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", - [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", - [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", - [BTN_B] = "BtnB", [BTN_C] = "BtnC", - [BTN_X] = "BtnX", [BTN_Y] = "BtnY", - [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", - [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", - [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", - [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", - [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", - [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", - [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", - [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", - [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", - [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", - [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", - [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", - [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", - [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", - [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", - [KEY_OPTION] = "Option", [KEY_INFO] = "Info", - [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", - [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", - [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", - [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", - [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", - [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", - [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", - [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", - [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", - [KEY_TV] = "TV", [KEY_TV2] = "TV2", - [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", - [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", - [KEY_CD] = "CD", [KEY_TAPE] = "Tape", - [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", - [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", - [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", - [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", - [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", - [KEY_LIST] = "List", [KEY_MEMO] = "Memo", - [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", - [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", - [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", - [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", - [KEY_LAST] = "Last", [KEY_AB] = "AB", - [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", - [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", - [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", - [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", - [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", - [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", - [KEY_DEL_LINE] = "DeleteLine", - [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", - [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", - [KEY_DOCUMENTS] = "Documents", - [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", - [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", - [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", - [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", - [KEY_FN_S] = "Fn+S", - [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", - [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", - [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", - [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", - [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", - [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", - [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", - [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", - [KEY_KBDILLUMUP] = "KbdIlluminationUp", - [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", -}; - -static char *relatives[REL_MAX + 1] = { - [REL_X] = "X", [REL_Y] = "Y", - [REL_Z] = "Z", [REL_HWHEEL] = "HWheel", - [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", - [REL_MISC] = "Misc", -}; - -static char *absolutes[ABS_MAX + 1] = { - [ABS_X] = "X", [ABS_Y] = "Y", - [ABS_Z] = "Z", [ABS_RX] = "Rx", - [ABS_RY] = "Ry", [ABS_RZ] = "Rz", - [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", - [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", - [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", - [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", - [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", - [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", - [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", - [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", - [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", - [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", -}; - -static char *misc[MSC_MAX + 1] = { - [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", - [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" -}; - -static char *leds[LED_MAX + 1] = { - [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", - [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", - [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", - [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", - [LED_MISC] = "Misc", -}; - -static char *repeats[REP_MAX + 1] = { - [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" -}; - -static char *sounds[SND_MAX + 1] = { - [SND_CLICK] = "Click", [SND_BELL] = "Bell", - [SND_TONE] = "Tone" -}; - -static char **names[EV_MAX + 1] = { - [EV_SYN] = syncs, [EV_KEY] = keys, - [EV_REL] = relatives, [EV_ABS] = absolutes, - [EV_MSC] = misc, [EV_LED] = leds, - [EV_SND] = sounds, [EV_REP] = repeats, -}; - -static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) { - - printk("%s.%s", events[type] ? events[type] : "?", - names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); -} diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index a8fc46c721c..4187f4ee9a9 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -32,7 +32,7 @@ #undef DEBUG #include -#include "hid.h" +#include /* * This table contains pointers to initializers. To add support for new diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 3a7e5fbff02..8756eb3263d 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -4,6 +4,7 @@ * Copyright (c) 2000-2001 Vojtech Pavlik * * USB HID to Linux Input mapping + * */ /* @@ -26,847 +27,4 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ -#include -#include -#include -#include - -#undef DEBUG - -#include "hid.h" - -#define unk KEY_UNKNOWN - -static const unsigned char hid_keyboard[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, - 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk -}; - -static const struct { - __s32 x; - __s32 y; -} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0) -#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0) -#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0) -#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) - -#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) -#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) - -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - -struct hidinput_key_translation { - u16 from; - u16 to; - u8 flags; -}; - -#define POWERBOOK_FLAG_FKEY 0x01 - -static struct hidinput_key_translation powerbook_fn_keys[] = { - { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY }, - { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY }, - { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY }, - { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY }, - { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY }, - { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY }, - { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY }, - { KEY_UP, KEY_PAGEUP }, - { KEY_DOWN, KEY_PAGEDOWN }, - { KEY_LEFT, KEY_HOME }, - { KEY_RIGHT, KEY_END }, - { } -}; - -static struct hidinput_key_translation powerbook_numlock_keys[] = { - { KEY_J, KEY_KP1 }, - { KEY_K, KEY_KP2 }, - { KEY_L, KEY_KP3 }, - { KEY_U, KEY_KP4 }, - { KEY_I, KEY_KP5 }, - { KEY_O, KEY_KP6 }, - { KEY_7, KEY_KP7 }, - { KEY_8, KEY_KP8 }, - { KEY_9, KEY_KP9 }, - { KEY_M, KEY_KP0 }, - { KEY_DOT, KEY_KPDOT }, - { KEY_SLASH, KEY_KPPLUS }, - { KEY_SEMICOLON, KEY_KPMINUS }, - { KEY_P, KEY_KPASTERISK }, - { KEY_MINUS, KEY_KPEQUAL }, - { KEY_0, KEY_KPSLASH }, - { KEY_F6, KEY_NUMLOCK }, - { KEY_KPENTER, KEY_KPENTER }, - { KEY_BACKSPACE, KEY_BACKSPACE }, - { } -}; - -static struct hidinput_key_translation powerbook_iso_keyboard[] = { - { KEY_GRAVE, KEY_102ND }, - { KEY_102ND, KEY_GRAVE }, - { } -}; - -static int usbhid_pb_fnmode = 1; -module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - -static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from) -{ - struct hidinput_key_translation *trans; - - /* Look for the translation */ - for (trans = table; trans->from; trans++) - if (trans->from == from) - return trans; - - return NULL; -} - -static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - struct hidinput_key_translation *trans; - - if (usage->code == KEY_FN) { - if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON; - else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON; - - input_event(input, usage->type, usage->code, value); - - return 1; - } - - if (usbhid_pb_fnmode) { - int do_translate; - - trans = find_translation(powerbook_fn_keys, usage->code); - if (trans) { - if (test_bit(usage->code, hid->pb_pressed_fn)) - do_translate = 1; - else if (trans->flags & POWERBOOK_FLAG_FKEY) - do_translate = - (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); - else - do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); - - if (do_translate) { - if (value) - set_bit(usage->code, hid->pb_pressed_fn); - else - clear_bit(usage->code, hid->pb_pressed_fn); - - input_event(input, usage->type, trans->to, value); - - return 1; - } - } - - if (test_bit(usage->code, hid->pb_pressed_numlock) || - test_bit(LED_NUML, input->led)) { - trans = find_translation(powerbook_numlock_keys, usage->code); - - if (trans) { - if (value) - set_bit(usage->code, hid->pb_pressed_numlock); - else - clear_bit(usage->code, hid->pb_pressed_numlock); - - input_event(input, usage->type, trans->to, value); - } - - return 1; - } - } - - if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { - trans = find_translation(powerbook_iso_keyboard, usage->code); - if (trans) { - input_event(input, usage->type, trans->to, value); - return 1; - } - } - - return 0; -} - -static void hidinput_pb_setup(struct input_dev *input) -{ - struct hidinput_key_translation *trans; - - set_bit(KEY_NUMLOCK, input->keybit); - - /* Enable all needed keys */ - for (trans = powerbook_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_numlock_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_iso_keyboard; trans->from; trans++) - set_bit(trans->to, input->keybit); -} -#else -static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - return 0; -} - -static inline void hidinput_pb_setup(struct input_dev *input) -{ -} -#endif - -static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage) -{ - struct input_dev *input = hidinput->input; - struct hid_device *device = input->private; - int max = 0, code; - unsigned long *bit = NULL; - - field->hidinput = hidinput; - -#ifdef DEBUG - printk(KERN_DEBUG "Mapping: "); - resolv_usage(usage->hid); - printk(" ---> "); -#endif - - if (field->flags & HID_MAIN_ITEM_CONSTANT) - goto ignore; - - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_UNDEFINED: - goto ignore; - - case HID_UP_KEYBOARD: - - set_bit(EV_REP, input->evbit); - - if ((usage->hid & HID_USAGE) < 256) { - if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; - map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); - } else - map_key(KEY_UNKNOWN); - - break; - - case HID_UP_BUTTON: - - code = ((usage->hid - 1) & 0xf); - - switch (field->application) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: - switch (field->physical) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: code += 0x100; - } - } - - map_key(code); - break; - - - case HID_UP_SIMULATION: - - switch (usage->hid & 0xffff) { - case 0xba: map_abs(ABS_RUDDER); break; - case 0xbb: map_abs(ABS_THROTTLE); break; - case 0xc4: map_abs(ABS_GAS); break; - case 0xc5: map_abs(ABS_BRAKE); break; - case 0xc8: map_abs(ABS_WHEEL); break; - default: goto ignore; - } - break; - - case HID_UP_GENDESK: - - if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ - switch (usage->hid & 0xf) { - case 0x1: map_key_clear(KEY_POWER); break; - case 0x2: map_key_clear(KEY_SLEEP); break; - case 0x3: map_key_clear(KEY_WAKEUP); break; - default: goto unknown; - } - break; - } - - if ((usage->hid & 0xf0) == 0x90) { /* D-pad */ - switch (usage->hid) { - case HID_GD_UP: usage->hat_dir = 1; break; - case HID_GD_DOWN: usage->hat_dir = 5; break; - case HID_GD_RIGHT: usage->hat_dir = 3; break; - case HID_GD_LEFT: usage->hat_dir = 7; break; - default: goto unknown; - } - if (field->dpad) { - map_abs(field->dpad); - goto ignore; - } - map_abs(ABS_HAT0X); - break; - } - - switch (usage->hid) { - - /* These usage IDs map directly to the usage codes. */ - case HID_GD_X: case HID_GD_Y: case HID_GD_Z: - case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: - case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: - if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel(usage->hid & 0xf); - else - map_abs(usage->hid & 0xf); - break; - - case HID_GD_HATSWITCH: - usage->hat_min = field->logical_minimum; - usage->hat_max = field->logical_maximum; - map_abs(ABS_HAT0X); - break; - - case HID_GD_START: map_key_clear(BTN_START); break; - case HID_GD_SELECT: map_key_clear(BTN_SELECT); break; - - default: goto unknown; - } - - break; - - case HID_UP_LED: - if (((usage->hid - 1) & 0xffff) >= LED_MAX) - goto ignore; - map_led((usage->hid - 1) & 0xffff); - break; - - case HID_UP_DIGITIZER: - - switch (usage->hid & 0xff) { - - case 0x30: /* TipPressure */ - if (!test_bit(BTN_TOUCH, input->keybit)) { - device->quirks |= HID_QUIRK_NOTOUCH; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_TOUCH, input->keybit); - } - - map_abs_clear(ABS_PRESSURE); - break; - - case 0x32: /* InRange */ - switch (field->physical & 0xff) { - case 0x21: map_key(BTN_TOOL_MOUSE); break; - case 0x22: map_key(BTN_TOOL_FINGER); break; - default: map_key(BTN_TOOL_PEN); break; - } - break; - - case 0x3c: /* Invert */ - map_key_clear(BTN_TOOL_RUBBER); - break; - - case 0x33: /* Touch */ - case 0x42: /* TipSwitch */ - case 0x43: /* TipSwitch2 */ - device->quirks &= ~HID_QUIRK_NOTOUCH; - map_key_clear(BTN_TOUCH); - break; - - case 0x44: /* BarrelSwitch */ - map_key_clear(BTN_STYLUS); - break; - - default: goto unknown; - } - break; - - case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ - - switch (usage->hid & HID_USAGE) { - case 0x000: goto ignore; - case 0x034: map_key_clear(KEY_SLEEP); break; - case 0x036: map_key_clear(BTN_MISC); break; - case 0x045: map_key_clear(KEY_RADIO); break; - case 0x08a: map_key_clear(KEY_WWW); break; - case 0x08d: map_key_clear(KEY_PROGRAM); break; - case 0x095: map_key_clear(KEY_HELP); break; - case 0x09c: map_key_clear(KEY_CHANNELUP); break; - case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; - case 0x0b0: map_key_clear(KEY_PLAY); break; - case 0x0b1: map_key_clear(KEY_PAUSE); break; - case 0x0b2: map_key_clear(KEY_RECORD); break; - case 0x0b3: map_key_clear(KEY_FASTFORWARD); break; - case 0x0b4: map_key_clear(KEY_REWIND); break; - case 0x0b5: map_key_clear(KEY_NEXTSONG); break; - case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break; - case 0x0b7: map_key_clear(KEY_STOPCD); break; - case 0x0b8: map_key_clear(KEY_EJECTCD); break; - case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; - case 0x0e0: map_abs_clear(ABS_VOLUME); break; - case 0x0e2: map_key_clear(KEY_MUTE); break; - case 0x0e5: map_key_clear(KEY_BASSBOOST); break; - case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; - case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; - case 0x183: map_key_clear(KEY_CONFIG); break; - case 0x18a: map_key_clear(KEY_MAIL); break; - case 0x192: map_key_clear(KEY_CALC); break; - case 0x194: map_key_clear(KEY_FILE); break; - case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; - case 0x201: map_key_clear(KEY_NEW); break; - case 0x207: map_key_clear(KEY_SAVE); break; - case 0x208: map_key_clear(KEY_PRINT); break; - case 0x209: map_key_clear(KEY_PROPS); break; - case 0x21a: map_key_clear(KEY_UNDO); break; - case 0x21b: map_key_clear(KEY_COPY); break; - case 0x21c: map_key_clear(KEY_CUT); break; - case 0x21d: map_key_clear(KEY_PASTE); break; - case 0x221: map_key_clear(KEY_FIND); break; - case 0x223: map_key_clear(KEY_HOMEPAGE); break; - case 0x224: map_key_clear(KEY_BACK); break; - case 0x225: map_key_clear(KEY_FORWARD); break; - case 0x226: map_key_clear(KEY_STOP); break; - case 0x227: map_key_clear(KEY_REFRESH); break; - case 0x22a: map_key_clear(KEY_BOOKMARKS); break; - case 0x233: map_key_clear(KEY_SCROLLUP); break; - case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel(REL_HWHEEL); break; - case 0x279: map_key_clear(KEY_REDO); break; - case 0x289: map_key_clear(KEY_REPLY); break; - case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; - case 0x28c: map_key_clear(KEY_SEND); break; - - /* Reported on a Cherry Cymotion keyboard */ - case 0x301: map_key_clear(KEY_PROG1); break; - case 0x302: map_key_clear(KEY_PROG2); break; - case 0x303: map_key_clear(KEY_PROG3); break; - - default: goto ignore; - } - break; - - case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ - - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x021: map_key_clear(KEY_PRINT); break; - case 0x070: map_key_clear(KEY_HP); break; - case 0x071: map_key_clear(KEY_CAMERA); break; - case 0x072: map_key_clear(KEY_SOUND); break; - case 0x073: map_key_clear(KEY_QUESTION); break; - case 0x080: map_key_clear(KEY_EMAIL); break; - case 0x081: map_key_clear(KEY_CHAT); break; - case 0x082: map_key_clear(KEY_SEARCH); break; - case 0x083: map_key_clear(KEY_CONNECT); break; - case 0x084: map_key_clear(KEY_FINANCE); break; - case 0x085: map_key_clear(KEY_SPORT); break; - case 0x086: map_key_clear(KEY_SHOP); break; - default: goto ignore; - } - break; - - case HID_UP_MSVENDOR: - goto ignore; - - case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ - - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x003: - /* The fn key on Apple PowerBooks */ - map_key_clear(KEY_FN); - hidinput_pb_setup(input); - break; - - default: goto ignore; - } - break; - - case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */ - - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x004: map_key_clear(KEY_AGAIN); break; - case 0x00d: map_key_clear(KEY_HOME); break; - case 0x024: map_key_clear(KEY_SHUFFLE); break; - case 0x025: map_key_clear(KEY_TV); break; - case 0x026: map_key_clear(KEY_MENU); break; - case 0x031: map_key_clear(KEY_AUDIO); break; - case 0x032: map_key_clear(KEY_TEXT); break; - case 0x033: map_key_clear(KEY_LAST); break; - case 0x047: map_key_clear(KEY_MP3); break; - case 0x048: map_key_clear(KEY_DVD); break; - case 0x049: map_key_clear(KEY_MEDIA); break; - case 0x04a: map_key_clear(KEY_VIDEO); break; - case 0x04b: map_key_clear(KEY_ANGLE); break; - case 0x04c: map_key_clear(KEY_LANGUAGE); break; - case 0x04d: map_key_clear(KEY_SUBTITLE); break; - case 0x051: map_key_clear(KEY_RED); break; - case 0x052: map_key_clear(KEY_CLOSE); break; - default: goto ignore; - } - break; - - case HID_UP_PID: - - switch(usage->hid & HID_USAGE) { - case 0xa4: map_key_clear(BTN_DEAD); break; - default: goto ignore; - } - break; - - default: - unknown: - if (field->report_size == 1) { - if (field->report->type == HID_OUTPUT_REPORT) { - map_led(LED_MISC); - break; - } - map_key(BTN_MISC); - break; - } - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - map_rel(REL_MISC); - break; - } - map_abs(ABS_MISC); - break; - } - - if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { - if (usage->hid == HID_GD_Z) - map_rel(REL_HWHEEL); - else if (usage->code == BTN_1) - map_key(BTN_2); - else if (usage->code == BTN_2) - map_key(BTN_1); - } - - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && - (usage->type == EV_REL) && (usage->code == REL_WHEEL)) - set_bit(REL_HWHEEL, bit); - - if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) - goto ignore; - - if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) && - usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE)) - field->flags &= ~HID_MAIN_ITEM_RELATIVE; - - set_bit(usage->type, input->evbit); - - while (usage->code <= max && test_and_set_bit(usage->code, bit)) - usage->code = find_next_zero_bit(bit, max + 1, usage->code); - - if (usage->code > max) - goto ignore; - - - if (usage->type == EV_ABS) { - - int a = field->logical_minimum; - int b = field->logical_maximum; - - if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { - a = field->logical_minimum = 0; - b = field->logical_maximum = 255; - } - - if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) - input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); - else input_set_abs_params(input, usage->code, a, b, 0, 0); - - } - - if (usage->type == EV_ABS && - (usage->hat_min < usage->hat_max || usage->hat_dir)) { - int i; - for (i = usage->code; i < usage->code + 2 && i <= max; i++) { - input_set_abs_params(input, i, -1, 1, 0, 0); - set_bit(i, input->absbit); - } - if (usage->hat_dir && !field->dpad) - field->dpad = usage->code; - } - -#ifdef DEBUG - resolv_event(usage->type, usage->code); - printk("\n"); -#endif - return; - -ignore: -#ifdef DEBUG - printk("IGNORED\n"); -#endif - return; -} - -void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - struct input_dev *input; - int *quirks = &hid->quirks; - - if (!field->hidinput) - return; - - input = field->hidinput->input; - - if (!usage->type) - return; - - if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { - if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - return; - } - - if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { - input_event(input, usage->type, usage->code, -value); - return; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { - input_event(input, usage->type, REL_HWHEEL, value); - return; - } - - if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) - return; - - if (usage->hat_min < usage->hat_max || usage->hat_dir) { - int hat_dir = usage->hat_dir; - if (!hat_dir) - hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; - if (hat_dir < 0 || hat_dir > 8) hat_dir = 0; - input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x); - input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ - *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ - if (value) { - input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); - return; - } - input_event(input, usage->type, usage->code, 0); - input_event(input, usage->type, BTN_TOOL_RUBBER, 0); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ - int a = field->logical_minimum; - int b = field->logical_maximum; - input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); - } - - if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ - dbg("Maximum Effects - %d",value); - return; - } - - if (usage->hid == (HID_UP_PID | 0x7fUL)) { - dbg("PID Pool Report\n"); - return; - } - - if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ - return; - - input_event(input, usage->type, usage->code, value); - - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) - input_event(input, usage->type, usage->code, 0); -} - -void hidinput_report_event(struct hid_device *hid, struct hid_report *report) -{ - struct hid_input *hidinput; - - list_for_each_entry(hidinput, &hid->inputs, list) - input_sync(hidinput->input); -} - -static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) -{ - struct hid_report *report; - int i, j; - - list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { - for (i = 0; i < report->maxfield; i++) { - *field = report->field[i]; - for (j = 0; j < (*field)->maxusage; j++) - if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) - return j; - } - } - return -1; -} - -static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct hid_device *hid = dev->private; - struct hid_field *field; - int offset; - - if (type == EV_FF) - return input_ff_event(dev, type, code, value); - - if (type != EV_LED) - return -1; - - if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { - warn("event field not found"); - return -1; - } - - hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); - - return 0; -} - -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return hid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - hid_close(hid); -} - -/* - * Register the input device; print a message. - * Configure the input layer interface - * Read all reports and initialize the absolute field values. - */ - -int hidinput_connect(struct hid_device *hid) -{ - struct usb_device *dev = hid->dev; - struct hid_report *report; - struct hid_input *hidinput = NULL; - struct input_dev *input_dev; - int i, j, k; - - INIT_LIST_HEAD(&hid->inputs); - - for (i = 0; i < hid->maxcollection; i++) - if (hid->collection[i].type == HID_COLLECTION_APPLICATION || - hid->collection[i].type == HID_COLLECTION_PHYSICAL) - if (IS_INPUT_APPLICATION(hid->collection[i].usage)) - break; - - if (i == hid->maxcollection) - return -1; - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) - list_for_each_entry(report, &hid->report_enum[k].report_list, list) { - - if (!report->maxfield) - continue; - - if (!hidinput) { - hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!hidinput || !input_dev) { - kfree(hidinput); - input_free_device(input_dev); - err("Out of memory during hid input probe"); - return -1; - } - - input_dev->private = hid; - input_dev->event = hidinput_input_event; - input_dev->open = hidinput_open; - input_dev->close = hidinput_close; - - input_dev->name = hid->name; - input_dev->phys = hid->phys; - input_dev->uniq = hid->uniq; - usb_to_input_id(dev, &input_dev->id); - input_dev->cdev.dev = &hid->intf->dev; - - hidinput->input = input_dev; - list_add_tail(&hidinput->list, &hid->inputs); - } - - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hidinput, report->field[i], - report->field[i]->usage + j); - - if (hid->quirks & HID_QUIRK_MULTI_INPUT) { - /* This will leave hidinput NULL, so that it - * allocates another one if we have more inputs on - * the same interface. Some devices (e.g. Happ's - * UGCI) cram a lot of unrelated inputs into the - * same interface. */ - hidinput->report = report; - input_register_device(hidinput->input); - hidinput = NULL; - } - } - - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if (hidinput) { - hid_ff_init(hid); - input_register_device(hidinput->input); - } - - return 0; -} - -void hidinput_disconnect(struct hid_device *hid) -{ - struct hid_input *hidinput, *next; - list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { - list_del(&hidinput->list); - input_unregister_device(hidinput->input); - kfree(hidinput); - } -} diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 93da222b6da..e977ba3d17e 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -29,7 +29,7 @@ #include #include -#include "hid.h" +#include struct device_type { u16 idVendor; diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c index 5420c13eb8e..b4caea3864e 100644 --- a/drivers/usb/input/hid-pidff.c +++ b/drivers/usb/input/hid-pidff.c @@ -28,7 +28,9 @@ #include #include -#include "hid.h" +#include + +#include "usbhid.h" #define PID_EFFECTS_MAX 64 diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 2d5be4c318a..1cd1418ad6a 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -32,7 +32,7 @@ #undef DEBUG #include -#include "hid.h" +#include /* Usages for thrustmaster devices I know about */ #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c index d2ce3214572..af1bfae39dc 100644 --- a/drivers/usb/input/hid-zpff.c +++ b/drivers/usb/input/hid-zpff.c @@ -27,7 +27,7 @@ #include #include -#include "hid.h" +#include struct zpff_device { struct hid_report *report; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h deleted file mode 100644 index 76ad68d9edf..00000000000 --- a/drivers/usb/input/hid.h +++ /dev/null @@ -1,540 +0,0 @@ -#ifndef __HID_H -#define __HID_H - -/* - * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include - -/* - * USB HID (Human Interface Device) interface class code - */ - -#define USB_INTERFACE_CLASS_HID 3 - -/* - * USB HID interface subclass and protocol codes - */ - -#define USB_INTERFACE_SUBCLASS_BOOT 1 -#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 -#define USB_INTERFACE_PROTOCOL_MOUSE 2 - -/* - * HID class requests - */ - -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_GET_IDLE 0x02 -#define HID_REQ_GET_PROTOCOL 0x03 -#define HID_REQ_SET_REPORT 0x09 -#define HID_REQ_SET_IDLE 0x0A -#define HID_REQ_SET_PROTOCOL 0x0B - -/* - * HID class descriptor types - */ - -#define HID_DT_HID (USB_TYPE_CLASS | 0x01) -#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) -#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) - -/* - * We parse each description item into this structure. Short items data - * values are expanded to 32-bit signed int, long items contain a pointer - * into the data area. - */ - -struct hid_item { - unsigned format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -/* - * HID report item format - */ - -#define HID_ITEM_FORMAT_SHORT 0 -#define HID_ITEM_FORMAT_LONG 1 - -/* - * Special tag indicating long items - */ - -#define HID_ITEM_TAG_LONG 15 - -/* - * HID report descriptor item type (prefix bit 2,3) - */ - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 - -/* - * HID report descriptor main item tags - */ - -#define HID_MAIN_ITEM_TAG_INPUT 8 -#define HID_MAIN_ITEM_TAG_OUTPUT 9 -#define HID_MAIN_ITEM_TAG_FEATURE 11 -#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 -#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 - -/* - * HID report descriptor main item contents - */ - -#define HID_MAIN_ITEM_CONSTANT 0x001 -#define HID_MAIN_ITEM_VARIABLE 0x002 -#define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 -#define HID_MAIN_ITEM_NONLINEAR 0x010 -#define HID_MAIN_ITEM_NO_PREFERRED 0x020 -#define HID_MAIN_ITEM_NULL_STATE 0x040 -#define HID_MAIN_ITEM_VOLATILE 0x080 -#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 - -/* - * HID report descriptor collection item types - */ - -#define HID_COLLECTION_PHYSICAL 0 -#define HID_COLLECTION_APPLICATION 1 -#define HID_COLLECTION_LOGICAL 2 - -/* - * HID report descriptor global item tags - */ - -#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 -#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 -#define HID_GLOBAL_ITEM_TAG_UNIT 6 -#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 -#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 -#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 -#define HID_GLOBAL_ITEM_TAG_PUSH 10 -#define HID_GLOBAL_ITEM_TAG_POP 11 - -/* - * HID report descriptor local item tags - */ - -#define HID_LOCAL_ITEM_TAG_USAGE 0 -#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 -#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 -#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 -#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 -#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 -#define HID_LOCAL_ITEM_TAG_DELIMITER 10 - -/* - * HID usage tables - */ - -#define HID_USAGE_PAGE 0xffff0000 - -#define HID_UP_UNDEFINED 0x00000000 -#define HID_UP_GENDESK 0x00010000 -#define HID_UP_SIMULATION 0x00020000 -#define HID_UP_KEYBOARD 0x00070000 -#define HID_UP_LED 0x00080000 -#define HID_UP_BUTTON 0x00090000 -#define HID_UP_ORDINAL 0x000a0000 -#define HID_UP_CONSUMER 0x000c0000 -#define HID_UP_DIGITIZER 0x000d0000 -#define HID_UP_PID 0x000f0000 -#define HID_UP_HPVENDOR 0xff7f0000 -#define HID_UP_MSVENDOR 0xff000000 -#define HID_UP_CUSTOM 0x00ff0000 -#define HID_UP_LOGIVENDOR 0xffbc0000 - -#define HID_USAGE 0x0000ffff - -#define HID_GD_POINTER 0x00010001 -#define HID_GD_MOUSE 0x00010002 -#define HID_GD_JOYSTICK 0x00010004 -#define HID_GD_GAMEPAD 0x00010005 -#define HID_GD_KEYBOARD 0x00010006 -#define HID_GD_KEYPAD 0x00010007 -#define HID_GD_MULTIAXIS 0x00010008 -#define HID_GD_X 0x00010030 -#define HID_GD_Y 0x00010031 -#define HID_GD_Z 0x00010032 -#define HID_GD_RX 0x00010033 -#define HID_GD_RY 0x00010034 -#define HID_GD_RZ 0x00010035 -#define HID_GD_SLIDER 0x00010036 -#define HID_GD_DIAL 0x00010037 -#define HID_GD_WHEEL 0x00010038 -#define HID_GD_HATSWITCH 0x00010039 -#define HID_GD_BUFFER 0x0001003a -#define HID_GD_BYTECOUNT 0x0001003b -#define HID_GD_MOTION 0x0001003c -#define HID_GD_START 0x0001003d -#define HID_GD_SELECT 0x0001003e -#define HID_GD_VX 0x00010040 -#define HID_GD_VY 0x00010041 -#define HID_GD_VZ 0x00010042 -#define HID_GD_VBRX 0x00010043 -#define HID_GD_VBRY 0x00010044 -#define HID_GD_VBRZ 0x00010045 -#define HID_GD_VNO 0x00010046 -#define HID_GD_FEATURE 0x00010047 -#define HID_GD_UP 0x00010090 -#define HID_GD_DOWN 0x00010091 -#define HID_GD_RIGHT 0x00010092 -#define HID_GD_LEFT 0x00010093 - -/* - * HID report types --- Ouch! HID spec says 1 2 3! - */ - -#define HID_INPUT_REPORT 0 -#define HID_OUTPUT_REPORT 1 -#define HID_FEATURE_REPORT 2 - -/* - * HID device quirks. - */ - -#define HID_QUIRK_INVERT 0x00000001 -#define HID_QUIRK_NOTOUCH 0x00000002 -#define HID_QUIRK_IGNORE 0x00000004 -#define HID_QUIRK_NOGET 0x00000008 -#define HID_QUIRK_HIDDEV 0x00000010 -#define HID_QUIRK_BADPAD 0x00000020 -#define HID_QUIRK_MULTI_INPUT 0x00000040 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 -#define HID_QUIRK_MIGHTYMOUSE 0x00000400 -#define HID_QUIRK_CYMOTION 0x00000800 -#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 -#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 -#define HID_QUIRK_INVERT_HWHEEL 0x00004000 -#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 -#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 - -/* - * This is the global environment of the parser. This information is - * persistent for main-items. The global environment can be saved and - * restored with PUSH/POP statements. - */ - -struct hid_global { - unsigned usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - unsigned report_id; - unsigned report_size; - unsigned report_count; -}; - -/* - * This is the local environment. It is persistent up the next main-item. - */ - -#define HID_MAX_DESCRIPTOR_SIZE 4096 -#define HID_MAX_USAGES 1024 -#define HID_DEFAULT_NUM_COLLECTIONS 16 - -struct hid_local { - unsigned usage[HID_MAX_USAGES]; /* usage array */ - unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ - unsigned usage_index; - unsigned usage_minimum; - unsigned delimiter_depth; - unsigned delimiter_branch; -}; - -/* - * This is the collection stack. We climb up the stack to determine - * application and function of each field. - */ - -struct hid_collection { - unsigned type; - unsigned usage; - unsigned level; -}; - -struct hid_usage { - unsigned hid; /* hid usage code */ - unsigned collection_index; /* index into collection array */ - /* hidinput data */ - __u16 code; /* input driver code */ - __u8 type; /* input driver type */ - __s8 hat_min; /* hat switch fun */ - __s8 hat_max; /* ditto */ - __s8 hat_dir; /* ditto */ -}; - -struct hid_input; - -struct hid_field { - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ - struct hid_usage *usage; /* usage table for this function */ - unsigned maxusage; /* maximum usage index */ - unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ - unsigned report_offset; /* bit offset in the report */ - unsigned report_size; /* size of this field in the report */ - unsigned report_count; /* number of this field in the report */ - unsigned report_type; /* (input,output,feature) */ - __s32 *value; /* last known value(s) */ - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - struct hid_report *report; /* associated report */ - unsigned index; /* index into report->field[] */ - /* hidinput data */ - struct hid_input *hidinput; /* associated input structure */ - __u16 dpad; /* dpad input code */ -}; - -#define HID_MAX_FIELDS 64 - -struct hid_report { - struct list_head list; - unsigned id; /* id of this report */ - unsigned type; /* report type */ - struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ - unsigned maxfield; /* maximum valid field index */ - unsigned size; /* size of the report (bits) */ - struct hid_device *device; /* associated device */ -}; - -struct hid_report_enum { - unsigned numbered; - struct list_head report_list; - struct hid_report *report_id_hash[256]; -}; - -#define HID_REPORT_TYPES 3 - -#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ -#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ -#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ -#define HID_OUTPUT_FIFO_SIZE 64 - -struct hid_control_fifo { - unsigned char dir; - struct hid_report *report; -}; - -#define HID_CLAIMED_INPUT 1 -#define HID_CLAIMED_HIDDEV 2 - -#define HID_CTRL_RUNNING 1 -#define HID_OUT_RUNNING 2 -#define HID_IN_RUNNING 3 -#define HID_RESET_PENDING 4 -#define HID_SUSPENDED 5 -#define HID_CLEAR_HALT 6 - -struct hid_input { - struct list_head list; - struct hid_report *report; - struct input_dev *input; -}; - -struct hid_device { /* device report descriptor */ - __u8 *rdesc; - unsigned rsize; - struct hid_collection *collection; /* List of HID collections */ - unsigned collection_size; /* Number of allocated hid_collections */ - unsigned maxcollection; /* Number of parsed collections */ - unsigned maxapplication; /* Number of applications */ - unsigned version; /* HID version */ - unsigned country; /* HID country */ - struct hid_report_enum report_enum[HID_REPORT_TYPES]; - - struct usb_device *dev; /* USB device */ - struct usb_interface *intf; /* USB interface */ - int ifnum; /* USB interface number */ - - unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ - struct timer_list io_retry; /* Retry timer */ - unsigned long stop_retry; /* Time to give up, in jiffies */ - unsigned int retry_delay; /* Delay length in ms */ - struct work_struct reset_work; /* Task context for resets */ - - unsigned int bufsize; /* URB buffer size */ - - struct urb *urbin; /* Input URB */ - char *inbuf; /* Input buffer */ - dma_addr_t inbuf_dma; /* Input buffer dma */ - spinlock_t inlock; /* Input fifo spinlock */ - - struct urb *urbctrl; /* Control URB */ - struct usb_ctrlrequest *cr; /* Control request struct */ - dma_addr_t cr_dma; /* Control request struct dma */ - struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ - unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ - char *ctrlbuf; /* Control buffer */ - dma_addr_t ctrlbuf_dma; /* Control buffer dma */ - spinlock_t ctrllock; /* Control fifo spinlock */ - - struct urb *urbout; /* Output URB */ - struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ - unsigned char outhead, outtail; /* Output pipe fifo head & tail */ - char *outbuf; /* Output buffer */ - dma_addr_t outbuf_dma; /* Output buffer dma */ - spinlock_t outlock; /* Output fifo spinlock */ - - unsigned claimed; /* Claimed by hidinput, hiddev? */ - unsigned quirks; /* Various quirks the device can pull on us */ - - struct list_head inputs; /* The list of inputs */ - void *hiddev; /* The hiddev structure */ - int minor; /* Hiddev minor number */ - - wait_queue_head_t wait; /* For sleeping */ - - int open; /* is the device open by anyone? */ - char name[128]; /* Device name */ - char phys[64]; /* Device physical location */ - char uniq[64]; /* Device unique identifier (serial #) */ - -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; - unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; -#endif -}; - -#define HID_GLOBAL_STACK_SIZE 4 -#define HID_COLLECTION_STACK_SIZE 4 - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; - unsigned global_stack_ptr; - struct hid_local local; - unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; - unsigned collection_stack_ptr; - struct hid_device *device; -}; - -struct hid_class_descriptor { - __u8 bDescriptorType; - __u16 wDescriptorLength; -} __attribute__ ((packed)); - -struct hid_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u16 bcdHID; - __u8 bCountryCode; - __u8 bNumDescriptors; - - struct hid_class_descriptor desc[1]; -} __attribute__ ((packed)); - -#ifdef DEBUG -#include "hid-debug.h" -#else -#define hid_dump_input(a,b) do { } while (0) -#define hid_dump_device(c) do { } while (0) -#define hid_dump_field(a,b) do { } while (0) -#define resolv_usage(a) do { } while (0) -#define resolv_event(a,b) do { } while (0) -#endif - -#endif - -#ifdef CONFIG_USB_HIDINPUT -/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ -/* We ignore a few input applications that are not widely used */ -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); -extern int hidinput_connect(struct hid_device *); -extern void hidinput_disconnect(struct hid_device *); -#else -#define IS_INPUT_APPLICATION(a) (0) -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } -static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } -static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } -static inline void hidinput_disconnect(struct hid_device *hid) { } -#endif - -int hid_open(struct hid_device *); -void hid_close(struct hid_device *); -int hid_set_field(struct hid_field *, unsigned, __s32); -void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); -void hid_init_reports(struct hid_device *hid); -int hid_wait_io(struct hid_device* hid); - - -#ifdef CONFIG_HID_FF -int hid_ff_init(struct hid_device *hid); - -int hid_lgff_init(struct hid_device *hid); -int hid_tmff_init(struct hid_device *hid); -int hid_zpff_init(struct hid_device *hid); -#ifdef CONFIG_HID_PID -int hid_pidff_init(struct hid_device *hid); -#else -static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } -#endif - -#else -static inline int hid_ff_init(struct hid_device *hid) { return -1; } -#endif - diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 7dc14d0cacc..cbd3b60d93b 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -32,8 +32,9 @@ #include #include #include -#include "hid.h" +#include #include +#include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS #define HIDDEV_MINOR_BASE 0 -- cgit v1.2.3 From 229695e51efc4ed5e04ab471c82591d0f432909d Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:40:53 +0100 Subject: [PATCH] Generic HID layer - API - fixed generic API (added neccessary EXPORT_SYMBOL, fixed hid.h to provide correct prototypes) - extended hid_device with open/close/event function pointers to driver-specific functions - added driver specific driver_data to hid_device Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 9 ++++++++- drivers/usb/input/hid-ff.c | 2 ++ drivers/usb/input/hiddev.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 06e169b6a17..462947f7413 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -497,7 +497,7 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign spin_unlock_irqrestore(&hid->ctrllock, flags); } -static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct hid_device *hid = dev->private; struct hid_field *field; @@ -1231,6 +1231,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); + hid->bus = BUS_USB; + hid->vendor = dev->descriptor.idVendor; + hid->product = dev->descriptor.idProduct; + usb_make_path(dev, hid->phys, sizeof(hid->phys)); strlcat(hid->phys, "/input", sizeof(hid->phys)); len = strlen(hid->phys); @@ -1250,6 +1254,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + hid->hidinput_input_event = usb_hidinput_input_event; + hid->hidinput_open = hidinput_open; + hid->hidinput_close = hidinput_close; return hid; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 4187f4ee9a9..7ecdafa8eb7 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -79,3 +79,5 @@ int hid_ff_init(struct hid_device* hid) return init->init(hid); } +EXPORT_SYMBOL_GPL(hid_ff_init); + diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index cbd3b60d93b..07d7996575c 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -197,7 +197,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, hiddev_send_event(hid, &uref); } - +EXPORT_SYMBOL_GPL(hiddev_hid_event); void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { -- cgit v1.2.3 From 4916b3a57fc94664677d439b911b8aaf86c7ec23 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:03 +0100 Subject: [PATCH] Generic HID layer - USB API - 'dev' in struct hid_device changed from struct usb_device to struct device and fixed all the users - renamed functions which are part of USB HID API from 'hid_*' to 'usbhid_*' - force feedback initialization moved from common part into USB-specific driver - added usbhid.h header for USB HID API users - removed USB-specific fields from struct hid_device and moved them to new usbhid_device, which is pointed to by hid_device->driver_data - fixed all USB users to use this new structure Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 419 +++++++++++++++++++++++------------------- drivers/usb/input/hid-ff.c | 4 +- drivers/usb/input/hid-lgff.c | 5 +- drivers/usb/input/hid-pidff.c | 54 +++--- drivers/usb/input/hid-tmff.c | 3 +- drivers/usb/input/hid-zpff.c | 5 +- drivers/usb/input/hiddev.c | 31 ++-- drivers/usb/input/usbhid.h | 84 +++++++++ 8 files changed, 367 insertions(+), 238 deletions(-) create mode 100644 drivers/usb/input/usbhid.h (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 462947f7413..0991c4b751a 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -35,6 +35,7 @@ #include #include +#include "usbhid.h" /* * Version Information @@ -66,15 +67,16 @@ static int hid_start_in(struct hid_device *hid) { unsigned long flags; int rc = 0; + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irqsave(&hid->inlock, flags); - if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) && - !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) { - rc = usb_submit_urb(hid->urbin, GFP_ATOMIC); + spin_lock_irqsave(&usbhid->inlock, flags); + if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && + !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { + rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); if (rc != 0) - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); } - spin_unlock_irqrestore(&hid->inlock, flags); + spin_unlock_irqrestore(&usbhid->inlock, flags); return rc; } @@ -82,8 +84,9 @@ static int hid_start_in(struct hid_device *hid) static void hid_retry_timeout(unsigned long _hid) { struct hid_device *hid = (struct hid_device *) _hid; + struct usbhid_device *usbhid = hid->driver_data; - dev_dbg(&hid->intf->dev, "retrying intr urb\n"); + dev_dbg(&usbhid->intf->dev, "retrying intr urb\n"); if (hid_start_in(hid)) hid_io_error(hid); } @@ -91,38 +94,39 @@ static void hid_retry_timeout(unsigned long _hid) /* Workqueue routine to reset the device or clear a halt */ static void hid_reset(struct work_struct *work) { - struct hid_device *hid = - container_of(work, struct hid_device, reset_work); + struct usbhid_device *usbhid = + container_of(work, struct usbhid_device, reset_work); + struct hid_device *hid = usbhid->hid; int rc_lock, rc = 0; - if (test_bit(HID_CLEAR_HALT, &hid->iofl)) { - dev_dbg(&hid->intf->dev, "clear halt\n"); - rc = usb_clear_halt(hid->dev, hid->urbin->pipe); - clear_bit(HID_CLEAR_HALT, &hid->iofl); + if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { + dev_dbg(&usbhid->intf->dev, "clear halt\n"); + rc = usb_clear_halt(to_usb_device(hid->dev), usbhid->urbin->pipe); + clear_bit(HID_CLEAR_HALT, &usbhid->iofl); hid_start_in(hid); } - else if (test_bit(HID_RESET_PENDING, &hid->iofl)) { - dev_dbg(&hid->intf->dev, "resetting device\n"); - rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); + else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { + dev_dbg(&usbhid->intf->dev, "resetting device\n"); + rc = rc_lock = usb_lock_device_for_reset(to_usb_device(hid->dev), usbhid->intf); if (rc_lock >= 0) { - rc = usb_reset_composite_device(hid->dev, hid->intf); + rc = usb_reset_composite_device(to_usb_device(hid->dev), usbhid->intf); if (rc_lock) - usb_unlock_device(hid->dev); + usb_unlock_device(to_usb_device(hid->dev)); } - clear_bit(HID_RESET_PENDING, &hid->iofl); + clear_bit(HID_RESET_PENDING, &usbhid->iofl); } switch (rc) { case 0: - if (!test_bit(HID_IN_RUNNING, &hid->iofl)) + if (!test_bit(HID_IN_RUNNING, &usbhid->iofl)) hid_io_error(hid); break; default: err("can't reset device, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, - hid->dev->devpath, - hid->ifnum, rc); + to_usb_device(hid->dev)->bus->bus_name, + to_usb_device(hid->dev)->devpath, + usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: case -ENODEV: @@ -135,33 +139,34 @@ static void hid_reset(struct work_struct *work) static void hid_io_error(struct hid_device *hid) { unsigned long flags; + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irqsave(&hid->inlock, flags); + spin_lock_irqsave(&usbhid->inlock, flags); /* Stop when disconnected */ - if (usb_get_intfdata(hid->intf) == NULL) + if (usb_get_intfdata(usbhid->intf) == NULL) goto done; /* When an error occurs, retry at increasing intervals */ - if (hid->retry_delay == 0) { - hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ - hid->stop_retry = jiffies + msecs_to_jiffies(1000); - } else if (hid->retry_delay < 100) - hid->retry_delay *= 2; + if (usbhid->retry_delay == 0) { + usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ + usbhid->stop_retry = jiffies + msecs_to_jiffies(1000); + } else if (usbhid->retry_delay < 100) + usbhid->retry_delay *= 2; - if (time_after(jiffies, hid->stop_retry)) { + if (time_after(jiffies, usbhid->stop_retry)) { /* Retries failed, so do a port reset */ - if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { - schedule_work(&hid->reset_work); + if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { + schedule_work(&usbhid->reset_work); goto done; } } - mod_timer(&hid->io_retry, - jiffies + msecs_to_jiffies(hid->retry_delay)); + mod_timer(&usbhid->io_retry, + jiffies + msecs_to_jiffies(usbhid->retry_delay)); done: - spin_unlock_irqrestore(&hid->inlock, flags); + spin_unlock_irqrestore(&usbhid->inlock, flags); } @@ -230,28 +235,29 @@ static int hid_input_report(int type, struct urb *urb, int interrupt) static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: /* success */ - hid->retry_delay = 0; + usbhid->retry_delay = 0; hid_input_report(HID_INPUT_REPORT, urb, 1); break; case -EPIPE: /* stall */ - clear_bit(HID_IN_RUNNING, &hid->iofl); - set_bit(HID_CLEAR_HALT, &hid->iofl); - schedule_work(&hid->reset_work); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); + set_bit(HID_CLEAR_HALT, &usbhid->iofl); + schedule_work(&usbhid->reset_work); return; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: /* unplug */ - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); return; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; default: /* error */ @@ -260,12 +266,12 @@ static void hid_irq_in(struct urb *urb) status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err("can't resubmit intr, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, - hid->dev->devpath, - hid->ifnum, status); + to_usb_device(hid->dev)->bus->bus_name, + to_usb_device(hid->dev)->devpath, + usbhid->ifnum, status); hid_io_error(hid); } } @@ -291,16 +297,17 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; + struct usbhid_device *usbhid = hid->driver_data; - report = hid->out[hid->outtail]; + report = usbhid->out[usbhid->outtail]; - hid_output_report(report, hid->outbuf); - hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - hid->urbout->dev = hid->dev; + hid_output_report(report, usbhid->outbuf); + usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); + usbhid->urbout->dev = to_usb_device(hid->dev); dbg("submitting out urb"); - if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) { + if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { err("usb_submit_urb(out) failed"); return -1; } @@ -313,42 +320,43 @@ static int hid_submit_ctrl(struct hid_device *hid) struct hid_report *report; unsigned char dir; int len; + struct usbhid_device *usbhid = hid->driver_data; - report = hid->ctrl[hid->ctrltail].report; - dir = hid->ctrl[hid->ctrltail].dir; + report = usbhid->ctrl[usbhid->ctrltail].report; + dir = usbhid->ctrl[usbhid->ctrltail].dir; len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { - hid_output_report(report, hid->ctrlbuf); - hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0); - hid->urbctrl->transfer_buffer_length = len; + hid_output_report(report, usbhid->ctrlbuf); + usbhid->urbctrl->pipe = usb_sndctrlpipe(to_usb_device(hid->dev), 0); + usbhid->urbctrl->transfer_buffer_length = len; } else { int maxpacket, padlen; - hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0); - maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0); + usbhid->urbctrl->pipe = usb_rcvctrlpipe(to_usb_device(hid->dev), 0); + maxpacket = usb_maxpacket(to_usb_device(hid->dev), usbhid->urbctrl->pipe, 0); if (maxpacket > 0) { padlen = (len + maxpacket - 1) / maxpacket; padlen *= maxpacket; - if (padlen > hid->bufsize) - padlen = hid->bufsize; + if (padlen > usbhid->bufsize) + padlen = usbhid->bufsize; } else padlen = 0; - hid->urbctrl->transfer_buffer_length = padlen; + usbhid->urbctrl->transfer_buffer_length = padlen; } - hid->urbctrl->dev = hid->dev; + usbhid->urbctrl->dev = to_usb_device(hid->dev); - hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; - hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; - hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); - hid->cr->wIndex = cpu_to_le16(hid->ifnum); - hid->cr->wLength = cpu_to_le16(len); + usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; + usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; + usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); + usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); + usbhid->cr->wLength = cpu_to_le16(len); dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u", - hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", - hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength); + usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", + usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); - if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { + if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { err("usb_submit_urb(ctrl) failed"); return -1; } @@ -363,6 +371,7 @@ static int hid_submit_ctrl(struct hid_device *hid) static void hid_irq_out(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; @@ -380,24 +389,24 @@ static void hid_irq_out(struct urb *urb) warn("output irq status %d received", urb->status); } - spin_lock_irqsave(&hid->outlock, flags); + spin_lock_irqsave(&usbhid->outlock, flags); if (unplug) - hid->outtail = hid->outhead; + usbhid->outtail = usbhid->outhead; else - hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); + usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); - if (hid->outhead != hid->outtail) { + if (usbhid->outhead != usbhid->outtail) { if (hid_submit_out(hid)) { - clear_bit(HID_OUT_RUNNING, &hid->iofl); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } - spin_unlock_irqrestore(&hid->outlock, flags); + spin_unlock_irqrestore(&usbhid->outlock, flags); return; } - clear_bit(HID_OUT_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + spin_unlock_irqrestore(&usbhid->outlock, flags); wake_up(&hid->wait); } @@ -408,15 +417,16 @@ static void hid_irq_out(struct urb *urb) static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; - spin_lock_irqsave(&hid->ctrllock, flags); + spin_lock_irqsave(&usbhid->ctrllock, flags); switch (urb->status) { case 0: /* success */ - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0); + if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) + hid_input_report(usbhid->ctrl[usbhid->ctrltail].report->type, urb, 0); break; case -ESHUTDOWN: /* unplug */ unplug = 1; @@ -431,70 +441,71 @@ static void hid_ctrl(struct urb *urb) } if (unplug) - hid->ctrltail = hid->ctrlhead; + usbhid->ctrltail = usbhid->ctrlhead; else - hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (hid->ctrlhead != hid->ctrltail) { + if (usbhid->ctrlhead != usbhid->ctrltail) { if (hid_submit_ctrl(hid)) { - clear_bit(HID_CTRL_RUNNING, &hid->iofl); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } - spin_unlock_irqrestore(&hid->ctrllock, flags); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); return; } - clear_bit(HID_CTRL_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); wake_up(&hid->wait); } -void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) +void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { int head; unsigned long flags; + struct usbhid_device *usbhid = hid->driver_data; if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) return; - if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { + if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { - spin_lock_irqsave(&hid->outlock, flags); + spin_lock_irqsave(&usbhid->outlock, flags); - if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { - spin_unlock_irqrestore(&hid->outlock, flags); + if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { + spin_unlock_irqrestore(&usbhid->outlock, flags); warn("output queue full"); return; } - hid->out[hid->outhead] = report; - hid->outhead = head; + usbhid->out[usbhid->outhead] = report; + usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (hid_submit_out(hid)) - clear_bit(HID_OUT_RUNNING, &hid->iofl); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); + spin_unlock_irqrestore(&usbhid->outlock, flags); return; } - spin_lock_irqsave(&hid->ctrllock, flags); + spin_lock_irqsave(&usbhid->ctrllock, flags); - if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { - spin_unlock_irqrestore(&hid->ctrllock, flags); + if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { + spin_unlock_irqrestore(&usbhid->ctrllock, flags); warn("control queue full"); return; } - hid->ctrl[hid->ctrlhead].report = report; - hid->ctrl[hid->ctrlhead].dir = dir; - hid->ctrlhead = head; + usbhid->ctrl[usbhid->ctrlhead].report = report; + usbhid->ctrl[usbhid->ctrlhead].dir = dir; + usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) if (hid_submit_ctrl(hid)) - clear_bit(HID_CTRL_RUNNING, &hid->iofl); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); } static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -515,15 +526,17 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un } hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); + usbhid_submit_report(hid, field->report, USB_DIR_OUT); return 0; } -int hid_wait_io(struct hid_device *hid) +int usbhid_wait_io(struct hid_device *hid) { - if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) && - !test_bit(HID_OUT_RUNNING, &hid->iofl)), + struct usbhid_device *usbhid = hid->driver_data; + + if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && + !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 10*HZ)) { dbg("timeout waiting for ctrl or out queue to clear"); return -1; @@ -555,7 +568,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, return result; } -int hid_open(struct hid_device *hid) +int usbhid_open(struct hid_device *hid) { ++hid->open; if (hid_start_in(hid)) @@ -563,22 +576,24 @@ int hid_open(struct hid_device *hid) return 0; } -void hid_close(struct hid_device *hid) +void usbhid_close(struct hid_device *hid) { + struct usbhid_device *usbhid = hid->driver_data; + if (!--hid->open) - usb_kill_urb(hid->urbin); + usb_kill_urb(usbhid->urbin); } static int hidinput_open(struct input_dev *dev) { struct hid_device *hid = dev->private; - return hid_open(hid); + return usbhid_open(hid); } static void hidinput_close(struct input_dev *dev) { struct hid_device *hid = dev->private; - hid_close(hid); + usbhid_close(hid); } #define USB_VENDOR_ID_PANJIT 0x134c @@ -590,26 +605,27 @@ static void hidinput_close(struct input_dev *dev) * Initialize all reports */ -void hid_init_reports(struct hid_device *hid) +void usbhid_init_reports(struct hid_device *hid) { struct hid_report *report; + struct usbhid_device *usbhid = hid->driver_data; int err, ret; list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) - hid_submit_report(hid, report, USB_DIR_IN); + usbhid_submit_report(hid, report, USB_DIR_IN); list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) - hid_submit_report(hid, report, USB_DIR_IN); + usbhid_submit_report(hid, report, USB_DIR_IN); err = 0; - ret = hid_wait_io(hid); + ret = usbhid_wait_io(hid); while (ret) { err |= ret; - if (test_bit(HID_CTRL_RUNNING, &hid->iofl)) - usb_kill_urb(hid->urbctrl); - if (test_bit(HID_OUT_RUNNING, &hid->iofl)) - usb_kill_urb(hid->urbout); - ret = hid_wait_io(hid); + if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + usb_kill_urb(usbhid->urbctrl); + if (test_bit(HID_OUT_RUNNING, &usbhid->iofl)) + usb_kill_urb(usbhid->urbout); + ret = usbhid_wait_io(hid); } if (err) @@ -1022,13 +1038,15 @@ static void hid_find_max_report(struct hid_device *hid, unsigned int type, int * static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) { - if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->inbuf_dma))) + struct usbhid_device *usbhid = hid->driver_data; + + if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma))) return -1; - if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->outbuf_dma))) + if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma))) return -1; - if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), GFP_ATOMIC, &hid->cr_dma))) + if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma))) return -1; - if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->ctrlbuf_dma))) + if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma))) return -1; return 0; @@ -1036,14 +1054,16 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { - if (hid->inbuf) - usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma); - if (hid->outbuf) - usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma); - if (hid->cr) - usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); - if (hid->ctrlbuf) - usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma); + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->inbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); + if (usbhid->outbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); + if (usbhid->cr) + usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); + if (usbhid->ctrlbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); } /* @@ -1069,6 +1089,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) unsigned quirks = 0, rsize = 0; char *rdesc; int n, len, insize = 0; + struct usbhid_device *usbhid; /* Ignore all Wacom devices */ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM) @@ -1138,13 +1159,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) kfree(rdesc); hid->quirks = quirks; - hid->bufsize = HID_MIN_BUFFER_SIZE; - hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize); - hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize); - hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize); + if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL))) + goto fail; + + hid->driver_data = usbhid; + usbhid->hid = hid; + + usbhid->bufsize = HID_MIN_BUFFER_SIZE; + hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize); + hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize); + hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize); - if (hid->bufsize > HID_MAX_BUFFER_SIZE) - hid->bufsize = HID_MAX_BUFFER_SIZE; + if (usbhid->bufsize > HID_MAX_BUFFER_SIZE) + usbhid->bufsize = HID_MAX_BUFFER_SIZE; hid_find_max_report(hid, HID_INPUT_REPORT, &insize); @@ -1173,47 +1200,47 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) interval = hid_mousepoll_interval; if (usb_endpoint_dir_in(endpoint)) { - if (hid->urbin) + if (usbhid->urbin) continue; - if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) + if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize, + usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize, hid_irq_in, hid, interval); - hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usbhid->urbin->transfer_dma = usbhid->inbuf_dma; + usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { - if (hid->urbout) + if (usbhid->urbout) continue; - if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL))) + if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, + usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0, hid_irq_out, hid, interval); - hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usbhid->urbout->transfer_dma = usbhid->outbuf_dma; + usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } } - if (!hid->urbin) { + if (!usbhid->urbin) { err("couldn't find an input interrupt endpoint"); goto fail; } init_waitqueue_head(&hid->wait); - INIT_WORK(&hid->reset_work, hid_reset); - setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid); + INIT_WORK(&usbhid->reset_work, hid_reset); + setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); - spin_lock_init(&hid->inlock); - spin_lock_init(&hid->outlock); - spin_lock_init(&hid->ctrllock); + spin_lock_init(&usbhid->inlock); + spin_lock_init(&usbhid->outlock); + spin_lock_init(&usbhid->ctrllock); hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - hid->dev = dev; - hid->intf = intf; - hid->ifnum = interface->desc.bInterfaceNumber; + hid->dev = &dev->dev; + usbhid->intf = intf; + usbhid->ifnum = interface->desc.bInterfaceNumber; hid->name[0] = 0; @@ -1245,15 +1272,15 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) hid->uniq[0] = 0; - hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); - if (!hid->urbctrl) + usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); + if (!usbhid->urbctrl) goto fail; - usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr, - hid->ctrlbuf, 1, hid_ctrl, hid); - hid->urbctrl->setup_dma = hid->cr_dma; - hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr, + usbhid->ctrlbuf, 1, hid_ctrl, hid); + usbhid->urbctrl->setup_dma = usbhid->cr_dma; + usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; + usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); hid->hidinput_input_event = usb_hidinput_input_event; hid->hidinput_open = hidinput_open; hid->hidinput_close = hidinput_close; @@ -1261,9 +1288,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) return hid; fail: - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbout); - usb_free_urb(hid->urbctrl); + usb_free_urb(usbhid->urbin); + usb_free_urb(usbhid->urbout); + usb_free_urb(usbhid->urbctrl); hid_free_buffers(dev, hid); hid_free_device(hid); @@ -1273,18 +1300,21 @@ fail: static void hid_disconnect(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid; if (!hid) return; - spin_lock_irq(&hid->inlock); /* Sync with error handler */ + usbhid = hid->driver_data; + + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ usb_set_intfdata(intf, NULL); - spin_unlock_irq(&hid->inlock); - usb_kill_urb(hid->urbin); - usb_kill_urb(hid->urbout); - usb_kill_urb(hid->urbctrl); + spin_unlock_irq(&usbhid->inlock); + usb_kill_urb(usbhid->urbin); + usb_kill_urb(usbhid->urbout); + usb_kill_urb(usbhid->urbctrl); - del_timer_sync(&hid->io_retry); + del_timer_sync(&usbhid->io_retry); flush_scheduled_work(); if (hid->claimed & HID_CLAIMED_INPUT) @@ -1292,11 +1322,11 @@ static void hid_disconnect(struct usb_interface *intf) if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbctrl); - usb_free_urb(hid->urbout); + usb_free_urb(usbhid->urbin); + usb_free_urb(usbhid->urbctrl); + usb_free_urb(usbhid->urbout); - hid_free_buffers(hid->dev, hid); + hid_free_buffers(to_usb_device(hid->dev), hid); hid_free_device(hid); } @@ -1313,7 +1343,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!(hid = usb_hid_configure(intf))) return -ENODEV; - hid_init_reports(hid); + usbhid_init_reports(hid); hid_dump_device(hid); if (!hidinput_connect(hid)) @@ -1329,6 +1359,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; } + /* This only gets called when we are a single-input (most of the + * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is + * only useful in this case, and not for multi-input quirks. */ + if ((hid->claimed & HID_CLAIMED_INPUT) && + !(hid->quirks & HID_QUIRK_MULTI_INPUT)) + hid_ff_init(hid); + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) @@ -1359,12 +1396,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) static int hid_suspend(struct usb_interface *intf, pm_message_t message) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irq(&hid->inlock); /* Sync with error handler */ - set_bit(HID_SUSPENDED, &hid->iofl); - spin_unlock_irq(&hid->inlock); - del_timer(&hid->io_retry); - usb_kill_urb(hid->urbin); + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ + set_bit(HID_SUSPENDED, &usbhid->iofl); + spin_unlock_irq(&usbhid->inlock); + del_timer(&usbhid->io_retry); + usb_kill_urb(usbhid->urbin); dev_dbg(&intf->dev, "suspend\n"); return 0; } @@ -1372,10 +1410,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) static int hid_resume(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid = hid->driver_data; int status; - clear_bit(HID_SUSPENDED, &hid->iofl); - hid->retry_delay = 0; + clear_bit(HID_SUSPENDED, &usbhid->iofl); + usbhid->retry_delay = 0; status = hid_start_in(hid); dev_dbg(&intf->dev, "resume status %d\n", status); return status; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 7ecdafa8eb7..f8f660ee3fa 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -70,8 +70,8 @@ static struct hid_ff_initializer inits[] = { int hid_ff_init(struct hid_device* hid) { struct hid_ff_initializer *init; - int vendor = le16_to_cpu(hid->dev->descriptor.idVendor); - int product = le16_to_cpu(hid->dev->descriptor.idProduct); + int vendor = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idVendor); + int product = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idProduct); for (init = inits; init->idVendor; init++) if (init->idVendor == vendor && init->idProduct == product) diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index e977ba3d17e..e4746626856 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -30,6 +30,7 @@ #include #include #include +#include "usbhid.h" struct device_type { u16 idVendor; @@ -75,7 +76,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[2] = x; report->field[0]->value[3] = y; dbg("(x, y)=(%04x, %04x)", x, y); - hid_submit_report(hid, report, USB_DIR_OUT); + usbhid_submit_report(hid, report, USB_DIR_OUT); break; case FF_RUMBLE: @@ -90,7 +91,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[2] = left; report->field[0]->value[3] = right; dbg("(left, right)=(%04x, %04x)", left, right); - hid_submit_report(hid, report, USB_DIR_OUT); + usbhid_submit_report(hid, report, USB_DIR_OUT); break; } return 0; diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c index b4caea3864e..cbd2d53feff 100644 --- a/drivers/usb/input/hid-pidff.c +++ b/drivers/usb/input/hid-pidff.c @@ -262,7 +262,7 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, debug("attack %u => %d", envelope->attack_level, pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], USB_DIR_OUT); } @@ -289,7 +289,7 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff, pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE], effect->u.constant.level); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], USB_DIR_OUT); } @@ -324,7 +324,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff, pidff->effect_direction); pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], USB_DIR_OUT); } @@ -356,7 +356,7 @@ static void pidff_set_periodic_report(struct pidff_device *pidff, pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], USB_DIR_OUT); } @@ -398,8 +398,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff, effect->u.condition[i].left_saturation); pidff_set(&pidff->set_condition[PID_DEAD_BAND], effect->u.condition[i].deadband); - hid_wait_io(pidff->hid); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], + usbhid_wait_io(pidff->hid); + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], USB_DIR_OUT); } } @@ -440,7 +440,7 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff, effect->u.ramp.start_level); pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], effect->u.ramp.end_level); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], USB_DIR_OUT); } @@ -465,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) int j; pidff->create_new_effect_type->value[0] = efnum; - hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], USB_DIR_OUT); debug("create_new_effect sent, type: %d", efnum); pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; pidff->block_load_status->value[0] = 0; - hid_wait_io(pidff->hid); + usbhid_wait_io(pidff->hid); for (j = 0; j < 60; j++) { debug("pid_block_load requested"); - hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], + usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], USB_DIR_IN); - hid_wait_io(pidff->hid); + usbhid_wait_io(pidff->hid); if (pidff->block_load_status->value[0] == pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { debug("device reported free memory: %d bytes", @@ -513,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; } - hid_wait_io(pidff->hid); - hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], + usbhid_wait_io(pidff->hid); + usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], USB_DIR_OUT); } @@ -536,7 +536,7 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value) static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) { pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; - hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], + usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], USB_DIR_OUT); } @@ -716,7 +716,7 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain) struct pidff_device *pidff = dev->ff->private; pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); - hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], + usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], USB_DIR_OUT); } @@ -741,7 +741,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) pidff_set(&pidff->set_effect[PID_GAIN], magnitude); pidff->set_effect[PID_START_DELAY].value[0] = 0; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], USB_DIR_OUT); } @@ -1165,19 +1165,19 @@ static void pidff_reset(struct pidff_device *pidff) pidff->device_control->value[0] = pidff->control_id[PID_RESET]; /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); pidff->device_control->value[0] = pidff->control_id[PID_ENABLE_ACTUATORS]; - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); /* pool report is sometimes messed up, refetch it */ - hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); + usbhid_wait_io(hid); if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0]; @@ -1189,9 +1189,9 @@ static void pidff_reset(struct pidff_device *pidff) break; } debug("pid_pool requested again"); - hid_submit_report(hid, pidff->reports[PID_POOL], + usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); - hid_wait_io(hid); + usbhid_wait_io(hid); } } } @@ -1277,7 +1277,7 @@ int hid_pidff_init(struct hid_device *hid) if (test_bit(FF_GAIN, dev->ffbit)) { pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); - hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], + usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], USB_DIR_OUT); } diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 1cd1418ad6a..ab67331620d 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -33,6 +33,7 @@ #include #include +#include "usbhid.h" /* Usages for thrustmaster devices I know about */ #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) @@ -70,7 +71,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef tmff->rumble->value[0] = left; tmff->rumble->value[1] = right; dbg("(left,right)=(%08x, %08x)", left, right); - hid_submit_report(hid, tmff->report, USB_DIR_OUT); + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); return 0; } diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c index af1bfae39dc..7bd8238ca21 100644 --- a/drivers/usb/input/hid-zpff.c +++ b/drivers/usb/input/hid-zpff.c @@ -28,6 +28,7 @@ #include #include #include +#include "usbhid.h" struct zpff_device { struct hid_report *report; @@ -56,7 +57,7 @@ static int hid_zpff_play(struct input_dev *dev, void *data, zpff->report->field[2]->value[0] = left; zpff->report->field[3]->value[0] = right; debug("running with 0x%02x 0x%02x", left, right); - hid_submit_report(hid, zpff->report, USB_DIR_OUT); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); return 0; } @@ -101,7 +102,7 @@ int hid_zpff_init(struct hid_device *hid) zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; - hid_submit_report(hid, zpff->report, USB_DIR_OUT); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); printk(KERN_INFO "Force feedback for Zeroplus based devices by " "Anssi Hannula \n"); diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 07d7996575c..0c2647eb9ee 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -240,7 +240,7 @@ static int hiddev_release(struct inode * inode, struct file * file) if (!--list->hiddev->open) { if (list->hiddev->exist) - hid_close(list->hiddev->hid); + usbhid_close(list->hiddev->hid); else kfree(list->hiddev); } @@ -271,7 +271,7 @@ static int hiddev_open(struct inode *inode, struct file *file) if (!list->hiddev->open++) if (list->hiddev->exist) - hid_open(hiddev_table[i]->hid); + usbhid_open(hiddev_table[i]->hid); return 0; } @@ -383,7 +383,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = hid->dev; + struct usb_device *dev = to_usb_device(hid->dev); struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; @@ -392,6 +392,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; + struct usbhid_device *usbhid = hid->driver_data; void __user *user_arg = (void __user *)arg; int i; @@ -421,7 +422,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd dinfo.bustype = BUS_USB; dinfo.busnum = dev->bus->busnum; dinfo.devnum = dev->devnum; - dinfo.ifnum = hid->ifnum; + dinfo.ifnum = usbhid->ifnum; dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); dinfo.product = le16_to_cpu(dev->descriptor.idProduct); dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); @@ -480,7 +481,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } case HIDIOCINITREPORT: - hid_init_reports(hid); + usbhid_init_reports(hid); return 0; @@ -494,8 +495,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_submit_report(hid, report, USB_DIR_IN); - hid_wait_io(hid); + usbhid_submit_report(hid, report, USB_DIR_IN); + usbhid_wait_io(hid); return 0; @@ -509,8 +510,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_submit_report(hid, report, USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, report, USB_DIR_OUT); + usbhid_wait_io(hid); return 0; @@ -746,6 +747,7 @@ static struct usb_class_driver hiddev_class = { int hiddev_connect(struct hid_device *hid) { struct hiddev *hiddev; + struct usbhid_device *usbhid = hid->driver_data; int i; int retval; @@ -761,7 +763,7 @@ int hiddev_connect(struct hid_device *hid) if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) return -1; - retval = usb_register_dev(hid->intf, &hiddev_class); + retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { err("Not able to get a minor for this device."); kfree(hiddev); @@ -773,10 +775,10 @@ int hiddev_connect(struct hid_device *hid) hiddev->hid = hid; hiddev->exist = 1; - hid->minor = hid->intf->minor; + hid->minor = usbhid->intf->minor; hid->hiddev = hiddev; - hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; + hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; return 0; } @@ -789,14 +791,15 @@ static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; + struct usbhid_device *usbhid = hid->driver_data; hiddev->exist = 0; hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + usb_deregister_dev(usbhid->intf, &hiddev_class); if (hiddev->open) { - hid_close(hiddev->hid); + usbhid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { kfree(hiddev); diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h new file mode 100644 index 00000000000..830107e5251 --- /dev/null +++ b/drivers/usb/input/usbhid.h @@ -0,0 +1,84 @@ +#ifndef __USBHID_H +#define __USBHID_H + +/* + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2006 Jiri Kosina + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +/* API provided by hid-core.c for USB HID drivers */ +int usbhid_wait_io(struct hid_device* hid); +void usbhid_close(struct hid_device *hid); +int usbhid_open(struct hid_device *hid); +void usbhid_init_reports(struct hid_device *hid); +void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); + +/* + * USB-specific HID struct, to be pointed to + * from struct hid_device->driver_data + */ + +struct usbhid_device { + struct hid_device *hid; /* pointer to corresponding HID dev */ + + struct usb_interface *intf; /* USB interface */ + int ifnum; /* USB interface number */ + + unsigned int bufsize; /* URB buffer size */ + + struct urb *urbin; /* Input URB */ + char *inbuf; /* Input buffer */ + dma_addr_t inbuf_dma; /* Input buffer dma */ + spinlock_t inlock; /* Input fifo spinlock */ + + struct urb *urbctrl; /* Control URB */ + struct usb_ctrlrequest *cr; /* Control request struct */ + dma_addr_t cr_dma; /* Control request struct dma */ + struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ + unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ + char *ctrlbuf; /* Control buffer */ + dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + spinlock_t ctrllock; /* Control fifo spinlock */ + + struct urb *urbout; /* Output URB */ + struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ + unsigned char outhead, outtail; /* Output pipe fifo head & tail */ + char *outbuf; /* Output buffer */ + dma_addr_t outbuf_dma; /* Output buffer dma */ + spinlock_t outlock; /* Output fifo spinlock */ + + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + struct timer_list io_retry; /* Retry timer */ + unsigned long stop_retry; /* Time to give up, in jiffies */ + unsigned int retry_delay; /* Delay length in ms */ + struct work_struct reset_work; /* Task context for resets */ + +}; + +#endif + -- cgit v1.2.3 From aa938f7974b82cfd9ee955031987344f332b7c77 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:10 +0100 Subject: [PATCH] Generic HID layer - hiddev - hiddev is USB-only (agreed with Marcel Holtmann that Bluetooth currently doesn't need it, and future planned interface (rawhid) will be more flexible and usable) - both HID and USB-hid can be now compiled as modules (wasn't possible before hiddev was fully separated from generic HID layer) Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 0991c4b751a..4fc828041d0 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1284,6 +1284,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hidinput_input_event = usb_hidinput_input_event; hid->hidinput_open = hidinput_open; hid->hidinput_close = hidinput_close; +#ifdef CONFIG_USB_HIDDEV + hid->hiddev_hid_event = hiddev_hid_event; +#endif return hid; -- cgit v1.2.3 From aa8de2f038baec993f07ef66fb3e94481d1ec22b Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:17 +0100 Subject: [PATCH] Generic HID layer - input and event reporting hid_input_report() was needlessly USB-specific in USB HID. This patch makes the function independent of HID implementation and fixes all the current users. Bluetooth patches comply with this prototype. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 67 ++++---------------------------------------- drivers/usb/input/hiddev.c | 1 + 2 files changed, 7 insertions(+), 61 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 4fc828041d0..a20ff61624b 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -169,65 +169,6 @@ done: spin_unlock_irqrestore(&usbhid->inlock, flags); } - -static int hid_input_report(int type, struct urb *urb, int interrupt) -{ - struct hid_device *hid = urb->context; - struct hid_report_enum *report_enum = hid->report_enum + type; - u8 *data = urb->transfer_buffer; - int len = urb->actual_length; - struct hid_report *report; - int n, size; - - if (!len) { - dbg("empty report"); - return -1; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); -#endif - - n = 0; /* Normally report number is 0 */ - if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ - n = *data++; - len--; - } - -#ifdef DEBUG_DATA - { - int i; - printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); - for (i = 0; i < len; i++) - printk(" %02x", data[i]); - printk("\n"); - } -#endif - - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); - return -1; - } - - size = ((report->size - 1) >> 3) + 1; - - if (len < size) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - memset(data + len, 0, size - len); - } - - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_report_event(hid, report); - - for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, interrupt); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_report_event(hid, report); - - return 0; -} - /* * Input interrupt completion handler. */ @@ -241,7 +182,9 @@ static void hid_irq_in(struct urb *urb) switch (urb->status) { case 0: /* success */ usbhid->retry_delay = 0; - hid_input_report(HID_INPUT_REPORT, urb, 1); + hid_input_report(urb->context, HID_INPUT_REPORT, + urb->transfer_buffer, + urb->actual_length, 1); break; case -EPIPE: /* stall */ clear_bit(HID_IN_RUNNING, &usbhid->iofl); @@ -426,7 +369,8 @@ static void hid_ctrl(struct urb *urb) switch (urb->status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) - hid_input_report(usbhid->ctrl[usbhid->ctrltail].report->type, urb, 0); + hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type, + urb->transfer_buffer, urb->actual_length, 0); break; case -ESHUTDOWN: /* unplug */ unplug = 1; @@ -1286,6 +1230,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hidinput_close = hidinput_close; #ifdef CONFIG_USB_HIDDEV hid->hiddev_hid_event = hiddev_hid_event; + hid->hiddev_report_event = hiddev_report_event; #endif return hid; diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 0c2647eb9ee..114d6c9f64b 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -214,6 +214,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report) hiddev_send_event(hid, &uref); } + /* * fasync file op */ -- cgit v1.2.3 From 4c2ae844b5ef85fd4b571c9c91ac48afa6ef2dfc Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:22 +0100 Subject: [PATCH] Generic HID layer - pb_fnmode pb_fnmode parameter has to be passed to usbhid, both for compatibility reasons and also because it logically belongs there. Also removes empty hid-input.c file in drivers/usb/input. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 8 ++++++++ drivers/usb/input/hid-input.c | 30 ------------------------------ 2 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 drivers/usb/input/hid-input.c (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a20ff61624b..89fa6885709 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -56,6 +56,11 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); +static int usbhid_pb_fnmode = 1; +module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); +MODULE_PARM_DESC(pb_fnmode, + "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); + /* * Input submission and I/O error handler. */ @@ -1232,6 +1237,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; #endif +#ifdef CONFIG_USB_HIDINPUT_POWERBOOK + hid->pb_fnmode = usbhid_pb_fnmode; +#endif return hid; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c deleted file mode 100644 index 8756eb3263d..00000000000 --- a/drivers/usb/input/hid-input.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * USB HID to Linux Input mapping - * - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - - -- cgit v1.2.3 From 63f3861d2fbf8ccbad1386ac9ac8b822c036ea00 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Dec 2006 18:41:30 +0100 Subject: [PATCH] Generic HID layer - build This modifies Makefiles and Kconfigs to properly reflect the creation of generic HID layer. It also removes the dependency of BROKEN, which was introduced by the first patch in series (see the comment). Also updates credits. Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann Cc: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 21 ++++++--------------- drivers/usb/input/Makefile | 3 --- 2 files changed, 6 insertions(+), 18 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 9b075319ed5..8a62d478575 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -6,9 +6,10 @@ comment "USB Input Devices" config USB_HID tristate "USB Human Interface Device (full HID) support" - depends on USB && BROKEN + default y + depends on USB && HID ---help--- - Say Y here if you want full HID support to connect keyboards, + Say Y here if you want full HID support to connect USB keyboards, mice, joysticks, graphic tablets, or any other HID based devices to your computer via USB. You also need to select HID Input layer support (below) if you want to use keyboards, mice, joysticks and @@ -27,20 +28,10 @@ config USB_HID comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB_HID && INPUT=n -config USB_HIDINPUT - bool "HID input layer support" - default y - depends on INPUT && USB_HID - help - Say Y here if you want to use a USB keyboard, mouse or joystick, - or any other HID input device. - - If unsure, say Y. - -config USB_HIDINPUT_POWERBOOK +config USB_HID_POWERBOOK bool "Enable support for iBook/PowerBook special keys" default n - depends on USB_HIDINPUT + depends on USB_HID help Say Y here if you want support for the special keys (Fn, Numlock) on Apple iBooks and PowerBooks. @@ -49,7 +40,7 @@ config USB_HIDINPUT_POWERBOOK config HID_FF bool "Force feedback support (EXPERIMENTAL)" - depends on USB_HIDINPUT && EXPERIMENTAL + depends on USB_HID && EXPERIMENTAL help Say Y here is you want force feedback support for a few HID devices. See below for a list of supported devices. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index d946d5213b3..1a24b5bfa05 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -11,9 +11,6 @@ usbhid-objs := hid-core.o ifeq ($(CONFIG_USB_HIDDEV),y) usbhid-objs += hiddev.o endif -ifeq ($(CONFIG_USB_HIDINPUT),y) - usbhid-objs += hid-input.o -endif ifeq ($(CONFIG_HID_PID),y) usbhid-objs += hid-pidff.o endif -- cgit v1.2.3 From cd86128088554d64fea1679191509f00e6353c5b Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 13 Dec 2006 00:34:52 -0800 Subject: [PATCH] Fix numerous kcalloc() calls, convert to kzalloc() All kcalloc() calls of the form "kcalloc(1,...)" are converted to the equivalent kzalloc() calls, and a few kcalloc() calls with the incorrect ordering of the first two arguments are fixed. Signed-off-by: Robert P. J. Day Cc: Jeff Garzik Cc: Alan Cox Cc: Dominik Brodowski Cc: Adam Belay Cc: James Bottomley Cc: Greg KH Cc: Mark Fasheh Cc: Trond Myklebust Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/misc/uss720.c | 2 +- drivers/usb/net/rndis_host.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 72f3db99ff9..3e0abbb49fe 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -598,7 +598,7 @@ at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags) { struct at91_request *req; - req = kcalloc(1, sizeof (struct at91_request), gfp_flags); + req = kzalloc(sizeof (struct at91_request), gfp_flags); if (!req) return NULL; diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 7e8a0acd52e..70250252ae2 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -705,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf, /* * Allocate parport interface */ - if (!(priv = kcalloc(sizeof(struct parport_uss720_private), 1, GFP_KERNEL))) { + if (!(priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL))) { usb_put_dev(usbdev); return -ENOMEM; } diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 99f26b3e502..ea5f44de3de 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -469,7 +469,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) struct rndis_halt *halt; /* try to clear any rndis state/activity (no i/o from stack!) */ - halt = kcalloc(1, sizeof *halt, GFP_KERNEL); + halt = kzalloc(sizeof *halt, GFP_KERNEL); if (halt) { halt->msg_type = RNDIS_MSG_HALT; halt->msg_len = ccpu2(sizeof *halt); -- cgit v1.2.3 From 5cbded585d129d0226cb48ac4202b253c781be26 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 13 Dec 2006 00:35:56 -0800 Subject: [PATCH] getting rid of all casts of k[cmz]alloc() calls Run this: #!/bin/sh for f in $(grep -Erl "\([^\)]*\) *k[cmz]alloc" *) ; do echo "De-casting $f..." perl -pi -e "s/ ?= ?\([^\)]*\) *(k[cmz]alloc) *\(/ = \1\(/" $f done And then go through and reinstate those cases where code is casting pointers to non-pointers. And then drop a few hunks which conflicted with outstanding work. Cc: Russell King , Ian Molton Cc: Mikael Starvik Cc: Yoshinori Sato Cc: Roman Zippel Cc: Geert Uytterhoeven Cc: Ralf Baechle Cc: Paul Mackerras Cc: Kyle McMartin Cc: Benjamin Herrenschmidt Cc: Martin Schwidefsky Cc: "David S. Miller" Cc: Jeff Dike Cc: Greg KH Cc: Jens Axboe Cc: Paul Fulghum Cc: Alan Cox Cc: Karsten Keil Cc: Mauro Carvalho Chehab Cc: Jeff Garzik Cc: James Bottomley Cc: Ian Kent Cc: Steven French Cc: David Woodhouse Cc: Neil Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/gadget/serial.c | 2 +- drivers/usb/host/hc_crisv10.c | 2 +- drivers/usb/misc/auerswald.c | 4 ++-- drivers/usb/serial/cypress_m8.c | 2 +- drivers/usb/serial/digi_acceleport.c | 4 ++-- drivers/usb/serial/io_ti.c | 2 +- drivers/usb/serial/ipaq.c | 2 +- drivers/usb/serial/kobil_sct.c | 4 ++-- drivers/usb/serial/pl2303.c | 2 +- drivers/usb/serial/ti_usb_3410_5052.c | 2 +- drivers/usb/serial/whiteheat.c | 4 ++-- drivers/usb/storage/sddr09.c | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 5516c59ed5e..2d12bf9f19d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -2195,7 +2195,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags) if (size == 0) return NULL; - gb = (struct gs_buf *)kmalloc(sizeof(struct gs_buf), kmalloc_flags); + gb = kmalloc(sizeof(struct gs_buf), kmalloc_flags); if (gb == NULL) return NULL; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 9325e46a68c..282d82efc0b 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -365,7 +365,7 @@ static inline struct urb *urb_list_first(int epid) /* Adds an urb_entry last in the list for this epid. */ static inline void urb_list_add(struct urb *urb, int epid) { - urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG); + urb_entry_t *urb_entry = kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG); assert(urb_entry); urb_entry->urb = urb; diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index c703f73e165..6c7f3efb1d4 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -766,7 +766,7 @@ static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned bep->bufp = kmalloc (bufsize, GFP_KERNEL); if (!bep->bufp) goto bl_fail; - bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL); + bep->dr = kmalloc(sizeof (struct usb_ctrlrequest), GFP_KERNEL); if (!bep->dr) goto bl_fail; bep->urbp = usb_alloc_urb (0, GFP_KERNEL); @@ -1969,7 +1969,7 @@ static int auerswald_probe (struct usb_interface *intf, info("device is a %s", cp->dev_desc); /* get the maximum allowed control transfer length */ - pbuf = (__le16 *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */ + pbuf = kmalloc(2, GFP_KERNEL); /* use an allocated buffer because of urb target */ if (!pbuf) { err( "out of memory"); goto pfail; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index a1fdb85b8c0..45cdf9bc43b 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1493,7 +1493,7 @@ static struct cypress_buf *cypress_buf_alloc(unsigned int size) if (size == 0) return NULL; - cb = (struct cypress_buf *)kmalloc(sizeof(struct cypress_buf), GFP_KERNEL); + cb = kmalloc(sizeof(struct cypress_buf), GFP_KERNEL); if (cb == NULL) return NULL; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 9d9ea874639..efd9ce3f931 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1681,7 +1681,7 @@ dbg( "digi_startup: TOP" ); for( i=0; itype->num_ports+1; i++ ) { /* allocate port private structure */ - priv = (struct digi_port *)kmalloc( sizeof(struct digi_port), + priv = kmalloc( sizeof(struct digi_port), GFP_KERNEL ); if( priv == (struct digi_port *)0 ) { while( --i >= 0 ) @@ -1714,7 +1714,7 @@ dbg( "digi_startup: TOP" ); } /* allocate serial private structure */ - serial_priv = (struct digi_serial *)kmalloc( sizeof(struct digi_serial), + serial_priv = kmalloc( sizeof(struct digi_serial), GFP_KERNEL ); if( serial_priv == (struct digi_serial *)0 ) { for( i=0; itype->num_ports+1; i++ ) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 2da2684e080..980285c0233 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2811,7 +2811,7 @@ static struct edge_buf *edge_buf_alloc(unsigned int size) if (size == 0) return NULL; - eb = (struct edge_buf *)kmalloc(sizeof(struct edge_buf), GFP_KERNEL); + eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL); if (eb == NULL) return NULL; diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index d72cf8bc7f7..42f757a5b87 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -595,7 +595,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) bytes_in = 0; bytes_out = 0; - priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL); + priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL); if (priv == NULL) { err("%s - Out of memory", __FUNCTION__); return -ENOMEM; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index e284d6c0fd3..62bea0c923b 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -269,7 +269,7 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) } // allocate memory for write_urb transfer buffer - port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); + port->write_urb->transfer_buffer = kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); if (! port->write_urb->transfer_buffer) { kfree(transfer_buffer); usb_free_urb(port->write_urb); @@ -696,7 +696,7 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, return 0; case TCFLSH: // 0x540B - transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); + transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { return -ENOBUFS; } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index d124d780e42..5dc2ac9afa9 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -159,7 +159,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) if (size == 0) return NULL; - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); if (pb == NULL) return NULL; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index f42eb9ea640..83189005c6f 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1710,7 +1710,7 @@ static struct circ_buf *ti_buf_alloc(void) { struct circ_buf *cb; - cb = (struct circ_buf *)kmalloc(sizeof(struct circ_buf), GFP_KERNEL); + cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL); if (cb == NULL) return NULL; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index dc45e58e2b8..5483d8564c1 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -416,7 +416,7 @@ static int whiteheat_attach (struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); + info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); if (info == NULL) { err("%s: Out of memory for port structures\n", serial->type->description); goto no_private; @@ -487,7 +487,7 @@ static int whiteheat_attach (struct usb_serial *serial) usb_set_serial_port_data(port, info); } - command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); + command_info = kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); if (command_info == NULL) { err("%s: Out of memory for port structures\n", serial->type->description); goto no_command_private; diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index fb8bacaae27..e3528eca29a 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -646,7 +646,7 @@ sddr09_read_sg_test_only(struct us_data *us) { return result; } - buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO); + buf = kmalloc(bulklen, GFP_NOIO); if (!buf) return -ENOMEM; -- cgit v1.2.3 From e3a0dd7ced76bb439ddeda244a9667e7b3800fc8 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 14 Dec 2006 11:49:53 +0100 Subject: [PATCH] Generic HID layer - build: USB_HID should select HID Let CONFIG_USB_HID imply CONFIG_HID. Making it only dependent might confuse users to choose CONFIG_HID, but no particular HID transport drivers. Signed-off-by: Jiri Kosina --- drivers/usb/input/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 8a62d478575..e308f6dc2b8 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -7,7 +7,8 @@ comment "USB Input Devices" config USB_HID tristate "USB Human Interface Device (full HID) support" default y - depends on USB && HID + depends on USB + select HID ---help--- Say Y here if you want full HID support to connect USB keyboards, mice, joysticks, graphic tablets, or any other HID based devices -- cgit v1.2.3 From 519ab5f2be65b72cf12ae99c89752bbe79b44df6 Mon Sep 17 00:00:00 2001 From: Yu Luming Date: Tue, 19 Dec 2006 12:56:15 -0800 Subject: ACPI: video: Add dev argument for backlight_device_register This patch set adds generic abstract layer support for acpi video driver to have generic user interface to control backlight and output switch control by leveraging the existing backlight sysfs class driver, and by adding a new video output sysfs class driver. This patch: Add dev argument for backlight_device_register to link the class device to real device object. The platform specific driver should find a way to get the real device object for their video device. [akpm@osdl.org: build fix] [akpm@osdl.org: fix msi-laptop.c] Signed-off-by: Luming Yu Cc: "Antonino A. Daplas" Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/usb/misc/appledisplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 6b23a1def9f..a4522e6c31e 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -283,7 +283,7 @@ static int appledisplay_probe(struct usb_interface *iface, /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); - pdata->bd = backlight_device_register(bl_name, pdata, + pdata->bd = backlight_device_register(bl_name, NULL, NULL, &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); -- cgit v1.2.3 From 6a7255e1df3cf8f89c2c0c6eeea866c6bb17cfb9 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 6 Dec 2006 20:27:32 +0000 Subject: USB: Fix oops in PhidgetServo The PhidgetServo causes an Oops when any of its sysfs attributes are read or written too, making the driver useless. Signed-off-by: Sean Young Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/phidgetservo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index 7163f05c5b2..0d9de2f7393 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -282,6 +282,7 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id) dev->dev = NULL; goto out; } + dev_set_drvdata(dev->dev, dev); servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1; -- cgit v1.2.3 From 96ca014d53d2c2f9d3b32fe6f2f003e660c3bc63 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 24 Nov 2006 12:55:59 +0100 Subject: USB: fix transvibrator disconnect race in disconnect you set the interface's private data to NULL. In your IO methods you unconditionally follow the pointer into never never land. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/trancevibrator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 33cd91d11ec..67e2fc20eee 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -120,8 +120,8 @@ static void tv_disconnect(struct usb_interface *interface) struct trancevibrator *dev; dev = usb_get_intfdata (interface); - usb_set_intfdata(interface, NULL); device_remove_file(&interface->dev, &dev_attr_speed); + usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); kfree(dev); } -- cgit v1.2.3 From 87f28bde949125901494f50e4b4a5b609a20a120 Mon Sep 17 00:00:00 2001 From: Eagle Jones Date: Fri, 24 Nov 2006 16:40:04 -0800 Subject: USB: airprime: add device id for dell wireless 5500 hsdpa card Added the device id (0x413c, 0x8115) for the Dell wireless HSDPA 5500, which is a rebranded Novatel EU730. Signed-off-by: Eagle Jones Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 96c73726d74..62a0df2db53 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -21,6 +21,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ { USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ + { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v1.2.3 From ec434e9b43c7d41bd6962b79f5374be5ca2ebe2d Mon Sep 17 00:00:00 2001 From: Jan Capek Date: Tue, 28 Nov 2006 22:35:12 +0100 Subject: USB: ftdi_sio - MachX product ID added below is a patch for the ftdi_sio driver to include a new device ID for CCS MachX PIC programmer. From: Jan Capek Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 41b0ad2d56a..6986e756f7c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -452,6 +452,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index bae117d359a..40dd394de58 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -312,8 +312,9 @@ /* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an in-circuit-debugger */ /* unit for PIC16's/PIC18's */ -#define FTDI_CCSICDU20_0_PID 0xF9D0 -#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSICDU20_0_PID 0xF9D0 +#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSMACHX_2_PID 0xF9D2 /* Inside Accesso contactless reader (http://www.insidefr.com) */ #define INSIDE_ACCESSO 0xFAD0 -- cgit v1.2.3 From 337445313ffb7a7e97f408500c7448044d54f921 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 27 Nov 2006 18:41:30 +0100 Subject: USB: removing ifdefed code from gl620a as David has objected to the patch against the gl620a driver, here's a patch implementing David' suggestion of removing the incomplete ifdefed code from the gl620a driver. Signed-off-by: Oliver Neukum Signed-off-by: David Brownell --- drivers/usb/net/gl620a.c | 154 ----------------------------------------------- 1 file changed, 154 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index a3242be2195..a6f0f4d934d 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -79,160 +79,6 @@ struct gl_header { struct gl_packet packets; }; -#ifdef GENELINK_ACK - -// FIXME: this code is incomplete, not debugged; it doesn't -// handle interrupts correctly; it should use the generic -// status IRQ code (which didn't exist back in 2001). - -struct gl_priv { - struct urb *irq_urb; - char irq_buf [INTERRUPT_BUFSIZE]; -}; - -static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value) -{ - int retval; - - retval = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - value, - 0, // index - 0, // data buffer - 0, // size - USB_CTRL_SET_TIMEOUT); - return retval; -} - -static void gl_interrupt_complete(struct urb *urb) -{ - int status = urb->status; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __FUNCTION__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); - } - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - -static int gl_interrupt_read(struct usbnet *dev) -{ - struct gl_priv *priv = dev->priv_data; - int retval; - - // issue usb interrupt read - if (priv && priv->irq_urb) { - // submit urb - if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0) - dbg("gl_interrupt_read: submit fail - %X...", retval); - else - dbg("gl_interrupt_read: submit success..."); - } - - return 0; -} - -// check whether another side is connected -static int genelink_check_connect(struct usbnet *dev) -{ - int retval; - - dbg("genelink_check_connect..."); - - // detect whether another side is connected - if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) { - dbg("%s: genelink_check_connect write fail - %X", - dev->net->name, retval); - return retval; - } - - // usb interrupt read to ack another side - if ((retval = gl_interrupt_read(dev)) != 0) { - dbg("%s: genelink_check_connect read fail - %X", - dev->net->name, retval); - return retval; - } - - dbg("%s: genelink_check_connect read success", dev->net->name); - return 0; -} - -// allocate and initialize the private data for genelink -static int genelink_init(struct usbnet *dev) -{ - struct gl_priv *priv; - - // allocate the private data structure - if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) { - dbg("%s: cannot allocate private data per device", - dev->net->name); - return -ENOMEM; - } - - // allocate irq urb - if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) { - dbg("%s: cannot allocate private irq urb per device", - dev->net->name); - kfree(priv); - return -ENOMEM; - } - - // fill irq urb - usb_fill_int_urb(priv->irq_urb, dev->udev, - usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE), - priv->irq_buf, INTERRUPT_BUFSIZE, - gl_interrupt_complete, 0, - GENELINK_INTERRUPT_INTERVAL); - - // set private data pointer - dev->priv_data = priv; - - return 0; -} - -// release the private data -static int genelink_free(struct usbnet *dev) -{ - struct gl_priv *priv = dev->priv_data; - - if (!priv) - return 0; - -// FIXME: can't cancel here; it's synchronous, and -// should have happened earlier in any case (interrupt -// handling needs to be generic) - - // cancel irq urb first - usb_kill_urb(priv->irq_urb); - - // free irq urb - usb_free_urb(priv->irq_urb); - - // free the private data structure - kfree(priv); - - return 0; -} - -#endif - static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { struct gl_header *header; -- cgit v1.2.3 From b1cff285ae8d21012ad3717e412b0f50066dc061 Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 4 Dec 2006 16:43:01 +0000 Subject: usb serial: Eliminate bogus ioctl code Several drivers have bogus ioctl code that tries unneccessarily to override the standard processing. In the three cases here the actual code is not only wrong but also not required as they implement the proper set_termios method as well. Remove the junk. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cypress_m8.c | 15 --------- drivers/usb/serial/kl5kusb105.c | 68 ----------------------------------------- drivers/usb/serial/mos7840.c | 6 ---- 3 files changed, 89 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 45cdf9bc43b..6bc1f404e18 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -962,21 +962,6 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi cypress_set_termios(port, &priv->tmp_termios); return (0); break; - /* these are called when setting baud rate from gpsd */ - case TCGETS: - if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { - return -EFAULT; - } - return (0); - break; - case TCSETS: - if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { - return -EFAULT; - } - /* here we need to call cypress_set_termios to invoke the new settings */ - cypress_set_termios(port, &priv->tmp_termios); - return (0); - break; /* This code comes from drivers/char/serial.c and ftdi_sio.c */ case TIOCMIWAIT: while (priv != NULL) { diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 73d755df484..5c4b06a99ac 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -87,10 +87,6 @@ static int klsi_105_write_room (struct usb_serial_port *port); static void klsi_105_read_bulk_callback (struct urb *urb); static void klsi_105_set_termios (struct usb_serial_port *port, struct ktermios *old); -static int klsi_105_ioctl (struct usb_serial_port *port, - struct file * file, - unsigned int cmd, - unsigned long arg); static void klsi_105_throttle (struct usb_serial_port *port); static void klsi_105_unthrottle (struct usb_serial_port *port); /* @@ -140,7 +136,6 @@ static struct usb_serial_driver kl5kusb105d_device = { .chars_in_buffer = klsi_105_chars_in_buffer, .write_room = klsi_105_write_room, .read_bulk_callback =klsi_105_read_bulk_callback, - .ioctl = klsi_105_ioctl, .set_termios = klsi_105_set_termios, /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, @@ -899,69 +894,6 @@ static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file, */ return retval; } - -static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct klsi_105_private *priv = usb_get_serial_port_data(port); - void __user *user_arg = (void __user *)arg; - - dbg("%scmd=0x%x", __FUNCTION__, cmd); - - /* Based on code from acm.c and others */ - switch (cmd) { - case TIOCMIWAIT: - /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ - /* TODO */ - dbg("%s - TIOCMIWAIT not handled", __FUNCTION__); - return -ENOIOCTLCMD; - case TIOCGICOUNT: - /* return count of modemline transitions */ - /* TODO */ - dbg("%s - TIOCGICOUNT not handled", __FUNCTION__); - return -ENOIOCTLCMD; - case TCGETS: - /* return current info to caller */ - dbg("%s - TCGETS data faked/incomplete", __FUNCTION__); - - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) - return -EFAULT; - - if (kernel_termios_to_user_termios((struct termios __user *)arg, - &priv->termios)) - return -EFAULT; - return 0; - case TCSETS: - /* set port termios to the one given by the user */ - dbg("%s - TCSETS not handled", __FUNCTION__); - - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) - return -EFAULT; - - if (user_termios_to_kernel_termios(&priv->termios, - (struct termios __user *)arg)) - return -EFAULT; - klsi_105_set_termios(port, &priv->termios); - return 0; - case TCSETSW: { - /* set port termios and try to wait for completion of last - * write operation */ - /* We guess here. If there are not too many write urbs - * outstanding, we lie. */ - /* what is the right way to wait here? schedule() ? */ - /* - while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE) - schedule(); - */ - return -ENOIOCTLCMD; - } - default: - dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd); - return(-ENOIOCTLCMD); - break; - } - return 0; -} /* klsi_105_ioctl */ static void klsi_105_throttle (struct usb_serial_port *port) { diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 8cc728a49e4..83f661403ba 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2460,12 +2460,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, tty_ldisc_deref(ld); return 0; - case TCGETS: - if (kernel_termios_to_user_termios - ((struct termios __user *)argp, tty->termios)) - return -EFAULT; - return 0; - case TIOCSERGETLSR: dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); return mos7840_get_lsr_info(mos7840_port, argp); -- cgit v1.2.3 From 8e42266965b9db03a86d2cf55400cd3afb67a114 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sun, 3 Dec 2006 09:46:35 +0100 Subject: USB: mutexification of usblp this patch: - converts usblp fully to mutex - makes sleeping interruptible where EINTR can be returned anyway Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 54 +++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 6303970e93c..24ee8be359f 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -130,7 +130,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H struct usblp { struct usb_device *dev; /* USB device */ - struct semaphore sem; /* locks this struct, especially "dev" */ + struct mutex mut; /* locks this struct, especially "dev" */ char *writebuf; /* write transfer_buffer */ char *readbuf; /* read transfer_buffer */ char *statusbuf; /* status transfer_buffer */ @@ -465,7 +465,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int twoints[2]; int retval = 0; - down (&usblp->sem); + mutex_lock (&usblp->mut); if (!usblp->present) { retval = -ENODEV; goto done; @@ -644,14 +644,14 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } done: - up (&usblp->sem); + mutex_unlock (&usblp->mut); return retval; } static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - int timeout, rv, err = 0, transfer_length = 0; + int timeout, intr, rv, err = 0, transfer_length = 0; size_t writecount = 0; while (writecount < count) { @@ -668,14 +668,16 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if (rv < 0) return writecount ? writecount : -EINTR; } - down (&usblp->sem); + intr = mutex_lock_interruptible (&usblp->mut); + if (intr) + return writecount ? writecount : -EINTR; if (!usblp->present) { - up (&usblp->sem); + mutex_unlock (&usblp->mut); return -ENODEV; } if (usblp->sleeping) { - up (&usblp->sem); + mutex_unlock (&usblp->mut); return writecount ? writecount : -ENODEV; } @@ -687,10 +689,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t err = usblp->writeurb->status; } else err = usblp_check_status(usblp, err); - up (&usblp->sem); + mutex_unlock (&usblp->mut); /* if the fault was due to disconnect, let khubd's - * call to usblp_disconnect() grab usblp->sem ... + * call to usblp_disconnect() grab usblp->mut ... */ schedule (); continue; @@ -702,7 +704,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t */ writecount += transfer_length; if (writecount == count) { - up(&usblp->sem); + mutex_unlock(&usblp->mut); break; } @@ -714,7 +716,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) { - up(&usblp->sem); + mutex_unlock(&usblp->mut); return writecount ? writecount : -EFAULT; } @@ -727,10 +729,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count = -EIO; else count = writecount ? writecount : -ENOMEM; - up (&usblp->sem); + mutex_unlock (&usblp->mut); break; } - up (&usblp->sem); + mutex_unlock (&usblp->mut); } return count; @@ -739,12 +741,14 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - int rv; + int rv, intr; if (!usblp->bidir) return -EINVAL; - down (&usblp->sem); + intr = mutex_lock_interruptible (&usblp->mut); + if (intr) + return -EINTR; if (!usblp->present) { count = -ENODEV; goto done; @@ -757,9 +761,9 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, count = -EAGAIN; goto done; } - up(&usblp->sem); + mutex_unlock(&usblp->mut); rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present); - down(&usblp->sem); + mutex_lock(&usblp->mut); if (rv < 0) { count = -EINTR; goto done; @@ -807,7 +811,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, } done: - up (&usblp->sem); + mutex_unlock (&usblp->mut); return count; } @@ -886,7 +890,7 @@ static int usblp_probe(struct usb_interface *intf, goto abort; } usblp->dev = dev; - init_MUTEX (&usblp->sem); + mutex_init (&usblp->mut); init_waitqueue_head(&usblp->wait); usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; usblp->intf = intf; @@ -1178,7 +1182,7 @@ static void usblp_disconnect(struct usb_interface *intf) device_remove_file(&intf->dev, &dev_attr_ieee1284_id); mutex_lock (&usblp_mutex); - down (&usblp->sem); + mutex_lock (&usblp->mut); usblp->present = 0; usb_set_intfdata (intf, NULL); @@ -1187,7 +1191,7 @@ static void usblp_disconnect(struct usb_interface *intf) usblp->writebuf, usblp->writeurb->transfer_dma); usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, usblp->readbuf, usblp->readurb->transfer_dma); - up (&usblp->sem); + mutex_unlock (&usblp->mut); if (!usblp->used) usblp_cleanup (usblp); @@ -1200,11 +1204,11 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message) /* this races against normal access and open */ mutex_lock (&usblp_mutex); - down (&usblp->sem); + mutex_lock (&usblp->mut); /* we take no more IO */ usblp->sleeping = 1; usblp_unlink_urbs(usblp); - up (&usblp->sem); + mutex_unlock (&usblp->mut); mutex_unlock (&usblp_mutex); return 0; @@ -1216,12 +1220,12 @@ static int usblp_resume (struct usb_interface *intf) int r; mutex_lock (&usblp_mutex); - down (&usblp->sem); + mutex_lock (&usblp->mut); usblp->sleeping = 0; r = handle_bidir (usblp); - up (&usblp->sem); + mutex_unlock (&usblp->mut); mutex_unlock (&usblp_mutex); return r; -- cgit v1.2.3 From e05998d50d0bf9de5409a178e2f9869c7d1ea83e Mon Sep 17 00:00:00 2001 From: Johannes Hoelzl Date: Sat, 2 Dec 2006 16:54:27 +0100 Subject: Add Baltech Reader ID to CP2101 driver this patch adds the Baltech Reader ID to the list of USB IDs in the CP2101 driver. From: Johannes Hoelzl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 2f9b7ac3266..7ebaffd6ed8 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -69,6 +69,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; -- cgit v1.2.3 From c2585d962572744271a7e254d48c747727441936 Mon Sep 17 00:00:00 2001 From: David Clare Date: Fri, 1 Dec 2006 18:24:38 -0800 Subject: USB: Prevent the funsoft serial device from entering raw mode Added a device specific ioctl function to prevent the disabling of canonical mode. EINVAL is returned for any TCSETSF ioctl that doesn't have ICANON set. This patch is for 2.6.17 or later kernels. When "hwinfo --modem" is executed it opens the funsoft USB serial device and disables canonical mode. The device is kept this way until hwininfo has finished probing any modems on a system. The funsoft device expects to be running in canonical mode. Switching the device to raw mode can cause incomplete data packets and device timeouts. Signed-off-by: David Clare Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/funsoft.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 77b977206a8..d3be9214c7c 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -14,6 +14,9 @@ #include #include #include +#include + +static int debug; static struct usb_device_id id_table [] = { { USB_DEVICE(0x1404, 0xcddc) }, @@ -21,6 +24,26 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); +static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct termios t; + + dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); + + if (cmd == TCSETSF) { + if (user_termios_to_kernel_termios(&t, (void __user *)arg)) + return -EFAULT; + + dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, + t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); + + if (!(t.c_lflag & ICANON)) + return -EINVAL; + } + return -ENOIOCTLCMD; +} + static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -39,6 +62,7 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, + .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) @@ -63,3 +87,6 @@ static void __exit funsoft_exit(void) module_init(funsoft_init); module_exit(funsoft_exit); MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); -- cgit v1.2.3 From abc9404bb0bcfa8677ab5978b2c8b60ab5ef7536 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 3 Dec 2006 20:53:58 -0500 Subject: USB: fix ohci.h over-use warnings When u132-hcd is built, it includes local header ohci.h, which appears to have been intended only for use by ohci-hcd. This throws warnings about functions which are defined and not used. The warnings thrown are because three small functions are implemented in the header, but not declared 'inline', a rather strange affair. Since these functions are small, let's go ahead and define them as 'inline', just like the inline functions surrounding them. This makes things more consistent, and kills the warnings. Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index a2f42a2f47c..fd93e7eca7b 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -602,7 +602,7 @@ static inline void disable (struct ohci_hcd *ohci) #define FIT (1 << 31) #define LSTHRESH 0x628 /* lowspeed bit threshold */ -static void periodic_reinit (struct ohci_hcd *ohci) +static inline void periodic_reinit (struct ohci_hcd *ohci) { u32 fi = ohci->fminterval & 0x03fff; u32 fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT; @@ -626,11 +626,11 @@ static void periodic_reinit (struct ohci_hcd *ohci) temp = ohci_readl (hc, &hc->regs->roothub.register); \ temp; }) -static u32 roothub_a (struct ohci_hcd *hc) +static inline u32 roothub_a (struct ohci_hcd *hc) { return read_roothub (hc, a, 0xfc0fe000); } static inline u32 roothub_b (struct ohci_hcd *hc) { return ohci_readl (hc, &hc->regs->roothub.b); } static inline u32 roothub_status (struct ohci_hcd *hc) { return ohci_readl (hc, &hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci_hcd *hc, int i) +static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i) { return read_roothub (hc, portstatus [i], 0xffe0fce0); } -- cgit v1.2.3 From 5859271ebd6c60d7d946bbbb6b485e164c6c614a Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Mon, 4 Dec 2006 14:27:36 +0200 Subject: USB: rtl8150 new device id This one adds another vendor ID to rtl8150 driver. Please apply. Signed-off-by: Petko Manolov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/rtl8150.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index c54235f73cb..e0eecda78ec 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -124,10 +124,11 @@ #define RX_URB_FAIL 3 /* Define these values to match your device */ -#define VENDOR_ID_REALTEK 0x0bda +#define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_MELCO 0x0411 -#define VENDOR_ID_MICRONET 0x3980 +#define VENDOR_ID_MICRONET 0x3980 #define VENDOR_ID_LONGSHINE 0x07b8 +#define VENDOR_ID_OQO 0x1557 #define VENDOR_ID_ZYXEL 0x0586 #define PRODUCT_ID_RTL8150 0x8150 @@ -144,6 +145,7 @@ static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, + {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)}, {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)}, {} }; -- cgit v1.2.3 From 16c76865df40357027479b6d85f59a07f8d01c8d Mon Sep 17 00:00:00 2001 From: Johann Wilhelm Date: Sat, 2 Dec 2006 07:16:32 +0100 Subject: usb-storage: Ignore the virtual cd-drive of the Huawei E220 USB Modem This prevents the kernel from detecting the virtual cd-drive with the Windows drivers. Signed-off-by: Johann Wilhelm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index db8b26012c7..7640bdd4fff 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1328,6 +1328,15 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* This prevents the kernel from detecting the virtual cd-drive with the + * Windows drivers. +*/ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff, + "HUAWEI", + "E220 USB-UMTS Install", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE), + /* Reported by Vilius Bilinkevicius Date: Sat, 2 Dec 2006 07:25:31 +0100 Subject: usb-gsm-driver: Added VendorId and ProductId for Huawei E220 USB Modem Added VendorId and ProductId for Huawei E220 USB Modem Signed-off-by: Johann Wilhelm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0ae4098718c..819266b7e2f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -79,6 +79,7 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_PRODUCT_COBRA 0x6500 #define OPTION_PRODUCT_COBRA2 0x6600 #define HUAWEI_PRODUCT_E600 0x1001 +#define HUAWEI_PRODUCT_E220 0x1003 #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 #define NOVATELWIRELESS_PRODUCT_U740 0x1400 #define ANYDATA_PRODUCT_ID 0x6501 @@ -90,6 +91,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, @@ -103,6 +105,7 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, -- cgit v1.2.3 From 071e0a2aee9c289f50b9329d0c26474ca94f7c7a Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 5 Dec 2006 17:09:51 -0800 Subject: USB: fix Wacom Intuos3 4x6 bugs Fixes Intuos3 4x6 bugs Signed-off-by: Ping Cheng Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/wacom_sys.c | 4 ++-- drivers/usb/input/wacom_wac.c | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index e7cc20ab815..12b42746ded 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -159,13 +159,13 @@ void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); - input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); + input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); } void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); - input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); + input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); } void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index 92726fe8937..4142e36730f 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -209,13 +209,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04); } - } - - if (data[1] & 0x10) wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */ + } else wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - wacom_report_key(wcombo, wacom->tool[0], data[1] & 0x10); + + if (data[1] & 0x10) /* only report prox-in when in area */ + wacom_report_key(wcombo, wacom->tool[0], 1); + if (!(data[1] & 0x90)) /* report prox-out when physically out */ + wacom_report_key(wcombo, wacom->tool[0], 0); wacom_input_sync(wcombo); /* send pad data */ @@ -405,7 +407,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) return 0; - if (wacom->features->type >= INTUOS3) { + if (wacom->features->type >= INTUOS3S) { wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); @@ -423,7 +425,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (data[1] & 0x02) { /* Rotation packet */ - if (wacom->features->type >= INTUOS3) { + if (wacom->features->type >= INTUOS3S) { /* I3 marker pen rotation reported as wheel * due to valuator limitation */ @@ -547,11 +549,11 @@ static struct wacom_features wacom_features[] = { { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, - { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE }, - { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE }, - { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE }, - { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE }, - { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Volito", 8, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE }, + { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, + { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE }, { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, @@ -580,7 +582,7 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S }, + { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { } -- cgit v1.2.3 From 66eb2e93b99b79bd3d55ecea2098a8369c1ded0d Mon Sep 17 00:00:00 2001 From: Burman Yan Date: Mon, 4 Dec 2006 15:22:40 -0800 Subject: USB AUERSWALD: replace kmalloc+memset with kzalloc Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/auerswald.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 6c7f3efb1d4..b5332e679c4 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -1376,7 +1376,7 @@ static int auerchar_open (struct inode *inode, struct file *file) } /* we have access to the device. Now lets allocate memory */ - ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); + ccp = kzalloc(sizeof(auerchar_t), GFP_KERNEL); if (ccp == NULL) { err ("out of memory"); ret = -ENOMEM; @@ -1384,7 +1384,6 @@ static int auerchar_open (struct inode *inode, struct file *file) } /* Initialize device descriptor */ - memset( ccp, 0, sizeof(auerchar_t)); init_MUTEX( &ccp->mutex); init_MUTEX( &ccp->readmutex); auerbuf_init (&ccp->bufctl); @@ -1912,14 +1911,13 @@ static int auerswald_probe (struct usb_interface *intf, return -ENODEV; /* allocate memory for our device and initialize it */ - cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL); + cp = kzalloc (sizeof(auerswald_t), GFP_KERNEL); if (cp == NULL) { err ("out of memory"); goto pfail; } /* Initialize device descriptor */ - memset (cp, 0, sizeof(auerswald_t)); init_MUTEX (&cp->mutex); cp->usbdev = usbdev; auerchain_init (&cp->controlchain); -- cgit v1.2.3 From fe1ec341df1b510e5e614ccdad4a89273d6f6fe8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 4 Dec 2006 15:22:40 -0800 Subject: USB: Nokia E70 is an unusual device Taken from http://bugzilla.kernel.org/show_bug.cgi?id=7508 When the Nokia E70 Phone is plugged in to the USB port, I get: end_request: I/O error, dev sda, sector 1824527 sd 0:0:0:0: SCSI error: return code = 0x10070000 end_request: I/O error, dev sda, sector 1824535 sd 0:0:0:0: SCSI error: return code = 0x10070000 The fix is to add these lines to drivers/usb/storage/unusual_devs.h: Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 7640bdd4fff..5fe7ff441a0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -153,6 +153,13 @@ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by */ +UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, + "Nokia", + "E70", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), + /* Reported by Jon Hart */ UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, "Nokia", -- cgit v1.2.3 From 5f8364b7d63acdc2216ca0f7d0a8557c318479ea Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 5 Dec 2006 16:29:55 -0500 Subject: UHCI: module parameter to ignore overcurrent changes Certain boards seem to like to issue false overcurrent notifications, for example on ports that don't have anything connected to them. This looks like a hardware error, at the level of noise to those ports' overcurrent input signals (or non-debounced VBUS comparators). This surfaces to users as truly massive amounts of syslog spam from khubd (which is appropriate for real hardware problems, except for the volume from multiple ports). Using this new "ignore_oc" flag helps such systems work more sanely, by preventing such indications from getting to khubd (and spamming syslog). The downside is of course that true overcurrent errors will be masked; they'll appear as spontaneous disconnects, without the diagnostics that will let users troubleshoot issues like short-circuited cables. In addition, controllers with no devices attached will be forced to poll for new devices rather than relying on interrupts, since each overcurrent event would generate a new interrupt. This patch (as826) is essentially a copy of David Brownell's ignore_oc patch for ehci-hcd, ported to uhci-hcd. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 13 ++++++++++++- drivers/usb/host/uhci-hub.c | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e87692c31be..acd101caeee 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -60,6 +60,11 @@ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ Alan Stern" #define DRIVER_DESC "USB Universal Host Controller Interface driver" +/* for flakey hardware, ignore overcurrent indicators */ +static int ignore_oc; +module_param(ignore_oc, bool, S_IRUGO); +MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); + /* * debug = 0, no debugging messages * debug = 1, dump failed URBs except for stalls @@ -169,6 +174,11 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) { int port; + /* If we have to ignore overcurrent events then almost by definition + * we can't depend on resume-detect interrupts. */ + if (ignore_oc) + return 1; + switch (to_pci_dev(uhci_dev(uhci))->vendor) { default: break; @@ -921,7 +931,8 @@ static int __init uhci_hcd_init(void) { int retval = -ENOMEM; - printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n"); + printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s\n", + ignore_oc ? ", overcurrent ignored" : ""); if (usb_disabled()) return -ENODEV; diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index f8347f1a10b..bacc25c53ba 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -52,10 +52,20 @@ static int any_ports_active(struct uhci_hcd *uhci) static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) { int port; + int mask = RWC_BITS; + + /* Some boards (both VIA and Intel apparently) report bogus + * overcurrent indications, causing massive log spam unless + * we completely ignore them. This doesn't seem to be a problem + * with the chipset so much as with the way it is connected on + * the motherboard; if the overcurrent input is left to float + * then it may constantly register false positives. */ + if (ignore_oc) + mask &= ~USBPORTSC_OCC; *buf = 0; for (port = 0; port < uhci->rh_numports; ++port) { - if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || + if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & mask) || test_bit(port, &uhci->port_c_suspend)) *buf |= (1 << (port + 1)); } @@ -263,7 +273,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wPortChange |= USB_PORT_STAT_C_CONNECTION; if (status & USBPORTSC_PEC) wPortChange |= USB_PORT_STAT_C_ENABLE; - if (status & USBPORTSC_OCC) + if ((status & USBPORTSC_OCC) && !ignore_oc) wPortChange |= USB_PORT_STAT_C_OVERCURRENT; if (test_bit(port, &uhci->port_c_suspend)) { -- cgit v1.2.3 From 6bea476cf628eb7bb18a036ac6a8fed1ad319951 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 5 Dec 2006 03:15:33 -0800 Subject: USB: gadget driver unbind() is optional; section fixes; misc Allow gadget drivers to omit the unbind() method. When they're statically linked, that's an appropriate memory saving tweak. Similarly, provide consistent/simpler handling for a should-not-happen error case: removing a peripheral controller driver when a gadget driver is still loaded. Such code dates back to early versions of the first implementation of the gadget API, and has never been triggered. Includes relevant section annotation fixs for gmidi.c, file_storage.c, and serial.c; we don't yet have an "init or exit" annotation. Also some whitespace fixes in gmidi.c (space at EOL, before tabs, etc). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 9 ++++----- drivers/usb/gadget/dummy_hcd.c | 7 ++++--- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/gmidi.c | 12 ++++++------ drivers/usb/gadget/goku_udc.c | 12 +++--------- drivers/usb/gadget/lh7a40x_udc.c | 13 ++++++++----- drivers/usb/gadget/net2280.c | 11 ++--------- drivers/usb/gadget/omap_udc.c | 13 ++++++++----- drivers/usb/gadget/pxa2xx_udc.c | 7 ++++--- drivers/usb/gadget/serial.c | 2 +- 10 files changed, 41 insertions(+), 47 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 3e0abbb49fe..81656337381 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1574,7 +1574,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->setup) { DBG("bad parameter.\n"); return -EINVAL; @@ -1611,7 +1610,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { struct at91_udc *udc = &controller; - if (!driver || driver != udc->driver) + if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; local_irq_disable(); @@ -1731,10 +1730,10 @@ static int __devexit at91udc_remove(struct platform_device *pdev) DBG("remove\n"); - pullup(udc, 0); + if (udc->driver) + return -EBUSY; - if (udc->driver != 0) - usb_gadget_unregister_driver(udc->driver); + pullup(udc, 0); device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f1f32d7be5f..3c2bc075ef4 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -779,7 +779,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) return -EINVAL; if (dum->driver) return -EBUSY; - if (!driver->bind || !driver->unbind || !driver->setup + if (!driver->bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; @@ -837,7 +837,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) err_bind_driver: driver_unregister (&driver->driver); err_register: - driver->unbind (&dum->gadget); + if (driver->unbind) + driver->unbind (&dum->gadget); spin_lock_irq (&dum->lock); dum->pullup = 0; set_link_state (dum); @@ -857,7 +858,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!dum) return -ENODEV; - if (!driver || driver != dum->driver) + if (!driver || driver != dum->driver || !driver->unbind) return -EINVAL; dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a265e262a2e..72f2ae96fbf 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -4100,7 +4100,7 @@ static struct usb_gadget_driver fsg_driver = { #endif .function = (char *) longname, .bind = fsg_bind, - .unbind = __exit_p(fsg_unbind), + .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, .suspend = fsg_suspend, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 31351826f2b..f1a679656c9 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -123,7 +123,7 @@ struct gmidi_device { struct usb_request *req; /* for control responses */ u8 config; struct usb_ep *in_ep, *out_ep; - struct snd_card *card; + struct snd_card *card; struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *in_substream; struct snd_rawmidi_substream *out_substream; @@ -490,7 +490,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req) int status = req->status; switch (status) { - case 0: /* normal completion */ + case 0: /* normal completion */ if (ep == dev->out_ep) { /* we received stuff. req is queued again, below */ @@ -505,7 +505,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req) break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -656,7 +656,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -1308,7 +1308,7 @@ static struct usb_gadget_driver gmidi_driver = { .speed = USB_SPEED_FULL, .function = (char *)longname, .bind = gmidi_bind, - .unbind = __exit_p(gmidi_unbind), + .unbind = gmidi_unbind, .setup = gmidi_setup, .disconnect = gmidi_disconnect, @@ -1316,7 +1316,7 @@ static struct usb_gadget_driver gmidi_driver = { .suspend = gmidi_suspend, .resume = gmidi_resume, - .driver = { + .driver = { .name = (char *)shortname, .owner = THIS_MODULE, }, diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 805a9826842..d0ef1d6b3fa 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1432,7 +1432,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1495,7 +1494,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); @@ -1808,13 +1807,8 @@ static void goku_remove(struct pci_dev *pdev) struct goku_udc *dev = pci_get_drvdata(pdev); DBG(dev, "%s\n", __FUNCTION__); - /* start with the driver above us */ - if (dev->driver) { - /* should have been done already by driver model core */ - WARN(dev, "pci remove, driver '%s' is still registered\n", - dev->driver->driver.name); - usb_gadget_unregister_driver(dev->driver); - } + + BUG_ON(dev->driver); #ifdef CONFIG_USB_GADGET_DEBUG_FILES remove_proc_entry(proc_node_name, NULL); diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 4a991564a03..a0a73c08a34 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -422,9 +422,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name); if (!driver - || driver->speed != USB_SPEED_FULL - || !driver->bind - || !driver->unbind || !driver->disconnect || !driver->setup) + || driver->speed != USB_SPEED_FULL + || !driver->bind + || !driver->disconnect + || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; @@ -471,7 +472,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); @@ -2125,9 +2126,11 @@ static int lh7a40x_udc_remove(struct platform_device *pdev) DEBUG("%s: %p\n", __FUNCTION__, pdev); + if (dev->driver) + return -EBUSY; + udc_disable(dev); remove_proc_files(); - usb_gadget_unregister_driver(dev->driver); free_irq(IRQ_USBINTR, dev); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 3024c679e38..569eb8ccf23 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2020,7 +2020,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_HIGH || !driver->bind - || !driver->unbind || !driver->setup) return -EINVAL; if (!dev) @@ -2107,7 +2106,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave (&dev->lock, flags); @@ -2803,13 +2802,7 @@ static void net2280_remove (struct pci_dev *pdev) { struct net2280 *dev = pci_get_drvdata (pdev); - /* start with the driver above us */ - if (dev->driver) { - /* should have been done already by driver model core */ - WARN (dev, "pci remove, driver '%s' is still registered\n", - dev->driver->driver.name); - usb_gadget_unregister_driver (dev->driver); - } + BUG_ON(dev->driver); /* then clean up the resources we allocated during probe() */ net2280_led_shutdown (dev); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 030d87c28c2..15d77c30793 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2043,7 +2043,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) // FIXME if otg, check: driver->is_otg || driver->speed < USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->setup) return -EINVAL; @@ -2087,9 +2086,11 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) status = otg_set_peripheral(udc->transceiver, &udc->gadget); if (status < 0) { ERR("can't bind to transceiver\n"); - driver->unbind (&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; + if (driver->unbind) { + driver->unbind (&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + } goto done; } } else { @@ -2117,7 +2118,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!udc) return -ENODEV; - if (!driver || driver != udc->driver) + if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; if (machine_is_omap_innovator() || machine_is_omap_osk()) @@ -2870,6 +2871,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev) if (!udc) return -ENODEV; + if (udc->driver) + return -EBUSY; udc->done = &done; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1ed506e9598..b78de969466 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1623,7 +1623,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1694,7 +1693,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; local_irq_disable(); @@ -2638,9 +2637,11 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) { struct pxa2xx_udc *dev = platform_get_drvdata(pdev); + if (dev->driver) + return -EBUSY; + udc_disable(dev); remove_proc_files(); - usb_gadget_unregister_driver(dev->driver); if (dev->got_irq) { free_irq(IRQ_USB, dev); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 2d12bf9f19d..f8a3ec64635 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -296,7 +296,7 @@ static struct usb_gadget_driver gs_gadget_driver = { #endif /* CONFIG_USB_GADGET_DUALSPEED */ .function = GS_LONG_NAME, .bind = gs_bind, - .unbind = __exit_p(gs_unbind), + .unbind = gs_unbind, .setup = gs_setup, .disconnect = gs_disconnect, .driver = { -- cgit v1.2.3 From dd9048af41d017f5f9ea18fb451a3b5dc89d6b83 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 5 Dec 2006 03:18:31 -0800 Subject: USB: ohci whitespace/comment fixups This is an OHCI cleanup patch ... it removes a lot of erroneous whitespace (space before tab, at end of line) as well as the obsolete inline changelog. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 2 +- drivers/usb/host/ohci-au1xxx.c | 4 +- drivers/usb/host/ohci-dbg.c | 8 +-- drivers/usb/host/ohci-ep93xx.c | 2 +- drivers/usb/host/ohci-hcd.c | 106 ++++++++++------------------------------ drivers/usb/host/ohci-hub.c | 12 ++--- drivers/usb/host/ohci-lh7a404.c | 8 +-- drivers/usb/host/ohci-mem.c | 10 ++-- drivers/usb/host/ohci-omap.c | 4 +- drivers/usb/host/ohci-pci.c | 16 +++--- drivers/usb/host/ohci-pnx4008.c | 4 +- drivers/usb/host/ohci-ppc-soc.c | 8 +-- drivers/usb/host/ohci-pxa27x.c | 10 ++-- drivers/usb/host/ohci-q.c | 103 +++++++++++++++++++------------------- drivers/usb/host/ohci-s3c2410.c | 4 +- drivers/usb/host/ohci-sa1111.c | 8 +-- drivers/usb/host/ohci.h | 86 ++++++++++++++++---------------- 17 files changed, 169 insertions(+), 226 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index b466581beb4..f15c84ea286 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -221,7 +221,7 @@ static const struct hc_driver ohci_at91_hc_driver = { */ .start = ohci_at91_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 24e23c5783d..e70b2430e2a 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -269,7 +269,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .start = ohci_au1xxx_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -336,7 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_au1xxx_driver = { .probe = ohci_hcd_au1xxx_drv_probe, .remove = ohci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_au1xxx_drv_suspend, */ /*.resume = ohci_hcd_au1xxx_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 0f47a57dac2..273d5ddb72b 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -16,7 +16,7 @@ case PIPE_CONTROL: temp = "ctrl"; break; \ case PIPE_BULK: temp = "bulk"; break; \ case PIPE_INTERRUPT: temp = "intr"; break; \ - default: temp = "isoc"; break; \ + default: temp = "isoc"; break; \ }; temp;}) #define pipestring(pipe) edstring(usb_pipetype(pipe)) @@ -205,13 +205,13 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) (temp & RH_PS_PSSC) ? " PSSC" : "", \ (temp & RH_PS_PESC) ? " PESC" : "", \ (temp & RH_PS_CSC) ? " CSC" : "", \ - \ + \ (temp & RH_PS_LSDA) ? " LSDA" : "", \ (temp & RH_PS_PPS) ? " PPS" : "", \ (temp & RH_PS_PRS) ? " PRS" : "", \ (temp & RH_PS_POCI) ? " POCI" : "", \ (temp & RH_PS_PSS) ? " PSS" : "", \ - \ + \ (temp & RH_PS_PES) ? " PES" : "", \ (temp & RH_PS_CCS) ? " CCS" : "" \ ); @@ -563,7 +563,7 @@ show_periodic (struct class_device *class_dev, char *buf) (info & ED_SKIP) ? " K" : "", (ed->hwHeadP & cpu_to_hc32(ohci, ED_H)) ? - " H" : ""); + " H" : ""); size -= temp; next += temp; diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 1bf5e7a4e73..43ae696b2ec 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -204,7 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) static struct platform_driver ohci_hcd_ep93xx_driver = { .probe = ohci_hcd_ep93xx_drv_probe, .remove = ohci_hcd_ep93xx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_hcd_ep93xx_drv_suspend, .resume = ohci_hcd_ep93xx_drv_resume, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index b28a9b60206..c31f00b7ab4 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -3,77 +3,21 @@ * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2004 David Brownell - * + * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] * [ (C) Copyright 1999 Linus Torvalds ] * [ (C) Copyright 1999 Gregory P. Smith] - * - * + * + * * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller * interfaces (though some non-x86 Intel chips use it). It supports * smarter hardware than UHCI. A download link for the spec available * through the http://www.usb.org website. * - * History: - * - * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer) - * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net) - * 2003/02/24 show registers in sysfs (Kevin Brosius) - * - * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and - * bandwidth accounting; if debugging, show schedules in driverfs - * 2002/07/19 fixes to management of ED and schedule state. - * 2002/06/09 SA-1111 support (Christopher Hoover) - * 2002/06/01 remember frame when HC won't see EDs any more; use that info - * to fix urb unlink races caused by interrupt latency assumptions; - * minor ED field and function naming updates - * 2002/01/18 package as a patch for 2.5.3; this should match the - * 2.4.17 kernel modulo some bugs being fixed. - * - * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes - * from post-2.4.5 patches. - * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning - * 2001/09/07 match PCI PM changes, errnos from Linus' tree - * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify; - * pbook pci quirks gone (please fix pbook pci sw!) (db) - * - * 2001/04/08 Identify version on module load (gb) - * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam); - pci_map_single (db) - * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db) - * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam) - * - * 2000/09/26 fixed races in removing the private portion of the urb - * 2000/09/07 disable bulk and control lists when unlinking the last - * endpoint descriptor in order to avoid unrecoverable errors on - * the Lucent chips. (rwc@sgi) - * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some - * urb unlink probs, indentation fixes - * 2000/08/11 various oops fixes mostly affecting iso and cleanup from - * device unplugs. - * 2000/06/28 use PCI hotplug framework, for better power management - * and for Cardbus support (David Brownell) - * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling - * when the controller loses power; handle UE; cleanup; ... - * - * v5.2 1999/12/07 URB 3rd preview, - * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi) - * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume - * i386: HUB, Keyboard, Mouse, Printer - * - * v4.3 1999/10/27 multiple HCs, bulk_request - * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes - * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl. - * v4.0 1999/08/18 - * v3.0 1999/06/25 - * v2.1 1999/05/09 code clean up - * v2.0 1999/05/04 - * v1.0 1999/04/27 initial release - * * This file is licenced under the GPL. */ - + #include #include #include @@ -89,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -183,11 +127,11 @@ static int ohci_urb_enqueue ( int i, size = 0; unsigned long flags; int retval = 0; - + #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "SUB", usb_pipein (pipe)); #endif - + /* every endpoint has a ed, locate and maybe (re)initialize it */ if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) return -ENOMEM; @@ -232,7 +176,7 @@ static int ohci_urb_enqueue ( memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); INIT_LIST_HEAD (&urb_priv->pending); urb_priv->length = size; - urb_priv->ed = ed; + urb_priv->ed = ed; /* allocate the TDs (deferring hash chain updates) */ for (i = 0; i < size; i++) { @@ -242,7 +186,7 @@ static int ohci_urb_enqueue ( urb_free_priv (ohci, urb_priv); return -ENOMEM; } - } + } spin_lock_irqsave (&ohci->lock, flags); @@ -313,13 +257,13 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; - + #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "UNLINK", 1); -#endif +#endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -512,11 +456,11 @@ static int ohci_init (struct ohci_hcd *ohci) /* Start an OHCI controller, set the BUS operational * resets USB and controller - * enable interrupts + * enable interrupts */ static int ohci_run (struct ohci_hcd *ohci) { - u32 mask, temp; + u32 mask, temp; int first = ohci->fminterval == 0; struct usb_hcd *hcd = ohci_to_hcd(ohci); @@ -534,7 +478,7 @@ static int ohci_run (struct ohci_hcd *ohci) /* also: power/overcurrent flags in roothub.a */ } - /* Reset USB nearly "by the book". RemoteWakeupConnected was + /* Reset USB nearly "by the book". RemoteWakeupConnected was * saved if boot firmware (BIOS/SMM/...) told us it's connected, * or if bus glue did the same (e.g. for PCI add-in cards with * PCI PM support). @@ -765,9 +709,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) dl_done_list (ohci); spin_unlock (&ohci->lock); if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } - + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -778,12 +722,12 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) finish_unlinks (ohci, ohci_frame_no(ohci)); if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); + ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); if (HC_IS_RUNNING(hcd->state)) { ohci_writel (ohci, ints, ®s->intrstatus); - ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); + ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); } @@ -794,7 +738,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ static void ohci_stop (struct usb_hcd *hcd) -{ +{ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n", @@ -812,8 +756,8 @@ static void ohci_stop (struct usb_hcd *hcd) remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { - dma_free_coherent (hcd->self.controller, - sizeof *ohci->hcca, + dma_free_coherent (hcd->self.controller, + sizeof *ohci->hcca, ohci->hcca, ohci->hcca_dma); ohci->hcca = NULL; ohci->hcca_dma = 0; @@ -836,7 +780,7 @@ static int ohci_restart (struct ohci_hcd *ohci) * recycle any "live" eds/tds (and urbs) right away. * later, khubd disconnect processing will recycle the other state, * (either as disconnect/reconnect, or maybe someday as a reset). - */ + */ spin_lock_irq(&ohci->lock); disable (ohci); usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub); @@ -875,11 +819,11 @@ static int ohci_restart (struct ohci_hcd *ohci) /* empty the interrupt branches */ for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0; - + /* no EDs to remove */ ohci->ed_rm_list = NULL; - /* empty control and bulk lists */ + /* empty control and bulk lists */ ohci->ed_controltail = NULL; ohci->ed_bulktail = NULL; diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 2441642cb7b..f9748b67e5e 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2004 David Brownell - * + * * This file is licenced under GPL */ @@ -23,13 +23,13 @@ (temp & RH_PS_PSSC) ? " PSSC" : "", \ (temp & RH_PS_PESC) ? " PESC" : "", \ (temp & RH_PS_CSC) ? " CSC" : "", \ - \ + \ (temp & RH_PS_LSDA) ? " LSDA" : "", \ (temp & RH_PS_PPS) ? " PPS" : "", \ (temp & RH_PS_PRS) ? " PRS" : "", \ (temp & RH_PS_POCI) ? " POCI" : "", \ (temp & RH_PS_PSS) ? " PSS" : "", \ - \ + \ (temp & RH_PS_PES) ? " PES" : "", \ (temp & RH_PS_CCS) ? " CCS" : "" \ ); @@ -484,7 +484,7 @@ ohci_hub_descriptor ( temp = 0; if (rh & RH_A_NPS) /* no power switching? */ temp |= 0x0002; - if (rh & RH_A_PSM) /* per-port power switching? */ + if (rh & RH_A_PSM) /* per-port power switching? */ temp |= 0x0001; if (rh & RH_A_NOCP) /* no overcurrent reporting? */ temp |= 0x0010; @@ -573,7 +573,7 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) if (!(temp & RH_PS_PRS)) break; udelay (500); - } + } if (!(temp & RH_PS_CCS)) break; diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index e121d97ed91..e9807cf73a2 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -38,7 +38,7 @@ static void lh7a404_start_hc(struct platform_device *dev) CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */ udelay(1000); USBH_CMDSTATUS = OHCI_HCR; - + printk(KERN_DEBUG __FILE__ ": Clock to USB host has been enabled \n"); } @@ -89,7 +89,7 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver, retval = -EBUSY; goto err1; } - + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { pr_debug("ioremap failed"); @@ -174,7 +174,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .start = ohci_lh7a404_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -242,7 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_lh7a404_driver = { .probe = ohci_hcd_lh7a404_drv_probe, .remove = ohci_hcd_lh7a404_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_lh7a404_drv_suspend, */ /*.resume = ohci_hcd_lh7a404_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index d976614eebd..2f20d3dc895 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -1,24 +1,24 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell - * + * * This file is licenced under the GPL. */ /*-------------------------------------------------------------------------*/ /* - * There's basically three types of memory: + * OHCI deals with three types of memory: * - data used only by the HCD ... kmalloc is fine * - async and periodic schedules, shared by HC and HCD ... these * need to use dma_pool or dma_alloc_coherent * - driver buffers, read/written by HC ... the hcd glue or the * device driver provides us with dma addresses * - * There's also PCI "register" data, which is memory mapped. - * No memory seen by this driver is pagable. + * There's also "register" data, which is memory mapped. + * No memory seen by this driver (or any HCD) may be paged out. */ /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 9c02177de50..27be1f93688 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -447,7 +447,7 @@ static const struct hc_driver ohci_omap_hc_driver = { .reset = ohci_omap_init, .start = ohci_omap_start, .stop = ohci_omap_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -533,7 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_omap_driver = { .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_omap_suspend, .resume = ohci_omap_resume, diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 87441855278..596e0b41e60 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -3,17 +3,17 @@ * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell - * + * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] * [ (C) Copyright 1999 Linus Torvalds ] * [ (C) Copyright 1999 Gregory P. Smith] - * + * * PCI Bus Glue * * This file is licenced under the GPL. */ - + #ifndef CONFIG_PCI #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif @@ -83,7 +83,7 @@ ohci_pci_start (struct usb_hcd *hcd) pci_dev_put(b); } - /* Check for Compaq's ZFMicro chipset, which needs short + /* Check for Compaq's ZFMicro chipset, which needs short * delays before control or bulk queues get re-activated * in finish_unlinks() */ @@ -238,8 +238,8 @@ static struct pci_driver ohci_pci_driver = { .shutdown = usb_hcd_pci_shutdown, }; - -static int __init ohci_hcd_pci_init (void) + +static int __init ohci_hcd_pci_init (void) { printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); if (usb_disabled()) @@ -253,8 +253,8 @@ module_init (ohci_hcd_pci_init); /*-------------------------------------------------------------------------*/ -static void __exit ohci_hcd_pci_cleanup (void) -{ +static void __exit ohci_hcd_pci_cleanup (void) +{ pci_unregister_driver (&ohci_pci_driver); } module_exit (ohci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 7f26f9bdbaf..3a8cbfb6905 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -4,7 +4,7 @@ * driver for Philips PNX4008 USB Host * * Authors: Dmitry Chigirev - * Vitaly Wool + * Vitaly Wool * * register initialization is based on code examples provided by Philips * Copyright (c) 2005 Koninklijke Philips Electronics N.V. @@ -29,7 +29,7 @@ #include #include -#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64) +#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64) /* USB_CTRL bit defines */ #define USB_SLAVE_HCLK_EN (1 << 24) diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index d9d1ae236bd..e1a7eb81731 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -5,7 +5,7 @@ * (C) Copyright 2000-2002 David Brownell * (C) Copyright 2002 Hewlett-Packard Company * (C) Copyright 2003-2005 MontaVista Software Inc. - * + * * Bus Glue for PPC On-Chip OHCI driver * Tested on Freescale MPC5200 and IBM STB04xxx * @@ -85,7 +85,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: - usb_put_hcd(hcd); + usb_put_hcd(hcd); return retval; } @@ -148,7 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .start = ohci_ppc_soc_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -197,7 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) static struct platform_driver ohci_hcd_ppc_soc_driver = { .probe = ohci_hcd_ppc_soc_drv_probe, .remove = ohci_hcd_ppc_soc_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index e176b04d7ae..3bbea844a9e 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -47,7 +47,7 @@ static int pxa27x_ohci_select_pmm( int mode ) switch ( mode ) { case PMM_NPS_MODE: UHCRHDA |= RH_A_NPS; - break; + break; case PMM_GLOBAL_MODE: UHCRHDA &= ~(RH_A_NPS & RH_A_PSM); break; @@ -60,7 +60,7 @@ static int pxa27x_ohci_select_pmm( int mode ) break; default: printk( KERN_ERR - "Invalid mode %d, set to non-power switch mode.\n", + "Invalid mode %d, set to non-power switch mode.\n", mode ); UHCRHDA |= RH_A_NPS; @@ -270,7 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .start = ohci_pxa27x_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -359,9 +359,9 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev) static struct platform_driver ohci_hcd_pxa27x_driver = { .probe = ohci_hcd_pxa27x_drv_probe, .remove = ohci_hcd_pxa27x_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM - .suspend = ohci_hcd_pxa27x_drv_suspend, + .suspend = ohci_hcd_pxa27x_drv_suspend, .resume = ohci_hcd_pxa27x_drv_resume, #endif .driver = { diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index fe1fe2f97cb..830a3fe8615 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell - * + * * This file is licenced under the GPL. */ @@ -89,7 +89,7 @@ __acquires(ohci->lock) /*-------------------------------------------------------------------------* * ED handling functions - *-------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------*/ /* search for the right schedule branch to use for a periodic ed. * does some load balancing; returns the branch, or negative errno. @@ -107,7 +107,6 @@ static int balance (struct ohci_hcd *ohci, int interval, int load) */ for (i = 0; i < interval ; i++) { if (branch < 0 || ohci->load [branch] > ohci->load [i]) { -#if 1 /* CONFIG_USB_BANDWIDTH */ int j; /* usb 1.1 says 90% of one frame */ @@ -117,8 +116,7 @@ static int balance (struct ohci_hcd *ohci, int interval, int load) } if (j < NUM_INTS) continue; -#endif - branch = i; + branch = i; } } return branch; @@ -171,7 +169,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) /* link an ed into one of the HC chains */ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) -{ +{ int branch; if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING) @@ -248,7 +246,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) } ed->branch = branch; periodic_link (ohci, ed); - } + } /* the HC may not see the schedule updates yet, but if it does * then they'll be properly ordered. @@ -277,7 +275,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) *prev = ed->ed_next; } ohci->load [i] -= ed->load; - } + } ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval; ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", @@ -285,7 +283,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) ed, ed->branch, ed->load, ed->interval); } -/* unlink an ed from one of the HC chains. +/* unlink an ed from one of the HC chains. * just the link to the ed is unlinked. * the link from the ed still points to another operational ed or 0 * so the HC can eventually finish the processing of the unlinked ed @@ -307,7 +305,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) * When finish_unlinks() runs later, after SOF interrupt, it will often * complete one or more URB unlinks before making that state change. */ -static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) +static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) { ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); wmb (); @@ -397,7 +395,7 @@ static struct ed *ed_get ( unsigned int pipe, int interval ) { - struct ed *ed; + struct ed *ed; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); @@ -413,9 +411,9 @@ static struct ed *ed_get ( goto done; } - /* dummy td; end of td list for ed */ + /* dummy td; end of td list for ed */ td = td_alloc (ohci, GFP_ATOMIC); - if (!td) { + if (!td) { /* out of memory */ ed_free (ohci, ed); ed = NULL; @@ -462,7 +460,7 @@ static struct ed *ed_get ( done: spin_unlock_irqrestore (&ohci->lock, flags); - return ed; + return ed; } /*-------------------------------------------------------------------------*/ @@ -474,7 +472,7 @@ done: * and that ed->state is ED_OPER */ static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ +{ ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE); ed_deschedule (ohci, ed); @@ -541,7 +539,7 @@ td_fill (struct ohci_hcd *ohci, u32 info, td->ed = urb_priv->ed; td->next_dl_td = NULL; td->index = index; - td->urb = urb; + td->urb = urb; td->data_dma = data; if (!len) data = 0; @@ -553,8 +551,8 @@ td_fill (struct ohci_hcd *ohci, u32 info, (data & 0x0FFF) | 0xE000); td->ed->last_iso = info & 0xffff; } else { - td->hwCBP = cpu_to_hc32 (ohci, data); - } + td->hwCBP = cpu_to_hc32 (ohci, data); + } if (data) td->hwBE = cpu_to_hc32 (ohci, data + len - 1); else @@ -597,7 +595,7 @@ static void td_submit_urb ( * use the device toggle bits for resetting, and rely on the fact * that resetting toggle is meaningless if the endpoint is active. */ - if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { + if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out, 1); urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); @@ -721,16 +719,16 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ - if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + if (tdINFO & TD_ISO) { + u16 tdPSW = ohci_hwPSW (ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that * only the first of 0..MAXPSW psws is used. */ - cc = (tdPSW >> 12) & 0xF; - if (tdINFO & TD_CC) /* hc didn't touch? */ + cc = (tdPSW >> 12) & 0xF; + if (tdINFO & TD_CC) /* hc didn't touch? */ return; if (usb_pipeout (urb->pipe)) @@ -758,7 +756,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) int type = usb_pipetype (urb->pipe); u32 tdBE = hc32_to_cpup (ohci, &td->hwBE); - cc = TD_CC_GET (tdINFO); + cc = TD_CC_GET (tdINFO); /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN @@ -787,7 +785,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb, td, 1 + td->index, cc, urb->actual_length, urb->transfer_buffer_length); - } + } } /*-------------------------------------------------------------------------*/ @@ -795,7 +793,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) static inline struct td * ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) { - struct urb *urb = td->urb; + struct urb *urb = td->urb; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -805,7 +803,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) */ ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); wmb (); - ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); + ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); /* put any later tds from this urb onto the donelist, after 'td', * order won't matter here: no errors, and nothing was transferred. @@ -833,7 +831,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) info &= ~cpu_to_hc32 (ohci, TD_CC); next->hwINFO = info; - next->next_dl_td = rev; + next->next_dl_td = rev; rev = next; ed->hwHeadP = next->hwNextTD | toggle; @@ -881,8 +879,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) /* get TD from hc's singly linked list, and * prepend to ours. ed->td_list changes later. */ - while (td_dma) { - int cc; + while (td_dma) { + int cc; td = dma_to_td (ohci, td_dma); if (!td) { @@ -901,10 +899,10 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) td_rev = ed_halted (ohci, td, cc, td_rev); - td->next_dl_td = td_rev; + td->next_dl_td = td_rev; td_rev = td; td_dma = hc32_to_cpup (ohci, &td->hwNextTD); - } + } return td_rev; } @@ -1013,9 +1011,9 @@ rescan_this: if (modified) goto rescan_all; - } + } - /* maybe reenable control and bulk lists */ + /* maybe reenable control and bulk lists */ if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state) && ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING && !ohci->ed_rm_list) { @@ -1041,20 +1039,20 @@ rescan_this: &ohci->regs->ed_bulkcurrent); } } - + /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; if (ohci->flags & OHCI_QUIRK_ZFMICRO) mdelay(1); - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - } + ohci_writel (ohci, ohci->hc_control, + &ohci->regs->control); + } if (command) { if (ohci->flags & OHCI_QUIRK_ZFMICRO) mdelay(1); - ohci_writel (ohci, command, &ohci->regs->cmdstatus); - } + ohci_writel (ohci, command, &ohci->regs->cmdstatus); + } } } @@ -1074,19 +1072,19 @@ dl_done_list (struct ohci_hcd *ohci) { struct td *td = dl_reverse_done_list (ohci); - while (td) { + while (td) { struct td *td_next = td->next_dl_td; struct urb *urb = td->urb; urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; + td_done (ohci, urb, td); + urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); + if (urb_priv->td_cnt == urb_priv->length) + finish_urb (ohci, urb); /* clean schedule: unlink EDs that are no longer busy */ if (list_empty (&ed->td_list)) { @@ -1094,25 +1092,26 @@ dl_done_list (struct ohci_hcd *ohci) start_ed_unlink (ohci, ed); /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE)) + } else if ((ed->hwINFO & cpu_to_hc32 (ohci, + ED_SKIP | ED_DEQUEUE)) == cpu_to_hc32 (ohci, ED_SKIP)) { td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { + if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); /* ... hc may need waking-up */ switch (ed->type) { case PIPE_CONTROL: ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); + &ohci->regs->cmdstatus); break; case PIPE_BULK: ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); + &ohci->regs->cmdstatus); break; } } } - td = td_next; - } + td = td_next; + } } diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 59e436424d4..b350d45033e 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -447,7 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .start = ohci_s3c2410_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -492,7 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev) static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ /*.resume = ohci_hcd_s3c2410_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 71371de32ad..fe0090e3367 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -4,7 +4,7 @@ * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell * (C) Copyright 2002 Hewlett-Packard Company - * + * * SA1111 Bus Glue * * Written by Christopher Hoover @@ -12,7 +12,7 @@ * * This file is licenced under the GPL. */ - + #include #include #include @@ -31,7 +31,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev) { unsigned int usb_rst = 0; - printk(KERN_DEBUG __FILE__ + printk(KERN_DEBUG __FILE__ ": starting SA-1111 OHCI USB Controller\n"); #ifdef CONFIG_SA1100_BADGE4 @@ -65,7 +65,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev) static void sa1111_stop_hc(struct sa1111_dev *dev) { unsigned int usb_rst; - printk(KERN_DEBUG __FILE__ + printk(KERN_DEBUG __FILE__ ": stopping SA-1111 OHCI USB Controller\n"); /* diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index fd93e7eca7b..405257f3e85 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell - * + * * This file is licenced under the GPL. */ @@ -14,7 +14,7 @@ */ typedef __u32 __bitwise __hc32; typedef __u16 __bitwise __hc16; - + /* * OHCI Endpoint Descriptor (ED) ... holds TD queue * See OHCI spec, section 4.2 @@ -24,7 +24,7 @@ typedef __u16 __bitwise __hc16; */ struct ed { /* first fields are hardware-specified */ - __hc32 hwINFO; /* endpoint config bitmap */ + __hc32 hwINFO; /* endpoint config bitmap */ /* info bits defined by hcd */ #define ED_DEQUEUE (1 << 27) /* info bits defined by the hardware */ @@ -52,11 +52,11 @@ struct ed { * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... */ u8 state; /* ED_{IDLE,UNLINK,OPER} */ -#define ED_IDLE 0x00 /* NOT linked to HC */ -#define ED_UNLINK 0x01 /* being unlinked from hc */ +#define ED_IDLE 0x00 /* NOT linked to HC */ +#define ED_UNLINK 0x01 /* being unlinked from hc */ #define ED_OPER 0x02 /* IS linked to hc */ - u8 type; /* PIPE_{BULK,...} */ + u8 type; /* PIPE_{BULK,...} */ /* periodic scheduling params (for intr and iso) */ u8 branch; @@ -70,7 +70,7 @@ struct ed { #define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ - + /* * OHCI Transfer Descriptor (TD) ... one per transfer segment * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) @@ -107,22 +107,22 @@ struct td { /* (no hwINFO #defines yet for iso tds) */ - __hc32 hwCBP; /* Current Buffer Pointer (or 0) */ - __hc32 hwNextTD; /* Next TD Pointer */ - __hc32 hwBE; /* Memory Buffer End Pointer */ + __hc32 hwCBP; /* Current Buffer Pointer (or 0) */ + __hc32 hwNextTD; /* Next TD Pointer */ + __hc32 hwBE; /* Memory Buffer End Pointer */ /* PSW is only for ISO. Only 1 PSW entry is used, but on * big-endian PPC hardware that's the second entry. */ #define MAXPSW 2 - __hc16 hwPSW [MAXPSW]; + __hc16 hwPSW [MAXPSW]; /* rest are purely for the driver's use */ - __u8 index; - struct ed *ed; - struct td *td_hash; /* dma-->td hashtable */ - struct td *next_dl_td; - struct urb *urb; + __u8 index; + struct ed *ed; + struct td *td_hash; /* dma-->td hashtable */ + struct td *next_dl_td; + struct urb *urb; dma_addr_t td_dma; /* addr of this TD */ dma_addr_t data_dma; /* addr of data it points to */ @@ -152,8 +152,8 @@ struct td { #define TD_NOTACCESSED 0x0F -/* map OHCI TD status codes (CC) to errno values */ -static const int cc_to_error [16] = { +/* map OHCI TD status codes (CC) to errno values */ +static const int cc_to_error [16] = { /* No Error */ 0, /* CRC Error */ -EILSEQ, /* Bit Stuff */ -EPROTO, @@ -169,7 +169,7 @@ static const int cc_to_error [16] = { /* BufferOver */ -ECOMM, /* BuffUnder */ -ENOSR, /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY + /* (for HCD) */ -EALREADY }; @@ -182,7 +182,7 @@ struct ohci_hcca { #define NUM_INTS 32 __hc32 int_table [NUM_INTS]; /* periodic schedule */ - /* + /* * OHCI defines u16 frame_no, followed by u16 zero pad. * Since some processors can't do 16 bit bus accesses, * portable access must be a 32 bits wide. @@ -262,10 +262,10 @@ struct ohci_regs { * HcCommandStatus (cmdstatus) register masks */ #define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_CLF (1 << 1) /* control list filled */ -#define OHCI_BLF (1 << 2) /* bulk list filled */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ +#define OHCI_CLF (1 << 1) /* control list filled */ +#define OHCI_BLF (1 << 2) /* bulk list filled */ +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_SOC (3 << 16) /* scheduling overrun count */ /* * masks used with interrupt registers: @@ -285,20 +285,20 @@ struct ohci_regs { /* OHCI ROOT HUB REGISTER MASKS */ - + /* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ +#define RH_PS_CCS 0x00000001 /* current connect status */ +#define RH_PS_PES 0x00000002 /* port enable status*/ +#define RH_PS_PSS 0x00000004 /* port suspend status */ +#define RH_PS_POCI 0x00000008 /* port over current indicator */ +#define RH_PS_PRS 0x00000010 /* port reset status */ +#define RH_PS_PPS 0x00000100 /* port power status */ +#define RH_PS_LSDA 0x00000200 /* low speed device attached */ +#define RH_PS_CSC 0x00010000 /* connect status change */ +#define RH_PS_PESC 0x00020000 /* port enable status change */ +#define RH_PS_PSSC 0x00040000 /* port suspend status change */ +#define RH_PS_OCIC 0x00080000 /* over current indicator change */ +#define RH_PS_PRSC 0x00100000 /* port reset status change */ /* roothub.status bits */ #define RH_HS_LPS 0x00000001 /* local power status */ @@ -333,7 +333,7 @@ typedef struct urb_priv { } urb_priv_t; #define TD_HASH_SIZE 64 /* power'o'two */ -// sizeof (struct td) ~= 64 == 2^6 ... +// sizeof (struct td) ~= 64 == 2^6 ... #define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) @@ -364,11 +364,11 @@ struct ohci_hcd { struct ed *ed_bulktail; /* last in bulk list */ struct ed *ed_controltail; /* last in ctrl list */ - struct ed *periodic [NUM_INTS]; /* shadow int_table */ + struct ed *periodic [NUM_INTS]; /* shadow int_table */ /* * OTG controllers and transceivers need software interaction; - * other external transceivers should be software-transparent + * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; @@ -385,7 +385,7 @@ struct ohci_hcd { */ int num_ports; int load [NUM_INTS]; - u32 hc_control; /* copy of hc control reg */ + u32 hc_control; /* copy of hc control reg */ unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ unsigned autostop:1; /* rh auto stopping/stopped */ @@ -598,7 +598,7 @@ static inline void disable (struct ohci_hcd *ohci) } #define FI 0x2edf /* 12000 bits per frame (-1) */ -#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) +#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) #define FIT (1 << 31) #define LSTHRESH 0x628 /* lowspeed bit threshold */ -- cgit v1.2.3 From ee269d98a9248fbb729c20ffda0f1b97e82c5c37 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 5 Dec 2006 03:20:31 -0800 Subject: USB: ohci at91 warning fix Remove a warning about an unused variable in the OHCI bus glue for at91. Signed-off-by: Andrew Victor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index f15c84ea286..cc405512fa1 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -187,7 +187,6 @@ ohci_at91_start (struct usb_hcd *hcd) { struct at91_usbh_data *board = hcd->self.controller->platform_data; struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct usb_device *root = hcd->self.root_hub; int ret; if ((ret = ohci_init(ohci)) < 0) -- cgit v1.2.3 From 23d10a9e376d6a9cd4afd4e27e5e403864f6729b Mon Sep 17 00:00:00 2001 From: Takamasa Ohtake Date: Wed, 6 Dec 2006 17:04:15 -0800 Subject: USB: ohci handles hardware faults during root port resets I have found a problem where the root_port_reset() goes into an infinite loop and stalls the kernel. This happens when a hardware fault inside the machine occurs during a small timing window. In case of USB device connection, if a USB device responds to hcd_submit_urb(), and later the controller fails before root_port_reset(), root_port_reset() will loop infinitely because ohci_readl() will always return "-1". Such a failure can include ejecting a CardBus OHCI controller. The probability of this problem is low, but it will increase if PnP type usage is frequent. The attached patch can solve this problem and I believe that it is better to fix this problem. Signed-off-by: Takamasa Ohtake Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index f9748b67e5e..216c9c9d4d6 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -555,7 +555,7 @@ static void start_hnp(struct ohci_hcd *ohci); #define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) /* called from some task, normally khubd */ -static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) +static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) { __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; u32 temp; @@ -570,6 +570,9 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) /* spin until any current reset finishes */ for (;;) { temp = ohci_readl (ohci, portstat); + /* handle e.g. CardBus eject */ + if (temp == ~(u32)0) + return -ESHUTDOWN; if (!(temp & RH_PS_PRS)) break; udelay (500); @@ -586,6 +589,8 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) now = ohci_readl(ohci, &ohci->regs->fmnumber); } while (tick_before(now, reset_done)); /* caller synchronizes using PRSC */ + + return 0; } static int ohci_hub_control ( @@ -702,7 +707,7 @@ static int ohci_hub_control ( &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_RESET: - root_port_reset (ohci, wIndex); + retval = root_port_reset (ohci, wIndex); break; default: goto error; -- cgit v1.2.3 From 5151d04068e37e710d2cc3962351ca0979fc5ad1 Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Mon, 9 Oct 2006 01:32:00 -0700 Subject: USB: OHCI support for PNX8550 OHCI HCD (Host Controller Driver) for USB. Bus Glue for PNX8550. Signed-off-by: Vitaly Wool Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 4 + drivers/usb/host/ohci-pnx8550.c | 258 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 drivers/usb/host/ohci-pnx8550.c (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c31f00b7ab4..c1c1d871aba 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -885,6 +885,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-au1xxx.c" #endif +#ifdef CONFIG_PNX8550 +#include "ohci-pnx8550.c" +#endif + #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC #include "ohci-ppc-soc.c" #endif diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c new file mode 100644 index 00000000000..6922b91b170 --- /dev/null +++ b/drivers/usb/host/ohci-pnx8550.c @@ -0,0 +1,258 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2005 Embedded Alley Solutions, Inc. + * + * Bus Glue for PNX8550 + * + * Written by Christopher Hoover + * Based on fragments of previous driver by Russell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta + * + * Modified for PNX8550 from ohci-sa1111.c and sa-omap.c + * by Vitaly Wool + * + * This file is licenced under the GPL. + */ + +#include +#include +#include +#include +#include + +#ifndef CONFIG_PNX8550 +#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined." +#endif + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void pnx8550_start_hc(struct platform_device *dev) +{ + /* + * Set register CLK48CTL to enable and 48MHz + */ + outl(0x00000003, PCI_BASE | 0x0004770c); + + /* + * Set register CLK12CTL to enable and 48MHz + */ + outl(0x00000003, PCI_BASE | 0x00047710); + + udelay(100); +} + +static void pnx8550_stop_hc(struct platform_device *dev) +{ + udelay(10); +} + + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + + +/** + * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + */ +int usb_hcd_pnx8550_probe (const struct hc_driver *driver, + struct platform_device *dev) +{ + int retval; + struct usb_hcd *hcd; + + if (dev->resource[0].flags != IORESOURCE_MEM || + dev->resource[1].flags != IORESOURCE_IRQ) { + dev_err (&dev->dev,"invalid resource type\n"); + return -ENOMEM; + } + + hcd = usb_create_hcd (driver, &dev->dev, "pnx8550"); + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = dev->resource[0].start; + hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] " + "failed\n", hcd->rsrc_start, hcd->rsrc_len); + retval = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n", + hcd->rsrc_start, hcd->rsrc_len); + retval = -ENOMEM; + goto err2; + } + + pnx8550_start_hc(dev); + + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); + if (retval == 0) + return retval; + + pnx8550_stop_hc(dev); + iounmap(hcd->regs); + err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + err1: + usb_put_hcd(hcd); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev) +{ + usb_remove_hcd(hcd); + pnx8550_stop_hc(dev); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); +} + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_pnx8550_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci); + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run (ohci)) < 0) { + err ("can't start %s", hcd->self.bus_name); + ohci_stop (hcd); + return ret; + } + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_pnx8550_hc_driver = { + .description = hcd_name, + .product_desc = "PNX8550 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_pnx8550_start, + .stop = ohci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev) +{ + int ret; + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev); + return ret; +} + +static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_hcd_pnx8550_remove(hcd, pdev); + return 0; +} + +MODULE_ALIAS("pnx8550-ohci"); + +static struct platform_driver ohci_hcd_pnx8550_driver = { + .driver = { + .name = "pnx8550-ohci", + }, + .probe = ohci_hcd_pnx8550_drv_probe, + .remove = ohci_hcd_pnx8550_drv_remove, +}; + +static int __init ohci_hcd_pnx8550_init (void) +{ + pr_debug (DRIVER_INFO " (pnx8550)"); + pr_debug ("block sizes: ed %d td %d\n", + sizeof (struct ed), sizeof (struct td)); + + return platform_driver_register(&ohci_hcd_pnx8550_driver); +} + +static void __exit ohci_hcd_pnx8550_cleanup (void) +{ + platform_driver_unregister(&ohci_hcd_pnx8550_driver); +} + +module_init (ohci_hcd_pnx8550_init); +module_exit (ohci_hcd_pnx8550_cleanup); -- cgit v1.2.3 From ffd3326bf6282b9f606e92ae57e8f47f2e10e6b5 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Thu, 7 Dec 2006 22:44:33 -0800 Subject: USB: at91 udc, support at91sam926x addresses This is an update to the AT91 USB Device (Gadget) driver. The base I/O address provided in the platform_device resources is now ioremap()'ed instead of using a statically mapped memory area. This helps portability to the newer AT91sam926x processors. The major change is that we now have to pass a 'struct at91_udc' parameter to at91_udp_read() and at91_udp_write(). Signed-off-by: Andrew Victor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 169 +++++++++++++++++++++--------------------- drivers/usb/gadget/at91_udc.h | 1 + 2 files changed, 84 insertions(+), 86 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 81656337381..b53b93700ca 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -43,12 +43,12 @@ #include #include +#include #include #include #include #include -#include #include #include @@ -78,27 +78,11 @@ static const char driver_name [] = "at91_udc"; static const char ep0name[] = "ep0"; -/*-------------------------------------------------------------------------*/ - -/* - * Read from a UDP register. - */ -static inline unsigned long at91_udp_read(unsigned int reg) -{ - void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP; - - return __raw_readl(udp_base + reg); -} - -/* - * Write to a UDP register. - */ -static inline void at91_udp_write(unsigned int reg, unsigned long value) -{ - void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP; - __raw_writel(value, udp_base + reg); -} +#define at91_udp_read(dev, reg) \ + __raw_readl((dev)->udp_baseaddr + (reg)) +#define at91_udp_write(dev, reg, val) \ + __raw_writel((val), (dev)->udp_baseaddr + (reg)) /*-------------------------------------------------------------------------*/ @@ -210,13 +194,13 @@ static int proc_udc_show(struct seq_file *s, void *unused) return 0; } - tmp = at91_udp_read(AT91_UDP_FRM_NUM); + tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM); seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp, (tmp & AT91_UDP_FRM_OK) ? " ok" : "", (tmp & AT91_UDP_FRM_ERR) ? " err" : "", (tmp & AT91_UDP_NUM)); - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp, (tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "", (tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "", @@ -224,13 +208,13 @@ static int proc_udc_show(struct seq_file *s, void *unused) (tmp & AT91_UDP_CONFG) ? " confg" : "", (tmp & AT91_UDP_FADDEN) ? " fadden" : ""); - tmp = at91_udp_read(AT91_UDP_FADDR); + tmp = at91_udp_read(udc, AT91_UDP_FADDR); seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp, (tmp & AT91_UDP_FEN) ? " fen" : "", (tmp & AT91_UDP_FADD)); - proc_irq_show(s, "imr ", at91_udp_read(AT91_UDP_IMR)); - proc_irq_show(s, "isr ", at91_udp_read(AT91_UDP_ISR)); + proc_irq_show(s, "imr ", at91_udp_read(udc, AT91_UDP_IMR)); + proc_irq_show(s, "isr ", at91_udp_read(udc, AT91_UDP_ISR)); if (udc->enabled && udc->vbus) { proc_ep_show(s, &udc->ep[0]); @@ -286,6 +270,7 @@ static inline void remove_debug_file(struct at91_udc *udc) {} static void done(struct at91_ep *ep, struct at91_request *req, int status) { unsigned stopped = ep->stopped; + struct at91_udc *udc = ep->udc; list_del_init(&req->queue); if (req->req.status == -EINPROGRESS) @@ -301,7 +286,7 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status) /* ep0 is always ready; other endpoints need a non-empty queue */ if (list_empty(&ep->queue) && ep->int_mask != (1 << 0)) - at91_udp_write(AT91_UDP_IDR, ep->int_mask); + at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask); } /*-------------------------------------------------------------------------*/ @@ -554,8 +539,8 @@ ok: * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, * since endpoint resets don't reset hw pingpong state. */ - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(dev, AT91_UDP_RST_EP, 0); local_irq_restore(flags); return 0; @@ -564,6 +549,7 @@ ok: static int at91_ep_disable (struct usb_ep * _ep) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; unsigned long flags; if (ep == &ep->udc->ep[0]) @@ -579,8 +565,8 @@ static int at91_ep_disable (struct usb_ep * _ep) /* reset fifos and endpoint */ if (ep->udc->clocked) { - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); __raw_writel(0, ep->creg); } @@ -695,10 +681,10 @@ static int at91_ep_queue(struct usb_ep *_ep, * reconfigures the endpoints. */ if (dev->wait_for_config_ack) { - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT); tmp ^= AT91_UDP_CONFG; VDBG("toggle config\n"); - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp); } if (req->req.length == 0) { ep0_in_status: @@ -727,7 +713,7 @@ ep0_in_status: if (req && !status) { list_add_tail (&req->queue, &ep->queue); - at91_udp_write(AT91_UDP_IER, ep->int_mask); + at91_udp_write(dev, AT91_UDP_IER, ep->int_mask); } done: local_irq_restore(flags); @@ -758,6 +744,7 @@ static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) static int at91_ep_set_halt(struct usb_ep *_ep, int value) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; u32 __iomem *creg; u32 csr; unsigned long flags; @@ -785,8 +772,8 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) csr |= AT91_UDP_FORCESTALL; VDBG("halt %s\n", ep->ep.name); } else { - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); csr &= ~AT91_UDP_FORCESTALL; } __raw_writel(csr, creg); @@ -813,9 +800,11 @@ static struct usb_ep_ops at91_ep_ops = { static int at91_get_frame(struct usb_gadget *gadget) { + struct at91_udc *udc = to_udc(gadget); + if (!to_udc(gadget)->clocked) return -EINVAL; - return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM; + return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM; } static int at91_wakeup(struct usb_gadget *gadget) @@ -833,11 +822,11 @@ static int at91_wakeup(struct usb_gadget *gadget) /* NOTE: some "early versions" handle ESR differently ... */ - glbstate = at91_udp_read(AT91_UDP_GLB_STAT); + glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT); if (!(glbstate & AT91_UDP_ESR)) goto done; glbstate |= AT91_UDP_ESR; - at91_udp_write(AT91_UDP_GLB_STAT, glbstate); + at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); done: local_irq_restore(flags); @@ -861,6 +850,7 @@ static void udc_reinit(struct at91_udc *udc) ep->stopped = 0; ep->fifo_bank = 0; ep->ep.maxpacket = ep->maxpacket; + ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i); // initialiser une queue par endpoint INIT_LIST_HEAD(&ep->queue); } @@ -915,13 +905,14 @@ static void pullup(struct at91_udc *udc, int is_on) if (!udc->enabled || !udc->vbus) is_on = 0; DBG("%sactive\n", is_on ? "" : "in"); + if (is_on) { clk_on(udc); - at91_udp_write(AT91_UDP_TXVC, 0); + at91_udp_write(udc, AT91_UDP_TXVC, 0); at91_set_gpio_value(udc->board.pullup_pin, 1); - } else { + } else { stop_activity(udc); - at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_set_gpio_value(udc->board.pullup_pin, 0); clk_off(udc); } @@ -1086,7 +1077,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) | USB_REQ_SET_CONFIGURATION: - tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; if (pkt.r.wValue) udc->wait_for_config_ack = (tmp == 0); else @@ -1103,7 +1094,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) | USB_REQ_GET_STATUS: tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED); - if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR) + if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR) tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP); PACKET("get device status\n"); __raw_writeb(tmp, dreg); @@ -1114,17 +1105,17 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_SET_FEATURE: if (w_value != USB_DEVICE_REMOTE_WAKEUP) goto stall; - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp |= AT91_UDP_ESR; - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); goto succeed; case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) | USB_REQ_CLEAR_FEATURE: if (w_value != USB_DEVICE_REMOTE_WAKEUP) goto stall; - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp &= ~AT91_UDP_ESR; - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); goto succeed; /* @@ -1206,8 +1197,8 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) } else if (ep->is_in) goto stall; - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); tmp = __raw_readl(ep->creg); tmp |= CLR_FX; tmp &= ~(SET_FX | AT91_UDP_FORCESTALL); @@ -1300,13 +1291,13 @@ static void handle_ep0(struct at91_udc *udc) if (udc->wait_for_addr_ack) { u32 tmp; - at91_udp_write(AT91_UDP_FADDR, + at91_udp_write(udc, AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr); - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp &= ~AT91_UDP_FADDEN; if (udc->addr) tmp |= AT91_UDP_FADDEN; - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); udc->wait_for_addr_ack = 0; VDBG("address %d\n", udc->addr); @@ -1374,28 +1365,28 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) while (rescans--) { u32 status; - status = at91_udp_read(AT91_UDP_ISR) - & at91_udp_read(AT91_UDP_IMR); + status = at91_udp_read(udc, AT91_UDP_ISR) + & at91_udp_read(udc, AT91_UDP_IMR); if (!status) break; /* USB reset irq: not maskable */ if (status & AT91_UDP_ENDBUSRES) { - at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); - at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS); + at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); + at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS); /* Atmel code clears this irq twice */ - at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES); - at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); VDBG("end bus reset\n"); udc->addr = 0; stop_activity(udc); /* enable ep0 */ - at91_udp_write(AT91_UDP_CSR(0), + at91_udp_write(udc, AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); udc->gadget.speed = USB_SPEED_FULL; udc->suspended = 0; - at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0)); + at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0)); /* * NOTE: this driver keeps clocks off unless the @@ -1406,9 +1397,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) /* host initiated suspend (3+ms bus idle) */ } else if (status & AT91_UDP_RXSUSP) { - at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP); - at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM); - at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP); // VDBG("bus suspend\n"); if (udc->suspended) continue; @@ -1425,9 +1416,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) /* host initiated resume */ } else if (status & AT91_UDP_RXRSM) { - at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM); - at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP); - at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); // VDBG("bus resume\n"); if (!udc->suspended) continue; @@ -1485,8 +1476,6 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(0)), .int_mask = 1 << 0, }, .ep[1] = { @@ -1497,8 +1486,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(1)), .int_mask = 1 << 1, }, .ep[2] = { @@ -1509,8 +1496,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(2)), .int_mask = 1 << 2, }, .ep[3] = { @@ -1521,8 +1506,6 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(3)), .int_mask = 1 << 3, }, .ep[4] = { @@ -1533,8 +1516,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(4)), .int_mask = 1 << 4, }, .ep[5] = { @@ -1545,8 +1526,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(5)), .int_mask = 1 << 5, }, /* ep6 and ep7 are also reserved (custom silicon might use them) */ @@ -1615,7 +1594,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) local_irq_disable(); udc->enabled = 0; - at91_udp_write(AT91_UDP_IDR, ~0); + at91_udp_write(udc, AT91_UDP_IDR, ~0); pullup(udc, 0); local_irq_enable(); @@ -1640,6 +1619,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct at91_udc *udc; int retval; + struct resource *res; if (!dev->platform_data) { /* small (so we copy it) but critical! */ @@ -1657,7 +1637,13 @@ static int __devinit at91udc_probe(struct platform_device *pdev) return -ENODEV; } - if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!request_mem_region(res->start, + res->end - res->start + 1, + driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; } @@ -1667,9 +1653,16 @@ static int __devinit at91udc_probe(struct platform_device *pdev) udc->gadget.dev.parent = dev; udc->board = *(struct at91_udc_data *) dev->platform_data; udc->pdev = pdev; - udc_reinit(udc); udc->enabled = 0; + udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1); + if (!udc->udp_baseaddr) { + release_mem_region(res->start, res->end - res->start + 1); + return -ENOMEM; + } + + udc_reinit(udc); + /* get interface and function clocks */ udc->iclk = clk_get(dev, "udc_clk"); udc->fclk = clk_get(dev, "udpck"); @@ -1684,8 +1677,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) /* don't do anything until we have both gadget driver and VBUS */ clk_enable(udc->iclk); - at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - at91_udp_write(AT91_UDP_IDR, 0xffffffff); + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ @@ -1719,7 +1712,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) fail1: device_unregister(&udc->gadget.dev); fail0: - release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); + release_mem_region(res->start, res->end - res->start + 1); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } @@ -1727,6 +1720,7 @@ fail0: static int __devexit at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); + struct resource *res; DBG("remove\n"); @@ -1741,7 +1735,10 @@ static int __devexit at91udc_remove(struct platform_device *pdev) free_irq(udc->board.vbus_pin, udc); free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); - release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); + + iounmap(udc->udp_baseaddr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); clk_put(udc->iclk); clk_put(udc->fclk); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 882af42e86c..a35f3b627d3 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -141,6 +141,7 @@ struct at91_udc { struct clk *iclk, *fclk; struct platform_device *pdev; struct proc_dir_entry *pde; + void __iomem *udp_baseaddr; int udp_irq; }; -- cgit v1.2.3 From 29ba4b533b677f3cd7f2fc901d51054555a8f243 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Thu, 7 Dec 2006 22:44:38 -0800 Subject: USB: at91_udc, misc fixes This is an update to the AT91 USB Device (Gadget) driver. Adds support for the Atmel AT91SAM9260 and AT91SAM9261 processors. The only difference is how they handle the pullup pin. [Patch from Patrice Vilchez] Need to clear any pending USB Device interrupts before registering the interrupt handler. The bootloader might have been using the USB Device port. [Patch from Peer Georgi] VBUS detection is handled by a GPIO interrupt which only triggers on a change. Is is therefore necessary to read the current VBUS state explicitly at startup. [Patch from Peer Georgi] Signed-off-by: Andrew Victor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 42 +++++++++++++++++++++++++++++++++++++++--- drivers/usb/gadget/at91_udc.h | 6 +++--- 2 files changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index b53b93700ca..c8954a6ddf8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -51,6 +51,8 @@ #include #include +#include +#include #include "at91_udc.h" @@ -909,11 +911,37 @@ static void pullup(struct at91_udc *udc, int is_on) if (is_on) { clk_on(udc); at91_udp_write(udc, AT91_UDP_TXVC, 0); - at91_set_gpio_value(udc->board.pullup_pin, 1); + if (cpu_is_at91rm9200()) + at91_set_gpio_value(udc->board.pullup_pin, 1); + else if (cpu_is_at91sam9260()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc |= AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261()) { + u32 usbpucr; + + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr |= AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } } else { stop_activity(udc); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - at91_set_gpio_value(udc->board.pullup_pin, 0); + if (cpu_is_at91rm9200()) + at91_set_gpio_value(udc->board.pullup_pin, 0); + else if (cpu_is_at91sam9260()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc &= ~AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261()) { + u32 usbpucr; + + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr &= ~AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } clk_off(udc); } } @@ -1668,7 +1696,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) udc->fclk = clk_get(dev, "udpck"); if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { DBG("clocks missing\n"); - return -ENODEV; + retval = -ENODEV; + goto fail0; } retval = device_register(&udc->gadget.dev); @@ -1679,6 +1708,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) clk_enable(udc->iclk); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); + /* Clear all pending interrupts - UDP may be used by bootloader. */ + at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ @@ -1690,6 +1721,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev) goto fail1; } if (udc->board.vbus_pin > 0) { + /* + * Get the initial state of VBUS - we cannot expect + * a pending interrupt. + */ + udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { DBG("request vbus irq %d failed\n", diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index a35f3b627d3..677089baa59 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -51,10 +51,10 @@ #define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ #define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ #define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ -#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */ +#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ #define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ -#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */ +#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ #define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ @@ -84,7 +84,7 @@ #define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ #define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ - +#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */ /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 4b87361d49c04894458f4d4e80f9669abc894ae1 Mon Sep 17 00:00:00 2001 From: Tony Olech Date: Wed, 6 Dec 2006 13:16:22 +0000 Subject: USB: u132-hcd/ftdi-elan: add support for Option GT 3G Quad card ELAN's U132 is a USB to CardBus OHCI controller adapter, designed specifically for CardBus 3G data cards to function in machines without a CardBus slot. The "ftdi-elan" module is a USB client driver, that detects a supported CardBus OHCI controller plugged into the U132 adapter and thereafter provides the conduit for for access by the "u132-hcd" module. The "u132-hcd" module is a (cut-down OHCI) host controller that supports a single OHCI function of the CardBus card inserted into the U132 adapter. The problem with the initial implementation is that when the CardBus card inserted into the U132 adapter has multiple functions (and a CardBus card can support up to 4 functions), it was the first function that was arbitrarily choosen. The first batch of 3G cards tested, like the Merlin Qualcomm V620, have two functions each supporting a seperate USB OHCI host controller, of which it was that first function that is wired up to the 3G modem. Then along comes the Vodafone Mobile Connect 3G/GPRS data card, aka "Option GT 3G Quad" as printed on it's rear or "Option N.V. GlobeTrotter Fusion Quad Lite" as read with "lspci -v". And it has the meaningful functionality in the second CardBus function. That presents a problem because it was the "ftdi-elan" module alone that knows how to communicate to the embedded CardBus slot and the "u132-hcd" module alone that knows how to access the pcmcia configuration and CardBus accessible memory space. And of course, the information about attached (internally hardwired) devices is contained within USB configuration embedded somewhere within the CardBus card. If only the "u132-hcd" module probe() interface could return a result code that propagated back to the instigating function platform_device_register() then the "ftdi-elan" module could try an alternative CardBus function. However in spite of the recent changes to the drivers/base/ routines that moved device_attach() from bus_add_device() to bus_attach_device() both of those routines lose the "failed to attach" 0 result code and thus the calling routine, namely device_add() is incapable of propaging the "failed to attach" condition back to platform_device_add() and consequently back to the caller of platform_device_register() Experiments show that patching bus_attach_device() to return ENODEV fails with the kernel locking up very early during boot. But, however, if the patch is restricted to calls from platform_device_add() then it does seem to work. Unfortunately, until the kernel's drivers/base is properly modified to propagate -ENODEV back to the caller of platform_device_register(), it is necessary to "fix" the "ftdi-elan" module by importing knowledge from the "u132-hcd" module. This is the reason for the duplicated functionality introduced in this patch. Signed-off-by: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 92 +++---- drivers/usb/misc/ftdi-elan.c | 592 ++++++++++++++++++++++++++++--------------- 2 files changed, 425 insertions(+), 259 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index a9d7119e317..a7fa0d75567 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -210,15 +211,16 @@ struct u132 { * these cannot be inlines because we need the structure offset!! * Does anyone have a better way????? */ +#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \ + offsetof(struct ohci_regs, member), 0, data); +#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \ + offsetof(struct ohci_regs, member), 0, data); #define u132_read_pcimem(u132, member, data) \ usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \ ohci_regs, member), 0, data); #define u132_write_pcimem(u132, member, data) \ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ ohci_regs, member), 0, data); -#define u132_write_pcimem_byte(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0x0e, data); static inline struct u132 *udev_to_u132(struct u132_udev *udev) { u8 udev_number = udev->udev_number; @@ -1574,59 +1576,12 @@ static char *hcfs2string(int state) return "?"; } -static int u132_usb_reset(struct u132 *u132) -{ - int retval; - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - u132->hc_control &= OHCI_CTRL_RWC; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - return 0; -} - static int u132_init(struct u132 *u132) { int retval; u32 control; u132_disable(u132); - u132->next_statechange = - jiffies; /* SMM owns the HC? not for long! */ { - u32 control; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (control & OHCI_CTRL_IR) { - u32 temp = 50; - retval = u132_write_pcimem(u132, intrenable, - OHCI_INTR_OC); - if (retval) - return retval; - retval = u132_write_pcimem_byte(u132, cmdstatus, - OHCI_OCR); - if (retval) - return retval; - check:{ - retval = u132_read_pcimem(u132, control, - &control); - if (retval) - return retval; - } - if (control & OHCI_CTRL_IR) { - msleep(10); - if (--temp == 0) { - dev_err(&u132->platform_dev->dev, "USB " - "HC takeover failed!(BIOS/SMM b" - "ug) control=%08X\n", control); - return -EBUSY; - } - goto check; - } - u132_usb_reset(u132); - } - } + u132->next_statechange = jiffies; retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); if (retval) return retval; @@ -1725,7 +1680,7 @@ static int u132_run(struct u132 *u132) retry:retval = u132_read_pcimem(u132, cmdstatus, &status); if (retval) return retval; - retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR); + retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); if (retval) return retval; extra:{ @@ -1782,7 +1737,7 @@ static int u132_run(struct u132 *u132) retval = u132_write_pcimem(u132, control, u132->hc_control); if (retval) return retval; - retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF); + retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); if (retval) return retval; retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); @@ -1839,8 +1794,8 @@ static void u132_hcd_stop(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" + "een removed %d\n", u132, hcd, u132->going); } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); @@ -2545,8 +2500,9 @@ static void u132_endpoint_disable(struct usb_hcd *hcd, { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" + ") has been removed %d\n", u132, hcd, hep, + u132->going); } else { struct u132_endp *endp = hep->hcpriv; if (endp) @@ -2790,7 +2746,6 @@ static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); - dump_stack(); return -ESHUTDOWN; } else { int i, changed = 0, length = 1; @@ -3034,12 +2989,15 @@ static int __devexit u132_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); if (hcd) { struct u132 *u132 = hcd_to_u132(hcd); - dump_stack(); if (u132->going++ > 1) { + dev_err(&u132->platform_dev->dev, "already being remove" + "d\n"); return -ENODEV; } else { int rings = MAX_U132_RINGS; int endps = MAX_U132_ENDPS; + dev_err(&u132->platform_dev->dev, "removing device u132" + ".%d\n", u132->sequence_num); msleep(100); down(&u132->sw_lock); u132_monitor_cancel_work(u132); @@ -3121,10 +3079,24 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) static int __devinit u132_probe(struct platform_device *pdev) { struct usb_hcd *hcd; + int retval; + u32 control; + u32 rh_a = -1; + u32 num_ports; msleep(100); if (u132_exiting > 0) { return -ENODEV; - } /* refuse to confuse usbcore */ + } + retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); + if (retval) + return retval; + retval = ftdi_read_pcimem(pdev, control, &control); + if (retval) + return retval; + retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); + if (retval) + return retval; + num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */ if (pdev->dev.dma_mask) { return -EINVAL; } diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 18b1925032a..41c0161abdb 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,10 @@ MODULE_AUTHOR("Tony Olech"); MODULE_DESCRIPTION("FTDI ELAN driver"); MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) +static int distrust_firmware = 1; +module_param(distrust_firmware, bool, 0); +MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" + "t setup"); extern struct platform_driver u132_platform_driver; static struct workqueue_struct *status_queue; static struct workqueue_struct *command_queue; @@ -66,7 +71,9 @@ static struct list_head ftdi_static_list; * end of the global variables protected by ftdi_module_lock */ #include "usb_u132.h" -#define TD_DEVNOTRESP 5 +#include +#include "../core/hcd.h" +#include "../host/ohci.h" /* Define these values to match your devices*/ #define USB_FTDI_ELAN_VENDOR_ID 0x0403 #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea @@ -551,7 +558,7 @@ static void ftdi_elan_status_work(struct work_struct *work) } else { dev_err(&ftdi->udev->dev, "initialized failed - trying " "again in 10 seconds\n"); - work_delay_in_msec = 10 *1000; + work_delay_in_msec = 1 *1000; } } else if (ftdi->registered == 0) { work_delay_in_msec = 10; @@ -2288,82 +2295,288 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) } } -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) + +#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ + offsetof(struct ohci_regs, member), 0, data); +#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ + offsetof(struct ohci_regs, member), 0, data); +#define OHCI_QUIRK_AMD756 0x01 +#define OHCI_QUIRK_SUPERIO 0x02 +#define OHCI_QUIRK_INITRESET 0x04 +#define OHCI_BIG_ENDIAN 0x08 +#define OHCI_QUIRK_ZFMICRO 0x10 +#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR +#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ + OHCI_INTR_WDH) +static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) +{ + int devices = 0; + int retval; + u32 hc_control; + int num_ports; + u32 control; + u32 rh_a = -1; + u32 status; + u32 fminterval; + u32 hc_fminterval; + u32 periodicstart; + u32 cmdstatus; + u32 roothub_a; + int mask = OHCI_INTR_INIT; + int sleep_time = 0; + int reset_timeout = 30; /* ... allow extra time */ + int temp; + retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); + if (retval) + return retval; + num_ports = rh_a & RH_A_NDP; + retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); + if (retval) + return retval; + hc_fminterval &= 0x3fff; + if (hc_fminterval != FI) { + } + hc_fminterval |= FSMP(hc_fminterval) << 16; + retval = ftdi_read_pcimem(ftdi, control, &hc_control); + if (retval) + return retval; + switch (hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + sleep_time = 0; + break; + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_USB_RESUME; + sleep_time = 10; + break; + default: + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_USB_RESET; + sleep_time = 50; + break; + } + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + msleep(sleep_time); + retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); + if (retval) + return retval; + if (!(roothub_a & RH_A_NPS)) { /* power down each port */ + for (temp = 0; temp < num_ports; temp++) { + retval = ftdi_write_pcimem(ftdi, + roothub.portstatus[temp], RH_PS_LSDA); + if (retval) + return retval; + } + } + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); + if (retval) + return retval; + extra:{ + retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); + if (retval) + return retval; + if (0 != (status & OHCI_HCR)) { + if (--reset_timeout == 0) { + dev_err(&ftdi->udev->dev, "USB HC reset timed o" + "ut!\n"); + return -ENODEV; + } else { + msleep(5); + goto extra; + } + } + } + if (quirk & OHCI_QUIRK_INITRESET) { + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + } + retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, fminterval, + ((fminterval & FIT) ^ FIT) | hc_fminterval); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, periodicstart, + ((9 *hc_fminterval) / 10) & 0x3fff); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); + if (retval) + return retval; + if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { + if (!(quirk & OHCI_QUIRK_INITRESET)) { + quirk |= OHCI_QUIRK_INITRESET; + goto retry; + } else + dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", + fminterval, periodicstart); + } /* start controller operations */ + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, intrstatus, mask); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, intrdisable, + OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | + OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | + OHCI_INTR_SO); + if (retval) + return retval; /* handle root hub init quirks ... */ + retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); + if (retval) + return retval; + roothub_a &= ~(RH_A_PSM | RH_A_OCPM); + if (quirk & OHCI_QUIRK_SUPERIO) { + roothub_a |= RH_A_NOCP; + roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); + retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); + if (retval) + return retval; + } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { + roothub_a |= RH_A_NPS; + retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); + if (retval) + return retval; + } + retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, roothub.b, + (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + mdelay((roothub_a >> 23) & 0x1fe); + for (temp = 0; temp < num_ports; temp++) { + u32 portstatus; + retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], + &portstatus); + if (retval) + return retval; + if (1 & portstatus) + devices += 1; + } + return devices; +} + +static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) { u32 latence_timer; - u32 controlreg; int UxxxStatus; u32 pcidata; int reg = 0; - int foundOHCI = 0; - u8 fn; - int activePCIfn = 0; - u32 pciVID = 0; - u32 pciPID = 0; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); + int activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); + reg = 16; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xFFFFFFFF); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xF0000000); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); + reg = 12; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &latence_timer); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + latence_timer &= 0xFFFF00FF; + latence_timer |= 0x00001600; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + latence_timer); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + reg = 4; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + 0x06); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - msleep(1000); - for (fn = 0; (fn < 4) && (!foundOHCI); fn++) { - activePCIfn = fn << 8; - ftdi->function = fn + 1; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); + for (reg = 0; reg <= 0x54; reg += 4) { + UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); if (UxxxStatus) return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == 0x1045) && (pciPID == 0xc861)) { - foundOHCI = 1; - } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) { - foundOHCI = 1; - } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) { - foundOHCI = 1; - } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) { - foundOHCI = 1; - } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) { - } - } - if (foundOHCI == 0) { - return -ENXIO; } - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; + return 0; +} + +static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) +{ + u32 latence_timer; + int UxxxStatus; + u32 pcidata; + int reg = 0; + int activePCIfn = fn << 8; UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); if (UxxxStatus) return UxxxStatus; @@ -2377,7 +2590,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) if (UxxxStatus) return UxxxStatus; UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); + 0x00000000); if (UxxxStatus) return UxxxStatus; UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, @@ -2401,7 +2614,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) return UxxxStatus; reg = 4; UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); + 0x00); if (UxxxStatus) return UxxxStatus; UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, @@ -2411,159 +2624,139 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) return 0; } +static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) +{ + int result; + int UxxxStatus; + UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); + if (UxxxStatus) + return UxxxStatus; + result = ftdi_elan_check_controller(ftdi, quirk); + UxxxStatus = ftdi_elan_close_controller(ftdi, fn); + if (UxxxStatus) + return UxxxStatus; + return result; +} + +static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) +{ + u32 controlreg; + u8 sensebits; + int UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); + if (UxxxStatus) + return UxxxStatus; + msleep(750); + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); + if (UxxxStatus) + return UxxxStatus; + msleep(250); + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + msleep(1000); + sensebits = (controlreg >> 16) & 0x000F; + if (0x0D == sensebits) + return 0; + else + return - ENXIO; +} + static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) { + int UxxxStatus; u32 pcidata; - int U132Status; - int reg; - int reset_repeat = 0; - do_reset:reg = 8; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01); - if (U132Status) - return U132Status; - reset_check:{ - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - if (pcidata & 1) { - msleep(500); - if (reset_repeat++ > 100) { - reset_repeat = 0; - goto do_reset; - } else - goto reset_check; + int reg = 0; + u8 fn; + int activePCIfn = 0; + int max_devices = 0; + int controllers = 0; + int unrecognized = 0; + ftdi->function = 0; + for (fn = 0; (fn < 4); fn++) { + u32 pciVID = 0; + u32 pciPID = 0; + int devices = 0; + activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + pciVID = pcidata & 0xFFFF; + pciPID = (pcidata >> 16) & 0xFFFF; + if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) + { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) + { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { + devices = ftdi_elan_found_controller(ftdi, fn, + OHCI_QUIRK_AMD756); + controllers += 1; + } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { + devices = ftdi_elan_found_controller(ftdi, fn, + OHCI_QUIRK_ZFMICRO); + controllers += 1; + } else if (0 == pcidata) { + } else + unrecognized += 1; + if (devices > max_devices) { + max_devices = devices; + ftdi->function = fn + 1; + ftdi->platform_data.vendor = pciVID; + ftdi->platform_data.device = pciPID; } } - goto dump_regs; - msleep(500); - reg = 0x28; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x40; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x34; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 4; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - msleep(250); - reg = 8; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x28; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 8; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x48; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x54; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x58; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x34; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - msleep(100); - reg = 0x50; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000); - if (U132Status) - return U132Status; - reg = 0x54; - power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - if (!(pcidata & 1)) { - msleep(500); - goto power_check; - } - msleep(3000); - reg = 0x54; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x58; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x54; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x54; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - msleep(750); - reg = 0x54; - if (0) { - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); - if (U132Status) - return U132Status; - } - if (0) { - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - } - reg = 0x54; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x58; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - dump_regs:for (reg = 0; reg <= 0x54; reg += 4) { - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; + if (ftdi->function > 0) { + UxxxStatus = ftdi_elan_setup_controller(ftdi, + ftdi->function - 1); + if (UxxxStatus) + return UxxxStatus; + return 0; + } else if (controllers > 0) { + return -ENXIO; + } else if (unrecognized > 0) { + return -ENXIO; + } else { + ftdi->enumerated = 0; + return -ENXIO; } - return 0; } @@ -2688,6 +2881,7 @@ static void ftdi_elan_disconnect(struct usb_interface *interface) platform_device_unregister(&ftdi->platform_dev); ftdi->synchronized = 0; ftdi->enumerated = 0; + ftdi->initialized = 0; ftdi->registered = 0; } flush_workqueue(status_queue); -- cgit v1.2.3 From bc92c32aa21cf2e8808f8cff0be0a2a653652e92 Mon Sep 17 00:00:00 2001 From: Wojtek Kaniewski Date: Fri, 8 Dec 2006 09:39:36 -0800 Subject: USB: at91_udc: allow drivers that support high speed This patch allows gadget drivers that support high speed (e.g. gadgetfs) to work properly with at91_udc. Fix suggested by Milan Svoboda in http://marc.theaimsgroup.com/?l=linux-usb-devel&m=115822184711817 Signed-off-by: Wojtek Kaniewski Acked-by: David Brownell Cc: Andrew Victor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index c8954a6ddf8..38a2e113e70 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1579,7 +1579,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) int retval; if (!driver - || driver->speed != USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !driver->bind || !driver->setup) { DBG("bad parameter.\n"); -- cgit v1.2.3 From 943c441948581bd01ab196a4d32da88bfa0f13ce Mon Sep 17 00:00:00 2001 From: Wojtek Kaniewski Date: Fri, 8 Dec 2006 03:23:00 -0800 Subject: USB: at91_udc: Cleanup variables after failure in usb_gadget_register_driver() This patch zeroes some variables when usb_gadget_register_driver() fails. gadgetfs does a dummy registration to get the name of the USB driver and then waits for user-land driver. If someone plugs the cable in the meantime, bad things happen, because at91_udc has been left in inconsistent state. Signed-off-by: Wojtek Kaniewski Acked-by: David Brownell Cc: Andrew Victor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 38a2e113e70..1926d39e480 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1601,6 +1601,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (retval) { DBG("driver->bind() returned %d\n", retval); udc->driver = NULL; + udc->gadget.dev.driver = NULL; + udc->gadget.dev.driver_data = NULL; + udc->enabled = 0; + udc->selfpowered = 0; return retval; } -- cgit v1.2.3 From bfb7fb79e913f60330037d1f302efee28d5f6770 Mon Sep 17 00:00:00 2001 From: Wojtek Kaniewski Date: Fri, 8 Dec 2006 03:26:00 -0800 Subject: USB: at91_udc: Additional checks This patch performs additional checks in at91_udc, just in case of some spurious interrupts or device enumeration. Signed-off-by: Wojtek Kaniewski Acked-by: David Brownell Cc: Andrew Victor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 1926d39e480..812c733ba8c 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -955,7 +955,10 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active) // VDBG("vbus %s\n", is_active ? "on" : "off"); local_irq_save(flags); udc->vbus = (is_active != 0); - pullup(udc, is_active); + if (udc->driver) + pullup(udc, is_active); + else + pullup(udc, 0); local_irq_restore(flags); return 0; } @@ -1241,7 +1244,10 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) #undef w_length /* pass request up to the gadget driver */ - status = udc->driver->setup(&udc->gadget, &pkt.r); + if (udc->driver) + status = udc->driver->setup(&udc->gadget, &pkt.r); + else + status = -ENODEV; if (status < 0) { stall: VDBG("req %02x.%02x protocol STALL; stat %d\n", -- cgit v1.2.3 From df251b8bfcc5879b947223746779f90018424a6d Mon Sep 17 00:00:00 2001 From: Chris Frey Date: Sat, 16 Dec 2006 02:37:42 -0500 Subject: USB: fix to usbfs_snoop logging of user defined control urbs When sending CONTROL URB's using the usual CONTROL ioctl, logging works fine, but when sending them via SUBMITURB, like VMWare does, the control fields are not logged. This patch fixes that. I didn't see any major changes to devio.c recently, so this patch should apply cleanly to even the latest kernel. I can resubmit if it doesn't. From: Chris Frey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3ed4cb2d56d..4b3a6ab29bd 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -962,7 +962,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EFAULT; } - snoop(&ps->dev->dev, "control urb\n"); + snoop(&ps->dev->dev, "control urb: bRequest=%02x " + "bRrequestType=%02x wValue=%04x " + "wIndex=%04x wLength=%04x\n", + dr->bRequest, dr->bRequestType, dr->wValue, + dr->wIndex, dr->wLength); break; case USBDEVFS_URB_TYPE_BULK: -- cgit v1.2.3 From a5176b78974451680bd93b8954230cf1a47dee1b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 19 Dec 2006 13:15:23 -0800 Subject: [PATCH] USB: Nokia E70 is an unusual device Taken from http://bugzilla.kernel.org/show_bug.cgi?id=7508 When the Nokia E70 Phone is plugged in to the USB port, I get: end_request: I/O error, dev sda, sector 1824527 sd 0:0:0:0: SCSI error: return code = 0x10070000 end_request: I/O error, dev sda, sector 1824535 sd 0:0:0:0: SCSI error: return code = 0x10070000 The fix is to add these lines to drivers/usb/storage/unusual_devs.h: Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5fe7ff441a0..f726b87c8fe 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -160,6 +160,13 @@ UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by */ +UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, + "Nokia", + "E70", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), + /* Reported by Jon Hart */ UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, "Nokia", -- cgit v1.2.3 From 11e82730ccdaf2a6c056d04b03368c5a9e7c1305 Mon Sep 17 00:00:00 2001 From: Eric Smith Date: Tue, 19 Dec 2006 13:15:25 -0800 Subject: [PATCH] usb serial: add support for Novatel S720/U720 CDMA/EV-DO modems Add USB vendor/device IDs for Novatel Wireless S720 and U720 CDMA/EV-DO modems to airprime.c. Signed-off-by: Eric Smith Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 62a0df2db53..f2ca76a9cba 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -19,6 +19,8 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1410, 0x1130) }, /* Novatel Wireless S720 CDMA/EV-DO */ + { USB_DEVICE(0x1410, 0x2110) }, /* Novatel Wireless U720 CDMA/EV-DO */ { USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ -- cgit v1.2.3 From c3052905033f8785bcb2c71d5ce40b84259e3a80 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 20 Dec 2006 11:46:03 -0800 Subject: USB Storage: remove duplicate Nokia entry in unusual_devs.h How many times are we going to merge this entry... Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f726b87c8fe..5fe7ff441a0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -160,13 +160,6 @@ UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), -/* Reported by */ -UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, - "Nokia", - "E70", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - /* Reported by Jon Hart */ UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, "Nokia", -- cgit v1.2.3 From 10f549fa1538849548787879d96bbb3450f06117 Mon Sep 17 00:00:00 2001 From: Soeren Sonnenburg Date: Fri, 29 Dec 2006 16:47:46 -0800 Subject: [PATCH] make fn_keys work again on power/macbooks The apple fn keys don't work anymore with 2.6.20-rc1. The reason is that USB_HID_POWERBOOK appears in several files although USB_HIDINPUT_POWERBOOK is the thing to be used. The patch fixes this. Cc: Greg KH Cc: Dmitry Torokhov Cc: Benjamin Herrenschmidt Cc: Jiri Kosina Cc: Marcel Holtmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/input/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index e308f6dc2b8..f877cd4f317 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -29,7 +29,7 @@ config USB_HID comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB_HID && INPUT=n -config USB_HID_POWERBOOK +config USB_HIDINPUT_POWERBOOK bool "Enable support for iBook/PowerBook special keys" default n depends on USB_HID -- cgit v1.2.3 From 69e4d94818cabf44d845b9f4b46d88de6e518dcf Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 3 Jan 2007 23:03:14 +0100 Subject: HID: fix help texts in Kconfig The help text for CONFIG_HID might imply for someone that it's necessary to enable it for any keyboard or mouse attached to the system. This is obviously not correct, so fix it to avoid confusing the users. Signed-off-by: Jiri Kosina --- drivers/usb/input/Kconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index f877cd4f317..258a5d09d3d 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -12,10 +12,8 @@ config USB_HID ---help--- Say Y here if you want full HID support to connect USB keyboards, mice, joysticks, graphic tablets, or any other HID based devices - to your computer via USB. You also need to select HID Input layer - support (below) if you want to use keyboards, mice, joysticks and - the like ... as well as Uninterruptible Power Supply (UPS) and - monitor control devices. + to your computer via USB, as well as Uninterruptible Power Supply + (UPS) and monitor control devices. You can't use this driver and the HIDBP (Boot Protocol) keyboard and mouse drivers at the same time. More information is available: -- cgit v1.2.3 From c80a70d53fa0ca47ad122cd75fe32b6f41c04eb1 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 15 Dec 2006 16:06:25 -0500 Subject: UHCI: make test for ASUS motherboard more specific Instead of matching all motherboards whose name contains "A7V8X" for a remote-wakeup hardware bug, this patch (as829) matches only those boards whose name is exactly equal to "A7V8X". Later motherboards don't seem to have the bug. (In fact, it's possible that only one motherboard in the world has the bug. With only one user reporting problems, it's hard to tell.) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index acd101caeee..fecc8c971c1 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -209,24 +209,16 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) static int remote_wakeup_is_broken(struct uhci_hcd *uhci) { - static struct dmi_system_id broken_wakeup_table[] = { - { - .ident = "Asus A7V8X", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"), - DMI_MATCH(DMI_BOARD_NAME, "A7V8X"), - DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"), - } - }, - { } - }; int port; + char *sys_info; + static char bad_Asus_board[] = "A7V8X"; /* One of Asus's motherboards has a bug which causes it to * wake up immediately from suspend-to-RAM if any of the ports * are connected. In such cases we will not set EGSM. */ - if (dmi_check_system(broken_wakeup_table)) { + sys_info = dmi_get_system_info(DMI_BOARD_NAME); + if (sys_info && !strcmp(sys_info, bad_Asus_board)) { for (port = 0; port < uhci->rh_numports; ++port) { if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & USBPORTSC_CCS) -- cgit v1.2.3 From 25c77b329467d563ec1fa5c3efab0b13996ce810 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 15 Dec 2006 16:08:13 -0500 Subject: UHCI: support device_may_wakeup This patch (as831) adds device_may_wakeup() support to uhci-hcd; it has been lacking for a long time. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index fecc8c971c1..e0d4c2358b3 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -257,7 +257,9 @@ __acquires(uhci->lock) int_enable = USBINTR_RESUME; if (remote_wakeup_is_broken(uhci)) egsm_enable = 0; - if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable) + if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable || + !device_may_wakeup( + &uhci_to_hcd(uhci)->self.root_hub->dev)) uhci->working_RD = int_enable = 0; outw(int_enable, uhci->io_addr + USBINTR); -- cgit v1.2.3 From 8c1527132c25512563b197b35453c7da22b4d699 Mon Sep 17 00:00:00 2001 From: Miguel Angel Alvarez Date: Thu, 14 Dec 2006 19:49:35 +0100 Subject: USB: fix interaction between different interfaces in an "Option" usb device Just the serial port in the first interface should control DTR and RTS lines. This way, the closing of the rest of the ports does not produce a= hangup in the communication. Signed-off-by: Miguel Angel Alvarez Signed-off-by: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 819266b7e2f..5ca04e82ea1 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -625,6 +625,9 @@ static int option_send_setup(struct usb_serial_port *port) dbg("%s", __FUNCTION__); + if (port->number != 0) + return 0; + portdata = usb_get_serial_port_data(port); if (port->tty) { -- cgit v1.2.3 From 6a3c3d495201490ba51a8a26daf400d89c410e6e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 14 Dec 2006 22:28:29 -0800 Subject: USB: funsoft is borken on sparc drivers/usb/serial/funsoft.c: In function `funsoft_ioctl': drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_iflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_iflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_iflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_oflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_oflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_oflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_cflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_lflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_lflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_lflag' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_line' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_line' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_line' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' drivers/usb/serial/funsoft.c:35: warning: dereferencing `void *' pointer drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: error: request for member `c_cc' in something not a structure or union drivers/usb/serial/funsoft.c:35: warning: type defaults to `int' in declaration of `type name' Cc: David Clare Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 2f4d303ee36..c8999ae5865 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -170,7 +170,7 @@ config USB_SERIAL_FTDI_SIO config USB_SERIAL_FUNSOFT tristate "USB Fundamental Software Dongle Driver" - depends on USB_SERIAL + depends on USB_SERIAL && !(SPARC || SPARC64) ---help--- Say Y here if you want to use the Fundamental Software dongle. -- cgit v1.2.3 From e6a6e472f55e0c8398650446b64c40e4a373b0c5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 10 Dec 2006 11:47:04 -0800 Subject: USB: omap_udc build fixes (sync with linux-omap) Resync the omap_udc driver with the latest from the Linux-OMAP tree. Changes include DMA API updates (it builds again!), clock/pm updates, minor bugfixes, whitespace. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 245 +++++++++++++++++++++++++++++++++--------- drivers/usb/gadget/omap_udc.h | 3 + 2 files changed, 195 insertions(+), 53 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 15d77c30793..cdcfd42843d 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,11 @@ /* bulk DMA seems to be behaving for both IN and OUT */ #define USE_DMA +/* FIXME: OMAP2 currently has some problem in DMA mode */ +#ifdef CONFIG_ARCH_OMAP2 +#undef USE_DMA +#endif + /* ISO too */ #define USE_ISO @@ -99,7 +105,7 @@ static unsigned fifo_mode = 0; * boot parameter "omap_udc:fifo_mode=42" */ module_param (fifo_mode, uint, 0); -MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)"); +MODULE_PARM_DESC (fifo_mode, "endpoint configuration"); #ifdef USE_DMA static unsigned use_dma = 1; @@ -122,7 +128,7 @@ static const char driver_desc [] = DRIVER_DESC; /*-------------------------------------------------------------------------*/ /* there's a notion of "current endpoint" for modifying endpoint - * state, and PIO access to its FIFO. + * state, and PIO access to its FIFO. */ static void use_ep(struct omap_ep *ep, u16 select) @@ -391,7 +397,7 @@ done(struct omap_ep *ep, struct omap_req *req, int status) #define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) -static inline int +static inline int write_packet(u8 *buf, struct omap_req *req, unsigned max) { unsigned len; @@ -456,7 +462,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req) return is_last; } -static inline int +static inline int read_packet(u8 *buf, struct omap_req *req, unsigned avail) { unsigned len; @@ -542,9 +548,9 @@ static inline dma_addr_t dma_csac(unsigned lch) /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is * read before the DMA controller finished disabling the channel. */ - csac = omap_readw(OMAP_DMA_CSAC(lch)); + csac = OMAP_DMA_CSAC_REG(lch); if (csac == 0) - csac = omap_readw(OMAP_DMA_CSAC(lch)); + csac = OMAP_DMA_CSAC_REG(lch); return csac; } @@ -555,9 +561,9 @@ static inline dma_addr_t dma_cdac(unsigned lch) /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is * read before the DMA controller finished disabling the channel. */ - cdac = omap_readw(OMAP_DMA_CDAC(lch)); + cdac = OMAP_DMA_CDAC_REG(lch); if (cdac == 0) - cdac = omap_readw(OMAP_DMA_CDAC(lch)); + cdac = OMAP_DMA_CDAC_REG(lch); return cdac; } @@ -582,7 +588,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) } #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \ - ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \ + ? OMAP_DMA_CSAC_REG(x) /* really: CPC */ \ : dma_cdac(x)) static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start) @@ -620,17 +626,19 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - length, 1, sync_mode); + length, 1, sync_mode, 0, 0); } else { length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); - txdma_ctrl = length; + txdma_ctrl = length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, - ep->ep.maxpacket >> 1, length, sync_mode); + ep->ep.maxpacket >> 1, length, sync_mode, + 0, 0); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, - OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, + 0, 0); omap_start_dma(ep->lch); ep->dma_counter = dma_csac(ep->lch); @@ -675,9 +683,11 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) req->dma_bytes = packets * ep->ep.maxpacket; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, ep->ep.maxpacket >> 1, packets, - OMAP_DMA_SYNC_ELEMENT); + OMAP_DMA_SYNC_ELEMENT, + 0, 0); omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, - OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, + 0, 0); ep->dma_counter = DMA_DEST_LAST(ep->lch); UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); @@ -820,7 +830,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, - (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), + 0, 0); } } else { status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, @@ -831,7 +842,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, - (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), + 0, 0); /* EMIFF */ omap_set_dma_dest_burst_mode(ep->lch, OMAP_DMA_DATA_BURST_4); @@ -846,7 +858,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) /* channel type P: hw synch (fifo) */ if (!cpu_is_omap15xx()) - omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch)); + OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2; } just_restart: @@ -893,7 +905,7 @@ static void dma_channel_release(struct omap_ep *ep) else req = NULL; - active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; + active = ((1 << 7) & OMAP_DMA_CCR_REG(ep->lch)) != 0; DBG("%s release %s %cxdma%d %p\n", ep->ep.name, active ? "active" : "idle", @@ -1117,7 +1129,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) */ dma_channel_release(ep); dma_channel_claim(ep, channel); - } else + } else done(ep, req, -ECONNRESET); spin_unlock_irqrestore(&ep->udc->lock, flags); return 0; @@ -1153,7 +1165,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) /* IN endpoints must already be idle */ if ((ep->bEndpointAddress & USB_DIR_IN) - && !list_empty(&ep->queue)) { + && !list_empty(&ep->queue)) { status = -EAGAIN; goto done; } @@ -1298,6 +1310,23 @@ static void pullup_disable(struct omap_udc *udc) UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } +static struct omap_udc *udc; + +static void omap_udc_enable_clock(int enable) +{ + if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL) + return; + + if (enable) { + clk_enable(udc->dc_clk); + clk_enable(udc->hhc_clk); + udelay(100); + } else { + clk_disable(udc->hhc_clk); + clk_disable(udc->dc_clk); + } +} + /* * Called by whatever detects VBUS sessions: external transceiver * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. @@ -1318,10 +1347,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active) else FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510; } + if (udc->dc_clk != NULL && is_active) { + if (!udc->clk_requested) { + omap_udc_enable_clock(1); + udc->clk_requested = 1; + } + } if (can_pullup(udc)) pullup_enable(udc); else pullup_disable(udc); + if (udc->dc_clk != NULL && !is_active) { + if (udc->clk_requested) { + omap_udc_enable_clock(0); + udc->clk_requested = 0; + } + } spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -1441,7 +1482,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) } } - /* IN/OUT packets mean we're in the DATA or STATUS stage. + /* IN/OUT packets mean we're in the DATA or STATUS stage. * This driver uses only uses protocol stalls (ep0 never halts), * and if we got this far the gadget driver already had a * chance to stall. Tries to be forgiving of host oddities. @@ -1509,7 +1550,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) } else if (stat == 0) UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = 0; - + /* activate status stage */ if (stat == 1) { done(ep0, req, 0); @@ -1866,7 +1907,7 @@ static void pio_out_timer(unsigned long _ep) spin_lock_irqsave(&ep->udc->lock, flags); if (!list_empty(&ep->queue) && ep->ackwait) { - use_ep(ep, 0); + use_ep(ep, UDC_EP_SEL); stat_flg = UDC_STAT_FLG_REG; if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN) @@ -1876,12 +1917,12 @@ static void pio_out_timer(unsigned long _ep) VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg); req = container_of(ep->queue.next, struct omap_req, queue); - UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL; (void) read_fifo(ep, req); UDC_EP_NUM_REG = ep->bEndpointAddress; UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; - } + } else + deselect_ep(); } mod_timer(&ep->timer, PIO_OUT_TIMEOUT); spin_unlock_irqrestore(&ep->udc->lock, flags); @@ -2028,7 +2069,17 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) /*-------------------------------------------------------------------------*/ -static struct omap_udc *udc; +static inline int machine_needs_vbus_session(void) +{ + return (machine_is_omap_innovator() + || machine_is_omap_osk() + || machine_is_omap_apollon() +#ifndef CONFIG_MACH_OMAP_H4_OTG + || machine_is_omap_h4() +#endif + || machine_is_sx1() + ); +} int usb_gadget_register_driver (struct usb_gadget_driver *driver) { @@ -2070,6 +2121,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); + if (udc->dc_clk != NULL) + omap_udc_enable_clock(1); + status = driver->bind (&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); @@ -2103,10 +2157,12 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) /* boards that don't have VBUS sensing can't autogate 48MHz; * can't enter deep sleep while a gadget driver is active. */ - if (machine_is_omap_innovator() || machine_is_omap_osk()) + if (machine_needs_vbus_session()) omap_vbus_session(&udc->gadget, 1); done: + if (udc->dc_clk != NULL) + omap_udc_enable_clock(0); return status; } EXPORT_SYMBOL(usb_gadget_register_driver); @@ -2121,7 +2177,10 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; - if (machine_is_omap_innovator() || machine_is_omap_osk()) + if (udc->dc_clk != NULL) + omap_udc_enable_clock(1); + + if (machine_needs_vbus_session()) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) @@ -2137,6 +2196,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) udc->gadget.dev.driver = NULL; udc->driver = NULL; + if (udc->dc_clk != NULL) + omap_udc_enable_clock(0); DBG("unregistered driver '%s'\n", driver->driver.name); return status; } @@ -2219,7 +2280,7 @@ static char *trx_mode(unsigned m, int enabled) case 0: return enabled ? "*6wire" : "unused"; case 1: return "4wire"; case 2: return "3wire"; - case 3: return "6wire"; + case 3: return "6wire"; default: return "unknown"; } } @@ -2228,11 +2289,18 @@ static int proc_otg_show(struct seq_file *s) { u32 tmp; u32 trans; + char *ctrl_name; tmp = OTG_REV_REG; - trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n", - tmp >> 4, tmp & 0xf, trans); + if (cpu_is_omap24xx()) { + ctrl_name = "control_devconf"; + trans = CONTROL_DEVCONF_REG; + } else { + ctrl_name = "tranceiver_ctrl"; + trans = USB_TRANSCEIVER_CTRL_REG; + } + seq_printf(s, "\nOTG rev %d.%d, %s %05x\n", + tmp >> 4, tmp & 0xf, ctrl_name, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, @@ -2307,7 +2375,7 @@ static int proc_udc_show(struct seq_file *s, void *_) driver_desc, use_dma ? " (dma)" : ""); - tmp = UDC_REV_REG & 0xff; + tmp = UDC_REV_REG & 0xff; seq_printf(s, "UDC rev %d.%d, fifo mode %d, gadget %s\n" "hmc %d, transceiver %s\n", @@ -2315,11 +2383,16 @@ static int proc_udc_show(struct seq_file *s, void *_) fifo_mode, udc->driver ? udc->driver->driver.name : "(none)", HMC, - udc->transceiver ? udc->transceiver->label : "(none)"); - seq_printf(s, "ULPD control %04x req %04x status %04x\n", - __REG16(ULPD_CLOCK_CTRL), - __REG16(ULPD_SOFT_REQ), - __REG16(ULPD_STATUS_REQ)); + udc->transceiver + ? udc->transceiver->label + : ((cpu_is_omap1710() || cpu_is_omap24xx()) + ? "external" : "(none)")); + if (cpu_class_is_omap1()) { + seq_printf(s, "ULPD control %04x req %04x status %04x\n", + __REG16(ULPD_CLOCK_CTRL), + __REG16(ULPD_SOFT_REQ), + __REG16(ULPD_STATUS_REQ)); + } /* OTG controller registers */ if (!cpu_is_omap15xx()) @@ -2504,9 +2577,10 @@ omap_ep_setup(char *name, u8 addr, u8 type, dbuf = 1; } else { /* double-buffering "not supported" on 15xx, - * and ignored for PIO-IN on 16xx + * and ignored for PIO-IN on newer chips + * (for more reliable behavior) */ - if (!use_dma || cpu_is_omap15xx()) + if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx()) dbuf = 0; switch (maxp) { @@ -2549,7 +2623,7 @@ omap_ep_setup(char *name, u8 addr, u8 type, ep->bEndpointAddress = addr; ep->bmAttributes = type; ep->double_buf = dbuf; - ep->udc = udc; + ep->udc = udc; ep->ep.name = ep->name; ep->ep.ops = &omap_ep_ops; @@ -2709,15 +2783,37 @@ static int __init omap_udc_probe(struct platform_device *pdev) struct otg_transceiver *xceiv = NULL; const char *type = NULL; struct omap_usb_config *config = pdev->dev.platform_data; + struct clk *dc_clk; + struct clk *hhc_clk; /* NOTE: "knows" the order of the resources! */ - if (!request_mem_region(pdev->resource[0].start, + if (!request_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1, driver_name)) { DBG("request_mem_region failed\n"); return -EBUSY; } + if (cpu_is_omap16xx()) { + dc_clk = clk_get(&pdev->dev, "usb_dc_ck"); + hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck"); + BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); + /* can't use omap_udc_enable_clock yet */ + clk_enable(dc_clk); + clk_enable(hhc_clk); + udelay(100); + } + + if (cpu_is_omap24xx()) { + dc_clk = clk_get(&pdev->dev, "usb_fck"); + hhc_clk = clk_get(&pdev->dev, "usb_l4_ick"); + BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); + /* can't use omap_udc_enable_clock yet */ + clk_enable(dc_clk); + clk_enable(hhc_clk); + udelay(100); + } + INFO("OMAP UDC rev %d.%d%s\n", UDC_REV_REG >> 4, UDC_REV_REG & 0xf, config->otg ? ", Mini-AB" : ""); @@ -2727,7 +2823,7 @@ static int __init omap_udc_probe(struct platform_device *pdev) hmc = HMC_1510; type = "(unknown)"; - if (machine_is_omap_innovator()) { + if (machine_is_omap_innovator() || machine_is_sx1()) { /* just set up software VBUS detect, and then * later rig it so we always report VBUS. * FIXME without really sensing VBUS, we can't @@ -2756,6 +2852,15 @@ static int __init omap_udc_probe(struct platform_device *pdev) } hmc = HMC_1610; + + if (cpu_is_omap24xx()) { + /* this could be transceiverless in one of the + * "we don't need to know" modes. + */ + type = "external"; + goto known; + } + switch (hmc) { case 0: /* POWERUP DEFAULT == 0 */ case 4: @@ -2794,6 +2899,7 @@ bad_on_1710: goto cleanup0; } } +known: INFO("hmc mode %d, %s transceiver\n", hmc, type); /* a "gadget" abstracts/virtualizes the controller */ @@ -2818,8 +2924,8 @@ bad_on_1710: status = request_irq(pdev->resource[1].start, omap_udc_irq, IRQF_SAMPLE_RANDOM, driver_name, udc); if (status != 0) { - ERR( "can't get irq %ld, err %d\n", - pdev->resource[1].start, status); + ERR("can't get irq %d, err %d\n", + (int) pdev->resource[1].start, status); goto cleanup1; } @@ -2827,24 +2933,41 @@ bad_on_1710: status = request_irq(pdev->resource[2].start, omap_udc_pio_irq, IRQF_SAMPLE_RANDOM, "omap_udc pio", udc); if (status != 0) { - ERR( "can't get irq %ld, err %d\n", - pdev->resource[2].start, status); + ERR("can't get irq %d, err %d\n", + (int) pdev->resource[2].start, status); goto cleanup2; } #ifdef USE_ISO status = request_irq(pdev->resource[3].start, omap_udc_iso_irq, IRQF_DISABLED, "omap_udc iso", udc); if (status != 0) { - ERR("can't get irq %ld, err %d\n", - pdev->resource[3].start, status); + ERR("can't get irq %d, err %d\n", + (int) pdev->resource[3].start, status); goto cleanup3; } #endif + if (cpu_is_omap16xx()) { + udc->dc_clk = dc_clk; + udc->hhc_clk = hhc_clk; + clk_disable(hhc_clk); + clk_disable(dc_clk); + } + + if (cpu_is_omap24xx()) { + udc->dc_clk = dc_clk; + udc->hhc_clk = hhc_clk; + /* FIXME OMAP2 don't release hhc & dc clock */ +#if 0 + clk_disable(hhc_clk); + clk_disable(dc_clk); +#endif + } create_proc_file(); - device_add(&udc->gadget.dev); - return 0; - + status = device_add(&udc->gadget.dev); + if (!status) + return status; + /* If fail, fall through */ #ifdef USE_ISO cleanup3: free_irq(pdev->resource[2].start, udc); @@ -2860,8 +2983,17 @@ cleanup1: cleanup0: if (xceiv) put_device(xceiv->dev); + + if (cpu_is_omap16xx() || cpu_is_omap24xx()) { + clk_disable(hhc_clk); + clk_disable(dc_clk); + clk_put(hhc_clk); + clk_put(dc_clk); + } + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); + return status; } @@ -2891,6 +3023,13 @@ static int __exit omap_udc_remove(struct platform_device *pdev) free_irq(pdev->resource[2].start, udc); free_irq(pdev->resource[1].start, udc); + if (udc->dc_clk) { + if (udc->clk_requested) + omap_udc_enable_clock(0); + clk_put(udc->hhc_clk); + clk_put(udc->dc_clk); + } + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index 652ee462734..1dc398bb9ab 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -175,6 +175,9 @@ struct omap_udc { unsigned ep0_reset_config:1; unsigned ep0_setup:1; struct completion *done; + struct clk *dc_clk; + struct clk *hhc_clk; + unsigned clk_requested:1; }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From f1cd4ad202ce34d29c847fd82df948ff67c17826 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Sun, 31 Dec 2006 00:19:50 -0800 Subject: USB Storage: unusual_devs: add supertop drives This combines patches from Alan Stern and Robert Schedel for two "Super Top" drives that need the IGNORE_RESIDUE flag but have different vendor IDs. Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5fe7ff441a0..5239e47914f 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1358,6 +1358,21 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Francesco Foresti */ +UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, + "Super Top", + "IDE DEVICE", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + +/* Reported by Robert Schedel + * Note: this is a 'super top' device like the above 14cd/6600 device */ +UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, + "Teac", + "HD-35PUK-B", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* patch submitted by Davide Perini * and Renato Perini */ -- cgit v1.2.3 From ad1428c96ebdee592aa475afe129530225bef186 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sun, 31 Dec 2006 13:43:26 -0800 Subject: USB storage: fix ipod ejecting issue This patch from Pete fixes the 'ejecting problem' on yet another ipod. Please applyt. Signed-off-by: Pete Zaitcev Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5239e47914f..cddef3efba0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -728,7 +728,7 @@ UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999, "Apple", "iPod", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), + US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999, "Apple", -- cgit v1.2.3 From c07be136a883a148a16ce4cd91163035631b37ea Mon Sep 17 00:00:00 2001 From: Sarah Bailey Date: Wed, 3 Jan 2007 21:37:22 -0800 Subject: USB: Fixed bug in endpoint release function. Error handling in usb_create_ep_files() is not correct unless the minor number is freed in ep_device_release(). Signed-off-by: Sarah Bailey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index c505b767cee..5e628ae3aec 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -268,6 +268,7 @@ static void ep_device_release(struct device *dev) struct ep_device *ep_dev = to_ep_device(dev); dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); + endpoint_free_minor(ep_dev); kfree(ep_dev); } @@ -349,7 +350,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint) sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); sysfs_remove_link(&ep_dev->dev.parent->kobj, name); sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); - endpoint_free_minor(ep_dev); device_unregister(&ep_dev->dev); endpoint->ep_dev = NULL; destroy_endpoint_class(); -- cgit v1.2.3 From c067dfc650a2d7d26d4b9bdecc339596f8746cff Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 3 Jan 2007 16:45:21 -0800 Subject: sisusb_con warning fixes x86_64: drivers/usb/misc/sisusbvga/sisusb_con.c: In function 'sisusbcon_putc': drivers/usb/misc/sisusbvga/sisusb_con.c:405: warning: cast from pointer to integer of different size drivers/usb/misc/sisusbvga/sisusb_con.c: In function 'sisusbcon_putcs': drivers/usb/misc/sisusbvga/sisusb_con.c:440: warning: cast from pointer to integer of different size drivers/usb/misc/sisusbvga/sisusb_con.c: In function 'sisusbcon_clear': drivers/usb/misc/sisusbvga/sisusb_con.c:494: warning: cast from pointer to integer of different size drivers/usb/misc/sisusbvga/sisusb_con.c: In function 'sisusbcon_bmove': drivers/usb/misc/sisusbvga/sisusb_con.c:566: warning: cast from pointer to integer of different size drivers/usb/misc/sisusbvga/sisusb_con.c: In function 'sisusbcon_switch': drivers/usb/misc/sisusbvga/sisusb_con.c:614: warning: cast from pointer to integer of different size drivers/usb/misc/sisusbvga/sisusb_con.c: In function 'sisusbcon_scroll_area': drivers/usb/misc/sisusbvga/sisusb_con.c:941: warning: cast from pointer to integer of different size Cc: Thomas Winischhofer Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_con.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index bf26c3c5699..9148694627d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -403,7 +403,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (u32)SISUSB_HADDR(x, y), 2, &written); + (long)SISUSB_HADDR(x, y), 2, &written); mutex_unlock(&sisusb->lock); } @@ -438,7 +438,7 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (u32)SISUSB_HADDR(x, y), count * 2, &written); + (long)SISUSB_HADDR(x, y), count * 2, &written); mutex_unlock(&sisusb->lock); } @@ -492,7 +492,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (u32)SISUSB_HADDR(x, y), length, &written); + (long)SISUSB_HADDR(x, y), length, &written); mutex_unlock(&sisusb->lock); } @@ -564,7 +564,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (u32)SISUSB_HADDR(dx, dy), length, &written); + (long)SISUSB_HADDR(dx, dy), length, &written); mutex_unlock(&sisusb->lock); } @@ -612,7 +612,7 @@ sisusbcon_switch(struct vc_data *c) length); sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, - (u32)SISUSB_HADDR(0, 0), + (long)SISUSB_HADDR(0, 0), length, &written); mutex_unlock(&sisusb->lock); @@ -939,7 +939,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (u32)SISUSB_HADDR(0, t), length, &written); + (long)SISUSB_HADDR(0, t), length, &written); mutex_unlock(&sisusb->lock); -- cgit v1.2.3 From 4f45d0387b407348de48c212ac5b3496ce6d2fda Mon Sep 17 00:00:00 2001 From: Martin Williges Date: Thu, 28 Dec 2006 20:52:10 +0100 Subject: USB: usblp.c - add Kyocera Mita FS 820 to list of "quirky" printers This patch gets the Kyocera FS-820 working with cups 1.2 via usb again. It adds the printer to the list of "quirky" printers. The printer seems not answer to ID requests some seconds after plugging in. Patch is based on linux-2.6.19.1. Background: As far as I could see (strace, usbmon), the Kyocera FS-820 answers to ID requests only a few seconds after plugging it in. This applies to detecting it with cups and is also true for the printing itself, which is initiated with an ID request. Since I have little usb knowledge, maybe someone can interpret the data, especially the fist bulk transfer - why request 8192 bytes? This is the second version of the patch. usbmon output of printing an email without patch: tail -F /tmp/printlog.txt c636e140 3374734463 S Bi:002:02 -115 8192 < c9d43b40 3374734494 S Ci:002:00 s a1 00 0000 0000 03ff 1023 < c9d43b40 3379732301 C Ci:002:00 -104 0 c636e140 3379733294 C Bi:002:02 -2 0 [...repeating...] with patch: tail -F /tmp/printlog.txt d9cb82c0 3729790131 S Ci:002:00 s a1 00 0000 0000 03ff 1023 < d9cb82c0 3729791725 C Ci:002:00 0 91 = 005b4944 3a46532d 3832303b 4d46473a 4b796f63 6572613b 434d443a 50434c58 df956320 3732493190 S Bo:002:01 -115 1347 = 1b252d31 32333435 5840504a 4c0a4050 4a4c2053 4554204d 414e5541 4c464545 [...more data...] Signed-off-by: Martin Williges Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 24ee8be359f..6377db1b446 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -217,6 +217,7 @@ static const struct quirk_printer_struct quirk_printers[] = { { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ + { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut */ { 0, 0 } }; -- cgit v1.2.3 From 14e51f28ade783cd948cd10202a696ff7e5d33d6 Mon Sep 17 00:00:00 2001 From: David Hollis Date: Thu, 28 Dec 2006 14:09:11 -0500 Subject: USB: asix: Fix AX88772 device PHY selection A small typo in ax88772_bind() prevents the device from selecting the proper PHY, leaving the device useless. The attached patch fixes this. If this patch can be added to the 2.6.19.x series as well, that would be helpful for end-users. Signed-off-by: David Hollis Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/asix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 95e682e2c9d..f538013965b 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -920,7 +920,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) goto out2; if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, - 0x0000, 0, 0, buf)) < 0) { + 1, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); goto out2; } -- cgit v1.2.3 From 88bf7b391dca840f03fe25e4ff8fe6b4319fa07b Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 10 Jan 2007 23:15:40 -0800 Subject: [PATCH] really fix funsoft driver Fix void cast and re-enable on sparc. Signed-off-by: David S. Miller Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/serial/Kconfig | 2 +- drivers/usb/serial/funsoft.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index c8999ae5865..2f4d303ee36 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -170,7 +170,7 @@ config USB_SERIAL_FTDI_SIO config USB_SERIAL_FUNSOFT tristate "USB Fundamental Software Dongle Driver" - depends on USB_SERIAL && !(SPARC || SPARC64) + depends on USB_SERIAL ---help--- Say Y here if you want to use the Fundamental Software dongle. diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index d3be9214c7c..31501c9361b 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -32,7 +32,7 @@ static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); if (cmd == TCSETSF) { - if (user_termios_to_kernel_termios(&t, (void __user *)arg)) + if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) return -EFAULT; dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, -- cgit v1.2.3 From e7c4e1a58f320bafb194a411a41de29abc19315f Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 12 Jan 2007 21:53:51 +0000 Subject: HID: fix some ARM builds due to HID brokenness - make USB_HID depend on INPUT We have USB_HID _newly_ selected in configurations which didn't have it before, which overrides CONFIG_HID and builds HID without input support. Nevertheless, here's a patch to solve more of the same that my original patch attempted to solve. The original patch is still required. Seems to solve the final instance of this problem here. Signed-off-by: Russell King Signed-off-by: Jiri Kosina --- drivers/usb/input/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 258a5d09d3d..c7d887540d8 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -7,7 +7,7 @@ comment "USB Input Devices" config USB_HID tristate "USB Human Interface Device (full HID) support" default y - depends on USB + depends on USB && INPUT select HID ---help--- Say Y here if you want full HID support to connect USB keyboards, -- cgit v1.2.3 From 694400641b0da92d88db60821235aa69eb8fa556 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Sun, 14 Jan 2007 22:12:43 +0100 Subject: HID: GEYSER4_ISO needs quirk I've got a newer MacBook with core2duo. Two keys on the keyboard are swapped, "unswaping" works with the same trick as GEYSER3_ISO. Signed-off-by: Adrian Friedli Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 89fa6885709..0350218d71d 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -951,7 +951,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, -- cgit v1.2.3 From be8209753b014f2d7a92b2ec3ff82db478fc86d1 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Fri, 19 Jan 2007 19:28:17 +0200 Subject: HID: put usb_interface instead of usb_device into hid->dev to fix udevinfo breakage The commit 4916b3a57fc94664677d439b911b8aaf86c7ec23 introduced a hid regression between 2.6.19 and 2.6.20-rc1. The device put in input_dev->cdev is now of type usb_device instead of usb_interface. Before: > # readlink -f /sys/class/input/input6/event4/device > /sys/devices/pci0000:00/0000:00:10.0/usb2/2-1/2-1:1.1 After: > # readlink -f /sys/class/input/input3/event3/device > /sys/devices/pci0000:00/0000:00:10.0/usb1/1-1 This causes breakage: > # udevinfo -q all -n /dev/input/event3 > P: /class/input/input3/event3 > N: input/event3 > S: input/by-path/pci-1-1--event- > E: ID_SERIAL=noserial > E: ID_PATH=pci-1-1- No ID_MODEL, ID_VENDOR, ID_REVISION, ID_TYPE etc etc. Fix this by assigning the intf->dev into hid->dev, and fixing all the users. Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 30 +++++++++++++++--------------- drivers/usb/input/hid-ff.c | 5 +++-- drivers/usb/input/hiddev.c | 2 +- drivers/usb/input/usbhid.h | 3 +++ 4 files changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 0350218d71d..521047bcc46 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -106,18 +106,18 @@ static void hid_reset(struct work_struct *work) if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { dev_dbg(&usbhid->intf->dev, "clear halt\n"); - rc = usb_clear_halt(to_usb_device(hid->dev), usbhid->urbin->pipe); + rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe); clear_bit(HID_CLEAR_HALT, &usbhid->iofl); hid_start_in(hid); } else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { dev_dbg(&usbhid->intf->dev, "resetting device\n"); - rc = rc_lock = usb_lock_device_for_reset(to_usb_device(hid->dev), usbhid->intf); + rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf); if (rc_lock >= 0) { - rc = usb_reset_composite_device(to_usb_device(hid->dev), usbhid->intf); + rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf); if (rc_lock) - usb_unlock_device(to_usb_device(hid->dev)); + usb_unlock_device(hid_to_usb_dev(hid)); } clear_bit(HID_RESET_PENDING, &usbhid->iofl); } @@ -129,8 +129,8 @@ static void hid_reset(struct work_struct *work) break; default: err("can't reset device, %s-%s/input%d, status %d", - to_usb_device(hid->dev)->bus->bus_name, - to_usb_device(hid->dev)->devpath, + hid_to_usb_dev(hid)->bus->bus_name, + hid_to_usb_dev(hid)->devpath, usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: @@ -217,8 +217,8 @@ static void hid_irq_in(struct urb *urb) clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err("can't resubmit intr, %s-%s/input%d, status %d", - to_usb_device(hid->dev)->bus->bus_name, - to_usb_device(hid->dev)->devpath, + hid_to_usb_dev(hid)->bus->bus_name, + hid_to_usb_dev(hid)->devpath, usbhid->ifnum, status); hid_io_error(hid); } @@ -251,7 +251,7 @@ static int hid_submit_out(struct hid_device *hid) hid_output_report(report, usbhid->outbuf); usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - usbhid->urbout->dev = to_usb_device(hid->dev); + usbhid->urbout->dev = hid_to_usb_dev(hid); dbg("submitting out urb"); @@ -276,13 +276,13 @@ static int hid_submit_ctrl(struct hid_device *hid) len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { hid_output_report(report, usbhid->ctrlbuf); - usbhid->urbctrl->pipe = usb_sndctrlpipe(to_usb_device(hid->dev), 0); + usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); usbhid->urbctrl->transfer_buffer_length = len; } else { int maxpacket, padlen; - usbhid->urbctrl->pipe = usb_rcvctrlpipe(to_usb_device(hid->dev), 0); - maxpacket = usb_maxpacket(to_usb_device(hid->dev), usbhid->urbctrl->pipe, 0); + usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0); + maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0); if (maxpacket > 0) { padlen = (len + maxpacket - 1) / maxpacket; padlen *= maxpacket; @@ -292,7 +292,7 @@ static int hid_submit_ctrl(struct hid_device *hid) padlen = 0; usbhid->urbctrl->transfer_buffer_length = padlen; } - usbhid->urbctrl->dev = to_usb_device(hid->dev); + usbhid->urbctrl->dev = hid_to_usb_dev(hid); usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; @@ -1187,7 +1187,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - hid->dev = &dev->dev; + hid->dev = &intf->dev; usbhid->intf = intf; usbhid->ifnum = interface->desc.bInterfaceNumber; @@ -1282,7 +1282,7 @@ static void hid_disconnect(struct usb_interface *intf) usb_free_urb(usbhid->urbctrl); usb_free_urb(usbhid->urbout); - hid_free_buffers(to_usb_device(hid->dev), hid); + hid_free_buffers(hid_to_usb_dev(hid), hid); hid_free_device(hid); } diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index f8f660ee3fa..59ed65e7a62 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -33,6 +33,7 @@ #include #include +#include "usbhid.h" /* * This table contains pointers to initializers. To add support for new @@ -70,8 +71,8 @@ static struct hid_ff_initializer inits[] = { int hid_ff_init(struct hid_device* hid) { struct hid_ff_initializer *init; - int vendor = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idVendor); - int product = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idProduct); + int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor); + int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct); for (init = inits; init->idVendor; init++) if (init->idVendor == vendor && init->idProduct == product) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 114d6c9f64b..a8b3d66cd49 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -384,7 +384,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = to_usb_device(hid->dev); + struct usb_device *dev = hid_to_usb_dev(hid); struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h index 830107e5251..0023f96d429 100644 --- a/drivers/usb/input/usbhid.h +++ b/drivers/usb/input/usbhid.h @@ -80,5 +80,8 @@ struct usbhid_device { }; +#define hid_to_usb_dev(hid_dev) \ + container_of(hid_dev->dev->parent, struct usb_device, dev) + #endif -- cgit v1.2.3 From d8c8a393166d6283003fb111d0b4a40931c0eda4 Mon Sep 17 00:00:00 2001 From: Jeremy Roberson Date: Fri, 19 Jan 2007 15:44:18 -0700 Subject: hid-core.c: Adds GTCO CalComp Interwrite IPanel PIDs to blacklist Adds GTCO CalComp Interwrite IPanels to the hid-core.c blacklist. Signed-off-by: Jeremy A. Roberson Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 521047bcc46..6e739efee6f 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -582,6 +582,8 @@ void usbhid_init_reports(struct hid_device *hid) } #define USB_VENDOR_ID_GTCO 0x078c +#define USB_VENDOR_ID_GTCO_IPANEL_1 0x08ca +#define USB_VENDOR_ID_GTCO_IPANEL_2 0x5543 #define USB_DEVICE_ID_GTCO_90 0x0090 #define USB_DEVICE_ID_GTCO_100 0x0100 #define USB_DEVICE_ID_GTCO_101 0x0101 @@ -627,6 +629,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_GTCO_1004 0x1004 #define USB_DEVICE_ID_GTCO_1005 0x1005 #define USB_DEVICE_ID_GTCO_1006 0x1006 +#define USB_DEVICE_ID_GTCO_10 0x0010 +#define USB_DEVICE_ID_GTCO_8 0x0008 +#define USB_DEVICE_ID_GTCO_d 0x000d #define USB_VENDOR_ID_WACOM 0x056a @@ -875,6 +880,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO_IPANEL_1, USB_DEVICE_ID_GTCO_10, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From c9d8c2b324d24ffb4fdcd93b3f752530a5a0a591 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Mon, 11 Dec 2006 18:17:45 +0100 Subject: usbtouchscreen: make ITM screens report BTN_TOUCH as zero when not touched ITM screens send invalid x/y data when not touched. this was fixes a while ago but the problem is if the screen is not touched anymore the driver never does not report BTN_TOUCH as zero. fix it by sending the report with the last valid coordinates when pressure is released. Signed-off-by: Daniel Ritz Cc: J.P. Delport Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/usbtouchscreen.c | 98 +++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 39 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index 7f3c57da9bc..86e37a20f8e 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -66,7 +66,7 @@ struct usbtouch_device_info { void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); int (*get_pkt_len) (unsigned char *pkt, int len); - int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press); + int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); int (*init) (struct usbtouch_usb *usbtouch); }; @@ -85,6 +85,9 @@ struct usbtouch_usb { struct usbtouch_device_info *type; char name[128]; char phys[64]; + + int x, y; + int touch, press; }; @@ -161,14 +164,14 @@ static struct usb_device_id usbtouch_devices[] = { #define EGALAX_PKT_TYPE_REPT 0x80 #define EGALAX_PKT_TYPE_DIAG 0x0A -static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) return 0; - *x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); - *y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); - *touch = pkt[0] & 0x01; + dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); + dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); + dev->touch = pkt[0] & 0x01; return 1; } @@ -195,11 +198,11 @@ static int egalax_get_pkt_len(unsigned char *buf, int len) * PanJit Part */ #ifdef CONFIG_USB_TOUCHSCREEN_PANJIT -static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = ((pkt[2] & 0x0F) << 8) | pkt[1]; - *y = ((pkt[4] & 0x0F) << 8) | pkt[3]; - *touch = pkt[0] & 0x01; + dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1]; + dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3]; + dev->touch = pkt[0] & 0x01; return 1; } @@ -215,11 +218,11 @@ static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int #define MTOUCHUSB_RESET 7 #define MTOUCHUSB_REQ_CTRLLR_ID 10 -static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = (pkt[8] << 8) | pkt[7]; - *y = (pkt[10] << 8) | pkt[9]; - *touch = (pkt[2] & 0x40) ? 1 : 0; + dev->x = (pkt[8] << 8) | pkt[7]; + dev->y = (pkt[10] << 8) | pkt[9]; + dev->touch = (pkt[2] & 0x40) ? 1 : 0; return 1; } @@ -260,14 +263,32 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) * ITM Part */ #ifdef CONFIG_USB_TOUCHSCREEN_ITM -static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); - *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); - *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); - *touch = ~pkt[7] & 0x20; + int touch; + /* + * ITM devices report invalid x/y data if not touched. + * if the screen was touched before but is not touched any more + * report touch as 0 with the last valid x/y data once. then stop + * reporting data until touched again. + */ + dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); + + touch = ~pkt[7] & 0x20; + if (!touch) { + if (dev->touch) { + dev->touch = 0; + return 1; + } - return *touch; + return 0; + } + + dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); + dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); + dev->touch = touch; + + return 1; } #endif @@ -276,7 +297,7 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr * eTurboTouch part */ #ifdef CONFIG_USB_TOUCHSCREEN_ETURBO -static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { unsigned int shift; @@ -285,9 +306,9 @@ static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int return 0; shift = (6 - (pkt[0] & 0x03)); - *x = ((pkt[3] << 7) | pkt[4]) >> shift; - *y = ((pkt[1] << 7) | pkt[2]) >> shift; - *touch = (pkt[0] & 0x10) ? 1 : 0; + dev->x = ((pkt[3] << 7) | pkt[4]) >> shift; + dev->y = ((pkt[1] << 7) | pkt[2]) >> shift; + dev->touch = (pkt[0] & 0x10) ? 1 : 0; return 1; } @@ -307,14 +328,14 @@ static int eturbo_get_pkt_len(unsigned char *buf, int len) * Gunze part */ #ifdef CONFIG_USB_TOUCHSCREEN_GUNZE -static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80)) return 0; - *x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F); - *y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F); - *touch = pkt[0] & 0x20; + dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F); + dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F); + dev->touch = pkt[0] & 0x20; return 1; } @@ -383,11 +404,11 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) } -static int dmc_tsc10_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = ((pkt[2] & 0x03) << 8) | pkt[1]; - *y = ((pkt[4] & 0x03) << 8) | pkt[3]; - *touch = pkt[0] & 0x01; + dev->x = ((pkt[2] & 0x03) << 8) | pkt[1]; + dev->y = ((pkt[4] & 0x03) << 8) | pkt[3]; + dev->touch = pkt[0] & 0x01; return 1; } @@ -492,23 +513,22 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, unsigned char *pkt, int len) { - int x, y, touch, press; struct usbtouch_device_info *type = usbtouch->type; - if (!type->read_data(pkt, &x, &y, &touch, &press)) + if (!type->read_data(usbtouch, pkt)) return; - input_report_key(usbtouch->input, BTN_TOUCH, touch); + input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); if (swap_xy) { - input_report_abs(usbtouch->input, ABS_X, y); - input_report_abs(usbtouch->input, ABS_Y, x); + input_report_abs(usbtouch->input, ABS_X, usbtouch->y); + input_report_abs(usbtouch->input, ABS_Y, usbtouch->x); } else { - input_report_abs(usbtouch->input, ABS_X, x); - input_report_abs(usbtouch->input, ABS_Y, y); + input_report_abs(usbtouch->input, ABS_X, usbtouch->x); + input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); } if (type->max_press) - input_report_abs(usbtouch->input, ABS_PRESSURE, press); + input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press); input_sync(usbtouch->input); } -- cgit v1.2.3 From d0ffff8fddd5853e4b2b101790ac0c3690655af5 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 11 Jan 2007 18:39:16 -0500 Subject: USB: asix: Detect internal PHY and enable/use accordingly Different AX88772 dongles use different PHYs; the chip is capable of using both a primary and secondary PHY, and supports an internal and external PHY. It appears that some DUB-E100 devices use the internal PHY, so trying to use an external one will not work (note that this is different across revisions, as well; the "A" and "B" revs of the DUB-E100 use different PHYs!). The data sheet for the AX88772 chip specifies that the internal PHY id will be 0x10, so if that's read from the EEPROM, we should use that rather than attempting to use an external PHY. Thanks to Mitch Bradley for pointing this out! Signed-off-by: Andres Salomon Cc: David Hollis Cc: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/asix.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index f538013965b..896449f0cf8 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -898,7 +898,7 @@ static int ax88772_link_reset(struct usbnet *dev) static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) { - int ret; + int ret, embd_phy; void *buf; u16 rx_ctl; struct asix_data *data = (struct asix_data *)&dev->data; @@ -919,13 +919,15 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0) goto out2; + /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ + embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, - 1, 0, 0, buf)) < 0) { + embd_phy, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); goto out2; } - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD)) < 0) + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0) goto out2; msleep(150); @@ -933,8 +935,14 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) goto out2; msleep(150); - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) - goto out2; + if (embd_phy) { + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0) + goto out2; + } + else { + if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0) + goto out2; + } msleep(150); rx_ctl = asix_read_rx_ctl(dev); -- cgit v1.2.3 From deb31f1764e0a11bcfe8d44e0658f83d83860e84 Mon Sep 17 00:00:00 2001 From: Daniel Gollub Date: Tue, 16 Jan 2007 11:03:01 +0100 Subject: USB: rndis_host: fix crash while probing a Nokia S60 mobile Bug fix for driver rndis_host which fixes rndis_host probing certain Nokia S60 (Series 60) mobiles. While the rndis_host get probed by usbnet and tries to bind the Nokia mobile the bind is going to fail. The rndis_host module tries to release the device, in a wrong way, which cause the oops. Fixes Bugzilla #7201 Signed-off-by: Daniel Gollub Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/rndis_host.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index ea5f44de3de..a322a16d9cf 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -379,6 +379,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) { int retval; struct net_device *net = dev->net; + struct cdc_state *info = (void *) &dev->data; union { void *buf; struct rndis_msg_hdr *header; @@ -397,7 +398,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) - goto done; + goto fail; net->hard_header_len += sizeof (struct rndis_data_hdr); @@ -412,10 +413,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); -fail: - usb_driver_release_interface(driver_of(intf), - ((struct cdc_state *)&(dev->data))->data); - goto done; + goto fail_and_release; } dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); /* REVISIT: peripheral "alignment" request is ignored ... */ @@ -431,7 +429,7 @@ fail: retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); - goto fail; + goto fail_and_release; } tmp = le32_to_cpu(u.get_c->offset); if (unlikely((tmp + 8) > (1024 - ETH_ALEN) @@ -439,7 +437,7 @@ fail: dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", tmp, le32_to_cpu(u.get_c->len)); retval = -EDOM; - goto fail; + goto fail_and_release; } memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN); @@ -455,11 +453,18 @@ fail: retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); - goto fail; + goto fail_and_release; } retval = 0; -done: + + kfree(u.buf); + return retval; + +fail_and_release: + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver_of(intf), info->data); +fail: kfree(u.buf); return retval; } -- cgit v1.2.3 From 8d2bad8788a6f968247df409f50c757b1a5489f4 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 11 Jan 2007 10:14:33 +0100 Subject: USB: make usbhid ignore Imation Disc Stakka on request of the sourceforge project for this device, a kind of robotized CD storage, it should be ignored by the generic driver. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6e739efee6f..ea3636d96e1 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -796,6 +796,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 +#define USB_VENDOR_ID_IMATION 0x0718 +#define USB_DEVICE_ID_DISC_STAKKA 0xd000 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -883,6 +886,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO_IPANEL_1, USB_DEVICE_ID_GTCO_10, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From 379885a9b204dec9d0009b6b450e104389b4a590 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sat, 13 Jan 2007 15:17:46 -0800 Subject: USB: unusual_devs.h for 0x046b:ff40 American Megatrends did something wrong in their floppy emulator. It breaks with both kinds of MODE SENSE which our stack sends. Alan and I tried a few tweaks, and got LUNs sensed right, but US_FL_NO_WP_DETECT is still needed. I set the firmware bracket to 1.00 exactly, in case AMI or Sun fix it with a firmware update. Hey, you never know. Signed-off-by: Pete Zaitcev Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index cddef3efba0..4ef6496e021 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -254,6 +254,18 @@ UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101, US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0), #endif +/* + * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.) + * Reported by Pete Zaitcev + * This device chokes on both version of MODE SENSE which we have, so + * use_10_for_ms is not effective, and we use US_FL_NO_WP_DETECT. + */ +UNUSUAL_DEV( 0x046b, 0xff40, 0x0100, 0x0100, + "AMI", + "Virtual Floppy", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NO_WP_DETECT), + /* Patch submitted by Philipp Friedrich */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, "Kyocera", -- cgit v1.2.3 From 53e8f84dc68f29c724bbb7e0675040386f6143ae Mon Sep 17 00:00:00 2001 From: "garrett_damore@tadpole.com" Date: Fri, 12 Jan 2007 17:10:28 -0800 Subject: USB: add vendor/device id for Option GT Max 3.6 cards This fixes http://bugzilla.kernel.org/show_bug.cgi?id=7814 Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5ca04e82ea1..0fed43a9687 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -78,6 +78,7 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_PRODUCT_FUSION2 0x6300 #define OPTION_PRODUCT_COBRA 0x6500 #define OPTION_PRODUCT_COBRA2 0x6600 +#define OPTION_PRODUCT_GTMAX36 0x6701 #define HUAWEI_PRODUCT_E600 0x1001 #define HUAWEI_PRODUCT_E220 0x1003 #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 @@ -90,6 +91,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, @@ -104,6 +106,7 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, -- cgit v1.2.3 From b1bf4f412b4818869106ffcb5304d69551697b9c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Jan 2007 15:41:03 -0800 Subject: USB: disable USB_MULTITHREAD_PROBE Disable the USB_MULTITHREAD_PROBE option because it causes crashes on people's machines and they never remember to actually read the config help files. No one likes this, everyone hates it, I'm going to go eat worms... The full logic will be ripped out later. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Kconfig | 16 ---------------- drivers/usb/core/hub.c | 9 +-------- 2 files changed, 1 insertion(+), 24 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index f8324d8d06a..3e66b2a9974 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -72,22 +72,6 @@ config USB_SUSPEND If you are unsure about this, say N here. -config USB_MULTITHREAD_PROBE - bool "USB Multi-threaded probe (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - default n - help - Say Y here if you want the USB core to spawn a new thread for - every USB device that is probed. This can cause a small speedup - in boot times on systems with a lot of different USB devices. - - This option should be safe to enable, but if any odd probing - problems are found, please disable it, or dynamically turn it - off in the /sys/module/usbcore/parameters/multithread_probe - file - - When in doubt, say N. - config USB_OTG bool depends on USB && EXPERIMENTAL diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2651c2e2a89..1988224b362 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -88,14 +88,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; /* multithreaded probe logic */ -static int multithread_probe = -#ifdef CONFIG_USB_MULTITHREAD_PROBE - 1; -#else - 0; -#endif -module_param(multithread_probe, bool, S_IRUGO); -MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread"); +static int multithread_probe = 0; /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; -- cgit v1.2.3 From caaf26325d70f5b559a647d4c11d84ef5a3341a4 Mon Sep 17 00:00:00 2001 From: Petr Stetiar Date: Wed, 17 Jan 2007 06:30:39 -0800 Subject: USB: Fix for typo in ohci-ep93xx.c Attached patch fixes typo in USB driver reported by Chase Douglas on linux-cirrus mailing list. http://www.freelists.org/archives/linux-cirrus/12-2006/msg00003.html Signed-off-by: Petr Stetiar Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-ep93xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 43ae696b2ec..3348b07f0fe 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -169,7 +169,7 @@ static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ochi_hcd *ohci = hcd_to_ohci(hcd); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); -- cgit v1.2.3 From 39559b4ff89e390c42633d23d257e793a1177e03 Mon Sep 17 00:00:00 2001 From: Manuel Osdoba Date: Thu, 18 Jan 2007 21:28:45 +0100 Subject: USB: unusual_devs.h entry for nokia 6233 In appendix a patch for the nokia 6233 mobile phone is included. The patch is against 2.6.20-rc5. It is my first patch. Hopefully it has the right format. The code makes my nokia 6233 on my computer work. From: Manuel Osdoba Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 4ef6496e021..b49f2a78189 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -197,6 +197,13 @@ UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Reported by Manuel Osdoba */ +UNUSUAL_DEV( 0x0421, 0x0492, 0x0452, 0x0452, + "Nokia", + "Nokia 6233", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Alex Corcoles */ UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, "Nokia", -- cgit v1.2.3 From c3ea6729feb304e0c3be74e8eca001215e78d1bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 23 Jan 2007 12:25:08 +0000 Subject: [PATCH] funsoft: ktermios fix Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/serial/funsoft.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 31501c9361b..2bebd63d5ed 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -27,7 +27,7 @@ MODULE_DEVICE_TABLE(usb, id_table); static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { - struct termios t; + struct ktermios t; dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); -- cgit v1.2.3 From ad2905f06512c70c44a7efd178536ad197c48528 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 23 Jan 2007 14:02:53 +0100 Subject: USB HID: fix hid_blacklist clash for 0x08ca/0x0010 commit d8c8a393166d6283003fb111d0b4a40931c0eda4 introduced a clash in hid_blacklist for 0x08ca/0x0010 (GTCO vs. AIPTEK). As the vendor of GTCO device doesn't seem to be interested in supporting their legacy HW with this conflicting ids, it is OK to remove it. Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index ea3636d96e1..b86480457a2 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -582,7 +582,6 @@ void usbhid_init_reports(struct hid_device *hid) } #define USB_VENDOR_ID_GTCO 0x078c -#define USB_VENDOR_ID_GTCO_IPANEL_1 0x08ca #define USB_VENDOR_ID_GTCO_IPANEL_2 0x5543 #define USB_DEVICE_ID_GTCO_90 0x0090 #define USB_DEVICE_ID_GTCO_100 0x0100 @@ -629,7 +628,6 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_GTCO_1004 0x1004 #define USB_DEVICE_ID_GTCO_1005 0x1005 #define USB_DEVICE_ID_GTCO_1006 0x1006 -#define USB_DEVICE_ID_GTCO_10 0x0010 #define USB_DEVICE_ID_GTCO_8 0x0008 #define USB_DEVICE_ID_GTCO_d 0x000d @@ -883,7 +881,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO_IPANEL_1, USB_DEVICE_ID_GTCO_10, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From 76398f9667e8369023ed5f4847fb59e9da8b6968 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 29 Jan 2007 12:44:41 +0100 Subject: HID: fix pb_fnmode and move it to generic HID The apple powerbook people are used to switch the pb_fnmode setting at runtime through writing to sysfs, altering the module parameter value. This was broken for them in 2.6.20-rc1 when generic HID layer was introduced, as the pb_fnmode flag was made per-hiddevice, instead of global variable. This patch moves the pb_fnmode module parameter from usbhid module to hid module, but apart from that retains backward compatibility with respect to changing the mode through sysfs. Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index b86480457a2..c6c9e72e5fd 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -56,11 +56,6 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -static int usbhid_pb_fnmode = 1; -module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - /* * Input submission and I/O error handler. */ @@ -1246,10 +1241,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; #endif -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - hid->pb_fnmode = usbhid_pb_fnmode; -#endif - return hid; fail: -- cgit v1.2.3 From 886ae1fa1380309d91cdb7e67bd4bf71e053c1d5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 4 Feb 2007 03:02:17 +0000 Subject: [PATCH] fix rtl8150 That code doesn't do what its author apparently thought it would do... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/net/rtl8150.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index e0eecda78ec..670262a38a0 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -284,7 +284,8 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg) u8 data[3], tmp; data[0] = phy; - *(data + 1) = cpu_to_le16p(®); + data[1] = reg & 0xff; + data[2] = (reg >> 8) & 0xff; tmp = indx | PHY_WRITE | PHY_GO; i = 0; -- cgit v1.2.3 From c4146067fd7889bc6fab6cdfd8b2795d745a2156 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 11 Jan 2007 16:51:16 +0200 Subject: hid: allow force feedback for multi-input devices Allow hid devices with HID_QUIRK_MULTI_INPUT to have force feedback. This was previously disabled because there were not any force feedback drivers for such devices. This will change with my upcoming patch. Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index c6c9e72e5fd..2971182bbdf 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1315,11 +1315,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; } - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if ((hid->claimed & HID_CLAIMED_INPUT) && - !(hid->quirks & HID_QUIRK_MULTI_INPUT)) + if ((hid->claimed & HID_CLAIMED_INPUT)) hid_ff_init(hid); printk(KERN_INFO); -- cgit v1.2.3 From 5556feae1c4e1cf2021b5fb2ef99973125de2250 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 11 Jan 2007 16:51:17 +0200 Subject: hid: quirk for multi-input devices with unneeded output reports Add new quirk HID_QUIRK_SKIP_OUTPUT_REPORTS to skip output reports when enumerating reports on a hid-input device. Add this quirk and HID_QUIRK_MULTI_INPUT to 0810:0001. PantherLord Twin USB Joystick, 0810:0001 has separate input reports for 2 distinct game controllers in the same interface, so it needs HID_QUIRK_MULTI_INPUT. However, the device also contains one output report per controller which is used to control the force feedback function, and we do not want those to appear as separate input devices as well. The simplest approach seems to be to add a quirk to skip output reports on 0810:0001, and allow the force feedback driver to handle those. Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 2971182bbdf..1fa42f40017 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -792,6 +792,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 +#define USB_VENDOR_ID_PANTHERLORD 0x0810 +#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -969,6 +972,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, + { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + { 0, 0 } }; -- cgit v1.2.3 From 20eb12790670985c8e30821218993bd260387b89 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 11 Jan 2007 16:51:18 +0200 Subject: hid: force feedback driver for PantherLord USB/PS2 2in1 Adapter Add a force feedback driver for PantherLord USB/PS2 2in1 Adapter, 0810:0001. The device identifies itself as "Twin USB Joystick". Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/usb/input/Kconfig | 8 +++ drivers/usb/input/Makefile | 3 + drivers/usb/input/hid-ff.c | 3 + drivers/usb/input/hid-plff.c | 129 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 drivers/usb/input/hid-plff.c (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index c7d887540d8..aa6a620c162 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -69,6 +69,14 @@ config LOGITECH_FF Note: if you say N here, this device will still be supported, but without force feedback. +config PANTHERLORD_FF + bool "PantherLord USB/PS2 2in1 Adapter support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want + to enable force feedback support for it. + config THRUSTMASTER_FF bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" depends on HID_FF && EXPERIMENTAL diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 1a24b5bfa05..a06024e5cd5 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -17,6 +17,9 @@ endif ifeq ($(CONFIG_LOGITECH_FF),y) usbhid-objs += hid-lgff.o endif +ifeq ($(CONFIG_PANTHERLORD_FF),y) + usbhid-objs += hid-plff.o +endif ifeq ($(CONFIG_THRUSTMASTER_FF),y) usbhid-objs += hid-tmff.o endif diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 59ed65e7a62..5d145058a5c 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -58,6 +58,9 @@ static struct hid_ff_initializer inits[] = { { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ #endif +#ifdef CONFIG_PANTHERLORD_FF + { 0x810, 0x0001, hid_plff_init }, +#endif #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb304, hid_tmff_init }, #endif diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c new file mode 100644 index 00000000000..76d2e6e14db --- /dev/null +++ b/drivers/usb/input/hid-plff.c @@ -0,0 +1,129 @@ +/* + * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices + * + * Copyright (c) 2007 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) + +#include +#include +#include +#include "usbhid.h" + +struct plff_device { + struct hid_report *report; +}; + +static int hid_plff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = dev->private; + struct plff_device *plff = data; + int left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + debug("called with 0x%04x 0x%04x", left, right); + + left = left * 0x7f / 0xffff; + right = right * 0x7f / 0xffff; + + plff->report->field[0]->value[2] = left; + plff->report->field[0]->value[3] = right; + debug("running with 0x%02x 0x%02x", left, right); + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + + return 0; +} + +int hid_plff_init(struct hid_device *hid) +{ + struct plff_device *plff; + struct hid_report *report; + struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct list_head *report_ptr = report_list; + struct input_dev *dev; + int error; + + /* The device contains 2 output reports (one for each + HID_QUIRK_MULTI_INPUT device), both containing 1 field, which + contains 4 ff00.0002 usages and 4 16bit absolute values. + + The 2 input reports also contain a field which contains + 8 ff00.0001 usages and 8 boolean values. Their meaning is + currently unknown. */ + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-plff: no output reports found\n"); + return -ENODEV; + } + + list_for_each_entry(hidinput, &hid->inputs, list) { + + report_ptr = report_ptr->next; + + if (report_ptr == report_list) { + printk(KERN_ERR "hid-plff: required output report is missing\n"); + return -ENODEV; + } + + report = list_entry(report_ptr, struct hid_report, list); + if (report->maxfield < 1) { + printk(KERN_ERR "hid-plff: no fields in the report\n"); + return -ENODEV; + } + + if (report->field[0]->report_count < 4) { + printk(KERN_ERR "hid-plff: not enough values in the field\n"); + return -ENODEV; + } + + plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); + if (!plff) + return -ENOMEM; + + dev = hidinput->input; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, plff, hid_plff_play); + if (error) { + kfree(plff); + return error; + } + + plff->report = report; + plff->report->field[0]->value[0] = 0x00; + plff->report->field[0]->value[1] = 0x00; + plff->report->field[0]->value[2] = 0x00; + plff->report->field[0]->value[3] = 0x00; + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + } + + printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 " + "2in1 Adapters by Anssi Hannula \n"); + + return 0; +} -- cgit v1.2.3 From c080d89ad91e98fec0e8fc5f448a1ad899bd85c7 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 25 Jan 2007 11:43:31 +0100 Subject: HID: hid debug from hid-debug.h to hid layer hid-debug.h contains a lot of code, and should not therefore be a header. This patch moves the code to generic hid layer as .c source, and introduces CONFIG_HID_DEBUG to conditionally compile it, instead of playing with #define DEBUG and including hid-debug.h. Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 1fa42f40017..6938c4e0e5e 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -35,6 +35,7 @@ #include #include +#include #include "usbhid.h" /* -- cgit v1.2.3 From 7c379146005d277982acde02da44c773de5e7e5a Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 24 Jan 2007 11:54:19 +0100 Subject: HID: API - fix leftovers of hidinput API in USB HID hidinput_{open,close}() functions do not belong to usbhid, but to the generic HID layer. Move them, and fix hooks in struct hid_device, so that now the callbacks are done to transport-specific _open() functions, but not input_open() functions. Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6938c4e0e5e..0392d0e8d02 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -529,18 +529,6 @@ void usbhid_close(struct hid_device *hid) usb_kill_urb(usbhid->urbin); } -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return usbhid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - usbhid_close(hid); -} - #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_TURBOX 0x062a @@ -1241,8 +1229,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); hid->hidinput_input_event = usb_hidinput_input_event; - hid->hidinput_open = hidinput_open; - hid->hidinput_close = hidinput_close; + hid->hid_open = usbhid_open; + hid->hid_close = usbhid_close; #ifdef CONFIG_USB_HIDDEV hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; -- cgit v1.2.3 From 8235ca3c05076f35d22578e8f530fd374104332a Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 26 Jan 2007 12:56:16 +0100 Subject: USB HID: remove hid_find_field_by_usage() The unused hid_find_field_by_usage() function has been commented out for a pretty long time. Remove it completely. Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 0392d0e8d02..cc1feb0ef29 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -221,23 +221,6 @@ static void hid_irq_in(struct urb *urb) } } -/* - * Find a report field with a specified HID usage. - */ -#if 0 -struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type) -{ - struct hid_report *report; - int i; - - list_for_each_entry(report, &hid->report_enum[type].report_list, list) - for (i = 0; i < report->maxfield; i++) - if (report->field[i]->logical == wanted_usage) - return report->field[i]; - return NULL; -} -#endif /* 0 */ - static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; -- cgit v1.2.3 From 43c7bf0472ec1f813fccc6012654399345898491 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 26 Jan 2007 12:58:24 +0100 Subject: USB HID: fix bogus comment in hid_get_class_descriptor() The comment in hid_get_class_descriptor() says a very obvious thing and is also violating codingstyle. Just remove it. Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index cc1feb0ef29..68b68a2b102 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -485,7 +485,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, { int result, retries = 4; - memset(buf,0,size); // Make sure we parse really received data + memset(buf, 0, size); do { result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), -- cgit v1.2.3 From a417a21e10831bca695b4ba9c74f4ddf5a95ac06 Mon Sep 17 00:00:00 2001 From: Soeren Sonnenburg Date: Mon, 5 Feb 2007 10:06:01 +0100 Subject: USB HID: handle multi-interface devices for Apple macbook pro properly Some HID devices by Apple have both keyboard and mouse interfaces; the keyboard interface is handled by usbhid, but the mouse (really touchpad) interface must be handled by the separate 'appletouch' driver. Using HID_QUIRK_IGNORE will make hiddev ignore both interfaces, therefore a new quirk flag to ignore only the mouse interface is required. Signed-off-by: Soeren Sonnenburg Signed-off-by: Sergey Vlasov Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 68b68a2b102..e07a3049072 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -742,6 +742,7 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_IR 0x8240 #define USB_VENDOR_ID_CHERRY 0x046a #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 @@ -921,19 +922,21 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, @@ -1041,6 +1044,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (quirks & HID_QUIRK_IGNORE) return NULL; + if ((quirks & HID_QUIRK_IGNORE_MOUSE) && + (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)) + return NULL; + + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && (!interface->desc.bNumEndpoints || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { -- cgit v1.2.3 From b29cf31d7ee7da285265577b0df5e62c6b5a6119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Fri, 26 Jan 2007 22:57:38 +0900 Subject: ASIX: Add IO-DATA ETG-US2 Support. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Jeff Garzik --- drivers/usb/net/asix.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 896449f0cf8..4206df2d61b 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -1449,6 +1449,10 @@ static const struct usb_device_id products [] = { // Linksys USB1000 USB_DEVICE (0x1737, 0x0039), .driver_info = (unsigned long) &ax88178_info, +}, { + // IO-DATA ETG-US2 + USB_DEVICE (0x04bb, 0x0930), + .driver_info = (unsigned long) &ax88178_info, }, { }, // END }; -- cgit v1.2.3 From e77c2baf75a2ba3d8e7ad8677b193db2d03acace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Fri, 26 Jan 2007 22:59:01 +0900 Subject: PEGASUS: Fix typo in Corega products. s/FEter/FEther/. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Jeff Garzik --- drivers/usb/net/pegasus.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 98f6898cae1..c7467823cd1 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004, +PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004, DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d, +PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, DEFAULT_GPIO_RESET ) -- cgit v1.2.3 From 80f745fb1b0fb11383cbb8df2c36aaaa0399b6e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: USB: add the sysfs driver name to all modules This adds the module name to all USB drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce1dd1..d505926aa9c 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -750,7 +750,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * usb_register_dev() to enable that functionality. This function no longer * takes care of that. */ -int usb_register_driver(struct usb_driver *new_driver, struct module *owner) +int usb_register_driver(struct usb_driver *new_driver, struct module *owner, + const char *mod_name) { int retval = 0; @@ -763,6 +764,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; new_driver->drvwrap.driver.owner = owner; + new_driver->drvwrap.driver.mod_name = mod_name; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); -- cgit v1.2.3 From f9f852df2faf76a2667949ddb4947d4b8f99f02f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 7 Oct 2006 21:54:55 +0200 Subject: Driver core: add device_type to struct device This allows us to add type specific attributes, uevent vars and release funtions. A subsystem can carry different types of devices like the "block" subsys has disks and partitions. Both types create a different set of attributes, but belong to the same subsystem. This corresponds to the low level objects: kobject -> device (object/device data) kobj_type -> device_type (type of object/device we are embedded in) kset -> class/bus (list of objects/devices of a subsystem) Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-lgff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index e4746626856..4f4fc3be192 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -32,7 +32,7 @@ #include #include "usbhid.h" -struct device_type { +struct dev_type { u16 idVendor; u16 idProduct; const signed short *ff; @@ -48,7 +48,7 @@ static const signed short ff_joystick[] = { -1 }; -static const struct device_type devices[] = { +static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, -- cgit v1.2.3 From 20b2e28fc5557cda2cc840f44c6744b61b068ad6 Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 24 Jan 2007 16:19:37 -0200 Subject: USB: unusual_devs.h for Sony floppy This patch increases the range for 0x054c:0x002c devices to make the following Sony USB floppy to work: T: Bus=02 Lev=01 Prnt=01 Port=02 Cnt=02 Dev#= 6 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=054c ProdID=002c Rev=20.00 S: Manufacturer=SONY S: Product=USB Floppy C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 3 Cls=08(stor.) Sub=04 Prot=00 Driver=usb-storage E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=127ms Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b49f2a78189..f0fe29c1241 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -573,7 +573,7 @@ UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110, #endif /* Submitted by Olaf Hering, SuSE Bugzilla #49049 */ -UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501, +UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000, "Sony", "USB Floppy Drive", US_SC_DEVICE, US_PR_DEVICE, NULL, -- cgit v1.2.3 From 6e8cf7751f9fb913095d6142d068f41fbf0424bb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 18 Jan 2007 00:20:19 -0800 Subject: USB: add EPIC support to the io_edgeport driver This patch adds EPiC support to the io_edgeport driver which adds support for a number of NCR printers: - NCR (Axiohm) 7401-K580 printer - NCR (TEC) 7401-K590 printer, 7402-K592 - NCR (TEC) 7167, 7168 printers - NCR (TEC) 7197, 7198, F306, F307, F309 printers - NCR (Axiohm) 7194 printer - NCR (Axiohm) 7158 printer and a few more. It is based on the 2.6.19 kernel. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/io_edgeport.c | 409 +++++++++++++++++++++++++++++++-------- drivers/usb/serial/io_edgeport.h | 6 +- drivers/usb/serial/io_tables.h | 50 +++++ drivers/usb/serial/io_usbvend.h | 5 + 4 files changed, 386 insertions(+), 84 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f623d58370a..cca1607857f 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -146,6 +146,8 @@ struct edgeport_serial { struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ struct edgeport_product_info product_info; /* Product Info */ + struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */ + int is_epic; /* flag if EPiC device or not */ __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ @@ -397,6 +399,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen) unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2); kfree(pStringDesc); + dbg("%s - USB String %s", __FUNCTION__, string); return strlen(string); } @@ -434,6 +437,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de } #endif +static void dump_product_info(struct edgeport_product_info *product_info) +{ + // Dump Product Info structure + dbg("**Product Information:"); + dbg(" ProductId %x", product_info->ProductId ); + dbg(" NumPorts %d", product_info->NumPorts ); + dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); + dbg(" IsServer %d", product_info->IsServer); + dbg(" IsRS232 %d", product_info->IsRS232 ); + dbg(" IsRS422 %d", product_info->IsRS422 ); + dbg(" IsRS485 %d", product_info->IsRS485 ); + dbg(" RomSize %d", product_info->RomSize ); + dbg(" RamSize %d", product_info->RamSize ); + dbg(" CpuRev %x", product_info->CpuRev ); + dbg(" BoardRev %x", product_info->BoardRev); + dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, + product_info->BootMinorVersion, + le16_to_cpu(product_info->BootBuildNumber)); + dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + le16_to_cpu(product_info->FirmwareBuildNumber)); + dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dbg(" EpicVer %d", product_info->EpicVer); +} + static void get_product_info(struct edgeport_serial *edge_serial) { struct edgeport_product_info *product_info = &edge_serial->product_info; @@ -495,30 +526,60 @@ static void get_product_info(struct edgeport_serial *edge_serial) break; } - // Dump Product Info structure - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId ); - dbg(" NumPorts %d", product_info->NumPorts ); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232 ); - dbg(" IsRS422 %d", product_info->IsRS422 ); - dbg(" IsRS485 %d", product_info->IsRS485 ); - dbg(" RomSize %d", product_info->RomSize ); - dbg(" RamSize %d", product_info->RamSize ); - dbg(" CpuRev %x", product_info->CpuRev ); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dump_product_info(product_info); +} +static int get_epic_descriptor(struct edgeport_serial *ep) +{ + int result; + struct usb_serial *serial = ep->serial; + struct edgeport_product_info *product_info = &ep->product_info; + struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_bits *bits; + + ep->is_epic = 0; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + USB_REQUEST_ION_GET_EPIC_DESC, + 0xC0, 0x00, 0x00, + &ep->epic_descriptor, + sizeof(struct edge_compatibility_descriptor), + 300); + + dbg("%s result = %d", __FUNCTION__, result); + + if (result > 0) { + ep->is_epic = 1; + memset(product_info, 0, sizeof(struct edgeport_product_info)); + + product_info->NumPorts = epic->NumPorts; + product_info->ProdInfoVer = 0; + product_info->FirmwareMajorVersion = epic->MajorVersion; + product_info->FirmwareMinorVersion = epic->MinorVersion; + product_info->FirmwareBuildNumber = epic->BuildNumber; + product_info->iDownloadFile = epic->iDownloadFile; + product_info->EpicVer = epic->EpicVer; + product_info->Epic = epic->Supports; + product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; + dump_product_info(product_info); + + bits = &ep->epic_descriptor.Supports; + dbg("**EPIC descriptor:"); + dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); + dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" ); + dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" ); + dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" ); + dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" ); + dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" ); + dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" ); + dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" ); + dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" ); + dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" ); + dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" ); + } + + return result; } @@ -1017,21 +1078,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) edge_port->closePending = TRUE; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); - send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPClose))) { + /* close the port */ + dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); + send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + } //port->close = TRUE; edge_port->closePending = FALSE; @@ -1694,29 +1763,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned static void edge_break (struct usb_serial_port *port, int break_state) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial); int status; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); - } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); - } - if (status) { - dbg("%s - error sending break set/clear command.", __FUNCTION__); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { + if (break_state == -1) { + dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); + } else { + dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); + } + if (status) { + dbg("%s - error sending break set/clear command.", __FUNCTION__); + } } return; @@ -2288,6 +2366,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer *****************************************************************************/ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; int cmdLen = 0; @@ -2295,6 +2374,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa int status; unsigned char number = edge_port->port->number - edge_port->port->serial->minor; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) { + dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", + edge_port->port->number, baudRate); + return 0; + } + dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate); status = calc_baud_rate_divisor (baudRate, &divisor); @@ -2374,6 +2461,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor) *****************************************************************************/ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; unsigned long cmdLen = 0; @@ -2381,6 +2469,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) && + (regNum == MCR))) { + dbg("SendCmdWriteUartReg - Not writting to MCR Register"); + return 0; + } + + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) && + (regNum == LCR))) { + dbg ("SendCmdWriteUartReg - Not writting to LCR Register"); + return 0; + } + // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x10, GFP_ATOMIC); if (cmdBuffer == NULL ) { @@ -2414,6 +2518,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r #endif static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); struct tty_struct *tty; int baud; unsigned cflag; @@ -2494,8 +2599,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi unsigned char stop_char = STOP_CHAR(tty); unsigned char start_char = START_CHAR(tty); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) { + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char); + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + } /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { @@ -2515,8 +2624,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi } /* Set flow control to the configured value */ - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); @@ -2728,6 +2843,13 @@ static int edge_startup (struct usb_serial *serial) struct edgeport_port *edge_port; struct usb_device *dev; int i, j; + int response; + int interrupt_in_found; + int bulk_in_found; + int bulk_out_found; + static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, + EDGE_COMPATIBILITY_MASK1, + EDGE_COMPATIBILITY_MASK2 }; dev = serial->dev; @@ -2750,38 +2872,50 @@ static int edge_startup (struct usb_serial *serial) dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); - /* get the manufacturing descriptor for this device */ - get_manufacturing_desc (edge_serial); + /* Read the epic descriptor */ + if (get_epic_descriptor(edge_serial) <= 0) { + /* memcpy descriptor to Supports structures */ + memcpy(&edge_serial->epic_descriptor.Supports, descriptor, + sizeof(struct edge_compatibility_bits)); - /* get the boot descriptor */ - get_boot_desc (edge_serial); + /* get the manufacturing descriptor for this device */ + get_manufacturing_desc (edge_serial); - get_product_info(edge_serial); + /* get the boot descriptor */ + get_boot_desc (edge_serial); + + get_product_info(edge_serial); + } /* set the number of ports from the manufacturing description */ /* serial->num_ports = serial->product_info.NumPorts; */ - if (edge_serial->product_info.NumPorts != serial->num_ports) { - warn("%s - Device Reported %d serial ports vs core " - "thinking we have %d ports, email greg@kroah.com this info.", - __FUNCTION__, edge_serial->product_info.NumPorts, - serial->num_ports); + if ((!edge_serial->is_epic) && + (edge_serial->product_info.NumPorts != serial->num_ports)) { + dev_warn(&serial->dev->dev, "Device Reported %d serial ports " + "vs. core thinking we have %d ports, email " + "greg@kroah.com this information.", + edge_serial->product_info.NumPorts, + serial->num_ports); } dbg("%s - time 1 %ld", __FUNCTION__, jiffies); - /* now load the application firmware into this device */ - load_application_firmware (edge_serial); + /* If not an EPiC device */ + if (!edge_serial->is_epic) { + /* now load the application firmware into this device */ + load_application_firmware (edge_serial); - dbg("%s - time 2 %ld", __FUNCTION__, jiffies); + dbg("%s - time 2 %ld", __FUNCTION__, jiffies); - /* Check current Edgeport EEPROM and update if necessary */ - update_edgeport_E2PROM (edge_serial); - - dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + /* Check current Edgeport EEPROM and update if necessary */ + update_edgeport_E2PROM (edge_serial); - /* set the configuration to use #1 */ -// dbg("set_configuration 1"); -// usb_set_configuration (dev, 1); + dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + + /* set the configuration to use #1 */ +// dbg("set_configuration 1"); +// usb_set_configuration (dev, 1); + } /* we set up the pointers to the endpoints in the edge_open function, * as the structures aren't created yet. */ @@ -2804,8 +2938,101 @@ static int edge_startup (struct usb_serial *serial) edge_port->port = serial->port[i]; usb_set_serial_port_data(serial->port[i], edge_port); } - - return 0; + + response = 0; + + if (edge_serial->is_epic) { + /* EPIC thing, set up our interrupt polling now and our read urb, so + * that the device knows it really is connected. */ + interrupt_in_found = bulk_in_found = bulk_out_found = FALSE; + for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) { + struct usb_endpoint_descriptor *endpoint; + int buffer_size; + + endpoint = &serial->interface->altsetting[0].endpoint[i].desc; + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + if ((!interrupt_in_found) && + (usb_endpoint_is_int_in(endpoint))) { + /* we found a interrupt in endpoint */ + dbg("found interrupt in"); + + /* not set up yet, so do it now */ + edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->interrupt_read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->interrupt_in_buffer) { + err("out of memory"); + usb_free_urb(edge_serial->interrupt_read_urb); + return -ENOMEM; + } + edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress; + + /* set up our interrupt urb */ + usb_fill_int_urb(edge_serial->interrupt_read_urb, + dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + edge_serial->interrupt_in_buffer, + buffer_size, + edge_interrupt_callback, + edge_serial, + endpoint->bInterval); + + interrupt_in_found = TRUE; + } + + if ((!bulk_in_found) && + (usb_endpoint_is_bulk_in(endpoint))) { + /* we found a bulk in endpoint */ + dbg("found bulk in"); + + /* not set up yet, so do it now */ + edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->bulk_in_buffer) { + err ("out of memory"); + usb_free_urb(edge_serial->read_urb); + return -ENOMEM; + } + edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress; + + /* set up our bulk in urb */ + usb_fill_bulk_urb(edge_serial->read_urb, dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), + edge_serial->bulk_in_buffer, + endpoint->wMaxPacketSize, + edge_bulk_in_callback, + edge_serial); + bulk_in_found = TRUE; + } + + if ((!bulk_out_found) && + (usb_endpoint_is_bulk_out(endpoint))) { + /* we found a bulk out endpoint */ + dbg("found bulk out"); + edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; + bulk_out_found = TRUE; + } + } + + if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) { + err ("Error - the proper endpoints were not found!"); + return -ENODEV; + } + + /* start interrupt read for this edgeport this interrupt will + * continue as long as the edgeport is connected */ + response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); + if (response) + err("%s - Error %d submitting control urb", __FUNCTION__, response); + } + return response; } @@ -2815,6 +3042,7 @@ static int edge_startup (struct usb_serial *serial) ****************************************************************************/ static void edge_shutdown (struct usb_serial *serial) { + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); int i; dbg("%s", __FUNCTION__); @@ -2824,7 +3052,18 @@ static void edge_shutdown (struct usb_serial *serial) kfree (usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); } - kfree (usb_get_serial_data(serial)); + /* free up our endpoint stuff */ + if (edge_serial->is_epic) { + usb_unlink_urb(edge_serial->interrupt_read_urb); + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_unlink_urb(edge_serial->read_urb); + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + } + + kfree(edge_serial); usb_set_serial_data(serial, NULL); } @@ -2846,6 +3085,9 @@ static int __init edgeport_init(void) retval = usb_serial_register(&edgeport_8port_device); if (retval) goto failed_8port_device_register; + retval = usb_serial_register(&epic_device); + if (retval) + goto failed_epic_device_register; retval = usb_register(&io_driver); if (retval) goto failed_usb_register; @@ -2853,6 +3095,8 @@ static int __init edgeport_init(void) return 0; failed_usb_register: + usb_serial_deregister(&epic_device); +failed_epic_device_register: usb_serial_deregister(&edgeport_8port_device); failed_8port_device_register: usb_serial_deregister(&edgeport_4port_device); @@ -2873,6 +3117,7 @@ static void __exit edgeport_exit (void) usb_serial_deregister (&edgeport_2port_device); usb_serial_deregister (&edgeport_4port_device); usb_serial_deregister (&edgeport_8port_device); + usb_serial_deregister (&epic_device); } module_init(edgeport_init); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 123fa8a904e..29a913a6dac 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -111,10 +111,12 @@ struct edgeport_product_info { __le16 FirmwareBuildNumber; /* zzzz (LE format) */ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ - __u8 Unused1[1]; /* Available */ + __u8 HardwareType; __u8 iDownloadFile; /* What to download to EPiC device */ - __u8 Unused2[2]; /* Available */ + __u8 EpicVer; /* What version of EPiC spec this device supports */ + + struct edge_compatibility_bits Epic; }; /* diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index fad561c04c7..3cbb8c19d92 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = { { } }; +static struct usb_device_id Epic_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } +}; + /* Devices that this driver supports */ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, @@ -70,6 +82,14 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, { } /* Terminating entry */ }; @@ -165,5 +185,35 @@ static struct usb_serial_driver edgeport_8port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; +static struct usb_serial_driver epic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "epic", + }, + .description = "EPiC device", + .id_table = Epic_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + #endif diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index f1804fd5a3d..e57fa117e48 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -30,6 +30,7 @@ #define USB_VENDOR_ID_ION 0x1608 // Our VID #define USB_VENDOR_ID_TI 0x0451 // TI VID +#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */ // // Definitions of USB product IDs (PID) @@ -334,6 +335,10 @@ struct edge_compatibility_bits }; +#define EDGE_COMPATIBILITY_MASK0 0x0001 +#define EDGE_COMPATIBILITY_MASK1 0x3FFF +#define EDGE_COMPATIBILITY_MASK2 0x0001 + struct edge_compatibility_descriptor { __u8 Length; // Descriptor Length (per USB spec) -- cgit v1.2.3 From 7bc3d635628db100c024aca7f836a18188e9bb62 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 19 Jun 2006 23:59:31 -0700 Subject: USB: move usb_device_class class devices to be real devices This moves the usb class devices that control the usbfs nodes to show up in the proper place in the larger device tree. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4b3a6ab29bd..74be846fc02 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig static struct usb_device *usbdev_lookup_minor(int minor) { - struct class_device *class_dev; - struct usb_device *dev = NULL; + struct device *device; + struct usb_device *udev = NULL; down(&usb_device_class->sem); - list_for_each_entry(class_dev, &usb_device_class->children, node) { - if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - dev = class_dev->class_data; + list_for_each_entry(device, &usb_device_class->devices, node) { + if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + udev = device->platform_data; break; } } up(&usb_device_class->sem); - return dev; + return udev; }; /* @@ -1596,19 +1596,19 @@ static int usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->class_dev = class_device_create(usb_device_class, NULL, - MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, + dev->usbfs_dev = device_create(usb_device_class, &dev->dev, + MKDEV(USB_DEVICE_MAJOR, minor), "usbdev%d.%d", dev->bus->busnum, dev->devnum); - if (IS_ERR(dev->class_dev)) - return PTR_ERR(dev->class_dev); + if (IS_ERR(dev->usbfs_dev)) + return PTR_ERR(dev->usbfs_dev); - dev->class_dev->class_data = dev; + dev->usbfs_dev->platform_data = dev; return 0; } static void usbdev_remove(struct usb_device *dev) { - class_device_unregister(dev->class_dev); + device_unregister(dev->usbfs_dev); } static int usbdev_notify(struct notifier_block *self, unsigned long action, -- cgit v1.2.3 From 0873c76485c126a4df70a6961fd354b21b7987f7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 20 Jun 2006 13:09:50 -0700 Subject: USB: convert usb class devices to real devices Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/file.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index f794f07cfb3..01c857ac27a 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class->class, NULL, - MKDEV(USB_MAJOR, minor), - &intf->dev, "%s", temp); - if (IS_ERR(intf->class_dev)) { + intf->usb_dev = device_create(usb_class->class, &intf->dev, + MKDEV(USB_MAJOR, minor), "%s", temp); + if (IS_ERR(intf->usb_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - retval = PTR_ERR(intf->class_dev); + retval = PTR_ERR(intf->usb_dev); } exit: return retval; @@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); - intf->class_dev = NULL; + device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); + intf->usb_dev = NULL; intf->minor = -1; destroy_usb_class(); } -- cgit v1.2.3 From 4302a595cd9c6363b495460497ecbda49fa16858 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 15 Dec 2006 06:53:55 +1100 Subject: USB: Rework the OHCI quirk mecanism as suggested by David This patch applies David Brownell's suggestion for reworking the OHCI quirk mechanism via a table of PCI IDs. It adapts the existing quirks to use that mechanism. This also moves the quirks to reset() as suggested by the comment in there. This is necessary as we need to have the endian properly set before we try to init the controller. Signed-off-by: Benjamin Herrenschmidt Acked-by: David Brownell Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-pci.c | 173 ++++++++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 63 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 596e0b41e60..82fbec305a6 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -20,79 +20,128 @@ /*-------------------------------------------------------------------------*/ -static int -ohci_pci_reset (struct usb_hcd *hcd) +/* AMD 756, for most chips (early revs), corrupts register + * values on read ... so enable the vendor workaround. + */ +static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - ohci_hcd_init (ohci); - return ohci_init (ohci); + ohci->flags = OHCI_QUIRK_AMD756; + ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); + + /* also erratum 10 (suspend/resume issues) */ + device_init_wakeup(&hcd->self.root_hub->dev, 0); + + return 0; } -static int __devinit -ohci_pci_start (struct usb_hcd *hcd) +/* Apple's OHCI driver has a lot of bizarre workarounds + * for this chip. Evidently control and bulk lists + * can get confused. (B&W G3 models, and ...) + */ +static int __devinit ohci_quirk_opti(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - /* REVISIT this whole block should move to reset(), which handles - * all the other one-time init. + ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n"); + + return 0; +} + +/* Check for NSC87560. We have to look at the bridge (fn1) to + * identify the USB (fn2). This quirk might apply to more or + * even all NSC stuff. + */ +static int __devinit ohci_quirk_ns(struct usb_hcd *hcd) +{ + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct pci_dev *b; + + b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); + if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO + && b->vendor == PCI_VENDOR_ID_NS) { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->flags |= OHCI_QUIRK_SUPERIO; + ohci_dbg (ohci, "Using NSC SuperIO setup\n"); + } + pci_dev_put(b); + + return 0; +} + +/* Check for Compaq's ZFMicro chipset, which needs short + * delays before control or bulk queues get re-activated + * in finish_unlinks() + */ +static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->flags |= OHCI_QUIRK_ZFMICRO; + ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + + return 0; +} + + +/* List of quirks for OHCI */ +static const struct pci_device_id ohci_pci_quirks[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c), + .driver_data = (unsigned long)ohci_quirk_amd756, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861), + .driver_data = (unsigned long)ohci_quirk_opti, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID), + .driver_data = (unsigned long)ohci_quirk_ns, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), + .driver_data = (unsigned long)ohci_quirk_zfmicro, + }, + /* FIXME for some of the early AMD 760 southbridges, OHCI + * won't work at all. blacklist them. */ + {}, +}; + +static int ohci_pci_reset (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret = 0; + if (hcd->self.controller) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + const struct pci_device_id *quirk_id; - /* AMD 756, for most chips (early revs), corrupts register - * values on read ... so enable the vendor workaround. - */ - if (pdev->vendor == PCI_VENDOR_ID_AMD - && pdev->device == 0x740c) { - ohci->flags = OHCI_QUIRK_AMD756; - ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); - /* also erratum 10 (suspend/resume issues) */ - device_init_wakeup(&hcd->self.root_hub->dev, 0); + quirk_id = pci_match_id(ohci_pci_quirks, pdev); + if (quirk_id != NULL) { + int (*quirk)(struct usb_hcd *ohci); + quirk = (void *)quirk_id->driver_data; + ret = quirk(hcd); } + } + if (ret == 0) { + ohci_hcd_init (ohci); + return ohci_init (ohci); + } + return ret; +} - /* FIXME for some of the early AMD 760 southbridges, OHCI - * won't work at all. blacklist them. - */ - - /* Apple's OHCI driver has a lot of bizarre workarounds - * for this chip. Evidently control and bulk lists - * can get confused. (B&W G3 models, and ...) - */ - else if (pdev->vendor == PCI_VENDOR_ID_OPTI - && pdev->device == 0xc861) { - ohci_dbg (ohci, - "WARNING: OPTi workarounds unavailable\n"); - } - /* Check for NSC87560. We have to look at the bridge (fn1) to - * identify the USB (fn2). This quirk might apply to more or - * even all NSC stuff. - */ - else if (pdev->vendor == PCI_VENDOR_ID_NS) { - struct pci_dev *b; - - b = pci_get_slot (pdev->bus, - PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); - if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO - && b->vendor == PCI_VENDOR_ID_NS) { - ohci->flags |= OHCI_QUIRK_SUPERIO; - ohci_dbg (ohci, "Using NSC SuperIO setup\n"); - } - pci_dev_put(b); - } +static int __devinit ohci_pci_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; - /* Check for Compaq's ZFMicro chipset, which needs short - * delays before control or bulk queues get re-activated - * in finish_unlinks() - */ - else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ - && pdev->device == 0xa0f8) { - ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, - "enabled Compaq ZFMicro chipset quirk\n"); - } +#ifdef CONFIG_PM /* avoid warnings about unused pdev */ + if (hcd->self.controller) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); /* RWC may not be set for add-in PCI cards, since boot * firmware probably ignored them. This transfers PCI @@ -101,16 +150,14 @@ ohci_pci_start (struct usb_hcd *hcd) if (device_may_wakeup(&pdev->dev)) ohci->hc_control |= OHCI_CTRL_RWC; } +#endif /* CONFIG_PM */ - /* NOTE: there may have already been a first reset, to - * keep bios/smm irqs from making trouble - */ - if ((ret = ohci_run (ohci)) < 0) { + ret = ohci_run (ohci); + if (ret < 0) { ohci_err (ohci, "can't start\n"); ohci_stop (hcd); - return ret; } - return 0; + return ret; } #ifdef CONFIG_PM -- cgit v1.2.3 From 11d1a4aa8d657478cb2e5d33f203ba8f01b9ac24 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 15 Dec 2006 06:54:03 +1100 Subject: USB: Implement support for "split" endian OHCI This patch separates support for big endian MMIO register access and big endian descriptors in order to support the Toshiba SCC implementation which has big endian registers but little endian in-memory descriptors. It simplifies the access functions a bit in ohci.h while at it. Signed-off-by: Benjamin Herrenschmidt Acked-by: David Brownell Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 10 ++- drivers/usb/host/ohci-pci.c | 26 +++++++ drivers/usb/host/ohci-ppc-soc.c | 2 +- drivers/usb/host/ohci.h | 147 ++++++++++++++++++++++++++-------------- 4 files changed, 130 insertions(+), 55 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index cc60759083b..faabce8bf39 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -101,7 +101,8 @@ config USB_OHCI_HCD_PPC_SOC bool "OHCI support for on-chip PPC USB controller" depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) default y - select USB_OHCI_BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO ---help--- Enables support for the USB controller on the MPC52xx or STB03xxx processor chip. If unsure, say Y. @@ -115,7 +116,12 @@ config USB_OHCI_HCD_PCI Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. -config USB_OHCI_BIG_ENDIAN +config USB_OHCI_BIG_ENDIAN_DESC + bool + depends on USB_OHCI_HCD + default n + +config USB_OHCI_BIG_ENDIAN_MMIO bool depends on USB_OHCI_HCD default n diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 82fbec305a6..292daf044b6 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -85,6 +85,27 @@ static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) return 0; } +/* Check for Toshiba SCC OHCI which has big endian registers + * and little endian in memory data structures + */ +static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + /* That chip is only present in the southbridge of some + * cell based platforms which are supposed to select + * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if + * that was the case though. + */ +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + ohci->flags |= OHCI_QUIRK_BE_MMIO; + ohci_dbg (ohci, "enabled big endian Toshiba quirk\n"); + return 0; +#else + ohci_err (ohci, "unsupported big endian Toshiba quirk\n"); + return -ENXIO; +#endif +} /* List of quirks for OHCI */ static const struct pci_device_id ohci_pci_quirks[] = { @@ -104,9 +125,14 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), .driver_data = (unsigned long)ohci_quirk_zfmicro, }, + { + PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6), + .driver_data = (unsigned long)ohci_quirk_toshiba_scc, + }, /* FIXME for some of the early AMD 760 southbridges, OHCI * won't work at all. blacklist them. */ + {}, }; diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index e1a7eb81731..c7ce8e638a2 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, } ohci = hcd_to_ohci(hcd); - ohci->flags |= OHCI_BIG_ENDIAN; + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 405257f3e85..fc7c1614cf9 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -394,8 +394,9 @@ struct ohci_hcd { #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ #define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ -#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */ -#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/ +#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ +#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ +#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ // there are also chip quirks/bugs in init logic }; @@ -439,117 +440,156 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) * a minority (notably the IBM STB04XXX and the Motorola MPC5200 * processors) implement them in big endian format. * + * In addition some more exotic implementations like the Toshiba + * Spider (aka SCC) cell southbridge are "mixed" endian, that is, + * they have a different endianness for registers vs. in-memory + * descriptors. + * * This attempts to support either format at compile time without a * runtime penalty, or both formats with the additional overhead * of checking a flag bit. + * + * That leads to some tricky Kconfig rules howevber. There are + * different defaults based on some arch/ppc platforms, though + * the basic rules are: + * + * Controller type Kconfig options needed + * --------------- ---------------------- + * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN + * + * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_ + * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + * + * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_ + * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC} + * + * (If you have a mixed endian controller, you -must- also define + * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building + * both your mixed endian and a fully big endian controller support in + * the same kernel image). */ -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC +#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN +#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC) +#else +#define big_endian_desc(ohci) 1 /* only big endian */ +#endif +#else +#define big_endian_desc(ohci) 0 /* only little endian */ +#endif +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN -#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */ +#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO) +#else +#define big_endian_mmio(ohci) 1 /* only big endian */ +#endif #else -#define big_endian(ohci) 1 /* only big endian */ +#define big_endian_mmio(ohci) 0 /* only little endian */ #endif /* * Big-endian read/write functions are arch-specific. * Other arches can be added if/when they're needed. + * + * REVISIT: arch/powerpc now has readl/writel_be, so the + * definition below can die once the STB04xxx support is + * finally ported over. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) #define readl_be(addr) in_be32((__force unsigned *)addr) #define writel_be(val, addr) out_be32((__force unsigned *)addr, val) #endif -static inline unsigned int ohci_readl (const struct ohci_hcd *ohci, - __hc32 __iomem * regs) +static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, + __hc32 __iomem * regs) { - return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs); + return big_endian_mmio(ohci) ? + readl_be ((__force u32 *)regs) : + readl ((__force u32 *)regs); } -static inline void ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) +static inline void _ohci_writel (const struct ohci_hcd *ohci, + const unsigned int val, __hc32 __iomem *regs) { - big_endian(ohci) ? writel_be (val, regs) : - writel (val, (__force u32 *)regs); + big_endian_mmio(ohci) ? + writel_be (val, (__force u32 *)regs) : + writel (val, (__force u32 *)regs); } -#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */ - -#define big_endian(ohci) 0 /* only little endian */ - #ifdef CONFIG_ARCH_LH7A404 - /* Marc Singer: at the time this code was written, the LH7A404 - * had a problem reading the USB host registers. This - * implementation of the ohci_readl function performs the read - * twice as a work-around. - */ -static inline unsigned int -ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs) -{ - *(volatile __force unsigned int*) regs; - return *(volatile __force unsigned int*) regs; -} +/* Marc Singer: at the time this code was written, the LH7A404 + * had a problem reading the USB host registers. This + * implementation of the ohci_readl function performs the read + * twice as a work-around. + */ +#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r)) +#define ohci_writel(o,v,r) _ohci_writel(o,v,r) #else - /* Standard version of ohci_readl uses standard, platform - * specific implementation. */ -static inline unsigned int -ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs) -{ - return readl(regs); -} +#define ohci_readl(o,r) _ohci_readl(o,r) +#define ohci_writel(o,v,r) _ohci_writel(o,v,r) #endif -static inline void ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) -{ - writel (val, regs); -} - -#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */ /*-------------------------------------------------------------------------*/ /* cpu to ohci */ static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x) { - return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x); + return big_endian_desc(ohci) ? + (__force __hc16)cpu_to_be16(x) : + (__force __hc16)cpu_to_le16(x); } static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x) { - return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x); + return big_endian_desc(ohci) ? + cpu_to_be16p(x) : + cpu_to_le16p(x); } static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x) { - return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x); + return big_endian_desc(ohci) ? + (__force __hc32)cpu_to_be32(x) : + (__force __hc32)cpu_to_le32(x); } static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x) { - return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x); + return big_endian_desc(ohci) ? + cpu_to_be32p(x) : + cpu_to_le32p(x); } /* ohci to cpu */ static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x) { - return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x); + return big_endian_desc(ohci) ? + be16_to_cpu((__force __be16)x) : + le16_to_cpu((__force __le16)x); } static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x) { - return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x); + return big_endian_desc(ohci) ? + be16_to_cpup((__force __be16 *)x) : + le16_to_cpup((__force __le16 *)x); } static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x) { - return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x); + return big_endian_desc(ohci) ? + be32_to_cpu((__force __be32)x) : + le32_to_cpu((__force __le32)x); } static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) { - return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x); + return big_endian_desc(ohci) ? + be32_to_cpup((__force __be32 *)x) : + le32_to_cpup((__force __le32 *)x); } /*-------------------------------------------------------------------------*/ @@ -557,6 +597,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. + * + * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over + * to arch/powerpc */ #ifdef CONFIG_STB03xxx @@ -568,7 +611,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) { u32 tmp; - if (big_endian(ohci)) { + if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); tmp >>= OHCI_BE_FRAME_NO_SHIFT; } else @@ -580,7 +623,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci, const struct td *td, int index) { - return (__hc16 *)(big_endian(ohci) ? + return (__hc16 *)(big_endian_desc(ohci) ? &td->hwPSW[index ^ 1] : &td->hwPSW[index]); } -- cgit v1.2.3 From 083522d76662cda71328df1f3d75e5a9057c7c9f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 15 Dec 2006 06:54:08 +1100 Subject: USB: Implement support for EHCI with big endian MMIO This patch implements supports for EHCI controllers whose MMIO registers are big endian and enables that functionality for the Toshiba SCC chip. It does _not_ add support for big endian in-memory data structures as this is not needed for that chip and I hope it will never be. The guts of the patch are to convert readl(...) to ehci_readl(ehci, ...) and similarly for register writes. Signed-off-by: Kou Ishizaki Signed-off-by: Benjamin Herrenschmidt Acked-by: Geoff Levand Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 5 ++ drivers/usb/host/ehci-dbg.c | 24 ++++----- drivers/usb/host/ehci-fsl.c | 8 +-- drivers/usb/host/ehci-hcd.c | 92 +++++++++++++++++--------------- drivers/usb/host/ehci-hub.c | 118 ++++++++++++++++++++++-------------------- drivers/usb/host/ehci-pci.c | 38 ++++++++++---- drivers/usb/host/ehci-q.c | 16 +++--- drivers/usb/host/ehci-sched.c | 22 ++++---- drivers/usb/host/ehci.h | 32 ++++++++++++ 9 files changed, 213 insertions(+), 142 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index faabce8bf39..83259985210 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED If unsure, say N. +config USB_EHCI_BIG_ENDIAN_MMIO + bool + depends on USB_EHCI_HCD + default n + config USB_ISP116X_HCD tristate "ISP116X HCD support" depends on USB diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 56349d21e6e..246afea9e83 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -43,7 +43,7 @@ */ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) { - u32 params = readl (&ehci->caps->hcs_params); + u32 params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci_dbg (ehci, "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n", @@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} * */ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) { - u32 params = readl (&ehci->caps->hcc_params); + u32 params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE (params)) { ehci_dbg (ehci, @@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf) } /* Capability Registers */ - i = HC_VERSION(readl (&ehci->caps->hc_capbase)); + i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); temp = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" "%s\n" @@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf) unsigned count = 256/4; pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params)); while (offset && count--) { pci_read_config_dword (pdev, offset, &cap); switch (cap & 0xff) { @@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf) #endif // FIXME interpret both types of params - i = readl (&ehci->caps->hcs_params); + i = ehci_readl(ehci, &ehci->caps->hcs_params); temp = scnprintf (next, size, "structural params 0x%08x\n", i); size -= temp; next += temp; - i = readl (&ehci->caps->hcc_params); + i = ehci_readl(ehci, &ehci->caps->hcc_params); temp = scnprintf (next, size, "capability params 0x%08x\n", i); size -= temp; next += temp; /* Operational Registers */ temp = dbg_status_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->status)); + ehci_readl(ehci, &ehci->regs->status)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = dbg_command_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->command)); + ehci_readl(ehci, &ehci->regs->command)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = dbg_intr_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->intr_enable)); + ehci_readl(ehci, &ehci->regs->intr_enable)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = scnprintf (next, size, "uframe %04x\n", - readl (&ehci->regs->frame_index)); + ehci_readl(ehci, &ehci->regs->frame_index)); size -= temp; next += temp; for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) { temp = dbg_port_buf (scratch, sizeof scratch, label, i, - readl (&ehci->regs->port_status [i - 1])); + ehci_readl(ehci, &ehci->regs->port_status [i - 1])); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) { temp = scnprintf (next, size, " debug control %08x\n", - readl (&ehci->debug->control)); + ehci_readl(ehci, &ehci->debug->control)); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 1a915e982c1..a52480505f7 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci, case FSL_USB2_PHY_NONE: break; } - writel(portsc, &ehci->regs->port_status[port_offset]); + ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); } static void mpc83xx_usb_setup(struct usb_hcd *hcd) @@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd) } /* put controller in host mode. */ - writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE); + ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE); out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); @@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(readl(&ehci->caps->hc_capbase)); + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 025d3331368..03d567e4d00 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) +static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) { u32 result; do { - result = readl (ptr); + result = ehci_readl(ehci, ptr); if (result == ~(u32)0) /* card removed */ return -ENODEV; result &= mask; @@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) /* force HC to halt state from unknown (EHCI spec section 2.3) */ static int ehci_halt (struct ehci_hcd *ehci) { - u32 temp = readl (&ehci->regs->status); + u32 temp = ehci_readl(ehci, &ehci->regs->status); /* disable any irqs left enabled by previous code */ - writel (0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); if ((temp & STS_HALT) != 0) return 0; - temp = readl (&ehci->regs->command); + temp = ehci_readl(ehci, &ehci->regs->command); temp &= ~CMD_RUN; - writel (temp, &ehci->regs->command); - return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); + ehci_writel(ehci, temp, &ehci->regs->command); + return handshake (ehci, &ehci->regs->status, + STS_HALT, STS_HALT, 16 * 125); } /* put TDI/ARC silicon into EHCI mode */ @@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci) u32 tmp; reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); - tmp = readl (reg_ptr); + tmp = ehci_readl(ehci, reg_ptr); tmp |= 0x3; - writel (tmp, reg_ptr); + ehci_writel(ehci, tmp, reg_ptr); } /* reset a non-running (STS_HALT == 1) controller */ static int ehci_reset (struct ehci_hcd *ehci) { int retval; - u32 command = readl (&ehci->regs->command); + u32 command = ehci_readl(ehci, &ehci->regs->command); command |= CMD_RESET; dbg_cmd (ehci, "reset", command); - writel (command, &ehci->regs->command); + ehci_writel(ehci, command, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci->next_statechange = jiffies; - retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); + retval = handshake (ehci, &ehci->regs->command, + CMD_RESET, 0, 250 * 1000); if (retval) return retval; @@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci) #endif /* wait for any schedule enables/disables to take effect */ - temp = readl (&ehci->regs->command) << 10; + temp = ehci_readl(ehci, &ehci->regs->command) << 10; temp &= STS_ASS | STS_PSS; - if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; } /* then disable anything that's still active */ - temp = readl (&ehci->regs->command); + temp = ehci_readl(ehci, &ehci->regs->command); temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - writel (temp, &ehci->regs->command); + ehci_writel(ehci, temp, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ - if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; @@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param) /* lost IAA irqs wedge things badly; seen with a vt8235 */ if (ehci->reclaim) { - u32 status = readl (&ehci->regs->status); + u32 status = ehci_readl(ehci, &ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); - writel (STS_IAA, &ehci->regs->status); + ehci_writel(ehci, STS_IAA, &ehci->regs->status); ehci->reclaim_ready = 1; } } @@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd) (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -379,11 +382,11 @@ static void ehci_stop (struct usb_hcd *hcd) ehci_quiesce (ehci); ehci_reset (ehci); - writel (0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); spin_unlock_irq(&ehci->lock); /* let companion controllers work when we aren't */ - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); remove_debug_files (ehci); @@ -402,7 +405,8 @@ static void ehci_stop (struct usb_hcd *hcd) ehci->stats.complete, ehci->stats.unlink); #endif - dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); + dbg_status (ehci, "ehci_stop completed", + ehci_readl(ehci, &ehci->regs->status)); } /* one-time init, only for memory state */ @@ -428,7 +432,7 @@ static int ehci_init(struct usb_hcd *hcd) return retval; /* controllers may cache some of the periodic schedule ... */ - hcc_params = readl(&ehci->caps->hcc_params); + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE(hcc_params)) // full frame cache ehci->i_thresh = 8; else // N microframes cached @@ -501,8 +505,8 @@ static int ehci_run (struct usb_hcd *hcd) ehci_mem_cleanup(ehci); return retval; } - writel(ehci->periodic_dma, &ehci->regs->frame_list); - writel((u32)ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); + ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); /* * hcc_params controls whether ehci->regs->segment must (!!!) @@ -516,9 +520,9 @@ static int ehci_run (struct usb_hcd *hcd) * Scsi_Host.highmem_io, and so forth. It's readonly to all * host side drivers though. */ - hcc_params = readl(&ehci->caps->hcc_params); + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_64BIT_ADDR(hcc_params)) { - writel(0, &ehci->regs->segment); + ehci_writel(ehci, 0, &ehci->regs->segment); #if 0 // this is deeply broken on almost all architectures if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK)) @@ -531,7 +535,7 @@ static int ehci_run (struct usb_hcd *hcd) // root hub will detect new devices (why?); NEC doesn't ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command |= CMD_RUN; - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); dbg_cmd (ehci, "init", ehci->command); /* @@ -541,17 +545,18 @@ static int ehci_run (struct usb_hcd *hcd) * and there's no companion controller unless maybe for USB OTG.) */ hcd->state = HC_STATE_RUNNING; - writel (FLAG_CF, &ehci->regs->configured_flag); - readl (&ehci->regs->command); /* unblock posted writes */ + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); + temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), temp >> 8, temp & 0xff, DRIVER_VERSION, ignore_oc ? ", overcurrent ignored" : ""); - writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ /* GRR this is run-once init(), being done every time the HC starts. * So long as they're part of class devices, we can't do it init() @@ -572,7 +577,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) spin_lock (&ehci->lock); - status = readl (&ehci->regs->status); + status = ehci_readl(ehci, &ehci->regs->status); /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { @@ -587,8 +592,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) } /* clear (just) interrupts */ - writel (status, &ehci->regs->status); - readl (&ehci->regs->command); /* unblock posted write */ + ehci_writel(ehci, status, &ehci->regs->status); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ bh = 0; #ifdef EHCI_VERBOSE_DEBUG @@ -619,11 +624,12 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) unsigned i = HCS_N_PORTS (ehci->hcs_params); /* resume root hub? */ - if (!(readl(&ehci->regs->command) & CMD_RUN)) + if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) usb_hcd_resume_root_hub(hcd); while (i--) { - int pstatus = readl (&ehci->regs->port_status [i]); + int pstatus = ehci_readl(ehci, + &ehci->regs->port_status [i]); if (pstatus & PORT_OWNER) continue; @@ -643,14 +649,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { /* bogus "fatal" IRQs appear on some chips... why? */ - status = readl (&ehci->regs->status); - dbg_cmd (ehci, "fatal", readl (&ehci->regs->command)); + status = ehci_readl(ehci, &ehci->regs->status); + dbg_cmd (ehci, "fatal", ehci_readl(ehci, + &ehci->regs->command)); dbg_status (ehci, "fatal", status); if (status & STS_HALT) { ehci_err (ehci, "fatal error\n"); dead: ehci_reset (ehci); - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); /* generic layer kills/unlinks all urbs, then * uses ehci_stop to clean up the rest */ @@ -873,7 +880,8 @@ done: static int ehci_get_frame (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; + return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) % + ehci->periodic_size; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index bfe5f307cba..df00fcbadfb 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci_quiesce (ehci); hcd->state = HC_STATE_QUIESCING; } - ehci->command = readl (&ehci->regs->command); + ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) ehci->reclaim_ready = 1; ehci_work(ehci); @@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci->bus_suspended = 0; while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; - u32 t1 = readl (reg) & ~PORT_RWC_BITS; + u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; u32 t2 = t1; /* keep track of which ports we suspend */ @@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); - writel (t2, reg); + ehci_writel(ehci, t2, reg); } } @@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; - writel(mask, &ehci->regs->intr_enable); - readl(&ehci->regs->intr_enable); + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); @@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd) * the last user of the controller, not reset/pm hardware keeping * state we gave to it. */ - temp = readl(&ehci->regs->intr_enable); + temp = ehci_readl(ehci, &ehci->regs->intr_enable); ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss"); /* at least some APM implementations will try to deliver * IRQs right away, so delay them until we're ready. */ - writel(0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); /* re-init operational registers */ - writel(0, &ehci->regs->segment); - writel(ehci->periodic_dma, &ehci->regs->frame_list); - writel((u32) ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, 0, &ehci->regs->segment); + ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); + ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* manually resume the ports we suspended during bus_suspend() */ i = HCS_N_PORTS (ehci->hcs_params); while (i--) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); temp &= ~(PORT_RWC_BITS | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); if (test_bit(i, &ehci->bus_suspended) && @@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); temp |= PORT_RESUME; } - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, &ehci->regs->port_status [i]); } i = HCS_N_PORTS (ehci->hcs_params); mdelay (20); while (i--) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); if (test_bit(i, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) { temp &= ~(PORT_RWC_BITS | PORT_RESUME); - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); } } - (void) readl (&ehci->regs->command); + (void) ehci_readl(ehci, &ehci->regs->command); /* maybe re-activate the schedule(s) */ temp = 0; @@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd) temp |= CMD_PSE; if (temp) { ehci->command |= temp; - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); } ehci->next_statechange = jiffies + msecs_to_jiffies(5); hcd->state = HC_STATE_RUNNING; /* Now we can safely re-enable irqs */ - writel(INTR_MASK, &ehci->regs->intr_enable); + ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); spin_unlock_irq (&ehci->lock); return 0; @@ -217,7 +217,8 @@ static int check_reset_complete ( // what happens if HCS_N_CC(params) == 0 ? port_status |= PORT_OWNER; port_status &= ~PORT_RWC_BITS; - writel (port_status, &ehci->regs->port_status [index]); + ehci_writel(ehci, port_status, + &ehci->regs->port_status [index]); } else ehci_dbg (ehci, "port %d high speed\n", index + 1); @@ -268,13 +269,14 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) /* port N changes (bit N)? */ spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < ports; i++) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); if (temp & PORT_OWNER) { /* don't report this in GetPortStatus */ if (temp & PORT_CSC) { temp &= ~PORT_RWC_BITS; temp |= PORT_CSC; - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, + &ehci->regs->port_status [i]); } continue; } @@ -373,18 +375,18 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]); if (temp & PORT_OWNER) break; switch (wValue) { case USB_PORT_FEAT_ENABLE: - writel (temp & ~PORT_PE, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~PORT_PE, + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_ENABLE: - writel((temp & ~PORT_RWC_BITS) | PORT_PEC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) @@ -396,8 +398,8 @@ static int ehci_hub_control ( goto error; /* resume signaling for 20 msec */ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - writel (temp | PORT_RESUME, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_RESUME, + &ehci->regs->port_status [wIndex]); ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (20); } @@ -407,16 +409,17 @@ static int ehci_hub_control ( break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp & ~(PORT_RWC_BITS | PORT_POWER), - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_POWER), + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_CONNECTION: - writel((temp & ~PORT_RWC_BITS) | PORT_CSC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_OVER_CURRENT: - writel((temp & ~PORT_RWC_BITS) | PORT_OCC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ @@ -424,7 +427,7 @@ static int ehci_hub_control ( default: goto error; } - readl (&ehci->regs->command); /* unblock posted write */ + ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ break; case GetHubDescriptor: ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) @@ -440,7 +443,7 @@ static int ehci_hub_control ( goto error; wIndex--; status = 0; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]); // wPortChange bits if (temp & PORT_CSC) @@ -458,12 +461,14 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = 0; /* stop resume signaling */ - temp = readl (&ehci->regs->port_status [wIndex]); - writel (temp & ~(PORT_RWC_BITS | PORT_RESUME), - &ehci->regs->port_status [wIndex]); - retval = handshake ( - &ehci->regs->port_status [wIndex], - PORT_RESUME, 0, 2000 /* 2msec */); + temp = ehci_readl(ehci, + &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_RESUME), + &ehci->regs->port_status [wIndex]); + retval = handshake(ehci, + &ehci->regs->port_status [wIndex], + PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { ehci_err (ehci, "port %d resume error %d\n", wIndex + 1, retval); @@ -480,13 +485,13 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = 0; /* force reset to complete */ - writel (temp & ~(PORT_RWC_BITS | PORT_RESET), - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), + &ehci->regs->port_status [wIndex]); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake ( - &ehci->regs->port_status [wIndex], + retval = handshake(ehci, + &ehci->regs->port_status [wIndex], PORT_RESET, 0, 750); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", @@ -496,7 +501,8 @@ static int ehci_hub_control ( /* see what we found out */ temp = check_reset_complete (ehci, wIndex, - readl (&ehci->regs->port_status [wIndex])); + ehci_readl(ehci, + &ehci->regs->port_status [wIndex])); } // don't show wPortStatus if it's owned by a companion hc @@ -541,7 +547,7 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]); if (temp & PORT_OWNER) break; @@ -555,13 +561,13 @@ static int ehci_hub_control ( goto error; if (device_may_wakeup(&hcd->self.root_hub->dev)) temp |= PORT_WAKE_BITS; - writel (temp | PORT_SUSPEND, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_SUSPEND, + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp | PORT_POWER, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_POWER, + &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_RESET: if (temp & PORT_RESUME) @@ -589,7 +595,8 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); } - writel (temp, &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, + &ehci->regs->port_status [wIndex]); break; /* For downstream facing ports (these): one hub port is put @@ -604,13 +611,14 @@ static int ehci_hub_control ( ehci_quiesce(ehci); ehci_halt(ehci); temp |= selector << 16; - writel (temp, &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, + &ehci->regs->port_status [wIndex]); break; default: goto error; } - readl (&ehci->regs->command); /* unblock posted writes */ + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ break; default: diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 4bc7970ba3e..12edc723ec7 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if ((temp & (3 << 13)) == (1 << 13)) { temp &= 0x1fff; ehci->debug = ehci_to_hcd(ehci)->regs + temp; - temp = readl(&ehci->debug->control); + temp = ehci_readl(ehci, &ehci->debug->control); ehci_info(ehci, "debug port %d%s\n", HCS_DEBUG_PORT(ehci->hcs_params), (temp & DBGP_ENABLED) @@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd) u32 temp; int retval; + switch (pdev->vendor) { + case PCI_VENDOR_ID_TOSHIBA_2: + /* celleb's companion chip */ + if (pdev->device == 0x01b5) { +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + ehci->big_endian_mmio = 1; +#else + ehci_warn(ehci, + "unsupported big endian Toshiba quirk\n"); +#endif + } + break; + } + ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); @@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) @@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) rc = -EINVAL; goto bail; } - writel (0, &ehci->regs->intr_enable); - (void)readl(&ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + (void)ehci_readl(ehci, &ehci->regs->intr_enable); /* make sure snapshot being resumed re-enumerates everything */ if (message.event == PM_EVENT_PRETHAW) { @@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* If CF is still set, we maintained PCI Vaux power. * Just undo the effect of ehci_pci_suspend(). */ - if (readl(&ehci->regs->configured_flag) == FLAG_CF) { + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { int mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; - writel(mask, &ehci->regs->intr_enable); - readl(&ehci->regs->intr_enable); + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); return 0; } @@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* here we "know" root ports should always stay powered */ ehci_port_power(ehci, 1); - writel(ehci->command, &ehci->regs->command); - writel(FLAG_CF, &ehci->regs->configured_flag); - readl(&ehci->regs->command); /* unblock posted writes */ + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ hcd->state = HC_STATE_SUSPENDED; return 0; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 62e46dc60e8..e7fbbd00e7c 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); if (!head->qh_next.qh) { - u32 cmd = readl (&ehci->regs->command); + u32 cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_ASE)) { /* in case a clear of CMD_ASE didn't take yet */ - (void) handshake (&ehci->regs->status, STS_ASS, 0, 150); + (void)handshake(ehci, &ehci->regs->status, + STS_ASS, 0, 150); cmd |= CMD_ASE | CMD_RUN; - writel (cmd, &ehci->regs->command); + ehci_writel(ehci, cmd, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* posted write need not be known to HC yet ... */ } @@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - int cmd = readl (&ehci->regs->command); + int cmd = ehci_readl(ehci, &ehci->regs->command); struct ehci_qh *prev; #ifdef DEBUG @@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) if (ehci_to_hcd(ehci)->state != HC_STATE_HALT && !ehci->reclaim) { /* ... and CMD_IAAD clear */ - writel (cmd & ~CMD_ASE, &ehci->regs->command); + ehci_writel(ehci, cmd & ~CMD_ASE, + &ehci->regs->command); wmb (); // handshake later, if we need to timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ehci->reclaim_ready = 0; cmd |= CMD_IAAD; - writel (cmd, &ehci->regs->command); - (void) readl (&ehci->regs->command); + ehci_writel(ehci, cmd, &ehci->regs->command); + (void)ehci_readl(ehci, &ehci->regs->command); timer_action (ehci, TIMER_IAA_WATCHDOG); } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 65c402a0fa7..7b5ae7111f2 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci) /* did clearing PSE did take effect yet? * takes effect only at frame boundaries... */ - status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); + status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125); if (status != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return status; } - cmd = readl (&ehci->regs->command) | CMD_PSE; - writel (cmd, &ehci->regs->command); + cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... PSS happens later */ ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* make sure ehci_work scans these */ - ehci->next_uframe = readl (&ehci->regs->frame_index) - % (ehci->periodic_size << 3); + ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index) + % (ehci->periodic_size << 3); return 0; } @@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci) /* did setting PSE not take effect yet? * takes effect only at frame boundaries... */ - status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); + status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); if (status != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return status; } - cmd = readl (&ehci->regs->command) & ~CMD_PSE; - writel (cmd, &ehci->regs->command); + cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... */ ehci->next_uframe = -1; @@ -1336,7 +1336,7 @@ iso_stream_schedule ( goto fail; } - now = readl (&ehci->regs->frame_index) % mod; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; /* when's the last uframe this urb could start? */ max = now + mod; @@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci) */ now_uframe = ehci->next_uframe; if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - clock = readl (&ehci->regs->frame_index); + clock = ehci_readl(ehci, &ehci->regs->frame_index); else clock = now_uframe + mod - 1; clock %= mod; @@ -2213,7 +2213,7 @@ restart: if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) break; ehci->next_uframe = now_uframe; - now = readl (&ehci->regs->frame_index) % mod; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; if (now_uframe == now) break; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 74dbc6c8228..5f28b74bb8d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -92,6 +92,7 @@ struct ehci_hcd { /* one per controller */ unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ unsigned no_selective_suspend:1; unsigned has_fsl_port_bug:1; /* FreeScale */ + unsigned big_endian_mmio:1; u8 sbrn; /* packed release number */ @@ -651,6 +652,37 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) #define ehci_has_fsl_portno_bug(e) (0) #endif +/* + * While most USB host controllers implement their registers in + * little-endian format, a minority (celleb companion chip) implement + * them in big endian format. + * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. + */ + +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO +#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio) +#else +#define ehci_big_endian_mmio(e) 0 +#endif + +static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, + __u32 __iomem * regs) +{ + return ehci_big_endian_mmio(ehci) ? + readl_be((__force u32 *)regs) : + readl((__force u32 *)regs); +} + +static inline void ehci_writel (const struct ehci_hcd *ehci, + const unsigned int val, __u32 __iomem *regs) +{ + ehci_big_endian_mmio(ehci) ? + writel_be(val, (__force u32 *)regs) : + writel(val, (__force u32 *)regs); +} /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From b32e904d54d163c6f97fc3c7586d381f4f11c3a5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 28 Dec 2006 15:26:59 +1100 Subject: USB: Fix OHCI warning This patch fixes a warning introduces by the split endian OHCI support patch on platforms that don't have readl_be/writel_be variants (though mostly harmless as those are called in an if (0) statement, but gcc still warns). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index fc7c1614cf9..0dafcda3729 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -505,17 +505,25 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs) { +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO return big_endian_mmio(ohci) ? readl_be ((__force u32 *)regs) : readl ((__force u32 *)regs); +#else + return readl ((__force u32 *)regs); +#endif } static inline void _ohci_writel (const struct ohci_hcd *ohci, const unsigned int val, __hc32 __iomem *regs) { +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO big_endian_mmio(ohci) ? writel_be (val, (__force u32 *)regs) : writel (val, (__force u32 *)regs); +#else + writel (val, (__force u32 *)regs); +#endif } #ifdef CONFIG_ARCH_LH7A404 -- cgit v1.2.3 From d728e327d4f86df439fa6b6f2f64b278394a58cc Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 28 Dec 2006 15:27:27 +1100 Subject: USB: Fix EHCI warning This patch fixes a warning introduced by the big endian MMIO EHCI support patch on platforms that don't have readl_be/writel_be variants (though mostly harmless as those are called in an if (0) statement, but gcc still warns). Signed-off-by: Benjamin Herrenschmidt --- drivers/usb/host/ehci.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 5f28b74bb8d..3ce7249085d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -671,17 +671,25 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, __u32 __iomem * regs) { +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO return ehci_big_endian_mmio(ehci) ? readl_be((__force u32 *)regs) : readl((__force u32 *)regs); +#else + return readl((__force u32 *)regs); +#endif } static inline void ehci_writel (const struct ehci_hcd *ehci, const unsigned int val, __u32 __iomem *regs) { +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO ehci_big_endian_mmio(ehci) ? writel_be(val, (__force u32 *)regs) : writel(val, (__force u32 *)regs); +#else + writel(val, (__force u32 *)regs); +#endif } /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 5f848137744106ee737f559454ce5adfceb38347 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 16 Dec 2006 15:34:53 -0800 Subject: USB: becomes This moves to to reduce some of the clutter of usb header files. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/config.c | 2 +- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/lh7a40x_udc.h | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/gadget/usbstring.c | 2 +- drivers/usb/gadget/zero.c | 2 +- drivers/usb/storage/onetouch.c | 1 - 16 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 8ed6c75adf0..638b8009b3b 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include "usbatm.h" diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 812c733ba8c..5a72743606f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 83b4866df9a..d18901b92cd 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 53d584589c2..f28af06905a 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d15bf22b9a0..ca8e0ebc79e 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 72f2ae96fbf..027b3150526 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -253,7 +253,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index f1a679656c9..d08a8d0e642 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index d0ef1d6b3fa..e873cf48824 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index e3bb78524c8..b3fe197e1ee 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -49,7 +49,7 @@ #include #include -#include +#include #include /* diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 569eb8ccf23..7617ff7bd5a 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index cdcfd42843d..140104341db 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b78de969466..0d225369847 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -56,7 +56,7 @@ #include #endif -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f8a3ec64635..6c742a90922 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index b1735767660..3459ea6c6c0 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 40710ea1b49..ebe04e0d287 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -84,7 +84,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index e565d3d2ab2..6d3dad3d1da 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "usb.h" #include "onetouch.h" -- cgit v1.2.3 From 4727810705d3cf8d565a2cd6c1045bc1db7d3532 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Dec 2006 11:42:12 +0100 Subject: USB: Remove unneeded void * casts in idmouse.c The patch removes unneeded void * casts for the following (void *) pointers: - struct file: private_data The patch also contains some whitespace and coding style cleanups in the relevant areas. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/idmouse.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index c9418535bef..15c70bd048c 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file) /* prevent a race condition with open() */ mutex_lock(&disconnect_mutex); - dev = (struct usb_idmouse *) file->private_data; + dev = file->private_data; if (dev == NULL) { mutex_unlock(&disconnect_mutex); @@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file) static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { - struct usb_idmouse *dev; + struct usb_idmouse *dev = file->private_data; int result; - dev = (struct usb_idmouse *) file->private_data; - /* lock this object */ - down (&dev->sem); + down(&dev->sem); /* verify that the device wasn't unplugged */ if (!dev->present) { - up (&dev->sem); + up(&dev->sem); return -ENODEV; } -- cgit v1.2.3 From 2cba72f02559ec0bbbcdba8d2604517515b55f03 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 15 Dec 2006 23:48:56 +0100 Subject: USB: mutexification of rio500 this makes the rio500 misc usb driver use mutexes and turns uninterruptible sleep into interruptible sleep where the semantics are not affected. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/rio500.c | 54 ++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 384fa376980..fdf68479a16 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -69,7 +69,7 @@ struct rio_usb_data { char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ wait_queue_head_t wait_q; /* for timeouts */ - struct semaphore lock; /* general race avoidance */ + struct mutex lock; /* general race avoidance */ }; static struct rio_usb_data rio_instance; @@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file) { struct rio_usb_data *rio = &rio_instance; - down(&(rio->lock)); + mutex_lock(&(rio->lock)); if (rio->isopen || !rio->present) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -EBUSY; } rio->isopen = 1; init_waitqueue_head(&rio->wait_q); - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); info("Rio opened."); @@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, int retries; int retval=0; - down(&(rio->lock)); + mutex_lock(&(rio->lock)); /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || @@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, err_out: - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return retval; } @@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer, int result = 0; int maxretry; int errn = 0; + int intr; - down(&(rio->lock)); + intr = mutex_lock_interruptible(&(rio->lock)); + if (intr) + return -EINTR; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || rio->rio_dev == NULL ) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } @@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer, goto error; } if (signal_pending(current)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return bytes_written ? bytes_written : -EINTR; } @@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer, buffer += copy_size; } while (count > 0); - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return bytes_written ? bytes_written : -EIO; error: - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return errn; } @@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) int result; int maxretry = 10; char *ibuf; + int intr; - down(&(rio->lock)); + intr = mutex_lock_interruptible(&(rio->lock)); + if (intr) + return -EINTR; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || rio->rio_dev == NULL ) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } @@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) while (count > 0) { if (signal_pending(current)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return read_count ? read_count : -EINTR; } if (!rio->rio_dev) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; @@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) count = this_read = partial; } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ if (!maxretry--) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); err("read_rio: maxretry timeout"); return -ETIME; } @@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) finish_wait(&rio->wait_q, &wait); continue; } else if (result != -EREMOTEIO) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); err("Read Whoops - result:%u partial:%u this_read:%u", result, partial, this_read); return -EIO; } else { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return (0); } if (this_read) { if (copy_to_user(buffer, ibuf, this_read)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -EFAULT; } count -= this_read; @@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) buffer += this_read; } } - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return read_count; } @@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf, } dbg("probe_rio: ibuf address:%p", rio->ibuf); - init_MUTEX(&(rio->lock)); + mutex_init(&(rio->lock)); usb_set_intfdata (intf, rio); rio->present = 1; @@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf) if (rio) { usb_deregister_dev(intf, &usb_rio_class); - down(&(rio->lock)); + mutex_lock(&(rio->lock)); if (rio->isopen) { rio->isopen = 0; /* better let it finish - the release will do whats needed */ rio->rio_dev = NULL; - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return; } kfree(rio->ibuf); @@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf) info("USB Rio disconnected."); rio->present = 0; - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); } } -- cgit v1.2.3 From 316547fdfae1be3847add6a18a711703e6d5ebc1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Dec 2006 00:03:38 -0800 Subject: USB: devio.c add missing INIT_LIST_HEAD() It should hopefully fix the list corruption bug on: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=214402 Add a missing INIT_LIST_HEAD() Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 74be846fc02..2087766f9e8 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file) ps->dev = dev; ps->file = file; spin_lock_init(&ps->lock); + INIT_LIST_HEAD(&ps->list); INIT_LIST_HEAD(&ps->async_pending); INIT_LIST_HEAD(&ps->async_completed); init_waitqueue_head(&ps->wait); -- cgit v1.2.3 From 2360e4aa64da412c29136113f8050b6aa9e757b8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 13 Dec 2006 13:07:10 -0800 Subject: USB: indicate active altsetting in proc/bus/usb/devices file Update /proc/bus/usb/devices output to report active altsettings. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index ea398e5d50a..1ff429c37d5 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -104,7 +104,7 @@ static const char *format_config = static const char *format_iface = /* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/ - "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; + "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; static const char *format_endpt = /* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */ @@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end, { const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; const char *driver_name = ""; + int active = 0; if (start > end) return start; down_read(&usb_bus_type.subsys.rwsem); - if (iface) + if (iface) { driver_name = (iface->dev.driver ? iface->dev.driver->name : "(none)"); + active = (desc == &iface->cur_altsetting->desc); + } start += sprintf(start, format_iface, + active ? '*' : ' ', /* mark active altsetting */ desc->bInterfaceNumber, desc->bAlternateSetting, desc->bNumEndpoints, -- cgit v1.2.3 From 1737bf2c5e78e331ad0a30b8c34edd1016d043c0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 15 Dec 2006 16:04:52 -0500 Subject: usbcore: remove unneeded error check This patch (as830) removes some unnecessary error checking. According to the kerneldoc, schedule_work() can't fail. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 149aa8bfb1f..8aca3574c2b 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) INIT_WORK(&req->work, driver_set_config_work); usb_get_dev(udev); - if (!schedule_work(&req->work)) { - usb_put_dev(udev); - kfree(req); - return -EINVAL; - } + schedule_work(&req->work); return 0; } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); -- cgit v1.2.3 From 11d5489873facd395653a4ee14669751bfe9bab5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 11 Dec 2006 15:59:04 -0800 Subject: USB: ethernet gadget interop with MCCI Windows driver It turns out that minor tweaks to the "CDC Subset" support in the Ethernet gadget driver, just updating a config descriptor, let it be automagically recognized by a Windows driver supported by MCCI. This patch adds those descriptors, so systems using PXA 255 processors (like Gumstix etc) can interop with those commercial MS-Windows drivers. This is a Good Thing since Microsoft's RNDIS code has bugginess issues, which are unfortunately compounded by "won't fix" issues as well as "the published specs are incomplete and wrong" issues. Being able to talk to the MCCI driver gives Windows users another connectivity option. (MCCI also has CDC Ethernet drivers, which can help most non-PXA processors.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 142 ++++++++++++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 39 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ca8e0ebc79e..72e2b65293c 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -72,9 +72,18 @@ * * There's some hardware that can't talk CDC. We make that hardware * implement a "minimalist" vendor-agnostic CDC core: same framing, but - * link-level setup only requires activating the configuration. - * Linux supports it, but other host operating systems may not. - * (This is a subset of CDC Ethernet.) + * link-level setup only requires activating the configuration. Only the + * endpoint descriptors, and product/vendor IDs, are relevant; no control + * operations are available. Linux supports it, but other host operating + * systems may not. (This is a subset of CDC Ethernet.) + * + * It turns out that if you add a few descriptors to that "CDC Subset", + * (Windows) host side drivers from MCCI can treat it as one submode of + * a proprietary scheme called "SAFE" ... without needing to know about + * specific product/vendor IDs. So we do that, making it easier to use + * those MS-Windows drivers. Those added descriptors make it resemble a + * CDC MDLM device, but they don't change device behavior at all. (See + * MCCI Engineering report 950198 "SAFE Networking Functions".) * * A third option is also in use. Rather than CDC Ethernet, or something * simpler, Microsoft pushes their own approach: RNDIS. The published @@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_S3C2410 +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_AT91 #define DEV_CONFIG_CDC #endif @@ -283,9 +296,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_S3C2410 -#define DEV_CONFIG_CDC -#endif /*-------------------------------------------------------------------------*/ @@ -487,8 +497,17 @@ rndis_config = { * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. * - * RNDIS shares a lot with CDC-Ethernet, since it's a variant of - * the CDC-ACM (modem) spec. + * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the + * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it + * may hang or oops. Since bugfixes (or accurate specs, letting Linux + * work around those bugs) are unlikely to ever come from MSFT, you may + * wish to avoid using RNDIS. + * + * MCCI offers an alternative to RNDIS if you need to connect to Windows + * but have hardware that can't support CDC Ethernet. We add descriptors + * to present the CDC Subset as a (nonconformant) CDC MDLM variant called + * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can + * get those drivers from MCCI, or bundled with various products. */ #ifdef DEV_CONFIG_CDC @@ -522,8 +541,6 @@ rndis_control_intf = { }; #endif -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - static const struct usb_cdc_header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -532,6 +549,8 @@ static const struct usb_cdc_header_desc header_desc = { .bcdCDC = __constant_cpu_to_le16 (0x0110), }; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) + static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -564,7 +583,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = { #endif -#ifdef DEV_CONFIG_CDC +#ifndef DEV_CONFIG_CDC + +/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various + * ways: data endpoints live in the control interface, there's no data + * interface, and it's not used to talk to a cell phone radio. + */ + +static const struct usb_cdc_mdlm_desc mdlm_desc = { + .bLength = sizeof mdlm_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_MDLM_TYPE, + + .bcdVersion = __constant_cpu_to_le16(0x0100), + .bGUID = { + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, + }, +}; + +/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we + * can't really use its struct. All we do here is say that we're using + * the submode of "SAFE" which directly matches the CDC Subset. + */ +static const u8 mdlm_detail_desc[] = { + 6, + USB_DT_CS_INTERFACE, + USB_CDC_MDLM_DETAIL_TYPE, + + 0, /* "SAFE" */ + 0, /* network control capabilities (none) */ + 0, /* network data capabilities ("raw" encapsulation) */ +}; + +#endif static const struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, @@ -579,7 +631,6 @@ static const struct usb_cdc_ether_desc ether_desc = { .bNumberPowerFilters = 0, }; -#endif #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -672,6 +723,9 @@ rndis_data_intf = { /* * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. + * + * To assist host side drivers, we fancy it up a bit, and add descriptors + * so some host side drivers will understand it as a "SAFE" variant. */ static const struct usb_interface_descriptor @@ -682,8 +736,8 @@ subset_data_intf = { .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, .bInterfaceProtocol = 0, .iInterface = STRING_DATA, }; @@ -731,10 +785,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = { static inline void __init fs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[4] = NULL; + fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + fs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc; + fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc; + fs_eth_function[8] = NULL; #else fs_eth_function[1] = NULL; #endif @@ -828,10 +887,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = { static inline void __init hs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - hs_eth_function[4] = NULL; + hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + hs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc; + hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc; + hs_eth_function[8] = NULL; #else hs_eth_function[1] = NULL; #endif @@ -878,10 +942,8 @@ static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; static char serial_number [20]; -#ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; -#endif /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -889,9 +951,9 @@ static struct usb_string strings [] = { { STRING_PRODUCT, product_desc, }, { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, + { STRING_ETHADDR, ethaddr, }, #ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, - { STRING_ETHADDR, ethaddr, }, { STRING_CONTROL, "CDC Communications Control", }, #endif #ifdef DEV_CONFIG_SUBSET @@ -986,10 +1048,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) } #endif - dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; - dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data @@ -2278,10 +2340,10 @@ eth_bind (struct usb_gadget *gadget) "RNDIS/%s", driver_desc); /* CDC subset ... recognized by Linux since 2.4.10, but Windows - * drivers aren't widely available. + * drivers aren't widely available. (That may be improved by + * supporting one submode of the "SAFE" variant of MDLM.) */ } else if (!cdc) { - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; device_desc.idVendor = __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); device_desc.idProduct = @@ -2352,6 +2414,10 @@ autoconf_fail: if (!cdc) { eth_config.bNumInterfaces = 1; eth_config.iConfiguration = STRING_SUBSET; + + /* use functions to set these up, in case we're built to work + * with multiple controllers and must override CDC Ethernet. + */ fs_subset_descriptors(); hs_subset_descriptors(); } @@ -2415,22 +2481,20 @@ autoconf_fail: /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly - * ends up in a persistent config database. + * ends up in a persistent config database. It's not clear if + * host side code for the SAFE thing cares -- its original BLAN + * thing didn't, Sharp never assigned those addresses on Zaurii. */ if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "self"); - if (cdc || rndis) { - if (get_ether_addr(host_addr, dev->host_mac)) - dev_warn(&gadget->dev, - "using random %s ethernet address\n", "host"); -#ifdef DEV_CONFIG_CDC - snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - dev->host_mac [0], dev->host_mac [1], - dev->host_mac [2], dev->host_mac [3], - dev->host_mac [4], dev->host_mac [5]); -#endif - } + if (get_ether_addr(host_addr, dev->host_mac)) + dev_warn(&gadget->dev, + "using random %s ethernet address\n", "host"); + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + dev->host_mac [0], dev->host_mac [1], + dev->host_mac [2], dev->host_mac [3], + dev->host_mac [4], dev->host_mac [5]); if (rndis) { status = rndis_init(); -- cgit v1.2.3 From ad55d71a3d4401f44b4ddee1412283c99eedd05c Mon Sep 17 00:00:00 2001 From: Ole Andre Vadla Ravnas Date: Thu, 14 Dec 2006 16:01:28 -0800 Subject: rndis_host learns ActiveSync basics Windows Mobile 5 based devices described as supporting "ActiveSync": - Speak RNDIS but lack the CDC and union descriptors. This patch updates the cdc ethernet code to fake ACM descriptors we need. - Require RNDIS_MSG_QUERY messages to include a buffer of the size the response should generate. This patch updates the rndis host code to pass this will-be-ignored data. The resulting RNDIS host code has been reported to work with several WM5 based devices. (Note that a fancier patch is available at synce.sf.net.) Some bugfixes, affecting not just ActiveSync: (a) when cleaning up after RNDS init fails, scrub the second interface just like cdc_ether does, so disconnect won't oops. (b) handle peripherals that use the pad-to-end-of-packet option; some devices can't talk to us if that option doesn't work. (c) when choosing configurations, don't forget about an RNDIS config just because the RNDIS driver is dynamically linked. Cleanup, streamlining, bugfixes, Kconfig, and matching hub driver update. Also for paranoia's sake, refuse to talk to something that looks like a real modem instead of RNDIS. Signed-off-by: Ole Andre Vadla Ravnaas Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 28 ++++++++++----- drivers/usb/net/Kconfig | 6 ++-- drivers/usb/net/cdc_ether.c | 60 ++++++++++++++++++++++++++++++-- drivers/usb/net/rndis_host.c | 81 +++++++++++++++++++++++++++++++++----------- 4 files changed, 144 insertions(+), 31 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index ebb20ff7ac5..b531a4fd30c 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -25,6 +25,20 @@ static inline const char *plural(int n) return (n == 1 ? "" : "s"); } +static int is_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_COMM + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff; +} + +static int is_activesync(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_MISC + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 1; +} + static int choose_configuration(struct usb_device *udev) { int i; @@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev) continue; } - /* If the first config's first interface is COMM/2/0xff - * (MSFT RNDIS), rule it out unless Linux has host-side - * RNDIS support. */ - if (i == 0 && desc - && desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff) { -#ifndef CONFIG_USB_NET_RNDIS_HOST + /* When the first config's first interface is one of Microsoft's + * pet nonstandard Ethernet-over-USB protocols, ignore it unless + * this kernel has enabled the necessary host side driver. + */ + if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) { +#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) continue; #else best = c; diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index e081836014a..a2b94ef512b 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -222,13 +222,15 @@ config USB_NET_MCS7830 adapters marketed under the DeLOCK brand. config USB_NET_RNDIS_HOST - tristate "Host for RNDIS devices (EXPERIMENTAL)" + tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL select USB_NET_CDCETHER help This option enables hosting "Remote NDIS" USB networking links, as encouraged by Microsoft (instead of CDC Ethernet!) for use in - various devices that may only support this protocol. + various devices that may only support this protocol. A variant + of this protocol (with even less public documentation) seems to + be at the root of Microsoft's "ActiveSync" too. Avoid using this protocol unless you have no better options. The protocol specification is incomplete, and is controlled by diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 44a91547146..e5cdafa258d 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -1,6 +1,7 @@ /* * CDC Ethernet based networking peripherals * Copyright (C) 2003-2005 by David Brownell + * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +36,29 @@ #include "usbnet.h" +#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) + +static int is_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_COMM + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff; +} + +static int is_activesync(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_MISC + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 1; +} + +#else + +#define is_rndis(desc) 0 +#define is_activesync(desc) 0 + +#endif + /* * probes control interface, claims data interface, collects the bulk * endpoints, activates data interface (if needed), maybe sets MTU. @@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) /* this assumes that if there's a non-RNDIS vendor variant * of cdc-acm, it'll fail RNDIS requests cleanly. */ - rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); + rndis = is_rndis(&intf->cur_altsetting->desc) + || is_activesync(&intf->cur_altsetting->desc); memset(info, 0, sizeof *info); info->control = intf; @@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) goto bad_desc; } break; + case USB_CDC_ACM_TYPE: + /* paranoia: disambiguate a "real" vendor-specific + * modem interface from an RNDIS non-modem. + */ + if (rndis) { + struct usb_cdc_acm_descriptor *d; + + d = (void *) buf; + if (d->bmCapabilities) { + dev_dbg(&intf->dev, + "ACM capabilities %02x, " + "not really RNDIS?\n", + d->bmCapabilities); + goto bad_desc; + } + } + break; case USB_CDC_UNION_TYPE: if (info->u) { dev_dbg(&intf->dev, "extra CDC union\n"); @@ -171,7 +213,21 @@ next_desc: buf += buf [0]; } - if (!info->header || !info->u || (!rndis && !info->ether)) { + /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors, + * so we'll hard-wire the interfaces and not check for descriptors. + */ + if (is_activesync(&intf->cur_altsetting->desc) && !info->u) { + info->control = usb_ifnum_to_if(dev->udev, 0); + info->data = usb_ifnum_to_if(dev->udev, 1); + if (!info->control || !info->data) { + dev_dbg(&intf->dev, + "activesync: master #0/%p slave #1/%p\n", + info->control, + info->data); + goto bad_desc; + } + + } else if (!info->header || !info->u || (!rndis && !info->ether)) { dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", info->header ? "" : "header ", info->u ? "" : "union ", diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index a322a16d9cf..be888d2d813 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -49,6 +49,8 @@ * - In some cases, MS-Windows will emit undocumented requests; this * matters more to peripheral implementations than host ones. * + * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". + * * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and * currently rare) "Ethernet Emulation Model" (EEM). @@ -61,6 +63,9 @@ * - control-in: GET_ENCAPSULATED * * We'll try to ignore the RESPONSE_AVAILABLE notifications. + * + * REVISIT some RNDIS implementations seem to have curious issues still + * to be resolved. */ struct rndis_msg_hdr { __le32 msg_type; /* RNDIS_MSG_* */ @@ -71,8 +76,14 @@ struct rndis_msg_hdr { // ... and more } __attribute__ ((packed)); -/* RNDIS defines this (absurdly huge) control timeout */ -#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000) +/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */ +#define CONTROL_BUFFER_SIZE 1025 + +/* RNDIS defines an (absurdly huge) 10 second control timeout, + * but ActiveSync seems to use a more usual 5 second timeout + * (which matches the USB 2.0 spec). + */ +#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000) #define ccpu2 __constant_cpu_to_le32 @@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb) static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) { struct cdc_state *info = (void *) &dev->data; + int master_ifnum; int retval; unsigned count; __le32 rsp; @@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) * disconnect(): either serialize, or dispatch responses on xid */ - /* Issue the request; don't bother byteswapping our xid */ + /* Issue the request; xid is unique, don't bother byteswapping it */ if (likely(buf->msg_type != RNDIS_MSG_HALT && buf->msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; @@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) xid = dev->xid++; buf->request_id = (__force __le32) xid; } + master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, + 0, master_ifnum, buf, le32_to_cpu(buf->msg_len), RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0 || xid == 0)) @@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { - memset(buf, 0, 1024); + memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), USB_CDC_GET_ENCAPSULATED_RESPONSE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, - buf, 1024, + 0, master_ifnum, + buf, CONTROL_BUFFER_SIZE, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { msg_len = le32_to_cpu(buf->msg_len); @@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, + 0, master_ifnum, msg, sizeof *msg, RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0)) @@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) u32 tmp; /* we can't rely on i/o from stack working, or stack allocation */ - u.buf = kmalloc(1024, GFP_KERNEL); + u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (!u.buf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) goto fail; - net->hard_header_len += sizeof (struct rndis_data_hdr); - - /* initialize; max transfer is 16KB at full speed */ u.init->msg_type = RNDIS_MSG_INIT; u.init->msg_len = ccpu2(sizeof *u.init); u.init->major_version = ccpu2(1); u.init->minor_version = ccpu2(0); - u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len); + /* max transfer (in spec) is 0x4000 at full speed, but for + * TX we'll stick to one Ethernet packet plus RNDIS framing. + * For RX we handle drivers that zero-pad to end-of-packet. + * Don't let userspace change these settings. + */ + net->hard_header_len += sizeof (struct rndis_data_hdr); + dev->hard_mtu = net->mtu + net->hard_header_len; + + dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); + dev->rx_urb_size &= ~(dev->maxpacket - 1); + u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); + + net->change_mtu = NULL; retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); + goto fail_and_release; + } + tmp = le32_to_cpu(u.init_c->max_transfer_size); + if (tmp < dev->hard_mtu) { + dev_err(&intf->dev, + "dev can't take %u byte packets (max %u)\n", + dev->hard_mtu, tmp); goto fail_and_release; } - dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); + /* REVISIT: peripheral "alignment" request is ignored ... */ - dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu, + dev_dbg(&intf->dev, + "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", + dev->hard_mtu, tmp, dev->rx_urb_size, 1 << le32_to_cpu(u.init_c->packet_alignment)); - /* get designated host ethernet address */ - memset(u.get, 0, sizeof *u.get); + /* Get designated host ethernet address. + * + * Adding a payload exactly the same size as the expected response + * payload is an evident requirement MSFT added for ActiveSync. + * This undocumented (and nonsensical) issue was found by sniffing + * protocol requests from the ActiveSync 4.1 Windows driver. + */ + memset(u.get, 0, sizeof *u.get + 48); u.get->msg_type = RNDIS_MSG_QUERY; - u.get->msg_len = ccpu2(sizeof *u.get); + u.get->msg_len = ccpu2(sizeof *u.get + 48); u.get->oid = OID_802_3_PERMANENT_ADDRESS; + u.get->len = ccpu2(48); + u.get->offset = ccpu2(20); retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { @@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) goto fail_and_release; } tmp = le32_to_cpu(u.get_c->offset); - if (unlikely((tmp + 8) > (1024 - ETH_ALEN) + if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN) || u.get_c->len != ccpu2(ETH_ALEN))) { dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", tmp, le32_to_cpu(u.get_c->len)); @@ -598,6 +637,10 @@ static const struct usb_device_id products [] = { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, +}, { + /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ + USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), + .driver_info = (unsigned long) &rndis_info, }, { }, // END }; -- cgit v1.2.3 From 5e16fabe5dbcff15de6cdcba406195fe6e4380df Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 13 Dec 2006 21:09:54 +0100 Subject: ohci: Rework bus glue integration to allow several at once The previous model had the module_init & module_exit function in the bus glue .c files themselves. That's a problem if several glues need to be selected at once and the driver is built has module. This case is quite common in embedded system where you want to handle both the integrated ohci controller and some extra controller on PCI. The ohci-hcd.c file now provide the module_init & module_exit and appropriate driver registering/unregistering is done conditionally, using #ifdefs. Signed-off-by: Sylvain Munaut Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 15 ------- drivers/usb/host/ohci-au1xxx.c | 16 ------- drivers/usb/host/ohci-ep93xx.c | 12 ------ drivers/usb/host/ohci-hcd.c | 92 +++++++++++++++++++++++++++++++++++------ drivers/usb/host/ohci-lh7a404.c | 16 ------- drivers/usb/host/ohci-omap.c | 19 --------- drivers/usb/host/ohci-pci.c | 20 --------- drivers/usb/host/ohci-pnx4008.c | 12 ------ drivers/usb/host/ohci-pnx8550.c | 16 ------- drivers/usb/host/ohci-ppc-soc.c | 16 ------- drivers/usb/host/ohci-pxa27x.c | 16 ------- drivers/usb/host/ohci-s3c2410.c | 12 ------ drivers/usb/host/ohci-sa1111.c | 16 ------- 13 files changed, 80 insertions(+), 198 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index cc405512fa1..53f62cf7698 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -320,18 +320,3 @@ static struct platform_driver ohci_hcd_at91_driver = { }, }; -static int __init ohci_hcd_at91_init (void) -{ - if (usb_disabled()) - return -ENODEV; - - return platform_driver_register(&ohci_hcd_at91_driver); -} - -static void __exit ohci_hcd_at91_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_at91_driver); -} - -module_init (ohci_hcd_at91_init); -module_exit (ohci_hcd_at91_cleanup); diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index e70b2430e2a..663a0600b6e 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = { }, }; -static int __init ohci_hcd_au1xxx_init (void) -{ - pr_debug (DRIVER_INFO " (Au1xxx)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_au1xxx_driver); -} - -static void __exit ohci_hcd_au1xxx_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_au1xxx_driver); -} - -module_init (ohci_hcd_au1xxx_init); -module_exit (ohci_hcd_au1xxx_cleanup); diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 3348b07f0fe..44c60fba76e 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = { }, }; -static int __init ohci_hcd_ep93xx_init(void) -{ - return platform_driver_register(&ohci_hcd_ep93xx_driver); -} - -static void __exit ohci_hcd_ep93xx_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_ep93xx_driver); -} - -module_init(ohci_hcd_ep93xx_init); -module_exit(ohci_hcd_ep93xx_cleanup); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c1c1d871aba..3f80003b40b 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -855,63 +855,131 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_PCI #include "ohci-pci.c" +#define PCI_DRIVER ohci_pci_driver #endif #ifdef CONFIG_SA1111 #include "ohci-sa1111.c" +#define SA1111_DRIVER ohci_hcd_sa1111_driver #endif #ifdef CONFIG_ARCH_S3C2410 #include "ohci-s3c2410.c" +#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver #endif #ifdef CONFIG_ARCH_OMAP #include "ohci-omap.c" +#define PLATFORM_DRIVER ohci_hcd_omap_driver #endif #ifdef CONFIG_ARCH_LH7A404 #include "ohci-lh7a404.c" +#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver #endif #ifdef CONFIG_PXA27x #include "ohci-pxa27x.c" +#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver #endif #ifdef CONFIG_ARCH_EP93XX #include "ohci-ep93xx.c" +#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif #ifdef CONFIG_SOC_AU1X00 #include "ohci-au1xxx.c" +#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver #endif #ifdef CONFIG_PNX8550 #include "ohci-pnx8550.c" +#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver #endif #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC #include "ohci-ppc-soc.c" +#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver #endif #ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" +#define PLATFORM_DRIVER ohci_hcd_at91_driver #endif #ifdef CONFIG_ARCH_PNX4008 #include "ohci-pnx4008.c" +#define PLATFORM_DRIVER usb_hcd_pnx4008_driver #endif -#if !(defined(CONFIG_PCI) \ - || defined(CONFIG_SA1111) \ - || defined(CONFIG_ARCH_S3C2410) \ - || defined(CONFIG_ARCH_OMAP) \ - || defined (CONFIG_ARCH_LH7A404) \ - || defined (CONFIG_PXA27x) \ - || defined (CONFIG_ARCH_EP93XX) \ - || defined (CONFIG_SOC_AU1X00) \ - || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ - || defined (CONFIG_ARCH_AT91) \ - || defined (CONFIG_ARCH_PNX4008) \ - ) + +#if !defined(PCI_DRIVER) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) #error "missing bus glue for ohci-hcd" #endif + +static int __init ohci_hcd_mod_init(void) +{ + int retval = 0; + int ls = 0; + + if (usb_disabled()) + return -ENODEV; + + printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name); + pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, + sizeof (struct ed), sizeof (struct td)); + +#ifdef PLATFORM_DRIVER + retval = platform_driver_register(&PLATFORM_DRIVER); + if (retval < 0) + return retval; + ls++; +#endif + +#ifdef SA1111_DRIVER + retval = sa1111_driver_register(&SA1111_DRIVER); + if (retval < 0) + goto error; + ls++; +#endif + +#ifdef PCI_DRIVER + retval = pci_register_driver(&PCI_DRIVER); + if (retval < 0) + goto error; + ls++; +#endif + + return retval; + + /* Error path */ +error: +#ifdef PLATFORM_DRIVER + if (ls--) + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +#ifdef SA1111_DRIVER + if (ls--) + sa1111_driver_unregister(&SA1111_DRIVER); +#endif + return retval; +} +module_init(ohci_hcd_mod_init); + +static void __exit ohci_hcd_mod_exit(void) +{ +#ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); +#endif +#ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +} +module_exit(ohci_hcd_mod_exit); + diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index e9807cf73a2..4a043abd85e 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = { }, }; -static int __init ohci_hcd_lh7a404_init (void) -{ - pr_debug (DRIVER_INFO " (LH7A404)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_lh7a404_driver); -} - -static void __exit ohci_hcd_lh7a404_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_lh7a404_driver); -} - -module_init (ohci_hcd_lh7a404_init); -module_exit (ohci_hcd_lh7a404_cleanup); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 27be1f93688..5cfa3d1c441 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = { }, }; -static int __init ohci_hcd_omap_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_omap_driver); -} - -static void __exit ohci_hcd_omap_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_omap_driver); -} - -module_init (ohci_hcd_omap_init); -module_exit (ohci_hcd_omap_cleanup); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 292daf044b6..b331ac4d0d6 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -311,23 +311,3 @@ static struct pci_driver ohci_pci_driver = { .shutdown = usb_hcd_pci_shutdown, }; - -static int __init ohci_hcd_pci_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - return pci_register_driver (&ohci_pci_driver); -} -module_init (ohci_hcd_pci_init); - -/*-------------------------------------------------------------------------*/ - -static void __exit ohci_hcd_pci_cleanup (void) -{ - pci_unregister_driver (&ohci_pci_driver); -} -module_exit (ohci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 3a8cbfb6905..893b172384d 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = { .remove = usb_hcd_pnx4008_remove, }; -static int __init usb_hcd_pnx4008_init(void) -{ - return platform_driver_register(&usb_hcd_pnx4008_driver); -} - -static void __exit usb_hcd_pnx4008_cleanup(void) -{ - return platform_driver_unregister(&usb_hcd_pnx4008_driver); -} - -module_init(usb_hcd_pnx4008_init); -module_exit(usb_hcd_pnx4008_cleanup); diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c index 6922b91b170..de45eb0051a 100644 --- a/drivers/usb/host/ohci-pnx8550.c +++ b/drivers/usb/host/ohci-pnx8550.c @@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = { .remove = ohci_hcd_pnx8550_drv_remove, }; -static int __init ohci_hcd_pnx8550_init (void) -{ - pr_debug (DRIVER_INFO " (pnx8550)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_pnx8550_driver); -} - -static void __exit ohci_hcd_pnx8550_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_pnx8550_driver); -} - -module_init (ohci_hcd_pnx8550_init); -module_exit (ohci_hcd_pnx8550_cleanup); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index c7ce8e638a2..1a2e1777ca6 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = { }, }; -static int __init ohci_hcd_ppc_soc_init(void) -{ - pr_debug(DRIVER_INFO " (PPC SOC)\n"); - pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed), - sizeof(struct td)); - - return platform_driver_register(&ohci_hcd_ppc_soc_driver); -} - -static void __exit ohci_hcd_ppc_soc_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_ppc_soc_driver); -} - -module_init(ohci_hcd_ppc_soc_init); -module_exit(ohci_hcd_ppc_soc_cleanup); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 3bbea844a9e..f1563dc319d 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { }, }; -static int __init ohci_hcd_pxa27x_init (void) -{ - pr_debug (DRIVER_INFO " (pxa27x)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_pxa27x_driver); -} - -static void __exit ohci_hcd_pxa27x_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_pxa27x_driver); -} - -module_init (ohci_hcd_pxa27x_init); -module_exit (ohci_hcd_pxa27x_cleanup); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index b350d45033e..6829814b7aa 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = { }, }; -static int __init ohci_hcd_s3c2410_init (void) -{ - return platform_driver_register(&ohci_hcd_s3c2410_driver); -} - -static void __exit ohci_hcd_s3c2410_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_s3c2410_driver); -} - -module_init (ohci_hcd_s3c2410_init); -module_exit (ohci_hcd_s3c2410_cleanup); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index fe0090e3367..0f48f2d9922 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = { .remove = ohci_hcd_sa1111_drv_remove, }; -static int __init ohci_hcd_sa1111_init (void) -{ - dbg (DRIVER_INFO " (SA-1111)"); - dbg ("block sizes: ed %d td %d", - sizeof (struct ed), sizeof (struct td)); - - return sa1111_driver_register(&ohci_hcd_sa1111_driver); -} - -static void __exit ohci_hcd_sa1111_cleanup (void) -{ - sa1111_driver_unregister(&ohci_hcd_sa1111_driver); -} - -module_init (ohci_hcd_sa1111_init); -module_exit (ohci_hcd_sa1111_cleanup); -- cgit v1.2.3 From 495a678fc62e850d15f860d39faee07ba0a8910c Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 13 Dec 2006 21:09:55 +0100 Subject: ohci: Add support for OHCI controller on the of_platform bus PPC embedded systems can have a ohci controller builtin. In the new model, it will end up as a driver on the of_platform bus, this patches takes care of them. Signed-off-by: Sylvain Munaut Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 23 +++- drivers/usb/host/ohci-hcd.c | 20 ++++ drivers/usb/host/ohci-ppc-of.c | 232 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/ohci-ppc-of.c (limited to 'drivers/usb') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 83259985210..62711870f8e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -112,9 +112,30 @@ config USB_OHCI_HCD_PPC_SOC Enables support for the USB controller on the MPC52xx or STB03xxx processor chip. If unsure, say Y. +config USB_OHCI_HCD_PPC_OF + bool "OHCI support for PPC USB controller on OF platform bus" + depends on USB_OHCI_HCD && PPC_OF + default y + ---help--- + Enables support for the USB controller PowerPC present on the + OpenFirmware platform bus. + +config USB_OHCI_HCD_PPC_OF_BE + bool "Support big endian HC" + depends on USB_OHCI_HCD_PPC_OF + default y + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO + +config USB_OHCI_HCD_PPC_OF_LE + bool "Support little endian HC" + depends on USB_OHCI_HCD_PPC_OF + default n + select USB_OHCI_LITTLE_ENDIAN + config USB_OHCI_HCD_PCI bool "OHCI support for PCI-bus USB controllers" - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) + depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) default y select USB_OHCI_LITTLE_ENDIAN ---help--- diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 3f80003b40b..8baecbdf062 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -914,8 +914,14 @@ MODULE_LICENSE ("GPL"); #endif +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF +#include "ohci-ppc-of.c" +#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ !defined(SA1111_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -939,6 +945,13 @@ static int __init ohci_hcd_mod_init(void) ls++; #endif +#ifdef OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); + if (retval < 0) + goto error; + ls++; +#endif + #ifdef SA1111_DRIVER retval = sa1111_driver_register(&SA1111_DRIVER); if (retval < 0) @@ -961,6 +974,10 @@ error: if (ls--) platform_driver_unregister(&PLATFORM_DRIVER); #endif +#ifdef OF_PLATFORM_DRIVER + if (ls--) + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); +#endif #ifdef SA1111_DRIVER if (ls--) sa1111_driver_unregister(&SA1111_DRIVER); @@ -977,6 +994,9 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef SA1111_DRIVER sa1111_driver_unregister(&SA1111_DRIVER); #endif +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); +#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c new file mode 100644 index 00000000000..08e237c7bc4 --- /dev/null +++ b/drivers/usb/host/ohci-ppc-of.c @@ -0,0 +1,232 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2006 Sylvain Munaut + * + * Bus glue for OHCI HC on the of_platform bus + * + * Modified for of_platform bus from ohci-sa1111.c + * + * This file is licenced under the GPL. + */ + +#include + +#include +#include + + +static int __devinit +ohci_ppc_of_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_ppc_of_hc_driver = { + .description = hcd_name, + .product_desc = "OF OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_ppc_of_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + + +static int __devinit +ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dn = op->node; + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + struct resource res; + int irq; + + int rv; + int is_bigendian; + + if (usb_disabled()) + return -ENODEV; + + is_bigendian = + device_is_compatible(dn, "ohci-bigendian") || + device_is_compatible(dn, "ohci-be"); + + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); + + rv = of_address_to_resource(dn, 0, &res); + if (rv) + return rv; + + hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res.start; + hcd->rsrc_len = res.end - res.start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); + rv = -EBUSY; + goto err_rmr; + } + + irq = irq_of_parse_and_map(dn, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); + rv = -EBUSY; + goto err_irq; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + printk(KERN_ERR __FILE__ ": ioremap failed\n"); + rv = -ENOMEM; + goto err_ioremap; + } + + ohci = hcd_to_ohci(hcd); + if (is_bigendian) + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + + ohci_hcd_init(ohci); + + rv = usb_add_hcd(hcd, irq, 0); + if (rv == 0) + return 0; + + iounmap(hcd->regs); +err_ioremap: + irq_dispose_mapping(irq); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return rv; +} + +static int ohci_hcd_ppc_of_remove(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); + + usb_remove_hcd(hcd); + + iounmap(hcd->regs); + irq_dispose_mapping(hcd->irq); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + usb_put_hcd(hcd); + + return 0; +} + +static int ohci_hcd_ppc_of_shutdown(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); + + return 0; +} + + +static struct of_device_id ohci_hcd_ppc_of_match[] = { +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE + { + .name = "usb", + .compatible = "ohci-bigendian", + }, + { + .name = "usb", + .compatible = "ohci-be", + }, +#endif +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE + { + .name = "usb", + .compatible = "ohci-littledian", + }, + { + .name = "usb", + .compatible = "ohci-le", + }, +#endif + {}, +}; +MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); + +#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ + !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) +#error "No endianess selected for ppc-of-ohci" +#endif + + +static struct of_platform_driver ohci_hcd_ppc_of_driver = { + .name = "ppc-of-ohci", + .match_table = ohci_hcd_ppc_of_match, + .probe = ohci_hcd_ppc_of_probe, + .remove = ohci_hcd_ppc_of_remove, + .shutdown = ohci_hcd_ppc_of_shutdown, +#ifdef CONFIG_PM + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ +#endif + .driver = { + .name = "ppc-of-ohci", + .owner = THIS_MODULE, + }, +}; + -- cgit v1.2.3 From 93bacefc4cc0b53e1cb6a336d43847154fdf6886 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 17 Dec 2006 21:50:23 +0100 Subject: USB serial: add dynamic id support to usb-serial core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Johannes Hölzl for fixing a few things and getting it all working properly. This adds support for dynamic usb ids to the usb serial core. The file "new_id" will show up under the usb serial driver, not the usb driver associated with the usb-serial driver (yeah, it can be a bit confusing at first glance...) This patch also modifies the USB core to allow the usb-serial core to reuse much of the dynamic id logic. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johannes Hölzl --- drivers/usb/core/driver.c | 35 +++++++++++++++++--------------- drivers/usb/serial/bus.c | 45 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/serial/usb-serial.c | 41 ++++++++++++++++++++++++++++++++----- 3 files changed, 100 insertions(+), 21 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce1dd1..0c0c03a4e03 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -28,24 +28,16 @@ #include "hcd.h" #include "usb.h" -static int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id); - -struct usb_dynid { - struct list_head node; - struct usb_device_id id; -}; - #ifdef CONFIG_HOTPLUG /* * Adds a new dynamic USBdevice ID to this driver, * and cause the driver to probe for all devices again. */ -static ssize_t store_new_id(struct device_driver *driver, - const char *buf, size_t count) +ssize_t usb_store_new_id(struct usb_dynids *dynids, + struct device_driver *driver, + const char *buf, size_t count) { - struct usb_driver *usb_drv = to_usb_driver(driver); struct usb_dynid *dynid; u32 idVendor = 0; u32 idProduct = 0; @@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver, dynid->id.idProduct = idProduct; dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; - spin_lock(&usb_drv->dynids.lock); - list_add_tail(&usb_drv->dynids.list, &dynid->node); - spin_unlock(&usb_drv->dynids.lock); + spin_lock(&dynids->lock); + list_add_tail(&dynids->list, &dynid->node); + spin_unlock(&dynids->lock); if (get_driver(driver)) { retval = driver_attach(driver); @@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver, return retval; return count; } +EXPORT_SYMBOL_GPL(usb_store_new_id); + +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_driver *usb_drv = to_usb_driver(driver); + + return usb_store_new_id(&usb_drv->dynids, driver, buf, count); +} static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); static int usb_create_newid_file(struct usb_driver *usb_drv) @@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver, EXPORT_SYMBOL(usb_driver_release_interface); /* returns 0 if no match, 1 if match */ -static int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id) +int usb_match_one_id(struct usb_interface *interface, + const struct usb_device_id *id) { struct usb_host_interface *intf; struct usb_device *dev; @@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface, return 1; } +EXPORT_SYMBOL_GPL(usb_match_one_id); + /** * usb_match_id - find first usb_device_id matching device or interface * @interface: the interface of interest diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 6542f220468..c08a38402b9 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -103,11 +103,52 @@ exit: return retval; } +#ifdef CONFIG_HOTPLUG +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); + + if (retval >= 0 && usb_drv->usb_driver != NULL) + retval = usb_store_new_id(&usb_drv->usb_driver->dynids, + &usb_drv->usb_driver->drvwrap.driver, + buf, count); + return retval; +} + +static struct driver_attribute drv_attrs[] = { + __ATTR(new_id, S_IWUSR, NULL, store_new_id), + __ATTR_NULL, +}; + +static void free_dynids(struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid, *n; + + spin_lock(&drv->dynids.lock); + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + +#else +static struct driver_attribute drv_attrs[] = { + __ATTR_NULL, +}; +static inline void free_dynids(struct usb_driver *drv) +{ +} +#endif + struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, + .drv_attrs = drv_attrs, }; int usb_serial_bus_register(struct usb_serial_driver *driver) @@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) int retval; driver->driver.bus = &usb_serial_bus_type; + spin_lock_init(&driver->dynids.lock); + INIT_LIST_HEAD(&driver->dynids.list); + retval = driver_register(&driver->driver); return retval; @@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) void usb_serial_bus_deregister(struct usb_serial_driver *driver) { + free_dynids(driver); driver_unregister(&driver->driver); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f6806cc8..90beb5c50e5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -596,6 +596,39 @@ static struct usb_serial * create_serial (struct usb_device *dev, return serial; } +static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, + struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid; + + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (usb_match_one_id(intf, &dynid->id)) { + spin_unlock(&drv->dynids.lock); + return &dynid->id; + } + } + spin_unlock(&drv->dynids.lock); + return NULL; +} + +static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, + struct usb_interface *intf) +{ + const struct usb_device_id *id; + + id = usb_match_id(intf, drv->id_table); + if (id) { + dbg("static descriptor matches"); + goto exit; + } + id = match_dynamic_id(intf, drv); + if (id) + dbg("dynamic descriptor matches"); +exit: + return id; +} + static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { struct list_head *p; @@ -605,11 +638,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac /* Check if the usb id matches a known device */ list_for_each(p, &usb_serial_driver_list) { t = list_entry(p, struct usb_serial_driver, driver_list); - id = usb_match_id(iface, t->id_table); - if (id != NULL) { - dbg("descriptor matches"); + id = get_iface_id(t, iface); + if (id) return t; - } } return NULL; @@ -661,7 +692,7 @@ int usb_serial_probe(struct usb_interface *interface, return -EIO; } - id = usb_match_id(interface, type->id_table); + id = get_iface_id(type, interface); retval = type->probe(serial, id); module_put(type->driver.owner); -- cgit v1.2.3 From d9b1b787736852f462dbf277b3ca708cbbf693ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20H=C3=B6lzl?= Date: Sun, 17 Dec 2006 21:50:24 +0100 Subject: USB serial: add driver pointer to all usb-serial drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every usb serial driver should have a pointer to the corresponding usb driver. So the usb serial core can add a new id not only to the usb serial driver, but also to the usb driver. Also the usb drivers of ark3116, mos7720 and mos7840 missed the flag no_dynamic_id=1. This is added now. Signed-off-by: Johannes Hölzl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/aircable.c | 16 +++++++++------- drivers/usb/serial/airprime.c | 1 + drivers/usb/serial/ark3116.c | 2 ++ drivers/usb/serial/belkin_sa.c | 1 + drivers/usb/serial/cp2101.c | 1 + drivers/usb/serial/cyberjack.c | 3 ++- drivers/usb/serial/cypress_m8.c | 3 +++ drivers/usb/serial/digi_acceleport.c | 2 ++ drivers/usb/serial/empeg.c | 1 + drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/funsoft.c | 1 + drivers/usb/serial/garmin_gps.c | 1 + drivers/usb/serial/generic.c | 35 ++++++++++++++++++++--------------- drivers/usb/serial/hp4x.c | 1 + drivers/usb/serial/io_edgeport.c | 8 -------- drivers/usb/serial/io_tables.h | 11 +++++++++++ drivers/usb/serial/io_ti.c | 2 ++ drivers/usb/serial/ipaq.c | 1 + drivers/usb/serial/ipw.c | 1 + drivers/usb/serial/ir-usb.c | 1 + drivers/usb/serial/keyspan.h | 4 ++++ drivers/usb/serial/keyspan_pda.c | 3 +++ drivers/usb/serial/kl5kusb105.c | 1 + drivers/usb/serial/kobil_sct.c | 1 + drivers/usb/serial/mct_u232.c | 1 + drivers/usb/serial/mos7720.c | 16 +++++++++------- drivers/usb/serial/mos7840.c | 16 +++++++++------- drivers/usb/serial/navman.c | 1 + drivers/usb/serial/omninet.c | 1 + drivers/usb/serial/option.c | 1 + drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/safe_serial.c | 1 + drivers/usb/serial/sierra.c | 2 ++ drivers/usb/serial/ti_usb_3410_5052.c | 2 ++ drivers/usb/serial/visor.c | 3 +++ drivers/usb/serial/whiteheat.c | 2 ++ 36 files changed, 104 insertions(+), 45 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 86bcf63b6ba..46c856a187a 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -572,8 +572,17 @@ static void aircable_unthrottle(struct usb_serial_port *port) schedule_work(&priv->rx_work); } +static struct usb_driver aircable_driver = { + .name = "aircable", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver aircable_device = { .description = "aircable", + .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, .attach = aircable_attach, @@ -587,13 +596,6 @@ static struct usb_serial_driver aircable_device = { .unthrottle = aircable_unthrottle, }; -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static int __init aircable_init (void) { int retval; diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index f2ca76a9cba..0af42e32fa0 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = { .owner = THIS_MODULE, .name = "airprime", }, + .usb_driver = &airprime_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5261cd22ee6..edd685791a6 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .no_dynamic_id = 1, }; static struct usb_serial_driver ark3116_device = { @@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = { .name = "ark3116", }, .id_table = id_table, + .usb_driver = &ark3116_driver, .num_interrupt_in = 1, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 38b4dae319e..3b800d277c4 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = { .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", + .usb_driver = &belkin_driver, .id_table = id_table_combined, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 7ebaffd6ed8..06b4fffc189 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = { .owner = THIS_MODULE, .name = "cp2101", }, + .usb_driver = &cp2101_driver, .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 0, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index a63c3286caa..4167753ed31 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = { .name = "cyberjack", }, .description = "Reiner SCT Cyberjack USB card reader", + .usb_driver = &cyberjack_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = { .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, - .write_room = cyberjack_write_room, + .write_room = cyberjack_write_room, .read_int_callback = cyberjack_read_int_callback, .read_bulk_callback = cyberjack_read_bulk_callback, .write_bulk_callback = cyberjack_write_bulk_callback, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 6bc1f404e18..57b8e27285f 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = { .name = "earthmate", }, .description = "DeLorme Earthmate USB", + .usb_driver = &cypress_driver, .id_table = id_table_earthmate, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = { .name = "cyphidcom", }, .description = "HID->COM RS232 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_cyphidcomrs232, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = { .name = "nokiaca42v2", }, .description = "Nokia CA-42 V2 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_nokiaca42v2, .num_interrupt_in = 1, .num_interrupt_out = 1, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index efd9ce3f931..0b0fb51bad3 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = { .name = "digi_2", }, .description = "Digi 2 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_2, .num_interrupt_in = 0, .num_bulk_in = 4, @@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = { .name = "digi_4", }, .description = "Digi 4 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_4, .num_interrupt_in = 0, .num_bulk_in = 5, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 92beeb19795..4703c8f8538 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = { .name = "empeg", }, .id_table = id_table, + .usb_driver = &empeg_driver, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6986e756f7c..35cad4249e5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -615,6 +615,7 @@ static struct usb_serial_driver ftdi_sio_device = { .name = "ftdi_sio", }, .description = "FTDI USB Serial Device", + .usb_driver = &ftdi_driver , .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 2bebd63d5ed..4092f6dc9ef 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = { .name = "funsoft", }, .id_table = id_table, + .usb_driver = &funsoft_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 6530d391ebe..74660a3aa67 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = { .name = "garmin_gps", }, .description = "Garmin GPS usb/tty", + .usb_driver = &garmin_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 36042937e77..601e0648dec 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -20,6 +20,10 @@ #include #include +static int generic_probe(struct usb_interface *interface, + const struct usb_device_id *id); + + static int debug; #ifdef CONFIG_USB_SERIAL_GENERIC @@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ +/* we want to look at all devices, as the vendor/product id can change + * depending on the command line argument */ +static struct usb_device_id generic_serial_ids[] = { + {.driver_info = 42}, + {} +}; + +static struct usb_driver generic_driver = { + .name = "usbserial_generic", + .probe = generic_probe, + .disconnect = usb_serial_disconnect, + .id_table = generic_serial_ids, + .no_dynamic_id = 1, +}; + /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { @@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = { .name = "generic", }, .id_table = generic_device_ids, + .usb_driver = &generic_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, @@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = { .shutdown = usb_serial_generic_shutdown, }; -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - static int generic_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface, return usb_serial_probe(interface, id); return -ENODEV; } - -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, - .no_dynamic_id = 1, -}; #endif int usb_serial_generic_register (int _debug) diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index ebcac701b06..6c6ebae741c 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = { .name = "hp4X", }, .id_table = id_table, + .usb_driver = &hp49gp_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index cca1607857f..6a26a2e683a 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -242,14 +242,6 @@ static void edge_shutdown (struct usb_serial *serial); #include "io_tables.h" /* all of the devices that this driver supports */ -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - /* function prototypes for all of our local functions */ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 3cbb8c19d92..6d300877254 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -95,12 +95,21 @@ static struct usb_device_id id_table_combined [] = { MODULE_DEVICE_TABLE (usb, id_table_combined); +static struct usb_driver io_driver = { + .name = "io_edgeport", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, .name = "edgeport_2", }, .description = "Edgeport 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -131,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = { .name = "edgeport_4", }, .description = "Edgeport 4 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_4port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -161,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = { .name = "edgeport_8", }, .description = "Edgeport 8 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_8port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 980285c0233..544098d2b77 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = { .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_1port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = { .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 42f757a5b87..a408184334e 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = { .name = "ipaq", }, .description = "PocketPC PDA", + .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index d3b9a351cef..1bc586064c7 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", + .usb_driver = &usb_ipw_driver, .id_table = usb_ipw_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 8fdf486e346..9d847f69291 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = { .name = "ir-usb", }, .description = "IR Dongle", + .usb_driver = &ir_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 6413d73c139..2dc8964916f 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -576,6 +576,7 @@ static struct usb_serial_driver keyspan_pre_device = { .name = "keyspan_no_firm", }, .description = "Keyspan - (without firmware)", + .usb_driver = &keyspan_driver, .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -590,6 +591,7 @@ static struct usb_serial_driver keyspan_1port_device = { .name = "keyspan_1", }, .description = "Keyspan 1 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -617,6 +619,7 @@ static struct usb_serial_driver keyspan_2port_device = { .name = "keyspan_2", }, .description = "Keyspan 2 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -644,6 +647,7 @@ static struct usb_serial_driver keyspan_4port_device = { .name = "keyspan_4", }, .description = "Keyspan 4 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 5, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 126b9703bba..da514cb785b 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = { .name = "keyspan_pda_pre", }, .description = "Keyspan PDA - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = { .name = "xircom_no_firm", }, .description = "Xircom / Entregra PGS - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = { .name = "keyspan_pda", }, .description = "Keyspan PDA", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_std, .num_interrupt_in = 1, .num_bulk_in = 0, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5c4b06a99ac..b2097c45a23 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = { .name = "kl5kusb105d", }, .description = "KL5KUSB105D / PalmConnect", + .usb_driver = &kl5kusb105d_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 62bea0c923b..0683b51f093 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = { .name = "kobil", }, .description = "KOBIL USB smart card terminal", + .usb_driver = &kobil_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 38b1d17e06e..4cd839b1407 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = { .name = "mct_u232", }, .description = "MCT U232", + .usb_driver = &mct_u232_driver, .id_table = id_table_combined, .num_interrupt_in = 2, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e55f4ed81d7..6109c6704a7 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial) usb_set_serial_data(serial, NULL); } +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7720_2port_driver = { .driver = { .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", + .usb_driver = &usb_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, @@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .read_bulk_callback = mos7720_bulk_in_callback, }; -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - static int __init moschip7720_init(void) { int retval; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 83f661403ba..b2264a87617 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2834,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial) } +static struct usb_driver io_driver = { + .name = "mos7840", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, + .usb_driver = &io_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, //NUM_DONT_CARE,//1, #ifdef check @@ -2869,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = { .read_int_callback = mos7840_interrupt_callback, }; -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - /**************************************************************************** * moschip7840_init * This is called by the module subsystem, or on startup to initialize us diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 054abee8165..90701111d74 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = { .name = "navman", }, .id_table = id_table, + .usb_driver = &navman_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index bc91d3b726f..0216ac12a27 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = { .name = "omninet", }, .description = "ZyXEL - omni.net lcd plus usb", + .usb_driver = &omninet_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0fed43a9687..ced9f32b29d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -135,6 +135,7 @@ static struct usb_serial_driver option_1port_device = { .name = "option1", }, .description = "GSM modem (1-port)", + .usb_driver = &option_driver, .id_table = option_ids1, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 5dc2ac9afa9..6c083d4e2c9 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = { .name = "pl2303", }, .id_table = id_table, + .usb_driver = &pl2303_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 30b7ebc8d45..5a03a3fc938 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = { .name = "safe_serial", }, .id_table = id_table, + .usb_driver = &safe_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6d8e91e00ec..8aca8a707a3 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -614,6 +614,7 @@ static struct usb_serial_driver sierra_1port_device = { }, .description = "Sierra USB modem (1 port)", .id_table = id_table_1port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, @@ -642,6 +643,7 @@ static struct usb_serial_driver sierra_3port_device = { }, .description = "Sierra USB modem (3 port)", .id_table = id_table_3port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 3, .num_bulk_out = 3, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 83189005c6f..4203e2b1a76 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = { .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = { .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index b09f0609605..02cd6f7a2d6 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -189,6 +189,7 @@ static struct usb_serial_driver handspring_device = { .name = "visor", }, .description = "Handspring Visor / Palm OS", + .usb_driver = &visor_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -219,6 +220,7 @@ static struct usb_serial_driver clie_5_device = { .name = "clie_5", }, .description = "Sony Clie 5.0", + .usb_driver = &visor_driver, .id_table = clie_id_5_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -249,6 +251,7 @@ static struct usb_serial_driver clie_3_5_device = { .name = "clie_3.5", }, .description = "Sony Clie 3.5", + .usb_driver = &visor_driver, .id_table = clie_id_3_5_table, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5483d8564c1..bf16e9e1d84 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = { .name = "whiteheatnofirm", }, .description = "Connect Tech - WhiteHEAT - (prerenumeration)", + .usb_driver = &whiteheat_driver, .id_table = id_table_prerenumeration, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = { .name = "whiteheat", }, .description = "Connect Tech - WhiteHEAT", + .usb_driver = &whiteheat_driver, .id_table = id_table_std, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, -- cgit v1.2.3 From 52d67f0b5c1b1827cd842020d40bdde4f7d04f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20H=C3=B6lzl?= Date: Sun, 17 Dec 2006 22:05:09 +0100 Subject: USB: Bugfix for aircable: Add module and name to usb_serial_driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While adding the dynamic-id support to usb serial I found a small bug in the air cable driver: Adds module and name information to the usb_serial_driver instance of aircable. So the aircable driver is correctly shown under /sys/bus/usb-serial/drivers/aircable and has the module link. Signed-off-by: Johannes Hölzl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/aircable.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 46c856a187a..11dad42c3c6 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -581,7 +581,10 @@ static struct usb_driver aircable_driver = { }; static struct usb_serial_driver aircable_device = { - .description = "aircable", + .driver = { + .owner = THIS_MODULE, + .name = "aircable", + }, .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, -- cgit v1.2.3 From 7ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5 Mon Sep 17 00:00:00 2001 From: John Daiker Date: Fri, 29 Dec 2006 19:02:06 -0800 Subject: USB Gadget file_storage.c: remove unnecessary casts Went looking through some usb stuff and found some unnecessary casts in file_storage.c This is part of the KernelJanitors TODO list. Signed-off-by: John Daiker Acked-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 027b3150526..f04a29a4664 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg) static void ep0_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_dev *fsg = ep->driver_data; if (req->actual > 0) dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); @@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; dump_msg(fsg, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) @@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) #ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg) } if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; + struct bulk_cs_wrap *csw = bh->buf; /* Store and send the Bulk-only CSW */ csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); @@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg) return 0; } else { // USB_PR_CBI - struct interrupt_data *buf = (struct interrupt_data *) - bh->buf; + struct interrupt_data *buf = bh->buf; /* Store and send the Interrupt data. UFI sends the ASC * and ASCQ bytes. Everything else sends a Type (which @@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg) static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf; + struct bulk_cb_wrap *cbw = req->buf; /* Was this a real packet? */ if (req->status) @@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg) static int fsg_main_thread(void *fsg_) { - struct fsg_dev *fsg = (struct fsg_dev *) fsg_; + struct fsg_dev *fsg = fsg_; /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ @@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); char *p; ssize_t rc; @@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int i; if (sscanf(buf, "%d", &i) != 1) @@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int rc = 0; if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { @@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref) static void lun_release(struct device *dev) { - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); kref_put(&fsg->ref, fsg_release); } -- cgit v1.2.3 From 6f23ee1fefdc1f80bd8a3ab04a1c41ab2dec14c9 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sat, 30 Dec 2006 22:43:10 -0800 Subject: USB: add binary API to usbmon This patch adds a new, "binary" API in addition to the old, text API usbmon had before. The new API allows for less CPU use, and it allows to capture all data from a packet where old API only captured 32 bytes at most. There are some limitations and conditions to this, e.g. in case someone constructs a URB with 1GB of data, it's not likely to be captured, because even the huge buffers of the new reader are finite. Nonetheless, I expect this new capability to capture all data for all real life scenarios. The downside is, a special user mode application is required where cat(1) worked before. I have sample code at http://people.redhat.com/zaitcev/linux/ and Paolo Abeni is working on patching libpcap. This patch was initially written by Paolo and later I tweaked it, and we had a little back-and-forth. So this is a jointly authored patch, but I am submitting this I am responsible for the bugs. Signed-off-by: Paolo Abeni Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/Makefile | 2 +- drivers/usb/mon/mon_bin.c | 1172 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/mon/mon_dma.c | 39 +- drivers/usb/mon/mon_main.c | 97 ++-- drivers/usb/mon/mon_text.c | 67 ++- drivers/usb/mon/usb_mon.h | 30 +- 6 files changed, 1352 insertions(+), 55 deletions(-) create mode 100644 drivers/usb/mon/mon_bin.c (limited to 'drivers/usb') diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index 3cf3ea3a88e..90c59535778 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -2,7 +2,7 @@ # Makefile for USB Core files and filesystem # -usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o +usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o # This does not use CONFIG_USB_MON because we want this to use a tristate. obj-$(CONFIG_USB) += usbmon.o diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c new file mode 100644 index 00000000000..c01dfe60367 --- /dev/null +++ b/drivers/usb/mon/mon_bin.c @@ -0,0 +1,1172 @@ +/* + * The USB Monitor, inspired by Dave Harding's USBMon. + * + * This is a binary format reader. + * + * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it) + * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb_mon.h" + +/* + * Defined by USB 2.0 clause 9.3, table 9.2. + */ +#define SETUP_LEN 8 + +/* ioctl macros */ +#define MON_IOC_MAGIC 0x92 + +#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) +/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */ +#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) +#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) +#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) +#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) +#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) +#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) +#ifdef CONFIG_COMPAT +#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32) +#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32) +#endif + +/* + * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc). + * But it's all right. Just use a simple way to make sure the chunk is never + * smaller than a page. + * + * N.B. An application does not know our chunk size. + * + * Woops, get_zeroed_page() returns a single page. I guess we're stuck with + * page-sized chunks for the time being. + */ +#define CHUNK_SIZE PAGE_SIZE +#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1)) + +/* + * The magic limit was calculated so that it allows the monitoring + * application to pick data once in two ticks. This way, another application, + * which presumably drives the bus, gets to hog CPU, yet we collect our data. + * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an + * enormous overhead built into the bus protocol, so we need about 1000 KB. + * + * This is still too much for most cases, where we just snoop a few + * descriptor fetches for enumeration. So, the default is a "reasonable" + * amount for systems with HZ=250 and incomplete bus saturation. + * + * XXX What about multi-megabyte URBs which take minutes to transfer? + */ +#define BUFF_MAX CHUNK_ALIGN(1200*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) + +/* + * The per-event API header (2 per URB). + * + * This structure is seen in userland as defined by the documentation. + */ +struct mon_bin_hdr { + u64 id; /* URB ID - from submission to callback */ + unsigned char type; /* Same as in text API; extensible. */ + unsigned char xfer_type; /* ISO, Intr, Control, Bulk */ + unsigned char epnum; /* Endpoint number and transfer direction */ + unsigned char devnum; /* Device address */ + unsigned short busnum; /* Bus number */ + char flag_setup; + char flag_data; + s64 ts_sec; /* gettimeofday */ + s32 ts_usec; /* gettimeofday */ + int status; + unsigned int len_urb; /* Length of data (submitted or actual) */ + unsigned int len_cap; /* Delivered length */ + unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ +}; + +/* per file statistic */ +struct mon_bin_stats { + u32 queued; + u32 dropped; +}; + +struct mon_bin_get { + struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */ + void __user *data; + size_t alloc; /* Length of data (can be zero) */ +}; + +struct mon_bin_mfetch { + u32 __user *offvec; /* Vector of events fetched */ + u32 nfetch; /* Number of events to fetch (out: fetched) */ + u32 nflush; /* Number of events to flush */ +}; + +#ifdef CONFIG_COMPAT +struct mon_bin_get32 { + u32 hdr32; + u32 data32; + u32 alloc32; +}; + +struct mon_bin_mfetch32 { + u32 offvec32; + u32 nfetch32; + u32 nflush32; +}; +#endif + +/* Having these two values same prevents wrapping of the mon_bin_hdr */ +#define PKT_ALIGN 64 +#define PKT_SIZE 64 + +/* max number of USB bus supported */ +#define MON_BIN_MAX_MINOR 128 + +/* + * The buffer: map of used pages. + */ +struct mon_pgmap { + struct page *pg; + unsigned char *ptr; /* XXX just use page_to_virt everywhere? */ +}; + +/* + * This gets associated with an open file struct. + */ +struct mon_reader_bin { + /* The buffer: one per open. */ + spinlock_t b_lock; /* Protect b_cnt, b_in */ + unsigned int b_size; /* Current size of the buffer - bytes */ + unsigned int b_cnt; /* Bytes used */ + unsigned int b_in, b_out; /* Offsets into buffer - bytes */ + unsigned int b_read; /* Amount of read data in curr. pkt. */ + struct mon_pgmap *b_vec; /* The map array */ + wait_queue_head_t b_wait; /* Wait for data here */ + + struct mutex fetch_lock; /* Protect b_read, b_out */ + int mmap_active; + + /* A list of these is needed for "bus 0". Some time later. */ + struct mon_reader r; + + /* Stats */ + unsigned int cnt_lost; +}; + +static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, + unsigned int offset) +{ + return (struct mon_bin_hdr *) + (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE); +} + +#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) + +static dev_t mon_bin_dev0; +static struct cdev mon_bin_cdev; + +static void mon_buff_area_fill(const struct mon_reader_bin *rp, + unsigned int offset, unsigned int size); +static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp); +static int mon_alloc_buff(struct mon_pgmap *map, int npages); +static void mon_free_buff(struct mon_pgmap *map, int npages); + +/* + * This is a "chunked memcpy". It does not manipulate any counters. + * But it returns the new offset for repeated application. + */ +unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, + unsigned int off, const unsigned char *from, unsigned int length) +{ + unsigned int step_len; + unsigned char *buf; + unsigned int in_page; + + while (length) { + /* + * Determine step_len. + */ + step_len = length; + in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); + if (in_page < step_len) + step_len = in_page; + + /* + * Copy data and advance pointers. + */ + buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; + memcpy(buf, from, step_len); + if ((off += step_len) >= this->b_size) off = 0; + from += step_len; + length -= step_len; + } + return off; +} + +/* + * This is a little worse than the above because it's "chunked copy_to_user". + * The return value is an error code, not an offset. + */ +static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off, + char __user *to, int length) +{ + unsigned int step_len; + unsigned char *buf; + unsigned int in_page; + + while (length) { + /* + * Determine step_len. + */ + step_len = length; + in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); + if (in_page < step_len) + step_len = in_page; + + /* + * Copy data and advance pointers. + */ + buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; + if (copy_to_user(to, buf, step_len)) + return -EINVAL; + if ((off += step_len) >= this->b_size) off = 0; + to += step_len; + length -= step_len; + } + return 0; +} + +/* + * Allocate an (aligned) area in the buffer. + * This is called under b_lock. + * Returns ~0 on failure. + */ +static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp, + unsigned int size) +{ + unsigned int offset; + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if (rp->b_cnt + size > rp->b_size) + return ~0; + offset = rp->b_in; + rp->b_cnt += size; + if ((rp->b_in += size) >= rp->b_size) + rp->b_in -= rp->b_size; + return offset; +} + +/* + * This is the same thing as mon_buff_area_alloc, only it does not allow + * buffers to wrap. This is needed by applications which pass references + * into mmap-ed buffers up their stacks (libpcap can do that). + * + * Currently, we always have the header stuck with the data, although + * it is not strictly speaking necessary. + * + * When a buffer would wrap, we place a filler packet to mark the space. + */ +static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp, + unsigned int size) +{ + unsigned int offset; + unsigned int fill_size; + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if (rp->b_cnt + size > rp->b_size) + return ~0; + if (rp->b_in + size > rp->b_size) { + /* + * This would wrap. Find if we still have space after + * skipping to the end of the buffer. If we do, place + * a filler packet and allocate a new packet. + */ + fill_size = rp->b_size - rp->b_in; + if (rp->b_cnt + size + fill_size > rp->b_size) + return ~0; + mon_buff_area_fill(rp, rp->b_in, fill_size); + + offset = 0; + rp->b_in = size; + rp->b_cnt += size + fill_size; + } else if (rp->b_in + size == rp->b_size) { + offset = rp->b_in; + rp->b_in = 0; + rp->b_cnt += size; + } else { + offset = rp->b_in; + rp->b_in += size; + rp->b_cnt += size; + } + return offset; +} + +/* + * Return a few (kilo-)bytes to the head of the buffer. + * This is used if a DMA fetch fails. + */ +static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size) +{ + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + rp->b_cnt -= size; + if (rp->b_in < size) + rp->b_in += rp->b_size; + rp->b_in -= size; +} + +/* + * This has to be called under both b_lock and fetch_lock, because + * it accesses both b_cnt and b_out. + */ +static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size) +{ + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + rp->b_cnt -= size; + if ((rp->b_out += size) >= rp->b_size) + rp->b_out -= rp->b_size; +} + +static void mon_buff_area_fill(const struct mon_reader_bin *rp, + unsigned int offset, unsigned int size) +{ + struct mon_bin_hdr *ep; + + ep = MON_OFF2HDR(rp, offset); + memset(ep, 0, PKT_SIZE); + ep->type = '@'; + ep->len_cap = size - PKT_SIZE; +} + +static inline char mon_bin_get_setup(unsigned char *setupb, + const struct urb *urb, char ev_type) +{ + + if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + return '-'; + + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) + return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); + if (urb->setup_packet == NULL) + return 'Z'; + + memcpy(setupb, urb->setup_packet, SETUP_LEN); + return 0; +} + +static char mon_bin_get_data(const struct mon_reader_bin *rp, + unsigned int offset, struct urb *urb, unsigned int length) +{ + + if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) { + mon_dmapeek_vec(rp, offset, urb->transfer_dma, length); + return 0; + } + + if (urb->transfer_buffer == NULL) + return 'Z'; + + mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); + return 0; +} + +static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, + char ev_type) +{ + unsigned long flags; + struct timeval ts; + unsigned int urb_length; + unsigned int offset; + unsigned int length; + struct mon_bin_hdr *ep; + char data_tag = 0; + + do_gettimeofday(&ts); + + spin_lock_irqsave(&rp->b_lock, flags); + + /* + * Find the maximum allowable length, then allocate space. + */ + urb_length = (ev_type == 'S') ? + urb->transfer_buffer_length : urb->actual_length; + length = urb_length; + + if (length >= rp->b_size/5) + length = rp->b_size/5; + + if (usb_pipein(urb->pipe)) { + if (ev_type == 'S') { + length = 0; + data_tag = '<'; + } + } else { + if (ev_type == 'C') { + length = 0; + data_tag = '>'; + } + } + + if (rp->mmap_active) + offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE); + else + offset = mon_buff_area_alloc(rp, length + PKT_SIZE); + if (offset == ~0) { + rp->cnt_lost++; + spin_unlock_irqrestore(&rp->b_lock, flags); + return; + } + + ep = MON_OFF2HDR(rp, offset); + if ((offset += PKT_SIZE) >= rp->b_size) offset = 0; + + /* + * Fill the allocated area. + */ + memset(ep, 0, PKT_SIZE); + ep->type = ev_type; + ep->xfer_type = usb_pipetype(urb->pipe); + /* We use the fact that usb_pipein() returns 0x80 */ + ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); + ep->devnum = usb_pipedevice(urb->pipe); + ep->busnum = rp->r.m_bus->u_bus->busnum; + ep->id = (unsigned long) urb; + ep->ts_sec = ts.tv_sec; + ep->ts_usec = ts.tv_usec; + ep->status = urb->status; + ep->len_urb = urb_length; + ep->len_cap = length; + + ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type); + if (length != 0) { + ep->flag_data = mon_bin_get_data(rp, offset, urb, length); + if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ + ep->len_cap = 0; + mon_buff_area_shrink(rp, length); + } + } else { + ep->flag_data = data_tag; + } + + spin_unlock_irqrestore(&rp->b_lock, flags); + + wake_up(&rp->b_wait); +} + +static void mon_bin_submit(void *data, struct urb *urb) +{ + struct mon_reader_bin *rp = data; + mon_bin_event(rp, urb, 'S'); +} + +static void mon_bin_complete(void *data, struct urb *urb) +{ + struct mon_reader_bin *rp = data; + mon_bin_event(rp, urb, 'C'); +} + +static void mon_bin_error(void *data, struct urb *urb, int error) +{ + struct mon_reader_bin *rp = data; + unsigned long flags; + unsigned int offset; + struct mon_bin_hdr *ep; + + spin_lock_irqsave(&rp->b_lock, flags); + + offset = mon_buff_area_alloc(rp, PKT_SIZE); + if (offset == ~0) { + /* Not incrementing cnt_lost. Just because. */ + spin_unlock_irqrestore(&rp->b_lock, flags); + return; + } + + ep = MON_OFF2HDR(rp, offset); + + memset(ep, 0, PKT_SIZE); + ep->type = 'E'; + ep->xfer_type = usb_pipetype(urb->pipe); + /* We use the fact that usb_pipein() returns 0x80 */ + ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); + ep->devnum = usb_pipedevice(urb->pipe); + ep->busnum = rp->r.m_bus->u_bus->busnum; + ep->id = (unsigned long) urb; + ep->status = error; + + ep->flag_setup = '-'; + ep->flag_data = 'E'; + + spin_unlock_irqrestore(&rp->b_lock, flags); + + wake_up(&rp->b_wait); +} + +static int mon_bin_open(struct inode *inode, struct file *file) +{ + struct mon_bus *mbus; + struct usb_bus *ubus; + struct mon_reader_bin *rp; + size_t size; + int rc; + + mutex_lock(&mon_lock); + if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) { + mutex_unlock(&mon_lock); + return -ENODEV; + } + if ((ubus = mbus->u_bus) == NULL) { + printk(KERN_ERR TAG ": consistency error on open\n"); + mutex_unlock(&mon_lock); + return -ENODEV; + } + + rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL); + if (rp == NULL) { + rc = -ENOMEM; + goto err_alloc; + } + spin_lock_init(&rp->b_lock); + init_waitqueue_head(&rp->b_wait); + mutex_init(&rp->fetch_lock); + + rp->b_size = BUFF_DFL; + + size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE); + if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) { + rc = -ENOMEM; + goto err_allocvec; + } + + if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0) + goto err_allocbuff; + + rp->r.m_bus = mbus; + rp->r.r_data = rp; + rp->r.rnf_submit = mon_bin_submit; + rp->r.rnf_error = mon_bin_error; + rp->r.rnf_complete = mon_bin_complete; + + mon_reader_add(mbus, &rp->r); + + file->private_data = rp; + mutex_unlock(&mon_lock); + return 0; + +err_allocbuff: + kfree(rp->b_vec); +err_allocvec: + kfree(rp); +err_alloc: + mutex_unlock(&mon_lock); + return rc; +} + +/* + * Extract an event from buffer and copy it to user space. + * Wait if there is no event ready. + * Returns zero or error. + */ +static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, + struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes) +{ + unsigned long flags; + struct mon_bin_hdr *ep; + size_t step_len; + unsigned int offset; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + ep = MON_OFF2HDR(rp, rp->b_out); + + if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + step_len = min(ep->len_cap, nbytes); + if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0; + + if (copy_from_buf(rp, offset, data, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + spin_lock_irqsave(&rp->b_lock, flags); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + + mutex_unlock(&rp->fetch_lock); + return 0; +} + +static int mon_bin_release(struct inode *inode, struct file *file) +{ + struct mon_reader_bin *rp = file->private_data; + struct mon_bus* mbus = rp->r.m_bus; + + mutex_lock(&mon_lock); + + if (mbus->nreaders <= 0) { + printk(KERN_ERR TAG ": consistency error on close\n"); + mutex_unlock(&mon_lock); + return 0; + } + mon_reader_del(mbus, &rp->r); + + mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); + kfree(rp->b_vec); + kfree(rp); + + mutex_unlock(&mon_lock); + return 0; +} + +static ssize_t mon_bin_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct mon_reader_bin *rp = file->private_data; + unsigned long flags; + struct mon_bin_hdr *ep; + unsigned int offset; + size_t step_len; + char *ptr; + ssize_t done = 0; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + ep = MON_OFF2HDR(rp, rp->b_out); + + if (rp->b_read < sizeof(struct mon_bin_hdr)) { + step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read); + ptr = ((char *)ep) + rp->b_read; + if (step_len && copy_to_user(buf, ptr, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + nbytes -= step_len; + buf += step_len; + rp->b_read += step_len; + done += step_len; + } + + if (rp->b_read >= sizeof(struct mon_bin_hdr)) { + step_len = min(nbytes, (size_t)ep->len_cap); + offset = rp->b_out + PKT_SIZE; + offset += rp->b_read - sizeof(struct mon_bin_hdr); + if (offset >= rp->b_size) + offset -= rp->b_size; + if (copy_from_buf(rp, offset, buf, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + nbytes -= step_len; + buf += step_len; + rp->b_read += step_len; + done += step_len; + } + + /* + * Check if whole packet was read, and if so, jump to the next one. + */ + if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) { + spin_lock_irqsave(&rp->b_lock, flags); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + } + + mutex_unlock(&rp->fetch_lock); + return done; +} + +/* + * Remove at most nevents from chunked buffer. + * Returns the number of removed events. + */ +static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents) +{ + unsigned long flags; + struct mon_bin_hdr *ep; + int i; + + mutex_lock(&rp->fetch_lock); + spin_lock_irqsave(&rp->b_lock, flags); + for (i = 0; i < nevents; ++i) { + if (MON_RING_EMPTY(rp)) + break; + + ep = MON_OFF2HDR(rp, rp->b_out); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + } + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + mutex_unlock(&rp->fetch_lock); + return i; +} + +/* + * Fetch at most max event offsets into the buffer and put them into vec. + * The events are usually freed later with mon_bin_flush. + * Return the effective number of events fetched. + */ +static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp, + u32 __user *vec, unsigned int max) +{ + unsigned int cur_out; + unsigned int bytes, avail; + unsigned int size; + unsigned int nevents; + struct mon_bin_hdr *ep; + unsigned long flags; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + spin_lock_irqsave(&rp->b_lock, flags); + avail = rp->b_cnt; + spin_unlock_irqrestore(&rp->b_lock, flags); + + cur_out = rp->b_out; + nevents = 0; + bytes = 0; + while (bytes < avail) { + if (nevents >= max) + break; + + ep = MON_OFF2HDR(rp, cur_out); + if (put_user(cur_out, &vec[nevents])) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + nevents++; + size = ep->len_cap + PKT_SIZE; + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if ((cur_out += size) >= rp->b_size) + cur_out -= rp->b_size; + bytes += size; + } + + mutex_unlock(&rp->fetch_lock); + return nevents; +} + +/* + * Count events. This is almost the same as the above mon_bin_fetch, + * only we do not store offsets into user vector, and we have no limit. + */ +static int mon_bin_queued(struct mon_reader_bin *rp) +{ + unsigned int cur_out; + unsigned int bytes, avail; + unsigned int size; + unsigned int nevents; + struct mon_bin_hdr *ep; + unsigned long flags; + + mutex_lock(&rp->fetch_lock); + + spin_lock_irqsave(&rp->b_lock, flags); + avail = rp->b_cnt; + spin_unlock_irqrestore(&rp->b_lock, flags); + + cur_out = rp->b_out; + nevents = 0; + bytes = 0; + while (bytes < avail) { + ep = MON_OFF2HDR(rp, cur_out); + + nevents++; + size = ep->len_cap + PKT_SIZE; + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if ((cur_out += size) >= rp->b_size) + cur_out -= rp->b_size; + bytes += size; + } + + mutex_unlock(&rp->fetch_lock); + return nevents; +} + +/* + */ +static int mon_bin_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mon_reader_bin *rp = file->private_data; + // struct mon_bus* mbus = rp->r.m_bus; + int ret = 0; + struct mon_bin_hdr *ep; + unsigned long flags; + + switch (cmd) { + + case MON_IOCQ_URB_LEN: + /* + * N.B. This only returns the size of data, without the header. + */ + spin_lock_irqsave(&rp->b_lock, flags); + if (!MON_RING_EMPTY(rp)) { + ep = MON_OFF2HDR(rp, rp->b_out); + ret = ep->len_cap; + } + spin_unlock_irqrestore(&rp->b_lock, flags); + break; + + case MON_IOCQ_RING_SIZE: + ret = rp->b_size; + break; + + case MON_IOCT_RING_SIZE: + /* + * Changing the buffer size will flush it's contents; the new + * buffer is allocated before releasing the old one to be sure + * the device will stay functional also in case of memory + * pressure. + */ + { + int size; + struct mon_pgmap *vec; + + if (arg < BUFF_MIN || arg > BUFF_MAX) + return -EINVAL; + + size = CHUNK_ALIGN(arg); + if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE), + GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + break; + } + + ret = mon_alloc_buff(vec, size/CHUNK_SIZE); + if (ret < 0) { + kfree(vec); + break; + } + + mutex_lock(&rp->fetch_lock); + spin_lock_irqsave(&rp->b_lock, flags); + mon_free_buff(rp->b_vec, size/CHUNK_SIZE); + kfree(rp->b_vec); + rp->b_vec = vec; + rp->b_size = size; + rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + mutex_unlock(&rp->fetch_lock); + } + break; + + case MON_IOCH_MFLUSH: + ret = mon_bin_flush(rp, arg); + break; + + case MON_IOCX_GET: + { + struct mon_bin_get getb; + + if (copy_from_user(&getb, (void __user *)arg, + sizeof(struct mon_bin_get))) + return -EFAULT; + + if (getb.alloc > 0x10000000) /* Want to cast to u32 */ + return -EINVAL; + ret = mon_bin_get_event(file, rp, + getb.hdr, getb.data, (unsigned int)getb.alloc); + } + break; + +#ifdef CONFIG_COMPAT + case MON_IOCX_GET32: { + struct mon_bin_get32 getb; + + if (copy_from_user(&getb, (void __user *)arg, + sizeof(struct mon_bin_get32))) + return -EFAULT; + + ret = mon_bin_get_event(file, rp, + compat_ptr(getb.hdr32), compat_ptr(getb.data32), + getb.alloc32); + } + break; +#endif + + case MON_IOCX_MFETCH: + { + struct mon_bin_mfetch mfetch; + struct mon_bin_mfetch __user *uptr; + + uptr = (struct mon_bin_mfetch __user *)arg; + + if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) + return -EFAULT; + + if (mfetch.nflush) { + ret = mon_bin_flush(rp, mfetch.nflush); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nflush)) + return -EFAULT; + } + ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nfetch)) + return -EFAULT; + ret = 0; + } + break; + +#ifdef CONFIG_COMPAT + case MON_IOCX_MFETCH32: + { + struct mon_bin_mfetch32 mfetch; + struct mon_bin_mfetch32 __user *uptr; + + uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg); + + if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) + return -EFAULT; + + if (mfetch.nflush32) { + ret = mon_bin_flush(rp, mfetch.nflush32); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nflush32)) + return -EFAULT; + } + ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32), + mfetch.nfetch32); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nfetch32)) + return -EFAULT; + ret = 0; + } + break; +#endif + + case MON_IOCG_STATS: { + struct mon_bin_stats __user *sp; + unsigned int nevents; + unsigned int ndropped; + + spin_lock_irqsave(&rp->b_lock, flags); + ndropped = rp->cnt_lost; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + nevents = mon_bin_queued(rp); + + sp = (struct mon_bin_stats __user *)arg; + if (put_user(rp->cnt_lost, &sp->dropped)) + return -EFAULT; + if (put_user(nevents, &sp->queued)) + return -EFAULT; + + } + break; + + default: + return -ENOTTY; + } + + return ret; +} + +static unsigned int +mon_bin_poll(struct file *file, struct poll_table_struct *wait) +{ + struct mon_reader_bin *rp = file->private_data; + unsigned int mask = 0; + unsigned long flags; + + if (file->f_mode & FMODE_READ) + poll_wait(file, &rp->b_wait, wait); + + spin_lock_irqsave(&rp->b_lock, flags); + if (!MON_RING_EMPTY(rp)) + mask |= POLLIN | POLLRDNORM; /* readable */ + spin_unlock_irqrestore(&rp->b_lock, flags); + return mask; +} + +/* + * open and close: just keep track of how many times the device is + * mapped, to use the proper memory allocation function. + */ +static void mon_bin_vma_open(struct vm_area_struct *vma) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + rp->mmap_active++; +} + +static void mon_bin_vma_close(struct vm_area_struct *vma) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + rp->mmap_active--; +} + +/* + * Map ring pages to user space. + */ +struct page *mon_bin_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + unsigned long offset, chunk_idx; + struct page *pageptr; + + offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + if (offset >= rp->b_size) + return NOPAGE_SIGBUS; + chunk_idx = offset / CHUNK_SIZE; + pageptr = rp->b_vec[chunk_idx].pg; + get_page(pageptr); + if (type) + *type = VM_FAULT_MINOR; + return pageptr; +} + +struct vm_operations_struct mon_bin_vm_ops = { + .open = mon_bin_vma_open, + .close = mon_bin_vma_close, + .nopage = mon_bin_vma_nopage, +}; + +int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) +{ + /* don't do anything here: "nopage" will set up page table entries */ + vma->vm_ops = &mon_bin_vm_ops; + vma->vm_flags |= VM_RESERVED; + vma->vm_private_data = filp->private_data; + mon_bin_vma_open(vma); + return 0; +} + +struct file_operations mon_fops_binary = { + .owner = THIS_MODULE, + .open = mon_bin_open, + .llseek = no_llseek, + .read = mon_bin_read, + /* .write = mon_text_write, */ + .poll = mon_bin_poll, + .ioctl = mon_bin_ioctl, + .release = mon_bin_release, +}; + +static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp) +{ + DECLARE_WAITQUEUE(waita, current); + unsigned long flags; + + add_wait_queue(&rp->b_wait, &waita); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&rp->b_lock, flags); + while (MON_RING_EMPTY(rp)) { + spin_unlock_irqrestore(&rp->b_lock, flags); + + if (file->f_flags & O_NONBLOCK) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&rp->b_wait, &waita); + return -EWOULDBLOCK; /* Same as EAGAIN in Linux */ + } + schedule(); + if (signal_pending(current)) { + remove_wait_queue(&rp->b_wait, &waita); + return -EINTR; + } + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&rp->b_lock, flags); + } + spin_unlock_irqrestore(&rp->b_lock, flags); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&rp->b_wait, &waita); + return 0; +} + +static int mon_alloc_buff(struct mon_pgmap *map, int npages) +{ + int n; + unsigned long vaddr; + + for (n = 0; n < npages; n++) { + vaddr = get_zeroed_page(GFP_KERNEL); + if (vaddr == 0) { + while (n-- != 0) + free_page((unsigned long) map[n].ptr); + return -ENOMEM; + } + map[n].ptr = (unsigned char *) vaddr; + map[n].pg = virt_to_page(vaddr); + } + return 0; +} + +static void mon_free_buff(struct mon_pgmap *map, int npages) +{ + int n; + + for (n = 0; n < npages; n++) + free_page((unsigned long) map[n].ptr); +} + +int __init mon_bin_init(void) +{ + int rc; + + rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon"); + if (rc < 0) + goto err_dev; + + cdev_init(&mon_bin_cdev, &mon_fops_binary); + mon_bin_cdev.owner = THIS_MODULE; + + rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR); + if (rc < 0) + goto err_add; + + return 0; + +err_add: + unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); +err_dev: + return rc; +} + +void __exit mon_bin_exit(void) +{ + cdev_del(&mon_bin_cdev); + unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); +} diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c index ddcfc01e77a..140cc80bd2b 100644 --- a/drivers/usb/mon/mon_dma.c +++ b/drivers/usb/mon/mon_dma.c @@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) local_irq_restore(flags); return 0; } + +void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int length) +{ + unsigned long flags; + unsigned int step_len; + struct page *pg; + unsigned char *map; + unsigned long page_off, page_len; + + local_irq_save(flags); + while (length) { + /* compute number of bytes we are going to copy in this page */ + step_len = length; + page_off = dma_addr & (PAGE_SIZE-1); + page_len = PAGE_SIZE - page_off; + if (page_len < step_len) + step_len = page_len; + + /* copy data and advance pointers */ + pg = phys_to_page(dma_addr); + map = kmap_atomic(pg, KM_IRQ0); + offset = mon_copy_to_buff(rp, offset, map + page_off, step_len); + kunmap_atomic(map, KM_IRQ0); + dma_addr += step_len; + length -= step_len; + } + local_irq_restore(flags); +} + #endif /* __i386__ */ #ifndef MON_HAS_UNMAP @@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) { return 'D'; } -#endif + +void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int length) +{ + ; +} + +#endif /* MON_HAS_UNMAP */ diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 394bbf2f68d..c9739e7b35e 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb); static void mon_stop(struct mon_bus *mbus); static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); static void mon_bus_drop(struct kref *r); -static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus); +static void mon_bus_init(struct usb_bus *ubus); DEFINE_MUTEX(mon_lock); -static struct dentry *mon_dir; /* /dbg/usbmon */ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ /* @@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus) */ static void mon_bus_add(struct usb_bus *ubus) { - mon_bus_init(mon_dir, ubus); + mon_bus_init(ubus); } /* @@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus) mutex_lock(&mon_lock); list_del(&mbus->bus_link); - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); + if (mbus->text_inited) + mon_text_del(mbus); mon_dissolve(mbus, ubus); kref_put(&mbus->ref, mon_bus_drop); @@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r) * - refcount USB bus struct * - link */ -static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) +static void mon_bus_init(struct usb_bus *ubus) { - struct dentry *d; struct mon_bus *mbus; - enum { NAMESZ = 10 }; - char name[NAMESZ]; - int rc; if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) goto err_alloc; @@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) ubus->mon_bus = mbus; mbus->uses_dma = ubus->uses_dma; - rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_t; - d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text); - if (d == NULL) - goto err_create_t; - mbus->dent_t = d; - - rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_s; - d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat); - if (d == NULL) - goto err_create_s; - mbus->dent_s = d; + mbus->text_inited = mon_text_add(mbus, ubus); + // mon_bin_add(...) mutex_lock(&mon_lock); list_add_tail(&mbus->bus_link, &mon_buses); mutex_unlock(&mon_lock); return; -err_create_s: -err_print_s: - debugfs_remove(mbus->dent_t); -err_create_t: -err_print_t: - kfree(mbus); err_alloc: return; } +/* + * Search a USB bus by number. Notice that USB bus numbers start from one, + * which we may later use to identify "all" with zero. + * + * This function must be called with mon_lock held. + * + * This is obviously inefficient and may be revised in the future. + */ +struct mon_bus *mon_bus_lookup(unsigned int num) +{ + struct list_head *p; + struct mon_bus *mbus; + + list_for_each (p, &mon_buses) { + mbus = list_entry(p, struct mon_bus, bus_link); + if (mbus->u_bus->busnum == num) { + return mbus; + } + } + return NULL; +} + static int __init mon_init(void) { struct usb_bus *ubus; - struct dentry *mondir; + int rc; - mondir = debugfs_create_dir("usbmon", NULL); - if (IS_ERR(mondir)) { - printk(KERN_NOTICE TAG ": debugfs is not available\n"); - return -ENODEV; - } - if (mondir == NULL) { - printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); - return -ENODEV; - } - mon_dir = mondir; + if ((rc = mon_text_init()) != 0) + goto err_text; + if ((rc = mon_bin_init()) != 0) + goto err_bin; if (usb_mon_register(&mon_ops_0) != 0) { printk(KERN_NOTICE TAG ": unable to register with the core\n"); - debugfs_remove(mondir); - return -ENODEV; + rc = -ENODEV; + goto err_reg; } // MOD_INC_USE_COUNT(which_module?); @@ -361,10 +352,17 @@ static int __init mon_init(void) mutex_lock(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { - mon_bus_init(mondir, ubus); + mon_bus_init(ubus); } mutex_unlock(&usb_bus_list_lock); return 0; + +err_reg: + mon_bin_exit(); +err_bin: + mon_text_exit(); +err_text: + return rc; } static void __exit mon_exit(void) @@ -381,8 +379,8 @@ static void __exit mon_exit(void) mbus = list_entry(p, struct mon_bus, bus_link); list_del(p); - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); + if (mbus->text_inited) + mon_text_del(mbus); /* * This never happens, because the open/close paths in @@ -401,7 +399,8 @@ static void __exit mon_exit(void) } mutex_unlock(&mon_lock); - debugfs_remove(mon_dir); + mon_text_exit(); + mon_bin_exit(); } module_init(mon_init); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 05cf2c9a8f8..d38a1279d9d 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "usb_mon.h" @@ -63,6 +64,8 @@ struct mon_reader_text { char slab_name[SLAB_NAME_SZ]; }; +static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ + static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); /* @@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file) return 0; } -const struct file_operations mon_fops_text = { +static const struct file_operations mon_fops_text = { .owner = THIS_MODULE, .open = mon_text_open, .llseek = no_llseek, @@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = { .release = mon_text_release, }; +int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) +{ + struct dentry *d; + enum { NAMESZ = 10 }; + char name[NAMESZ]; + int rc; + + rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); + if (rc <= 0 || rc >= NAMESZ) + goto err_print_t; + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text); + if (d == NULL) + goto err_create_t; + mbus->dent_t = d; + + /* XXX The stats do not belong to here (text API), but oh well... */ + rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); + if (rc <= 0 || rc >= NAMESZ) + goto err_print_s; + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); + if (d == NULL) + goto err_create_s; + mbus->dent_s = d; + + return 1; + +err_create_s: +err_print_s: + debugfs_remove(mbus->dent_t); + mbus->dent_t = NULL; +err_create_t: +err_print_t: + return 0; +} + +void mon_text_del(struct mon_bus *mbus) +{ + debugfs_remove(mbus->dent_t); + debugfs_remove(mbus->dent_s); +} + /* * Slab interface: constructor. */ @@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla memset(mem, 0xe5, sizeof(struct mon_event_text)); } +int __init mon_text_init(void) +{ + struct dentry *mondir; + + mondir = debugfs_create_dir("usbmon", NULL); + if (IS_ERR(mondir)) { + printk(KERN_NOTICE TAG ": debugfs is not available\n"); + return -ENODEV; + } + if (mondir == NULL) { + printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); + return -ENODEV; + } + mon_dir = mondir; + return 0; +} + +void __exit mon_text_exit(void) +{ + debugfs_remove(mon_dir); +} diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index ab9d02d5df7..4f949ce8a7f 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -17,9 +17,11 @@ struct mon_bus { struct list_head bus_link; spinlock_t lock; + struct usb_bus *u_bus; + + int text_inited; struct dentry *dent_s; /* Debugging file */ struct dentry *dent_t; /* Text interface file */ - struct usb_bus *u_bus; int uses_dma; /* Ref */ @@ -48,13 +50,35 @@ struct mon_reader { void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r); +struct mon_bus *mon_bus_lookup(unsigned int num); + +int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus); +void mon_text_del(struct mon_bus *mbus); +// void mon_bin_add(struct mon_bus *); + +int __init mon_text_init(void); +void __exit mon_text_exit(void); +int __init mon_bin_init(void); +void __exit mon_bin_exit(void); + /* - */ + * DMA interface. + * + * XXX The vectored side needs a serious re-thinking. Abstracting vectors, + * like in Paolo's original patch, produces a double pkmap. We need an idea. +*/ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); +struct mon_reader_bin; +extern void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int len); +extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp, + unsigned int offset, const unsigned char *from, unsigned int len); + +/* + */ extern struct mutex mon_lock; -extern const struct file_operations mon_fops_text; extern const struct file_operations mon_fops_stat; #endif /* __USB_MON_H */ -- cgit v1.2.3 From f38649fee955c19f4df9b9e7267f87702712d973 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 5 Jan 2007 17:42:35 +0100 Subject: USB: race on disconnect in mdc800 I overlooked one. Setting the flag and killing the URBs must be under the lock so that no URB is submitted after usb_kill_urb() Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/image/mdc800.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 63a84bbc310..d308afd0693 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf) usb_deregister_dev(intf, &mdc800_class); + /* must be under lock to make sure no URB + is submitted after usb_kill_urb() */ + mutex_lock(&mdc800->io_lock); mdc800->state=NOT_CONNECTED; usb_kill_urb(mdc800->irq_urb); usb_kill_urb(mdc800->write_urb); usb_kill_urb(mdc800->download_urb); + mutex_unlock(&mdc800->io_lock); mdc800->dev = NULL; usb_set_intfdata(intf, NULL); -- cgit v1.2.3 From f3fe239b67424d88104e32076aec902c0642925f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 8 Jan 2007 12:00:28 -0500 Subject: UHCI: improved debugging checks for the frame list This patch (as768) improves the debugging checks for the uhci-hcd frame list. The number of entries displayed is limited to 10, and the driver now checks for the correct Skeleton QH link value at the end of each chain of Isochronous TDs. The code to compute these link values is now used in two spots, so it is moved into its own separate subroutine. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 48 +++++++++++++++++++++++++++++++++++----- drivers/usb/host/uhci-hcd.c | 51 ++++++++++++++++++++++++------------------- 2 files changed, 72 insertions(+), 27 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index e345f15b7d8..b40bc1ac9b8 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -347,6 +347,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) struct uhci_qh *qh; struct uhci_td *td; struct list_head *tmp, *head; + int nframes, nerrs; out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); @@ -355,23 +356,60 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) return out - buf; out += sprintf(out, "Frame List\n"); + nframes = 10; + nerrs = 0; for (i = 0; i < UHCI_NUMFRAMES; ++i) { + __le32 link, qh_dma; + + j = 0; td = uhci->frame_cpu[i]; + link = uhci->frame[i]; if (!td) - continue; + goto check_link; - out += sprintf(out, "- Frame %d\n", i); \ - if (td->dma_handle != (dma_addr_t)uhci->frame[i]) - out += sprintf(out, " frame list does not match td->dma_handle!\n"); + if (nframes > 0) { + out += sprintf(out, "- Frame %d -> (%08x)\n", + i, le32_to_cpu(link)); + j = 1; + } head = &td->fl_list; tmp = head; do { td = list_entry(tmp, struct uhci_td, fl_list); tmp = tmp->next; - out += uhci_show_td(td, out, len - (out - buf), 4); + if (cpu_to_le32(td->dma_handle) != link) { + if (nframes > 0) + out += sprintf(out, " link does " + "not match list entry!\n"); + else + ++nerrs; + } + if (nframes > 0) + out += uhci_show_td(td, out, + len - (out - buf), 4); + link = td->link; } while (tmp != head); + +check_link: + qh_dma = uhci_frame_skel_link(uhci, i); + if (link != qh_dma) { + if (nframes > 0) { + if (!j) { + out += sprintf(out, + "- Frame %d -> (%08x)\n", + i, le32_to_cpu(link)); + j = 1; + } + out += sprintf(out, " link does not match " + "QH (%08x)!\n", le32_to_cpu(qh_dma)); + } else + ++nerrs; + } + nframes -= j; } + if (nerrs > 0) + out += sprintf(out, "Skipped %d bad links\n", nerrs); out += sprintf(out, "Skeleton QHs\n"); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e0d4c2358b3..49b9d390b95 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); static void wakeup_rh(struct uhci_hcd *uhci); static void uhci_get_current_frame_number(struct uhci_hcd *uhci); +/* + * Calculate the link pointer DMA value for the first Skeleton QH in a frame. + */ +static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) +{ + int skelnum; + + /* + * The interrupt queues will be interleaved as evenly as possible. + * There's not much to be done about period-1 interrupts; they have + * to occur in every frame. But we can schedule period-2 interrupts + * in odd-numbered frames, period-4 interrupts in frames congruent + * to 2 (mod 4), and so on. This way each frame only has two + * interrupt QHs, which will help spread out bandwidth utilization. + * + * ffs (Find First bit Set) does exactly what we need: + * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], + * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. + * ffs >= 7 => not on any high-period queue, so use + * skel_int1_qh = skelqh[9]. + * Add in UHCI_NUMFRAMES to insure at least one bit is set. + */ + skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); + if (skelnum <= 1) + skelnum = 9; + return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle); +} + #include "uhci-debug.c" #include "uhci-q.c" #include "uhci-hub.c" @@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd) /* * Fill the frame list: make all entries point to the proper * interrupt queue. - * - * The interrupt queues will be interleaved as evenly as possible. - * There's not much to be done about period-1 interrupts; they have - * to occur in every frame. But we can schedule period-2 interrupts - * in odd-numbered frames, period-4 interrupts in frames congruent - * to 2 (mod 4), and so on. This way each frame only has two - * interrupt QHs, which will help spread out bandwidth utilization. */ for (i = 0; i < UHCI_NUMFRAMES; i++) { - int irq; - - /* - * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], - * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. - * ffs >= 7 => not on any high-period queue, so use - * skel_int1_qh = skelqh[9]. - * Add UHCI_NUMFRAMES to insure at least one bit is set. - */ - irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES); - if (irq <= 1) - irq = 9; /* Only place we don't use the frame list routines */ - uhci->frame[i] = UHCI_PTR_QH | - cpu_to_le32(uhci->skelqh[irq]->dma_handle); + uhci->frame[i] = uhci_frame_skel_link(uhci, i); } /* -- cgit v1.2.3 From 85a975d0ce48dfa8dec5bf1bd970f8fd2c48af32 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 8 Jan 2007 12:01:43 -0500 Subject: UHCI: no dummy TDs for Iso QHs Isochronous queues don't need a dummy TD because the Queue Header isn't managed by the hardware. This patch (as836) removes the unnecessary dummy TDs. The patch also fixes a long-standing typo in a comment (a "don't" was missing -- potentially very confusing!). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 2 +- drivers/usb/host/uhci-q.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index b40bc1ac9b8..3fbb5ba8024 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -208,7 +208,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) space, "", nurbs); } - if (qh->udev) { + if (qh->dummy_td) { out += sprintf(out, "%*s Dummy TD\n", space, ""); out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0); } diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 30b88459ac7..5afcc522728 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -248,16 +248,18 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, INIT_LIST_HEAD(&qh->node); if (udev) { /* Normal QH */ - qh->dummy_td = uhci_alloc_td(uhci); - if (!qh->dummy_td) { - dma_pool_free(uhci->qh_pool, qh, dma_handle); - return NULL; + qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (qh->type != USB_ENDPOINT_XFER_ISOC) { + qh->dummy_td = uhci_alloc_td(uhci); + if (!qh->dummy_td) { + dma_pool_free(uhci->qh_pool, qh, dma_handle); + return NULL; + } } qh->state = QH_STATE_IDLE; qh->hep = hep; qh->udev = udev; hep->hcpriv = qh; - qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; } else { /* Skeleton QH */ qh->state = QH_STATE_ACTIVE; @@ -275,7 +277,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) list_del(&qh->node); if (qh->udev) { qh->hep->hcpriv = NULL; - uhci_free_td(uhci, qh->dummy_td); + if (qh->dummy_td) + uhci_free_td(uhci, qh->dummy_td); } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } @@ -327,7 +330,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, goto done; qh->element = UHCI_PTR_TERM; - /* Control pipes have to worry about toggles */ + /* Control pipes don't have to worry about toggles */ if (qh->type == USB_ENDPOINT_XFER_CONTROL) goto done; -- cgit v1.2.3 From f3f4906516a084bbd9aa3da7592e6b029fe78f5b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 8 Jan 2007 16:18:05 -0500 Subject: usb-storage: SCSI level fixes This patch (as835) removes from usb-storage the code which sets all devices to a SCSI level of at least SCSI-2. The original reasons for doing this no longer apply, and in fact it prevents certain kinds of ATA pass-thru commands from being used. The patch also marks CB and CBI devices that are SCSI-0 (legacy SCSI) as being single-LUN, since the combined SCSI-over-USB transport protocol has no way to convey LUN information to these devices. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/scsiglue.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e1072d52d64..70234f5dbee 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev) * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Set the SCSI level to at least 2. We'll leave it at 3 if that's - * what is originally reported. We need this to avoid confusing - * the SCSI layer with devices that report 0 or 1, but need 10-byte - * commands (ala ATAPI devices behind certain bridges, or devices - * which simply have broken INQUIRY data). - * - * NOTE: This means /dev/sg programs (ala cdrecord) will get the - * actual information. This seems to be the preference for - * programs like that. - * - * NOTE: This also means that /proc/scsi/scsi and sysfs may report - * the actual value or the modified one, depending on where the - * data comes from. - */ - if (sdev->scsi_level < SCSI_2) - sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; - /* Many devices have trouble transfering more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). @@ -176,7 +159,9 @@ static int slave_configure(struct scsi_device *sdev) * a Get-Max-LUN request, we won't lose much by setting the * revision level down to 2. The only devices that would be * affected are those with sparse LUNs. */ - sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; + if (sdev->scsi_level > SCSI_2) + sdev->sdev_target->scsi_level = + sdev->scsi_level = SCSI_2; /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable * Hardware Error) when any low-level error occurs, @@ -194,6 +179,16 @@ static int slave_configure(struct scsi_device *sdev) sdev->use_10_for_ms = 1; } + /* The CB and CBI transports have no way to pass LUN values + * other than the bits in the second byte of a CDB. But those + * bits don't get set to the LUN value if the device reports + * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily + * be single-LUN. + */ + if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) && + sdev->scsi_level == SCSI_UNKNOWN) + us->max_lun = 0; + /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM * REMOVAL command, so suppress those commands. */ if (us->flags & US_FL_NOT_LOCKABLE) -- cgit v1.2.3 From 6dde896e4eac122f388263f0097b691acdc0396f Mon Sep 17 00:00:00 2001 From: Marc Pignat Date: Tue, 9 Jan 2007 14:00:11 -0800 Subject: USB: ohci-at91 refcount fix for irq wake enables The attached patch fixes the unbalanced calls to enable_irq_wake() and disable_irq_wake() in the AT91 USB Host driver. It should resolve these kernel messages: Unbalanced IRQ x wake disable BUG: warning at kernel/irq/manage.c:167/set_irq_wake() (The original code was debugged before a bug in the genirq wakeup irq logic was fixed by adding the IRQ wake enable/disable refcounting. Not all code yet uses the bugfixed model.) Signed-off-by: Andrew Victor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 53f62cf7698..93034648727 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd, at91_stop_hc(pdev); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - disable_irq_wake(hcd->irq); clk_put(fclk); clk_put(iclk); @@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) if (device_may_wakeup(&pdev->dev)) enable_irq_wake(hcd->irq); - else - disable_irq_wake(hcd->irq); /* * The integrated transceivers seem unable to notice disconnect, @@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) { + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(hcd->irq); + if (!clocked) { clk_enable(iclk); clk_enable(fclk); -- cgit v1.2.3 From 2505107def8b300576223367e3b603620d825e52 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 15 Jan 2007 11:30:28 -0800 Subject: usb: gadgetfs whitespace cleanup Remove some whitespace bugs in gadgetfs (mostly from someone's patch updating the AIO support). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3fb1044a4db..10a5f7a164d 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,7 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ +// #define DEBUG /* data to help fault diagnosis */ // #define VERBOSE /* extra debug messages (success too) */ #include @@ -565,29 +565,29 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) ssize_t len, total; int i; - /* we "retry" to get the right mm context for this: */ - - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - - if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { - if (len == 0) - len = -EFAULT; - break; - } - - total -= this; - len += this; - if (total == 0) - break; - } - kfree(priv->buf); - kfree(priv); - aio_put_req(iocb); - return len; + /* we "retry" to get the right mm context for this: */ + + /* copy stuff into user buffers */ + total = priv->actual; + len = 0; + for (i=0; i < priv->nr_segs; i++) { + ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); + + if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (len == 0) + len = -EFAULT; + break; + } + + total -= this; + len += this; + if (total == 0) + break; + } + kfree(priv->buf); + kfree(priv); + aio_put_req(iocb); + return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -636,7 +636,7 @@ ep_aio_rwtail( size_t len, struct ep_data *epdata, const struct iovec *iv, - unsigned long nr_segs + unsigned long nr_segs ) { struct kiocb_priv *priv; @@ -1808,7 +1808,7 @@ static struct usb_gadget_driver gadgetfs_driver = { .disconnect = gadgetfs_disconnect, .suspend = gadgetfs_suspend, - .driver = { + .driver = { .name = (char *) shortname, }, }; @@ -1829,7 +1829,7 @@ static struct usb_gadget_driver probe_driver = { .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, - .driver = { + .driver = { .name = "nop", }, }; @@ -1849,7 +1849,7 @@ static struct usb_gadget_driver probe_driver = { * . full/low speed config ... all wTotalLength bytes (with interface, * class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; - * this one's optional except for high-speed hardware + * this one's optional except for high-speed hardware * . device descriptor * * Endpoints are not yet enabled. Drivers may want to immediately -- cgit v1.2.3 From 511779fd9eb7ed67116e4a1cad802363d2d58b20 Mon Sep 17 00:00:00 2001 From: Phil Endecott Date: Mon, 15 Jan 2007 11:35:01 -0800 Subject: usb: gadgetfs remove delayed init mode Gadgetfs had a mode in which endpoint descriptors were written by the user program before connection. This mode had some bugs, and hasn't seen much (if any) use. This patch removes that mode, leaving the mode of operation where the user program waits for endpoint 0 to report a SET_CONFIGURATION, and only then configures the endpoints. From: "Phil Endecott" Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 60 ++++++++++------------------------------------ 1 file changed, 12 insertions(+), 48 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 10a5f7a164d..0f00249720b 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -59,11 +59,11 @@ * may serve as a source of device events, used to handle all control * requests other than basic enumeration. * - * - Then either immediately, or after a SET_CONFIGURATION control request, - * ep_config() is called when each /dev/gadget/ep* file is configured - * (by writing endpoint descriptors). Afterwards these files are used - * to write() IN data or to read() OUT data. To halt the endpoint, a - * "wrong direction" request is issued (like reading an IN endpoint). + * - Then, after a SET_CONFIGURATION control request, ep_config() is + * called when each /dev/gadget/ep* file is configured (by writing + * endpoint descriptors). Afterwards these files are used to write() + * IN data or to read() OUT data. To halt the endpoint, a "wrong + * direction" request is issued (like reading an IN endpoint). * * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe * not possible on all hardware. For example, precise fault handling with @@ -188,7 +188,6 @@ static struct dev_data *dev_new (void) enum ep_state { STATE_EP_DISABLED = 0, STATE_EP_READY, - STATE_EP_DEFER_ENABLE, STATE_EP_ENABLED, STATE_EP_UNBOUND, }; @@ -313,18 +312,10 @@ nonblock: if ((val = down_interruptible (&epdata->lock)) < 0) return val; -newstate: + switch (epdata->state) { case STATE_EP_ENABLED: break; - case STATE_EP_DEFER_ENABLE: - DBG (epdata->dev, "%s wait for host\n", epdata->name); - if ((val = wait_event_interruptible (epdata->wait, - epdata->state != STATE_EP_DEFER_ENABLE - || epdata->dev->state == STATE_DEV_UNBOUND - )) < 0) - goto fail; - goto newstate; // case STATE_EP_DISABLED: /* "can't happen" */ // case STATE_EP_READY: /* "can't happen" */ default: /* error! */ @@ -333,7 +324,6 @@ newstate: // FALLTHROUGH case STATE_EP_UNBOUND: /* clean disconnect */ val = -ENODEV; -fail: up (&epdata->lock); } return val; @@ -852,9 +842,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) break; #endif default: - DBG (data->dev, "unconnected, %s init deferred\n", + DBG(data->dev, "unconnected, %s init abandoned\n", data->name); - data->state = STATE_EP_DEFER_ENABLE; + value = -EINVAL; } if (value == 0) { fd->f_op = &ep_io_operations; @@ -1393,8 +1383,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_UNCONNECTED) { - struct usb_ep *ep; - struct ep_data *data; dev->state = STATE_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1411,27 +1399,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) event->u.speed = gadget->speed; ep0_readable (dev); - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - data = ep->driver_data; - /* ... down_trylock (&data->lock) ... */ - if (data->state != STATE_EP_DEFER_ENABLE) - continue; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) - value = usb_ep_enable (ep, &data->hs_desc); - else -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - value = usb_ep_enable (ep, &data->desc); - if (value) { - ERROR (dev, "deferred %s enable --> %d\n", - data->name, value); - continue; - } - data->state = STATE_EP_ENABLED; - wake_up (&data->wait); - DBG (dev, "woke up %s waiters\n", data->name); - } - /* host may have given up waiting for response. we can miss control * requests handled lower down (device/endpoint status and features); * then ep0_{read,write} will report the wrong status. controller @@ -1852,16 +1819,13 @@ static struct usb_gadget_driver probe_driver = { * this one's optional except for high-speed hardware * . device descriptor * - * Endpoints are not yet enabled. Drivers may want to immediately - * initialize them, using the /dev/gadget/ep* files that are available - * as soon as the kernel sees the configuration, or they can wait - * until device configuration and interface altsetting changes create + * Endpoints are not yet enabled. Drivers must wait until device + * configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that - * $CHIP file is open. Events may then be read from that descriptor, - * such as configuration notifications. More complex drivers will handle - * some control requests in user space. + * $CHIP file is open. Events must then be read from that descriptor, + * such as configuration notifications. */ static int is_valid_config (struct usb_config_descriptor *config) -- cgit v1.2.3 From b98b98f97c519894c64bf1bee6b7957e687dfc41 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 16 Jan 2007 09:47:12 +0100 Subject: USB: power management for kaweth - implements suspend when the network interface is down - fixes a typo in comments - adds debugging output for power management - fixes a compiler warning Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/kaweth.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index fa78326d0bf..f29eed30e4f 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = { .suspend = kaweth_suspend, .resume = kaweth_resume, .id_table = usb_klsi_table, + .supports_autosuspend = 1, }; typedef __u8 eth_addr_t[6]; @@ -225,6 +226,7 @@ struct kaweth_device struct delayed_work lowmem_work; struct usb_device *dev; + struct usb_interface *intf; struct net_device *net; wait_queue_head_t term_wait; @@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net) dbg("Opening network device."); + res = usb_autopm_get_interface(kaweth->intf); + if (res) { + err("Interface cannot be resumed."); + return -EIO; + } res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) - return -EIO; + goto err_out; usb_fill_int_urb( kaweth->irq_urb, @@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net) res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); if (res) { usb_kill_urb(kaweth->rx_urb); - return -EIO; + goto err_out; } kaweth->opened = 1; @@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net) kaweth_async_set_rx_mode(kaweth); return 0; + +err_out: + usb_autopm_enable(kaweth->intf); + return -EIO; } /**************************************************************** - * kaweth_close + * kaweth_kill_urbs ****************************************************************/ static void kaweth_kill_urbs(struct kaweth_device *kaweth) { @@ -724,6 +735,8 @@ static int kaweth_close(struct net_device *net) kaweth->status &= ~KAWETH_STATUS_CLOSING; + usb_autopm_enable(kaweth->intf); + return 0; } @@ -908,6 +921,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) struct kaweth_device *kaweth = usb_get_intfdata(intf); unsigned long flags; + dbg("Suspending device"); spin_lock_irqsave(&kaweth->device_lock, flags); kaweth->status |= KAWETH_STATUS_SUSPENDING; spin_unlock_irqrestore(&kaweth->device_lock, flags); @@ -924,6 +938,7 @@ static int kaweth_resume(struct usb_interface *intf) struct kaweth_device *kaweth = usb_get_intfdata(intf); unsigned long flags; + dbg("Resuming device"); spin_lock_irqsave(&kaweth->device_lock, flags); kaweth->status &= ~KAWETH_STATUS_SUSPENDING; spin_unlock_irqrestore(&kaweth->device_lock, flags); @@ -1086,6 +1101,8 @@ err_fw: dbg("Initializing net device."); + kaweth->intf = intf; + kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kaweth->tx_urb) goto err_free_netdev; @@ -1265,7 +1282,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, { struct urb *urb; int retv; - int length; + int length = 0; /* shut up GCC */ urb = usb_alloc_urb(0, GFP_NOIO); if (!urb) -- cgit v1.2.3 From b3ebd5222141efa489d95592b7d4536766530e56 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 16 Jan 2007 12:01:26 +0100 Subject: USB: better ethtool support for kaweth this implements enough ethtool support to make NetworkManager happy. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/kaweth.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index f29eed30e4f..36a989160a6 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -742,12 +742,22 @@ static int kaweth_close(struct net_device *net) static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + struct kaweth_device *kaweth = netdev_priv(dev); strlcpy(info->driver, driver_name, sizeof(info->driver)); + usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); +} + +static u32 kaweth_get_link(struct net_device *dev) +{ + struct kaweth_device *kaweth = netdev_priv(dev); + + return kaweth->linkstate; } static struct ethtool_ops ops = { - .get_drvinfo = kaweth_get_drvinfo + .get_drvinfo = kaweth_get_drvinfo, + .get_link = kaweth_get_link }; /**************************************************************** -- cgit v1.2.3 From ad75a41085d80c8ce5e885962c15779935f8267e Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Mon, 15 Jan 2007 20:11:47 -0800 Subject: USB: ps3 ehci bus glue USB EHCI driver bus glue for the PS3 game console. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 25 +++++- drivers/usb/host/ehci-ps3.c | 193 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/ehci-ps3.c (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 03d567e4d00..9ec896218fe 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -907,7 +907,13 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver #endif -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) +#ifdef CONFIG_PPC_PS3 +#include "ehci-ps3.c" +#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver +#endif + +#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -932,6 +938,20 @@ static int __init ehci_hcd_init(void) #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif + return retval; + } +#endif + +#ifdef PS3_SYSTEM_BUS_DRIVER + retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) { +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +#ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); +#endif + return retval; } #endif @@ -947,6 +967,9 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +#endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c new file mode 100644 index 00000000000..371f194a9d3 --- /dev/null +++ b/drivers/usb/host/ehci-ps3.c @@ -0,0 +1,193 @@ +/* + * PS3 EHCI Host Controller driver + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static int ps3_ehci_hc_reset(struct usb_hcd *hcd) +{ + int result; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + ehci->big_endian_mmio = 1; + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, + &ehci->caps->hc_capbase)); + + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + result = ehci_halt(ehci); + + if (result) + return result; + + result = ehci_init(hcd); + + if (result) + return result; + + ehci_port_power(ehci, 0); + + return result; +} + +static const struct hc_driver ps3_ehci_hc_driver = { + .description = hcd_name, + .product_desc = "PS3 EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = ps3_ehci_hc_reset, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .get_frame_number = ehci_get_frame, + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#if defined(CONFIG_PM) + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + + +static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) +{ + int result; + struct usb_hcd *hcd; + unsigned int virq; + static u64 dummy_mask = DMA_32BIT_MASK; + + if (usb_disabled()) { + result = -ENODEV; + goto fail_start; + } + + result = ps3_mmio_region_create(dev->m_region); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", + __func__, __LINE__); + result = -EPERM; + goto fail_mmio; + } + + dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, + __LINE__, dev->m_region->lpar_addr); + + result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", + __func__, __LINE__, virq); + result = -EPERM; + goto fail_irq; + } + + dev->core.power.power_state = PMSG_ON; + dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + + hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id); + + if (!hcd) { + dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, + __LINE__); + result = -ENOMEM; + goto fail_create_hcd; + } + + hcd->rsrc_start = dev->m_region->lpar_addr; + hcd->rsrc_len = dev->m_region->len; + hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); + + if (!hcd->regs) { + dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + result = -EPERM; + goto fail_ioremap; + } + + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_start); + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_len); + dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, + (unsigned long)hcd->regs); + dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, + (unsigned long)virq); + + ps3_system_bus_set_driver_data(dev, hcd); + + result = usb_add_hcd(hcd, virq, IRQF_DISABLED); + + if (result) { + dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", + __func__, __LINE__, result); + goto fail_add_hcd; + } + + return result; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + usb_put_hcd(hcd); +fail_create_hcd: + ps3_free_io_irq(virq); +fail_irq: + ps3_free_mmio_region(dev->m_region); +fail_mmio: +fail_start: + return result; +} + +static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev) +{ + struct usb_hcd *hcd = + (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + + usb_put_hcd(hcd); + ps3_system_bus_set_driver_data(dev, NULL); + + return 0; +} + +MODULE_ALIAS("ps3-ehci"); + +static struct ps3_system_bus_driver ps3_ehci_sb_driver = { + .match_id = PS3_MATCH_ID_EHCI, + .core = { + .name = "ps3-ehci-driver", + }, + .probe = ps3_ehci_sb_probe, + .remove = ps3_ehci_sb_remove, +}; -- cgit v1.2.3 From 4a1a4d8b87389e35c3af04c0d0a95f6a0391b964 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Mon, 15 Jan 2007 20:11:52 -0800 Subject: USB: ps3 controller hid quirk Add the USB HID quirk HID_QUIRK_SONY_PS3_CONTROLLER. This sends an HID_REQ_GET_REPORT to the the PS3 controller to put the device into 'operational mode'. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index e07a3049072..84983d1b716 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -768,6 +768,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_PANTHERLORD 0x0810 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 +#define USB_VENDOR_ID_SONY 0x054c +#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -949,6 +952,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { 0, 0 } }; @@ -1013,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize) } } +/* + * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller + * to "operational". Without this, the ps3 controller will not report any + * events. + */ +static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) +{ + int result; + char *buf = kmalloc(18, GFP_KERNEL); + + if (!buf) + return; + + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + HID_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + (3 << 8) | 0xf2, ifnum, buf, 17, + USB_CTRL_GET_TIMEOUT); + + if (result < 0) + err("%s failed: %d\n", __func__, result); + + kfree(buf); +} + static struct hid_device *usb_hid_configure(struct usb_interface *intf) { struct usb_host_interface *interface = intf->cur_altsetting; @@ -1303,6 +1334,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if ((hid->claimed & HID_CLAIMED_INPUT)) hid_ff_init(hid); + if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER) + hid_fixup_sony_ps3_controller(interface_to_usbdev(intf), + intf->cur_altsetting->desc.bInterfaceNumber); + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) -- cgit v1.2.3 From de44743b033942731f6b898c2d389f7ee5ac890b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Jan 2007 20:12:06 -0800 Subject: USB: ohci error handling cleanup Restructure the ohci_hcd_mod_init error handling code in to better support the multiple platform drivers. This does not change the functionality. Signed-off-by: Benjamin Herrenschmidt Cc: David Brownell Signed-off-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8baecbdf062..2c4a6299e4c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -929,7 +929,6 @@ MODULE_LICENSE ("GPL"); static int __init ohci_hcd_mod_init(void) { int retval = 0; - int ls = 0; if (usb_disabled()) return -ENODEV; @@ -941,46 +940,44 @@ static int __init ohci_hcd_mod_init(void) #ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); if (retval < 0) - return retval; - ls++; + goto error_platform; #endif #ifdef OF_PLATFORM_DRIVER retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); if (retval < 0) - goto error; - ls++; + goto error_of_platform; #endif #ifdef SA1111_DRIVER retval = sa1111_driver_register(&SA1111_DRIVER); if (retval < 0) - goto error; - ls++; + goto error_sa1111; #endif #ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); if (retval < 0) - goto error; - ls++; + goto error_pci; #endif return retval; /* Error path */ -error: -#ifdef PLATFORM_DRIVER - if (ls--) - platform_driver_unregister(&PLATFORM_DRIVER); +#ifdef PCI_DRIVER + error_pci: +#endif +#ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); + error_sa1111: #endif #ifdef OF_PLATFORM_DRIVER - if (ls--) - of_unregister_platform_driver(&OF_PLATFORM_DRIVER); + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); + error_of_platform: #endif -#ifdef SA1111_DRIVER - if (ls--) - sa1111_driver_unregister(&SA1111_DRIVER); +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); + error_platform: #endif return retval; } -- cgit v1.2.3 From 6a6c957eba20814456bc4bffbd4ec42406f9eb02 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Mon, 15 Jan 2007 20:12:10 -0800 Subject: USB: ps3 ohci bus glue USB OHCI driver bus glue for the PS3 game console. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 21 ++++- drivers/usb/host/ohci-ps3.c | 196 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/ohci-ps3.c (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2c4a6299e4c..fa6a7ceaa0d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -919,10 +919,16 @@ MODULE_LICENSE ("GPL"); #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver #endif +#ifdef CONFIG_PPC_PS3 +#include "ohci-ps3.c" +#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ - !defined(SA1111_DRIVER) + !defined(SA1111_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -937,6 +943,12 @@ static int __init ohci_hcd_mod_init(void) pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); +#ifdef PS3_SYSTEM_BUS_DRIVER + retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) + goto error_ps3; +#endif + #ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); if (retval < 0) @@ -978,6 +990,10 @@ static int __init ohci_hcd_mod_init(void) #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); error_platform: +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + error_ps3: #endif return retval; } @@ -997,6 +1013,9 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +#endif } module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c new file mode 100644 index 00000000000..69d948b4a70 --- /dev/null +++ b/drivers/usb/host/ohci-ps3.c @@ -0,0 +1,196 @@ +/* + * PS3 OHCI Host Controller driver + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static int ps3_ohci_hc_reset(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci->flags |= OHCI_QUIRK_BE_MMIO; + ohci_hcd_init(ohci); + return ohci_init(ohci); +} + +static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) +{ + int result; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + /* Handle root hub init quirk in spider south bridge. */ + /* Also set PwrOn2PwrGood to 0x7f (254ms). */ + + ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, + &ohci->regs->roothub.a); + ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); + + result = ohci_run(ohci); + + if (result < 0) { + err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + } + + return result; +} + +static const struct hc_driver ps3_ohci_hc_driver = { + .description = hcd_name, + .product_desc = "PS3 OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + .reset = ps3_ohci_hc_reset, + .start = ps3_ohci_hc_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + .get_frame_number = ohci_get_frame, + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .start_port_reset = ohci_start_port_reset, +#if defined(CONFIG_PM) + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif +}; + +/* redefine dev_dbg to do a syntax check */ + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + +static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) +{ + int result; + struct usb_hcd *hcd; + unsigned int virq; + static u64 dummy_mask = DMA_32BIT_MASK; + + if (usb_disabled()) { + result = -ENODEV; + goto fail_start; + } + + result = ps3_mmio_region_create(dev->m_region); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", + __func__, __LINE__); + result = -EPERM; + goto fail_mmio; + } + + dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, + __LINE__, dev->m_region->lpar_addr); + + result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", + __func__, __LINE__, virq); + result = -EPERM; + goto fail_irq; + } + + dev->core.power.power_state = PMSG_ON; + dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + + hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id); + + if (!hcd) { + dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, + __LINE__); + result = -ENOMEM; + goto fail_create_hcd; + } + + hcd->rsrc_start = dev->m_region->lpar_addr; + hcd->rsrc_len = dev->m_region->len; + hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); + + if (!hcd->regs) { + dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + result = -EPERM; + goto fail_ioremap; + } + + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_start); + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_len); + dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, + (unsigned long)hcd->regs); + dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, + (unsigned long)virq); + + ps3_system_bus_set_driver_data(dev, hcd); + + result = usb_add_hcd(hcd, virq, IRQF_DISABLED); + + if (result) { + dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", + __func__, __LINE__, result); + goto fail_add_hcd; + } + + return result; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + usb_put_hcd(hcd); +fail_create_hcd: + ps3_free_io_irq(virq); +fail_irq: + ps3_free_mmio_region(dev->m_region); +fail_mmio: +fail_start: + return result; +} + +static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev) +{ + struct usb_hcd *hcd = + (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + + usb_put_hcd(hcd); + ps3_system_bus_set_driver_data(dev, NULL); + + return 0; +} + +MODULE_ALIAS("ps3-ohci"); + +static struct ps3_system_bus_driver ps3_ohci_sb_driver = { + .match_id = PS3_MATCH_ID_OHCI, + .core = { + .name = "ps3-ohci-driver", + }, + .probe = ps3_ohci_sb_probe, + .remove = ps3_ohci_sb_remove, +}; -- cgit v1.2.3 From 3ca2a3211ee5078d49b04fe7149ff2a76473be51 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 11:56:32 -0500 Subject: UHCI: fix bandwidth allocation This patch (as840) fixes the bandwidth allocation mechanism in uhci-hcd. It has never worked correctly. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 21 +++- drivers/usb/host/uhci-hcd.h | 8 ++ drivers/usb/host/uhci-q.c | 241 ++++++++++++++++++++++++++++++------------ 3 files changed, 201 insertions(+), 69 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 3fbb5ba8024..5d6c06bc452 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) space, "", qh, qtype, le32_to_cpu(qh->link), le32_to_cpu(element)); if (qh->type == USB_ENDPOINT_XFER_ISOC) - out += sprintf(out, "%*s period %d frame %x desc [%p]\n", - space, "", qh->period, qh->iso_frame, - qh->iso_packet_desc); + out += sprintf(out, "%*s period %d phase %d load %d us, " + "frame %x desc [%p]\n", + space, "", qh->period, qh->phase, qh->load, + qh->iso_frame, qh->iso_packet_desc); + else if (qh->type == USB_ENDPOINT_XFER_INT) + out += sprintf(out, "%*s period %d phase %d load %d us\n", + space, "", qh->period, qh->phase, qh->load); if (element & UHCI_PTR_QH) out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); @@ -352,6 +356,17 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); + + out += sprintf(out, "Periodic load table\n"); + for (i = 0; i < MAX_PHASE; ++i) { + out += sprintf(out, "\t%d", uhci->load[i]); + if (i % 8 == 7) + *out++ = '\n'; + } + out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n", + uhci->total_load, + uhci_to_hcd(uhci)->self.bandwidth_int_reqs, + uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs); if (debug <= 1) return out - buf; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 108e3de2dc2..74469b5bcb6 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -83,6 +83,7 @@ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames * can be scheduled */ +#define MAX_PHASE 32 /* Periodic scheduling length */ /* When no queues need Full-Speed Bandwidth Reclamation, * delay this long before turning FSBR off */ @@ -141,6 +142,8 @@ struct uhci_qh { unsigned long advance_jiffies; /* Time of last queue advance */ unsigned int unlink_frame; /* When the QH was unlinked */ unsigned int period; /* For Interrupt and Isochronous QHs */ + short phase; /* Between 0 and period-1 */ + short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ int iso_status; /* Status for Isochronous URBs */ @@ -153,6 +156,8 @@ struct uhci_qh { unsigned int needs_fixup:1; /* Must fix the TD toggle values */ unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */ + unsigned int bandwidth_reserved:1; /* Periodic bandwidth has + * been allocated */ } __attribute__((aligned(16))); /* @@ -414,6 +419,9 @@ struct uhci_hcd { wait_queue_head_t waitqh; /* endpoint_disable waiters */ int num_waiting; /* Number of waiters */ + + int total_load; /* Sum of array values */ + short load[MAX_PHASE]; /* Periodic allocations */ }; /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 5afcc522728..2cbb239e63f 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -261,6 +261,14 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, qh->udev = udev; hep->hcpriv = qh; + if (qh->type == USB_ENDPOINT_XFER_INT || + qh->type == USB_ENDPOINT_XFER_ISOC) + qh->load = usb_calc_bus_time(udev->speed, + usb_endpoint_dir_in(&hep->desc), + qh->type == USB_ENDPOINT_XFER_ISOC, + le16_to_cpu(hep->desc.wMaxPacketSize)) + / 1000 + 1; + } else { /* Skeleton QH */ qh->state = QH_STATE_ACTIVE; qh->type = -1; @@ -496,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) wake_up_all(&uhci->waitqh); } +/* + * Find the highest existing bandwidth load for a given phase and period. + */ +static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period) +{ + int highest_load = uhci->load[phase]; + + for (phase += period; phase < MAX_PHASE; phase += period) + highest_load = max_t(int, highest_load, uhci->load[phase]); + return highest_load; +} + +/* + * Set qh->phase to the optimal phase for a periodic transfer and + * check whether the bandwidth requirement is acceptable. + */ +static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int minimax_load; + + /* Find the optimal phase (unless it is already set) and get + * its load value. */ + if (qh->phase >= 0) + minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); + else { + int phase, load; + int max_phase = min_t(int, MAX_PHASE, qh->period); + + qh->phase = 0; + minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); + for (phase = 1; phase < max_phase; ++phase) { + load = uhci_highest_load(uhci, phase, qh->period); + if (load < minimax_load) { + minimax_load = load; + qh->phase = phase; + } + } + } + + /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */ + if (minimax_load + qh->load > 900) { + dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: " + "period %d, phase %d, %d + %d us\n", + qh->period, qh->phase, minimax_load, qh->load); + return -ENOSPC; + } + return 0; +} + +/* + * Reserve a periodic QH's bandwidth in the schedule + */ +static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + int load = qh->load; + char *p = "??"; + + for (i = qh->phase; i < MAX_PHASE; i += qh->period) { + uhci->load[i] += load; + uhci->total_load += load; + } + uhci_to_hcd(uhci)->self.bandwidth_allocated = + uhci->total_load / MAX_PHASE; + switch (qh->type) { + case USB_ENDPOINT_XFER_INT: + ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs; + p = "INT"; + break; + case USB_ENDPOINT_XFER_ISOC: + ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; + p = "ISO"; + break; + } + qh->bandwidth_reserved = 1; + dev_dbg(uhci_dev(uhci), + "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", + "reserve", qh->udev->devnum, + qh->hep->desc.bEndpointAddress, p, + qh->period, qh->phase, load); +} + +/* + * Release a periodic QH's bandwidth reservation + */ +static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + int load = qh->load; + char *p = "??"; + + for (i = qh->phase; i < MAX_PHASE; i += qh->period) { + uhci->load[i] -= load; + uhci->total_load -= load; + } + uhci_to_hcd(uhci)->self.bandwidth_allocated = + uhci->total_load / MAX_PHASE; + switch (qh->type) { + case USB_ENDPOINT_XFER_INT: + --uhci_to_hcd(uhci)->self.bandwidth_int_reqs; + p = "INT"; + break; + case USB_ENDPOINT_XFER_ISOC: + --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; + p = "ISO"; + break; + } + qh->bandwidth_reserved = 0; + dev_dbg(uhci_dev(uhci), + "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", + "release", qh->udev->devnum, + qh->hep->desc.bEndpointAddress, p, + qh->period, qh->phase, load); +} + static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { @@ -799,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, wmb(); qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); qh->dummy_td = td; - qh->period = urb->interval; usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle); @@ -830,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { - int exponent; + int ret; /* USB 1.1 interrupt transfers only involve one packet per interval. * Drivers can submit URBs of any length, but longer ones will need * multiple intervals to complete. */ - /* Figure out which power-of-two queue to use */ - for (exponent = 7; exponent >= 0; --exponent) { - if ((1 << exponent) <= urb->interval) - break; - } - if (exponent < 0) - return -EINVAL; - urb->interval = 1 << exponent; + if (!qh->bandwidth_reserved) { + int exponent; - if (qh->period == 0) + /* Figure out which power-of-two queue to use */ + for (exponent = 7; exponent >= 0; --exponent) { + if ((1 << exponent) <= urb->interval) + break; + } + if (exponent < 0) + return -EINVAL; + qh->period = 1 << exponent; qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)]; - else if (qh->period != urb->interval) - return -EINVAL; /* Can't change the period */ - return uhci_submit_common(uhci, urb, qh); + /* For now, interrupt phase is fixed by the layout + * of the QH lists. */ + qh->phase = (qh->period / 2) & (MAX_PHASE - 1); + ret = uhci_check_bandwidth(uhci, qh); + if (ret) + return ret; + } else if (qh->period > urb->interval) + return -EINVAL; /* Can't decrease the period */ + + ret = uhci_submit_common(uhci, urb, qh); + if (ret == 0) { + urb->interval = qh->period; + if (!qh->bandwidth_reserved) + uhci_reserve_bandwidth(uhci, qh); + } + return ret; } /* @@ -998,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, return -EFBIG; /* Check the period and figure out the starting frame number */ - if (qh->period == 0) { + if (!qh->bandwidth_reserved) { + qh->period = urb->interval; if (urb->transfer_flags & URB_ISO_ASAP) { + qh->phase = -1; /* Find the best phase */ + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; + + /* Allow a little time to allocate the TDs */ uhci_get_current_frame_number(uhci); - urb->start_frame = uhci->frame_number + 10; + frame = uhci->frame_number + 10; + + /* Move forward to the first frame having the + * correct phase */ + urb->start_frame = frame + ((qh->phase - frame) & + (qh->period - 1)); } else { i = urb->start_frame - uhci->last_iso_frame; if (i <= 0 || i >= UHCI_NUMFRAMES) return -EINVAL; + qh->phase = urb->start_frame & (qh->period - 1); + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; } + } else if (qh->period != urb->interval) { return -EINVAL; /* Can't change the period */ @@ -1052,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, /* Set the interrupt-on-completion flag on the last packet. */ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); - qh->skel = uhci->skel_iso_qh; - qh->period = urb->interval; - /* Add the TDs to the frame list */ frame = urb->start_frame; list_for_each_entry(td, &urbp->td_list, list) { @@ -1068,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, qh->iso_status = 0; } + qh->skel = uhci->skel_iso_qh; + if (!qh->bandwidth_reserved) + uhci_reserve_bandwidth(uhci, qh); return 0; } @@ -1122,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, unsigned long flags; struct urb_priv *urbp; struct uhci_qh *qh; - int bustime; spin_lock_irqsave(&uhci->lock, flags); @@ -1152,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, ret = uhci_submit_bulk(uhci, urb, qh); break; case USB_ENDPOINT_XFER_INT: - if (list_empty(&qh->queue)) { - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) - ret = bustime; - else { - ret = uhci_submit_interrupt(uhci, urb, qh); - if (ret == 0) - usb_claim_bandwidth(urb->dev, urb, bustime, 0); - } - } else { /* inherit from parent */ - struct urb_priv *eurbp; - - eurbp = list_entry(qh->queue.prev, struct urb_priv, - node); - urb->bandwidth = eurbp->urb->bandwidth; - ret = uhci_submit_interrupt(uhci, urb, qh); - } + ret = uhci_submit_interrupt(uhci, urb, qh); break; case USB_ENDPOINT_XFER_ISOC: urb->error_count = 0; - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - ret = bustime; - break; - } - ret = uhci_submit_isochronous(uhci, urb, qh); - if (ret == 0) - usb_claim_bandwidth(urb->dev, urb, bustime, 1); break; } if (ret != 0) @@ -1277,24 +1405,6 @@ __acquires(uhci->lock) uhci_free_urb_priv(uhci, urbp); - switch (qh->type) { - case USB_ENDPOINT_XFER_ISOC: - /* Release bandwidth for Interrupt or Isoc. transfers */ - if (urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 1); - break; - case USB_ENDPOINT_XFER_INT: - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Make sure we don't release if we have a queued URB */ - if (list_empty(&qh->queue) && urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 0); - else - /* bandwidth was passed on to queued URB, */ - /* so don't let usb_unlink_urb() release it */ - urb->bandwidth = 0; - break; - } - spin_unlock(&uhci->lock); usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); spin_lock(&uhci->lock); @@ -1303,9 +1413,8 @@ __acquires(uhci->lock) * reserved bandwidth. */ if (list_empty(&qh->queue)) { uhci_unlink_qh(uhci, qh); - - /* Bandwidth stuff not yet implemented */ - qh->period = 0; + if (qh->bandwidth_reserved) + uhci_release_bandwidth(uhci, qh); } } -- cgit v1.2.3 From 896fbd7199035958013d106329843d8ae9618753 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 11:57:13 -0500 Subject: usbcore: remove unused bandwith-related code This patch (as841) removes from usbcore a couple of support routines meant to help with bandwidth allocation. With the changes to uhci-hcd in the previous patch, these routines are no longer used anywhere. Also removed is the CONFIG_USB_BANDWIDTH option; it no longer does anything and is no longer needed since the HCDs now handle bandwidth issues correctly. Signed-off-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Kconfig | 13 ----- drivers/usb/core/hcd.c | 137 ----------------------------------------------- drivers/usb/core/hcd.h | 6 --- drivers/usb/core/urb.c | 1 - 4 files changed, 157 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 3e66b2a9974..2fc0f88a3d8 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -33,19 +33,6 @@ config USB_DEVICEFS Most users want to say Y here. -config USB_BANDWIDTH - bool "Enforce USB bandwidth allocation (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - help - If you say Y here, the USB subsystem enforces USB bandwidth - allocation and will prevent some device opens from succeeding - if they would cause USB bandwidth usage to go above 90% of - the bus bandwidth. - - If you say N here, these conditions will cause warning messages - about USB bandwidth usage to be logged and some devices or - drivers may not work correctly. - config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation (EXPERIMENTAL)" depends on USB && EXPERIMENTAL diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 10064af65d1..b26c19e8d19 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -45,8 +45,6 @@ #include "hub.h" -// #define USB_BANDWIDTH_MESSAGES - /*-------------------------------------------------------------------------*/ /* @@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) } EXPORT_SYMBOL (usb_calc_bus_time); -/* - * usb_check_bandwidth(): - * - * old_alloc is from host_controller->bandwidth_allocated in microseconds; - * bustime is from calc_bus_time(), but converted to microseconds. - * - * returns if successful, - * or -ENOSPC if bandwidth request fails. - * - * FIXME: - * This initial implementation does not use Endpoint.bInterval - * in managing bandwidth allocation. - * It probably needs to be expanded to use Endpoint.bInterval. - * This can be done as a later enhancement (correction). - * - * This will also probably require some kind of - * frame allocation tracking...meaning, for example, - * that if multiple drivers request interrupts every 10 USB frames, - * they don't all have to be allocated at - * frame numbers N, N+10, N+20, etc. Some of them could be at - * N+11, N+21, N+31, etc., and others at - * N+12, N+22, N+32, etc. - * - * Similarly for isochronous transfers... - * - * Individual HCDs can schedule more directly ... this logic - * is not correct for high speed transfers. - */ -int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) -{ - unsigned int pipe = urb->pipe; - long bustime; - int is_in = usb_pipein (pipe); - int is_iso = usb_pipeisoc (pipe); - int old_alloc = dev->bus->bandwidth_allocated; - int new_alloc; - - - bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, - usb_maxpacket (dev, pipe, !is_in))); - if (is_iso) - bustime /= urb->number_of_packets; - - new_alloc = old_alloc + (int) bustime; - if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { -#ifdef DEBUG - char *mode = -#ifdef CONFIG_USB_BANDWIDTH - ""; -#else - "would have "; -#endif - dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n", - mode, old_alloc, bustime, new_alloc); -#endif -#ifdef CONFIG_USB_BANDWIDTH - bustime = -ENOSPC; /* report error */ -#endif - } - - return bustime; -} -EXPORT_SYMBOL (usb_check_bandwidth); - - -/** - * usb_claim_bandwidth - records bandwidth for a periodic transfer - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @bustime: bandwidth consumed, in (average) microseconds per frame - * @isoc: true iff the request is isochronous - * - * Bus bandwidth reservations are recorded purely for diagnostic purposes. - * HCDs are expected not to overcommit periodic bandwidth, and to record such - * reservations whenever endpoints are added to the periodic schedule. - * - * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's - * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable - * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how - * large its periodic schedule is. - */ -void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) -{ - dev->bus->bandwidth_allocated += bustime; - if (isoc) - dev->bus->bandwidth_isoc_reqs++; - else - dev->bus->bandwidth_int_reqs++; - urb->bandwidth = bustime; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n", - bustime, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif -} -EXPORT_SYMBOL (usb_claim_bandwidth); - - -/** - * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @isoc: true iff the request is isochronous - * - * This records that previously allocated bandwidth has been released. - * Bandwidth is released when endpoints are removed from the host controller's - * periodic schedule. - */ -void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) -{ - dev->bus->bandwidth_allocated -= urb->bandwidth; - if (isoc) - dev->bus->bandwidth_isoc_reqs--; - else - dev->bus->bandwidth_int_reqs--; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n", - urb->bandwidth, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif - urb->bandwidth = 0; -} -EXPORT_SYMBOL (usb_release_bandwidth); - /*-------------------------------------------------------------------------*/ @@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb) { unsigned long flags; - /* Release any periodic transfer bandwidth */ - if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, - usb_pipeisoc (urb->pipe)); - /* clear all state linking urb to this dev (and hcd) */ spin_lock_irqsave (&hcd_data_lock, flags); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8f8df0d4382..2a269ca2051 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev); #define NS_TO_US(ns) ((ns + 500L) / 1000L) /* convert & round nanoseconds to microseconds */ -extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, - int bustime, int isoc); -extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, - int isoc); /* * Full/low speed bandwidth allocation constants/support. @@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, #define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) #define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) -extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); - /* * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9801d08edac..a4fa3e66c30 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -235,7 +235,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->status = -EINPROGRESS; urb->actual_length = 0; - urb->bandwidth = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests -- cgit v1.2.3 From e6316565e568b3b5733be10cfca3c27259bef499 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 11:58:00 -0500 Subject: EHCI: local variable for port status register This patch (as708) introduces a local variable to hold the port status-register address in ehci-hub.c. There's not much improvement in the object code, but it sure is a lot easier to read. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 55 ++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index df00fcbadfb..12f881ff4b2 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -193,6 +193,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) static int check_reset_complete ( struct ehci_hcd *ehci, int index, + u32 __iomem *status_reg, int port_status ) { if (!(port_status & PORT_CONNECT)) { @@ -217,8 +218,7 @@ static int check_reset_complete ( // what happens if HCS_N_CC(params) == 0 ? port_status |= PORT_OWNER; port_status &= ~PORT_RWC_BITS; - ehci_writel(ehci, port_status, - &ehci->regs->port_status [index]); + ehci_writel(ehci, port_status, status_reg); } else ehci_dbg (ehci, "port %d high speed\n", index + 1); @@ -347,6 +347,7 @@ static int ehci_hub_control ( ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int ports = HCS_N_PORTS (ehci->hcs_params); + u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1]; u32 temp, status; unsigned long flags; int retval = 0; @@ -375,18 +376,17 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); if (temp & PORT_OWNER) break; switch (wValue) { case USB_PORT_FEAT_ENABLE: - ehci_writel(ehci, temp & ~PORT_PE, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~PORT_PE, status_reg); break; case USB_PORT_FEAT_C_ENABLE: ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, - &ehci->regs->port_status [wIndex]); + status_reg); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) @@ -399,7 +399,7 @@ static int ehci_hub_control ( /* resume signaling for 20 msec */ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); ehci_writel(ehci, temp | PORT_RESUME, - &ehci->regs->port_status [wIndex]); + status_reg); ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (20); } @@ -411,15 +411,15 @@ static int ehci_hub_control ( if (HCS_PPC (ehci->hcs_params)) ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_POWER), - &ehci->regs->port_status [wIndex]); + status_reg); break; case USB_PORT_FEAT_C_CONNECTION: ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, - &ehci->regs->port_status [wIndex]); + status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, - &ehci->regs->port_status [wIndex]); + status_reg); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ @@ -443,7 +443,7 @@ static int ehci_hub_control ( goto error; wIndex--; status = 0; - temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); // wPortChange bits if (temp & PORT_CSC) @@ -461,13 +461,11 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = 0; /* stop resume signaling */ - temp = ehci_readl(ehci, - &ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_RESUME), - &ehci->regs->port_status [wIndex]); - retval = handshake(ehci, - &ehci->regs->port_status [wIndex], + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + retval = handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { ehci_err (ehci, "port %d resume error %d\n", @@ -486,12 +484,11 @@ static int ehci_hub_control ( /* force reset to complete */ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), - &ehci->regs->port_status [wIndex]); + status_reg); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake(ehci, - &ehci->regs->port_status [wIndex], + retval = handshake(ehci, status_reg, PORT_RESET, 0, 750); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", @@ -500,9 +497,8 @@ static int ehci_hub_control ( } /* see what we found out */ - temp = check_reset_complete (ehci, wIndex, - ehci_readl(ehci, - &ehci->regs->port_status [wIndex])); + temp = check_reset_complete (ehci, wIndex, status_reg, + ehci_readl(ehci, status_reg)); } // don't show wPortStatus if it's owned by a companion hc @@ -547,7 +543,7 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); if (temp & PORT_OWNER) break; @@ -561,13 +557,12 @@ static int ehci_hub_control ( goto error; if (device_may_wakeup(&hcd->self.root_hub->dev)) temp |= PORT_WAKE_BITS; - ehci_writel(ehci, temp | PORT_SUSPEND, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) ehci_writel(ehci, temp | PORT_POWER, - &ehci->regs->port_status [wIndex]); + status_reg); break; case USB_PORT_FEAT_RESET: if (temp & PORT_RESUME) @@ -595,8 +590,7 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); } - ehci_writel(ehci, temp, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, status_reg); break; /* For downstream facing ports (these): one hub port is put @@ -611,8 +605,7 @@ static int ehci_hub_control ( ehci_quiesce(ehci); ehci_halt(ehci); temp |= selector << 16; - ehci_writel(ehci, temp, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, status_reg); break; default: -- cgit v1.2.3 From 625b5c9a0069ef1b61feb3ce599b39f1b04b5666 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 11:58:47 -0500 Subject: EHCI: don't hide ports owned by the companion This patch (as709) changes the way ehci-hcd presents port status values for ports owned by the companion controller. It no longer hides the information; in particular, it allows the core to see the disconnect event that occurs when a full- or low-speed device is switched over to the companion. This is required for the next patch in this series. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 64 +++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 12f881ff4b2..076474d95db 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -270,16 +270,14 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < ports; i++) { temp = ehci_readl(ehci, &ehci->regs->port_status [i]); - if (temp & PORT_OWNER) { - /* don't report this in GetPortStatus */ - if (temp & PORT_CSC) { - temp &= ~PORT_RWC_BITS; - temp |= PORT_CSC; - ehci_writel(ehci, temp, - &ehci->regs->port_status [i]); - } - continue; - } + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; if ((temp & mask) != 0 @@ -377,8 +375,13 @@ static int ehci_hub_control ( goto error; wIndex--; temp = ehci_readl(ehci, status_reg); - if (temp & PORT_OWNER) - break; + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_FEAT_C_CONNECTION). + */ switch (wValue) { case USB_PORT_FEAT_ENABLE: @@ -501,24 +504,27 @@ static int ehci_hub_control ( ehci_readl(ehci, status_reg)); } - // don't show wPortStatus if it's owned by a companion hc - if (!(temp & PORT_OWNER)) { - if (temp & PORT_CONNECT) { - status |= 1 << USB_PORT_FEAT_CONNECTION; - // status may be from integrated TT - status |= ehci_port_speed(ehci, temp); - } - if (temp & PORT_PE) - status |= 1 << USB_PORT_FEAT_ENABLE; - if (temp & (PORT_SUSPEND|PORT_RESUME)) - status |= 1 << USB_PORT_FEAT_SUSPEND; - if (temp & PORT_OC) - status |= 1 << USB_PORT_FEAT_OVER_CURRENT; - if (temp & PORT_RESET) - status |= 1 << USB_PORT_FEAT_RESET; - if (temp & PORT_POWER) - status |= 1 << USB_PORT_FEAT_POWER; + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + // status may be from integrated TT + status |= ehci_port_speed(ehci, temp); } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & (PORT_SUSPEND|PORT_RESUME)) + status |= 1 << USB_PORT_FEAT_SUSPEND; + if (temp & PORT_OC) + status |= 1 << USB_PORT_FEAT_OVER_CURRENT; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; #ifndef EHCI_VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ -- cgit v1.2.3 From 57e06c11372eccf5acebdd4664eb025fee76c561 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 11:59:45 -0500 Subject: EHCI: force high-speed devices to run at full speed This patch (as710) adds a sysfs class-device attribute file named "companion" for EHCI controllers. The file contains a list of port numbers that are dedicated to the companion controller; by writing a port number to the file the user can force a high-speed device attached directly to the computer to run at full speed. (As far as I know it is not possible to do this for a device attached to an external hub.) A port is removed from the file by writing the negative of its port number. Several users have asked for this facility and it seems like a useful thing to have. Every now and then one runs across a device which behaves much better at full speed than at high speed. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 2 + drivers/usb/host/ehci-hub.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci.h | 6 ++- 3 files changed, 114 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 9ec896218fe..92c62911f57 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -388,6 +388,7 @@ static void ehci_stop (struct usb_hcd *hcd) /* let companion controllers work when we aren't */ ehci_writel(ehci, 0, &ehci->regs->configured_flag); + remove_companion_file(ehci); remove_debug_files (ehci); /* root hub is shut down separately (first, when possible) */ @@ -563,6 +564,7 @@ static int ehci_run (struct usb_hcd *hcd) * since the class device isn't created that early. */ create_debug_files(ehci); + create_companion_file(ehci); return 0; } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 076474d95db..3cfba69e076 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -188,6 +188,103 @@ static int ehci_bus_resume (struct usb_hcd *hcd) #endif /* CONFIG_PM */ +/*-------------------------------------------------------------------------*/ + +/* Display the ports dedicated to the companion controller */ +static ssize_t show_companion(struct class_device *class_dev, char *buf) +{ + struct ehci_hcd *ehci; + int nports, index, n; + int count = PAGE_SIZE; + char *ptr = buf; + + ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + nports = HCS_N_PORTS(ehci->hcs_params); + + for (index = 0; index < nports; ++index) { + if (test_bit(index, &ehci->companion_ports)) { + n = scnprintf(ptr, count, "%d\n", index + 1); + ptr += n; + count -= n; + } + } + return ptr - buf; +} + +/* + * Dedicate or undedicate a port to the companion controller. + * Syntax is "[-]portnum", where a leading '-' sign means + * return control of the port to the EHCI controller. + */ +static ssize_t store_companion(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + int portnum, new_owner, try; + u32 __iomem *status_reg; + u32 port_status; + + ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + new_owner = PORT_OWNER; /* Owned by companion */ + if (sscanf(buf, "%d", &portnum) != 1) + return -EINVAL; + if (portnum < 0) { + portnum = - portnum; + new_owner = 0; /* Owned by EHCI */ + } + if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) + return -ENOENT; + status_reg = &ehci->regs->port_status[--portnum]; + if (new_owner) + set_bit(portnum, &ehci->companion_ports); + else + clear_bit(portnum, &ehci->companion_ports); + + /* + * The controller won't set the OWNER bit if the port is + * enabled, so this loop will sometimes require at least two + * iterations: one to disable the port and one to set OWNER. + */ + + for (try = 4; try > 0; --try) { + spin_lock_irq(&ehci->lock); + port_status = ehci_readl(ehci, status_reg); + if ((port_status & PORT_OWNER) == new_owner + || (port_status & (PORT_OWNER | PORT_CONNECT)) + == 0) + try = 0; + else { + port_status ^= PORT_OWNER; + port_status &= ~(PORT_PE | PORT_RWC_BITS); + ehci_writel(ehci, port_status, status_reg); + } + spin_unlock_irq(&ehci->lock); + if (try > 1) + msleep(5); + } + return count; +} +static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion); + +static inline void create_companion_file(struct ehci_hcd *ehci) +{ + int i; + + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev, + &class_device_attr_companion); +} + +static inline void remove_companion_file(struct ehci_hcd *ehci) +{ + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev, + &class_device_attr_companion); +} + + /*-------------------------------------------------------------------------*/ static int check_reset_complete ( @@ -504,6 +601,16 @@ static int ehci_hub_control ( ehci_readl(ehci, status_reg)); } + /* transfer dedicated ports to the companion hc */ + if ((temp & PORT_CONNECT) && + test_bit(wIndex, &ehci->companion_ports)) { + temp &= ~PORT_RWC_BITS; + temp |= PORT_OWNER; + ehci_writel(ehci, temp, status_reg); + ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1); + temp = ehci_readl(ehci, status_reg); + } + /* * Even if OWNER is set, there's no harm letting khubd * see the wPortStatus values (they should all be 0 except diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 3ce7249085d..ec0da0343be 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -74,7 +74,11 @@ struct ehci_hcd { /* one per controller */ /* per root hub port */ unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; - unsigned long bus_suspended; + /* bit vectors (one bit per port) */ + unsigned long bus_suspended; /* which ports were + already suspended at the start of a bus suspend */ + unsigned long companion_ports; /* which ports are + dedicated to the companion controller */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ -- cgit v1.2.3 From 66e56ce75e39210415fb12ceacd5f3580ad72d50 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 12:46:39 -0800 Subject: USB: at91_udc wakeup event updates This updates the AT91 UDC driver's handling of wakeup events: - Fix a bug in the original scheme, which was never updated after the {enable,disable}_irq_wake() semantics were updated to address refcounting issues (i.e. behave for shared irqs). - Couple handling of both type of wakeup events, to be more direct. The controller can be source of wakeup events for cases like bus reset and USB resume. On some boards, VBUS sensing is also IRQ driven. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 19 +++++++++++-------- drivers/usb/gadget/at91_udc.h | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 5a72743606f..f39050145f1 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) || !wake || at91_suspend_entering_slow_clock()) { pullup(udc, 0); - disable_irq_wake(udc->udp_irq); + wake = 0; } else enable_irq_wake(udc->udp_irq); - if (udc->board.vbus_pin > 0) { - if (wake) - enable_irq_wake(udc->board.vbus_pin); - else - disable_irq_wake(udc->board.vbus_pin); - } + udc->active_suspend = wake; + if (udc->board.vbus_pin > 0 && wake) + enable_irq_wake(udc->board.vbus_pin); return 0; } @@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); + if (udc->board.vbus_pin > 0 && udc->active_suspend) + disable_irq_wake(udc->board.vbus_pin); + /* maybe reconnect to host; if so, clocks on */ - pullup(udc, 1); + if (udc->active_suspend) + disable_irq_wake(udc->udp_irq); + else + pullup(udc, 1); return 0; } #else diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 677089baa59..7e34e2f864f 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -136,6 +136,7 @@ struct at91_udc { unsigned wait_for_addr_ack:1; unsigned wait_for_config_ack:1; unsigned selfpowered:1; + unsigned active_suspend:1; u8 addr; struct at91_udc_data board; struct clk *iclk, *fclk; -- cgit v1.2.3 From 3ede760f0e46317c6716ead8facff88f6a924a49 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 11 Jan 2007 14:35:50 +0100 Subject: USB: total removal of multithreaded probing in usb The whole approach is simply wrong. Forking a thread means that - errors are ignored - locking is ignored Doing this correctly would require major surgery for questionable benefit. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 64 +++++++++++++++++--------------------------------- 1 file changed, 21 insertions(+), 43 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1988224b362..590ec82d051 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; -/* multithreaded probe logic */ -static int multithread_probe = 0; - /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); @@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) static int __usb_port_suspend(struct usb_device *, int port1); #endif -static int __usb_new_device(void *void_data) +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) { - struct usb_device *udev = void_data; int err; /* Lock ourself into memory in order to keep a probe sequence @@ -1375,44 +1391,6 @@ fail: goto exit; } -/** - * usb_new_device - perform initial device setup (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * The return value for this function depends on if the - * multithread_probe variable is set or not. If it's set, it will - * return a if the probe thread was successfully created or not. If the - * variable is not set, it will return if the device is configured - * properly or not. interfaces, in sysfs); else a negative errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. - */ -int usb_new_device(struct usb_device *udev) -{ - struct task_struct *probe_task; - int ret = 0; - - if (multithread_probe) { - probe_task = kthread_run(__usb_new_device, udev, - "usb-probe-%s", udev->devnum); - if (IS_ERR(probe_task)) - ret = PTR_ERR(probe_task); - } else - ret = __usb_new_device(udev); - - return ret; -} - static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { -- cgit v1.2.3 From fdcba53e2d58272bcdb5f1fad694602ccf02ad46 Mon Sep 17 00:00:00 2001 From: Rainer Weikusat Date: Wed, 3 Jan 2007 15:36:25 +0100 Subject: fix for bugzilla #7544 (keyspan USB-to-serial converter) At least the Keyspan USA-19HS USB-to-serial converter supports two different configurations, one where the input endpoints have interrupt transfer type and one where they are bulk endpoints. The default UHCI configuration uses the interrupt input endpoints. The keyspan driver, OTOH, assumes that the device has only bulk endpoints (all URBs are initialized by calling usb_fill_bulk_urb in keyspan.c/ keyspan_setup_urb). This causes the interval field of the input URBs to have a value of zero instead of one, which 'accidentally' worked with Linux at least up to 2.6.17.11 but stopped to with 2.6.18, which changed the UHCI support code handling URBs for interrupt endpoints. The patch below modifies to driver to initialize its input URBs either as interrupt or as bulk URBs, depending on the transfertype contained in the associated endpoint descriptor (only tested with the default configuration) enabling the driver to again receive data from the serial converter. Greg K-H reworked the patch. Signed-off-by: Rainer Weikusat Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/keyspan.c | 49 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 9d2fdfd6865..e6966f12ed5 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial) } /* Helper functions used by keyspan_setup_urbs */ +static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial, + int endpoint) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep; + int i; + + iface_desc = serial->interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + ep = &iface_desc->endpoint[i].desc; + if (ep->bEndpointAddress == endpoint) + return ep; + } + dev_warn(&serial->interface->dev, "found no endpoint descriptor for " + "endpoint %x\n", endpoint); + return NULL; +} + static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, void (*callback)(struct urb *)) { struct urb *urb; + struct usb_endpoint_descriptor const *ep_desc; + char const *ep_type_name; if (endpoint == -1) return NULL; /* endpoint not needed */ @@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, return NULL; } - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); + ep_desc = find_ep(serial, endpoint); + if (!ep_desc) { + /* leak the urb, something's wrong and the callers don't care */ + return urb; + } + if (usb_endpoint_xfer_int(ep_desc)) { + ep_type_name = "INT"; + usb_fill_int_urb(urb, serial->dev, + usb_sndintpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx, + ep_desc->bInterval); + } else if (usb_endpoint_xfer_bulk(ep_desc)) { + ep_type_name = "BULK"; + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + } else { + dev_warn(&serial->interface->dev, + "unsupported endpoint type %x\n", + ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + usb_free_urb(urb); + return NULL; + } + dbg("%s - using urb %p for %s endpoint %x", + __func__, urb, ep_type_name, endpoint); return urb; } -- cgit v1.2.3 From 34ef50e5b1f96c2d8c0f3d28b7d407743806256c Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sat, 13 Jan 2007 07:29:26 +0100 Subject: USB: race fixes for usb-serial step 1 - introduce a spinlock for serial_table to eliminate the window between looking up a device and getting a reference - delay inscription of a new device into serial_table until it is fully initialised - make sure disconnect() kills all URBs to avoid leckage across a soft unbind Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 44 +++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 90beb5c50e5..3780362eb9f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = { static int debug; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ +static spinlock_t table_lock; static LIST_HEAD(usb_serial_driver_list); struct usb_serial *usb_serial_get_by_index(unsigned index) { - struct usb_serial *serial = serial_table[index]; + struct usb_serial *serial; + + spin_lock(&table_lock); + serial = serial_table[index]; if (serial) kref_get(&serial->kref); + spin_unlock(&table_lock); return serial; } @@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po dbg("%s %d", __FUNCTION__, num_ports); *minor = 0; + spin_lock(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { if (serial_table[i]) continue; @@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po dbg("%s - minor base = %d", __FUNCTION__, *minor); for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) serial_table[i] = serial; + spin_unlock(&table_lock); return serial; } + spin_unlock(&table_lock); return NULL; } @@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial) if (serial == NULL) return; + spin_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) { serial_table[serial->minor + i] = NULL; } + spin_unlock(&table_lock); } static void destroy_serial(struct kref *kref) @@ -559,15 +569,20 @@ static void port_release(struct device *dev) port_free(port); } -static void port_free(struct usb_serial_port *port) +static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); - usb_free_urb(port->read_urb); usb_kill_urb(port->write_urb); - usb_free_urb(port->write_urb); usb_kill_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); +} + +static void port_free(struct usb_serial_port *port) +{ + kill_traffic(port); + usb_free_urb(port->read_urb); + usb_free_urb(port->write_urb); + usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); @@ -802,12 +817,6 @@ int usb_serial_probe(struct usb_interface *interface, num_ports = type->num_ports; } - if (get_free_serial (serial, num_ports, &minor) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); - kfree (serial); - return -ENOMEM; - } - serial->minor = minor; serial->num_ports = num_ports; serial->num_bulk_in = num_bulk_in; @@ -956,6 +965,11 @@ int usb_serial_probe(struct usb_interface *interface, } } + if (get_free_serial (serial, num_ports, &minor) == NULL) { + dev_err(&interface->dev, "No more free serial devices\n"); + goto probe_error; + } + /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; @@ -1033,8 +1047,11 @@ void usb_serial_disconnect(struct usb_interface *interface) if (serial) { for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port && port->tty) - tty_hangup(port->tty); + if (port) { + if (port->tty) + tty_hangup(port->tty); + kill_traffic(port); + } } /* let the last holder of this object * cause it to be cleaned up */ @@ -1071,6 +1088,7 @@ static int __init usb_serial_init(void) return -ENOMEM; /* Initialize our global data */ + spin_lock_init(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial_table[i] = NULL; } -- cgit v1.2.3 From 4b10f0f3a0d4caa8b615cd1f770a70912967a3cd Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sat, 13 Jan 2007 07:31:27 +0100 Subject: USB: race fixes for usb-serial, step 2 - take BKL before looking up a driver to associate with a device to make sure the module is not unloaded after looking up but before association & bumping module count Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 3780362eb9f..685fb69bcc3 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -685,14 +685,17 @@ int usb_serial_probe(struct usb_interface *interface, int num_ports = 0; int max_endpoints; + lock_kernel(); /* guard against unloading a serial driver module */ type = search_serial_device(interface); if (!type) { + unlock_kernel(); dbg("none matched"); return -ENODEV; } serial = create_serial (dev, interface, type); if (!serial) { + unlock_kernel(); dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -702,6 +705,7 @@ int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id; if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -712,6 +716,7 @@ int usb_serial_probe(struct usb_interface *interface, module_put(type->driver.owner); if (retval) { + unlock_kernel(); dbg ("sub driver rejected device"); kfree (serial); return retval; @@ -781,6 +786,7 @@ int usb_serial_probe(struct usb_interface *interface, * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { + unlock_kernel(); dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree (serial); return -ENODEV; @@ -796,6 +802,7 @@ int usb_serial_probe(struct usb_interface *interface, if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { + unlock_kernel(); dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree (serial); return -EIO; @@ -806,6 +813,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -831,6 +839,8 @@ int usb_serial_probe(struct usb_interface *interface, max_endpoints = max(max_endpoints, num_interrupt_out); max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; + unlock_kernel(); + dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); @@ -1187,7 +1197,7 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, shutdown); } -int usb_serial_register(struct usb_serial_driver *driver) +int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ { int retval; @@ -1211,7 +1221,7 @@ int usb_serial_register(struct usb_serial_driver *driver) } -void usb_serial_deregister(struct usb_serial_driver *device) +void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */ { info("USB Serial deregistering driver %s", device->description); list_del(&device->driver_list); -- cgit v1.2.3 From 3ff4fd94c86259e44d58946af34231a1586b5d93 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sat, 13 Jan 2007 07:32:27 +0100 Subject: USB: race fixes for usb-serial, step 3 - fix an error code returned if a device has been disconnected Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 685fb69bcc3..6bf22a28adb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -281,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) { struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + int retval = -ENODEV; if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; @@ -289,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); if (!port->open_count) { + retval = -EINVAL; dbg("%s - port not opened", __FUNCTION__); goto exit; } -- cgit v1.2.3 From 7489d14943181731ef8694e2ea2d5a919b93b956 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 22:51:04 -0800 Subject: USB: gadgetfs cleanups Minor gadgetfs cleanups: - EP0 state constants become consistently STATE_DEV_* rather than sometimes omitting the "DEV_"; STATE_EP_* were already consistent. - Comment that ep0 state is protected by the spinlock, and update code that was neglecting that rule. None of this is expected to change behavior. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 75 +++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 34 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 0f00249720b..cbdcb3c10c5 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -98,16 +98,16 @@ enum ep0_state { * must always write descriptors to initialize the device, then * the device becomes UNCONNECTED until enumeration. */ - STATE_OPENED, + STATE_DEV_OPENED, /* From then on, ep0 fd is in either of two basic modes: * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it * - SETUP: read/write will transfer control data and succeed; * or if "wrong direction", performs protocol stall */ - STATE_UNCONNECTED, - STATE_CONNECTED, - STATE_SETUP, + STATE_DEV_UNCONNECTED, + STATE_DEV_CONNECTED, + STATE_DEV_SETUP, /* UNBOUND means the driver closed ep0, so the device won't be * accessible again (DEV_DISABLED) until all fds are closed. @@ -121,7 +121,7 @@ enum ep0_state { struct dev_data { spinlock_t lock; atomic_t count; - enum ep0_state state; + enum ep0_state state; /* P: lock */ struct usb_gadgetfs_event event [N_EVENT]; unsigned ev_next; struct fasync_struct *fasync; @@ -942,8 +942,14 @@ static void ep0_complete (struct usb_ep *ep, struct usb_request *req) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else if (dev->state == STATE_SETUP) - dev->state = STATE_CONNECTED; + } else { + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state == STATE_DEV_SETUP) + dev->state = STATE_DEV_CONNECTED; + spin_unlock_irqrestore(&dev->lock, flags); + } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) @@ -988,13 +994,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) } /* control DATA stage */ - if ((state = dev->state) == STATE_SETUP) { + if ((state = dev->state) == STATE_DEV_SETUP) { if (dev->setup_in) { /* stall IN */ VDEBUG(dev, "ep0in stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else if (len == 0) { /* ack SET_CONFIGURATION etc */ struct usb_ep *ep = dev->gadget->ep0; @@ -1002,7 +1008,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) if ((retval = setup_req (ep, req, 0)) == 0) retval = usb_ep_queue (ep, req, GFP_ATOMIC); - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; /* assume that was SET_CONFIGURATION */ if (dev->current_config) { @@ -1061,7 +1067,7 @@ scan: len = min (len, tmp * sizeof (struct usb_gadgetfs_event)); n = len / sizeof (struct usb_gadgetfs_event); - /* ep0 can't deliver events when STATE_SETUP */ + /* ep0 can't deliver events when STATE_DEV_SETUP */ for (i = 0; i < n; i++) { if (dev->event [i].type == GADGETFS_SETUP) { len = i + 1; @@ -1088,7 +1094,7 @@ scan: sizeof (struct usb_gadgetfs_event) * (tmp - len)); if (n == 0) - dev->state = STATE_SETUP; + dev->state = STATE_DEV_SETUP; spin_unlock_irq (&dev->lock); } return retval; @@ -1103,8 +1109,8 @@ scan: DBG (dev, "fail %s, state %d\n", __FUNCTION__, state); retval = -ESRCH; break; - case STATE_UNCONNECTED: - case STATE_CONNECTED: + case STATE_DEV_UNCONNECTED: + case STATE_DEV_CONNECTED: spin_unlock_irq (&dev->lock); DBG (dev, "%s wait\n", __FUNCTION__); @@ -1131,7 +1137,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) switch (type) { /* these events purge the queue */ case GADGETFS_DISCONNECT: - if (dev->state == STATE_SETUP) + if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; // FALL THROUGH case GADGETFS_CONNECT: @@ -1178,7 +1184,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) retval = -EIDRM; /* data and/or status stage for control request */ - } else if (dev->state == STATE_SETUP) { + } else if (dev->state == STATE_DEV_SETUP) { /* IN DATA+STATUS caller makes len <= wLength */ if (dev->setup_in) { @@ -1209,7 +1215,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) VDEBUG(dev, "ep0out stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else { DBG(dev, "bogus ep0out stall!\n"); } @@ -1251,7 +1257,9 @@ dev_release (struct inode *inode, struct file *fd) put_dev (dev); /* other endpoints were all decoupled from this device */ + spin_lock_irq(&dev->lock); dev->state = STATE_DEV_DISABLED; + spin_unlock_irq(&dev->lock); return 0; } @@ -1272,7 +1280,7 @@ ep0_poll (struct file *fd, poll_table *wait) goto out; } - if (dev->state == STATE_SETUP) { + if (dev->state == STATE_DEV_SETUP) { if (dev->setup_in || dev->setup_can_stall) mask = POLLOUT; } else { @@ -1382,9 +1390,9 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; - if (dev->state == STATE_UNCONNECTED) { + if (dev->state == STATE_DEV_UNCONNECTED) { - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1404,7 +1412,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * then ep0_{read,write} will report the wrong status. controller * driver will have aborted pending i/o. */ - } else if (dev->state == STATE_SETUP) + } else if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; req->buf = dev->rbuf; @@ -1550,7 +1558,7 @@ delegate: } /* proceed with data transfer and status phases? */ - if (value >= 0 && dev->state != STATE_SETUP) { + if (value >= 0 && dev->state != STATE_DEV_SETUP) { req->length = value; req->zero = value < w_length; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); @@ -1714,7 +1722,9 @@ gadgetfs_bind (struct usb_gadget *gadget) goto enomem; INFO (dev, "bound to %s driver\n", gadget->name); - dev->state = STATE_UNCONNECTED; + spin_lock_irq(&dev->lock); + dev->state = STATE_DEV_UNCONNECTED; + spin_unlock_irq(&dev->lock); get_dev (dev); return 0; @@ -1729,11 +1739,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget) struct dev_data *dev = get_gadget_data (gadget); spin_lock (&dev->lock); - if (dev->state == STATE_UNCONNECTED) { - DBG (dev, "already unconnected\n"); + if (dev->state == STATE_DEV_UNCONNECTED) goto exit; - } - dev->state = STATE_UNCONNECTED; + dev->state = STATE_DEV_UNCONNECTED; INFO (dev, "disconnected\n"); next_event (dev, GADGETFS_DISCONNECT); @@ -1750,9 +1758,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) INFO (dev, "suspended from state %d\n", dev->state); spin_lock (&dev->lock); switch (dev->state) { - case STATE_SETUP: // VERY odd... host died?? - case STATE_CONNECTED: - case STATE_UNCONNECTED: + case STATE_DEV_SETUP: // VERY odd... host died?? + case STATE_DEV_CONNECTED: + case STATE_DEV_UNCONNECTED: next_event (dev, GADGETFS_SUSPEND); ep0_readable (dev); /* FALLTHROUGH */ @@ -1848,9 +1856,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) u32 tag; char *kbuf; - if (dev->state != STATE_OPENED) - return -EEXIST; - if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) return -EINVAL; @@ -1942,13 +1947,15 @@ dev_open (struct inode *inode, struct file *fd) struct dev_data *dev = inode->i_private; int value = -EBUSY; + spin_lock_irq(&dev->lock); if (dev->state == STATE_DEV_DISABLED) { dev->ev_next = 0; - dev->state = STATE_OPENED; + dev->state = STATE_DEV_OPENED; fd->private_data = dev; get_dev (dev); value = 0; } + spin_unlock_irq(&dev->lock); return value; } -- cgit v1.2.3 From 0864c7a9286b02319d3db2103bada1c2269c1e1e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 22:53:58 -0800 Subject: USB: gadgetfs simplifications This simplifies event reading by eliminating arithmetic and being more direct/obvious, and tweaks some debug messages slightly. The math elimination will change timings, sometimes enough to allow a race to appear. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index cbdcb3c10c5..ea8e3160d05 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1062,39 +1062,36 @@ scan: /* return queued events right away */ if (dev->ev_next != 0) { unsigned i, n; - int tmp = dev->ev_next; - len = min (len, tmp * sizeof (struct usb_gadgetfs_event)); n = len / sizeof (struct usb_gadgetfs_event); + if (dev->ev_next < n) + n = dev->ev_next; - /* ep0 can't deliver events when STATE_DEV_SETUP */ + /* ep0 i/o has special semantics during STATE_DEV_SETUP */ for (i = 0; i < n; i++) { if (dev->event [i].type == GADGETFS_SETUP) { - len = i + 1; - len *= sizeof (struct usb_gadgetfs_event); - n = 0; + dev->state = STATE_DEV_SETUP; + n = i + 1; break; } } spin_unlock_irq (&dev->lock); + len = n * sizeof (struct usb_gadgetfs_event); if (copy_to_user (buf, &dev->event, len)) retval = -EFAULT; else retval = len; if (len > 0) { - len /= sizeof (struct usb_gadgetfs_event); - /* NOTE this doesn't guard against broken drivers; * concurrent ep0 readers may lose events. */ spin_lock_irq (&dev->lock); - dev->ev_next -= len; - if (dev->ev_next != 0) - memmove (&dev->event, &dev->event [len], + if (dev->ev_next > n) { + memmove(&dev->event[0], &dev->event[n], sizeof (struct usb_gadgetfs_event) - * (tmp - len)); - if (n == 0) - dev->state = STATE_DEV_SETUP; + * (dev->ev_next - n)); + } + dev->ev_next -= n; spin_unlock_irq (&dev->lock); } return retval; @@ -1149,7 +1146,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) for (i = 0; i != dev->ev_next; i++) { if (dev->event [i].type != type) continue; - DBG (dev, "discard old event %d\n", type); + DBG(dev, "discard old event[%d] %d\n", i, type); dev->ev_next--; if (i == dev->ev_next) break; @@ -1162,9 +1159,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) default: BUG (); } + VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type); event = &dev->event [dev->ev_next++]; BUG_ON (dev->ev_next > N_EVENT); - VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next); memset (event, 0, sizeof *event); event->type = type; return event; -- cgit v1.2.3 From 5b89db02a5a7c8bad3c6fb7888778082a441b385 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 22:56:26 -0800 Subject: USB: gadgetfs race fix This resolves a race in gadgetfs associated with changing device/ep0 when processing control requests. The fix is to change that state earlier, when the control response is issued, so there's no window in which userspace could see the wrong state; and enlarge the scope of the spinlock during the ep0 request completion handler. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ea8e3160d05..e5ce4f0bb7c 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -933,28 +933,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) static void ep0_complete (struct usb_ep *ep, struct usb_request *req) { struct dev_data *dev = ep->driver_data; + unsigned long flags; int free = 1; /* for control OUT, data must still get to userspace */ + spin_lock_irqsave(&dev->lock, flags); if (!dev->setup_in) { dev->setup_out_error = (req->status != 0); if (!dev->setup_out_error) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->state == STATE_DEV_SETUP) - dev->state = STATE_DEV_CONNECTED; - spin_unlock_irqrestore(&dev->lock, flags); } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) clean_req (ep, req); req->complete = epio_complete; + spin_unlock_irqrestore(&dev->lock, flags); } static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) @@ -1036,6 +1032,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) spin_lock_irq (&dev->lock); if (retval) goto done; + + if (dev->state != STATE_DEV_SETUP) { + retval = -ECANCELED; + goto done; + } + dev->state = STATE_DEV_CONNECTED; + if (dev->setup_out_error) retval = -EIO; else { @@ -1187,6 +1190,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (dev->setup_in) { retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { + dev->state = STATE_DEV_CONNECTED; spin_unlock_irq (&dev->lock); if (copy_from_user (dev->req->buf, buf, len)) retval = -EFAULT; -- cgit v1.2.3 From ce46794f77f698eaf3b80922fafac5a9379085e0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 23:06:07 -0800 Subject: USB: gadgetfs behaves better on userspace init bug Resolve an initizlization issue that could come up if the userspace driver wrote invalid descriptors to a dual-speed device. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index e5ce4f0bb7c..1c5e1ee7e36 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1392,17 +1392,17 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { - - dev->state = STATE_DEV_CONNECTED; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; - #ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { + spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } #endif /* CONFIG_USB_GADGET_DUALSPEED */ + dev->state = STATE_DEV_CONNECTED; + dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; + INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); event->u.speed = gadget->speed; -- cgit v1.2.3 From 49631ca7f3e2fd05186028b453fa27f75b830de7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 23:28:48 -0800 Subject: USB: gadgetfs AIO tweaks This patch (as837) fixes several mistakes in the AIO interface of the gadgetfs driver: The ki_retry method is not supposed to do a put on the kiocb. The extra call to aio_put_req() causes memory corruption. (Note: This call was removed before, by patch as691, and then mysteriously re-introduced later.) Even if a read transfer is cancelled, we can and should send to the user all the data that did manage to get transferred. Testing for AIO cancellation in the I/O completion handler is both racy and (now) unnecessary. aio_complete() does its own checking, in a safe manner. Signed-off-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 1c5e1ee7e36..34296e79edc 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -576,7 +576,6 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) } kfree(priv->buf); kfree(priv); - aio_put_req(iocb); return len; } @@ -590,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&epdata->dev->lock); priv->req = NULL; priv->epdata = NULL; - if (priv->iv == NULL - || unlikely(req->actual == 0) - || unlikely(kiocbIsCancelled(iocb))) { + + /* if this was a write or a read returning no data then we + * don't need to copy anything to userspace, so we can + * complete the aio request immediately. + */ + if (priv->iv == NULL || unlikely(req->actual == 0)) { kfree(req->buf); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ - if (unlikely(kiocbIsCancelled(iocb))) - aio_put_req(iocb); - else - aio_complete(iocb, - req->actual ? req->actual : req->status, + aio_complete(iocb, req->actual ? req->actual : req->status, req->status); } else { /* retry() won't report both; so we hide some faults */ -- cgit v1.2.3 From 1f5b9cc9e4cf5847e7550c4079cebb80170e71dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=E5vard=20Skinnemoen?= Date: Wed, 17 Jan 2007 11:03:29 -0800 Subject: USB: list atmel husb2_udc gadget controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This identifies the driver for the Atmel HUSB2 Device Controller, as integrated into the first AVR32 chip, the AT32AP700. From: Håvard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gadget_chips.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index aa80f091072..2e3d6620d21 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -75,6 +75,12 @@ #define gadget_is_pxa27x(g) 0 #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) +#else +#define gadget_is_husb2dev(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_S3C2410 #define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name) #else @@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x16; else if (gadget_is_mpc8272(gadget)) return 0x17; + else if (gadget_is_husb2dev(gadget)) + return 0x18; return -ENOENT; } -- cgit v1.2.3 From ef3ff462a31987629c4d0488550fbbb66fbfcc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=E5vard=20Skinnemoen?= Date: Mon, 27 Feb 2006 18:15:04 +0100 Subject: USB: usb ethernet gadget recognizes HUSB2DEV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define DEV_CONFIG_CDC when compiling for HUSB2DEV. From: Håvard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 72e2b65293c..22e3c944364 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -279,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. -- cgit v1.2.3 From e43062dd208594caa94536b8ba4b762d4a16330d Mon Sep 17 00:00:00 2001 From: Kevin Lloyd Date: Wed, 17 Jan 2007 16:04:18 -0800 Subject: USB: Sierra Wireless auto set D0 This patch ensures that the device is turned on when inserted into the system. It also adds more VID/PIDs and matches the N_OUT_URB with the airprime driver. Signed-off-by: Kevin Lloyd Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 8aca8a707a3..ecedd833818 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -13,10 +13,9 @@ Portions based on the option driver by Matthias Urlichs Whom based his on the Keyspan driver by Hugh Blemings - History: */ -#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_VERSION "v.1.0.6" #define DRIVER_AUTHOR "Kevin Lloyd " #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -31,14 +30,15 @@ static struct usb_device_id id_table [] = { + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ @@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = { }; static struct usb_device_id id_table_3port [] = { + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ { } @@ -81,7 +82,7 @@ static int debug; /* per port private data */ #define N_IN_URB 4 -#define N_OUT_URB 1 +#define N_OUT_URB 4 #define IN_BUFLEN 4096 #define OUT_BUFLEN 128 @@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) struct usb_serial *serial = port->serial; int i, err; struct urb *urb; + int result; + __u16 set_mode_dzero = 0x0000; portdata = usb_get_serial_port_data(port); @@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) port->tty->low_latency = 1; + /* set mode to D0 */ + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x00, 0x40, set_mode_dzero, 0, NULL, + 0, USB_CTRL_SET_TIMEOUT); + sierra_send_setup(port); return (0); -- cgit v1.2.3 From a19ceb56cbd1e1beff3e9cf6042e1f31f6487aa6 Mon Sep 17 00:00:00 2001 From: Jeremy Roberson Date: Thu, 18 Jan 2007 08:10:25 -0700 Subject: USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products Added a kernel module (gtco) to the USB Input subsystem. This kernel module adds support for all GTCO CalComp USB InterWrite School products. Signed-off-by: Jeremy A. Roberson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 12 + drivers/usb/input/Makefile | 1 + drivers/usb/input/gtco.c | 1104 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1117 insertions(+) create mode 100644 drivers/usb/input/gtco.c (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index aa6a620c162..2e71d3cca19 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -352,3 +352,15 @@ config USB_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. + +config USB_GTCO + tristate "GTCO CalComp/InterWrite USB Support" + depends on USB && INPUT + ---help--- + Say Y here if you want to use the USB version of the GTCO + CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called gtco. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index a06024e5cd5..a9d206c945e 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o +obj-$(CONFIG_USB_GTCO) += gtco.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c new file mode 100644 index 00000000000..203cdc1bbba --- /dev/null +++ b/drivers/usb/input/gtco.c @@ -0,0 +1,1104 @@ +/* -*- linux-c -*- + +GTCO digitizer USB driver + +Use the err(), dbg() and info() macros from usb.h for system logging + +TO CHECK: Is pressure done right on report 5? + +Copyright (C) 2006 GTCO CalComp + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name of GTCO-CalComp not be used in advertising +or publicity pertaining to distribution of the software without specific, +written prior permission. GTCO-CalComp makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +GTCO CalComp, Inc. +7125 Riverwood Drive +Columbia, MD 21046 + +Jeremy Roberson jroberson@gtcocalcomp.com +Scott Hill shill@gtcocalcomp.com +*/ + + + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +/* Version with a Major number of 2 is for kernel inclusion only. */ +#define GTCO_VERSION "2.00.0006" + + +/* MACROS */ + +#define VENDOR_ID_GTCO 0x078C +#define PID_400 0x400 +#define PID_401 0x401 +#define PID_1000 0x1000 +#define PID_1001 0x1001 +#define PID_1002 0x1002 + +/* Max size of a single report */ +#define REPORT_MAX_SIZE 10 + + +/* Bitmask whether pen is in range */ +#define MASK_INRANGE 0x20 +#define MASK_BUTTON 0x01F + +#define PATHLENGTH 64 + +/* DATA STRUCTURES */ + +/* Device table */ +static struct usb_device_id gtco_usbid_table [] = { + { USB_DEVICE(VENDOR_ID_GTCO, PID_400) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_401) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) }, + { } +}; +MODULE_DEVICE_TABLE (usb, gtco_usbid_table); + + +/* Structure to hold all of our device specific stuff */ +struct gtco { + + struct input_dev *inputdevice; /* input device struct pointer */ + struct usb_device *usbdev; /* the usb device for this device */ + struct urb *urbinfo; /* urb for incoming reports */ + dma_addr_t buf_dma; /* dma addr of the data buffer*/ + unsigned char * buffer; /* databuffer for reports */ + + char usbpath[PATHLENGTH]; + int openCount; + + /* Information pulled from Report Descriptor */ + u32 usage; + u32 min_X; + u32 max_X; + u32 min_Y; + u32 max_Y; + s8 mintilt_X; + s8 maxtilt_X; + s8 mintilt_Y; + s8 maxtilt_Y; + u32 maxpressure; + u32 minpressure; +}; + + + +/* Code for parsing the HID REPORT DESCRIPTOR */ + +/* From HID1.11 spec */ +struct hid_descriptor +{ + struct usb_descriptor_header header; + __le16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + u8 bDescriptorType; + __le16 wDescriptorLength; +} __attribute__ ((packed)); + + +#define HID_DESCRIPTOR_SIZE 9 +#define HID_DEVICE_TYPE 33 +#define REPORT_DEVICE_TYPE 34 + + +#define PREF_TAG(x) ((x)>>4) +#define PREF_TYPE(x) ((x>>2)&0x03) +#define PREF_SIZE(x) ((x)&0x03) + +#define TYPE_MAIN 0 +#define TYPE_GLOBAL 1 +#define TYPE_LOCAL 2 +#define TYPE_RESERVED 3 + +#define TAG_MAIN_INPUT 0x8 +#define TAG_MAIN_OUTPUT 0x9 +#define TAG_MAIN_FEATURE 0xB +#define TAG_MAIN_COL_START 0xA +#define TAG_MAIN_COL_END 0xC + +#define TAG_GLOB_USAGE 0 +#define TAG_GLOB_LOG_MIN 1 +#define TAG_GLOB_LOG_MAX 2 +#define TAG_GLOB_PHYS_MIN 3 +#define TAG_GLOB_PHYS_MAX 4 +#define TAG_GLOB_UNIT_EXP 5 +#define TAG_GLOB_UNIT 6 +#define TAG_GLOB_REPORT_SZ 7 +#define TAG_GLOB_REPORT_ID 8 +#define TAG_GLOB_REPORT_CNT 9 +#define TAG_GLOB_PUSH 10 +#define TAG_GLOB_POP 11 + +#define TAG_GLOB_MAX 12 + +#define DIGITIZER_USAGE_TIP_PRESSURE 0x30 +#define DIGITIZER_USAGE_TILT_X 0x3D +#define DIGITIZER_USAGE_TILT_Y 0x3E + + +/* + * + * This is an abbreviated parser for the HID Report Descriptor. We + * know what devices we are talking to, so this is by no means meant + * to be generic. We can make some safe assumptions: + * + * - We know there are no LONG tags, all short + * - We know that we have no MAIN Feature and MAIN Output items + * - We know what the IRQ reports are supposed to look like. + * + * The main purpose of this is to use the HID report desc to figure + * out the mins and maxs of the fields in the IRQ reports. The IRQ + * reports for 400/401 change slightly if the max X is bigger than 64K. + * + */ +static void parse_hid_report_descriptor(struct gtco *device, char * report, + int length) +{ + int x,i=0; + + /* Tag primitive vars */ + __u8 prefix; + __u8 size; + __u8 tag; + __u8 type; + __u8 data = 0; + __u16 data16 = 0; + __u32 data32 = 0; + + + /* For parsing logic */ + int inputnum = 0; + __u32 usage = 0; + + /* Global Values, indexed by TAG */ + __u32 globalval[TAG_GLOB_MAX]; + __u32 oldval[TAG_GLOB_MAX]; + + /* Debug stuff */ + char maintype='x'; + char globtype[12]; + int indent=0; + char indentstr[10]=""; + + + + dbg("======>>>>>>PARSE<<<<<<======"); + + /* Walk this report and pull out the info we need */ + while (imax_X == 0){ + device->max_X = globalval[TAG_GLOB_LOG_MAX]; + device->min_X = globalval[TAG_GLOB_LOG_MIN]; + } + + break; + case 1: /* Y coord */ + dbg("GER: Y Usage: 0x%x",usage); + if (device->max_Y == 0){ + device->max_Y = globalval[TAG_GLOB_LOG_MAX]; + device->min_Y = globalval[TAG_GLOB_LOG_MIN]; + } + break; + default: + /* Tilt X */ + if (usage == DIGITIZER_USAGE_TILT_X){ + if (device->maxtilt_X == 0){ + device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX]; + device->mintilt_X = globalval[TAG_GLOB_LOG_MIN]; + } + } + + /* Tilt Y */ + if (usage == DIGITIZER_USAGE_TILT_Y){ + if (device->maxtilt_Y == 0){ + device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX]; + device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN]; + } + } + + + /* Pressure */ + if (usage == DIGITIZER_USAGE_TIP_PRESSURE){ + if (device->maxpressure == 0){ + device->maxpressure = globalval[TAG_GLOB_LOG_MAX]; + device->minpressure = globalval[TAG_GLOB_LOG_MIN]; + } + } + + break; + } + + inputnum++; + + + break; + case TAG_MAIN_OUTPUT: + maintype='O'; + break; + case TAG_MAIN_FEATURE: + maintype='F'; + break; + case TAG_MAIN_COL_START: + maintype='S'; + + if (data==0){ + dbg("======>>>>>> Physical"); + strcpy(globtype,"Physical"); + }else{ + dbg("======>>>>>>"); + } + + /* Indent the debug output */ + indent++; + for (x=0;xusage == 0){ + device->usage = data; + } + strcpy(globtype,"USAGE"); + break; + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"LOG_MIN"); + break; + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"LOG_MAX"); + break; + case TAG_GLOB_PHYS_MIN : + strcpy(globtype,"PHYS_MIN"); + break; + case TAG_GLOB_PHYS_MAX : + strcpy(globtype,"PHYS_MAX"); + break; + case TAG_GLOB_UNIT_EXP : + strcpy(globtype,"EXP"); + break; + case TAG_GLOB_UNIT : + strcpy(globtype,"UNIT"); + break; + case TAG_GLOB_REPORT_SZ : + strcpy(globtype,"REPORT_SZ"); + break; + case TAG_GLOB_REPORT_ID : + strcpy(globtype,"REPORT_ID"); + /* New report, restart numbering */ + inputnum=0; + break; + case TAG_GLOB_REPORT_CNT: + strcpy(globtype,"REPORT_CNT"); + break; + case TAG_GLOB_PUSH : + strcpy(globtype,"PUSH"); + break; + case TAG_GLOB_POP: + strcpy(globtype,"POP"); + break; + } + + + /* Check to make sure we have a good tag number + so we don't overflow array */ + if (tag < TAG_GLOB_MAX){ + switch (size){ + case 1: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data); + globalval[tag]=data; + break; + case 2: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16); + globalval[tag]=data16; + break; + case 4: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32); + globalval[tag]=data32; + break; + } + }else{ + dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ", + indentstr,tag,size); + } + + + break; + + case TYPE_LOCAL: + switch(tag){ + case TAG_GLOB_USAGE: + strcpy(globtype,"USAGE"); + /* Always 1 byte */ + usage = data; + break; + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"MIN"); + break; + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"MAX"); + break; + default: + strcpy(globtype,"UNKNOWN"); + } + + switch (size){ + case 1: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data); + break; + case 2: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data16); + break; + case 4: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data32); + break; + } + + break; + } + + } + +} + + + +/* INPUT DRIVER Routines */ + + +/* + * Called when opening the input device. This will submit the URB to + * the usb system so we start getting reports + */ +static int gtco_input_open(struct input_dev *inputdev) +{ + struct gtco *device; + device = inputdev->private; + + device->urbinfo->dev = device->usbdev; + if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) { + return -EIO; + } + return 0; +} + +/** + Called when closing the input device. This will unlink the URB +*/ +static void gtco_input_close(struct input_dev *inputdev) +{ + struct gtco *device = inputdev->private; + + usb_kill_urb(device->urbinfo); + +} + + +/* + * Setup input device capabilities. Tell the input system what this + * device is capable of generating. + * + * This information is based on what is read from the HID report and + * placed in the struct gtco structure + * + */ +static void gtco_setup_caps(struct input_dev *inputdev) +{ + struct gtco *device = inputdev->private; + + + /* Which events */ + inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + + + /* Misc event menu block */ + inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ; + + + /* Absolute values based on HID report info */ + input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, + 0, 0); + input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y, + 0, 0); + + /* Proximity */ + input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0); + + /* Tilt & pressure */ + input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X, + device->maxtilt_X, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y, + device->maxtilt_Y, 0, 0); + input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, + device->maxpressure, 0, 0); + + + /* Transducer */ + input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0); + +} + + + +/* USB Routines */ + + +/* + * URB callback routine. Called when we get IRQ reports from the + * digitizer. + * + * This bridges the USB and input device worlds. It generates events + * on the input device based on the USB reports. + */ +static void gtco_urb_callback(struct urb *urbinfo) +{ + + + struct gtco *device = urbinfo->context; + struct input_dev *inputdev; + int rc; + u32 val = 0; + s8 valsigned = 0; + char le_buffer[2]; + + inputdev = device->inputdevice; + + + /* Was callback OK? */ + if ((urbinfo->status == -ECONNRESET ) || + (urbinfo->status == -ENOENT ) || + (urbinfo->status == -ESHUTDOWN )){ + + /* Shutdown is occurring. Return and don't queue up any more */ + return; + } + + if (urbinfo->status != 0 ) { + /* Some unknown error. Hopefully temporary. Just go and */ + /* requeue an URB */ + goto resubmit; + } + + /* + * Good URB, now process + */ + + /* PID dependent when we interpret the report */ + if ((inputdev->id.product == PID_1000 )|| + (inputdev->id.product == PID_1001 )|| + (inputdev->id.product == PID_1002 )) + { + + /* + * Switch on the report ID + * Conveniently, the reports have more information, the higher + * the report number. We can just fall through the case + * statements if we start with the highest number report + */ + switch(device->buffer[0]){ + case 5: + /* Pressure is 9 bits */ + val = ((u16)(device->buffer[8]) << 1); + val |= (u16)(device->buffer[7] >> 7); + input_report_abs(inputdev, ABS_PRESSURE, + device->buffer[8]); + + /* Mask out the Y tilt value used for pressure */ + device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); + + + /* Fall thru */ + case 4: + /* Tilt */ + + /* Sign extend these 7 bit numbers. */ + if (device->buffer[6] & 0x40) + device->buffer[6] |= 0x80; + + if (device->buffer[7] & 0x40) + device->buffer[7] |= 0x80; + + + valsigned = (device->buffer[6]); + input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned); + + valsigned = (device->buffer[7]); + input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); + + /* Fall thru */ + + case 2: + case 3: + /* Convert buttons, only 5 bits possible */ + val = (device->buffer[5])&MASK_BUTTON; + + /* We don't apply any meaning to the bitmask, + just report */ + input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + /* Fall thru */ + case 1: + + /* All reports have X and Y coords in the same place */ + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1]))); + input_report_abs(inputdev, ABS_X, val); + + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3]))); + input_report_abs(inputdev, ABS_Y, val); + + + /* Ditto for proximity bit */ + if (device->buffer[5]& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } + input_report_abs(inputdev, ABS_DISTANCE, val); + + + /* Report 1 is an exception to how we handle buttons */ + /* Buttons are an index, not a bitmask */ + if (device->buffer[0] == 1){ + + /* Convert buttons, 5 bit index */ + /* Report value of index set as one, + the rest as 0 */ + val = device->buffer[5]& MASK_BUTTON; + dbg("======>>>>>>REPORT 1: val 0x%X(%d)", + val,val); + + /* + * We don't apply any meaning to the button + * index, just report it + */ + input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + + } + + break; + case 7: + /* Menu blocks */ + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); + + + break; + + } + + + } + /* Other pid class */ + if ((inputdev->id.product == PID_400 )|| + (inputdev->id.product == PID_401 )) + { + + /* Report 2 */ + if (device->buffer[0] == 2){ + /* Menu blocks */ + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); + } + + /* Report 1 */ + if (device->buffer[0] == 1){ + char buttonbyte; + + + /* IF X max > 64K, we still a bit from the y report */ + if (device->max_X > 0x10000){ + + val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1]))); + val |= (u32)(((u8)device->buffer[3]&0x1)<< 16); + + input_report_abs(inputdev, ABS_X, val); + + le_buffer[0] = (u8)((u8)(device->buffer[3])>>1); + le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7); + + le_buffer[1] = (u8)(device->buffer[4]>>1); + le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7); + + val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer))); + + input_report_abs(inputdev, ABS_Y, val); + + + /* + * Shift the button byte right by one to + * make it look like the standard report + */ + buttonbyte = (device->buffer[5])>>1; + }else{ + + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1])))); + input_report_abs(inputdev, ABS_X, val); + + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3])))); + input_report_abs(inputdev, ABS_Y, val); + + buttonbyte = device->buffer[5]; + + } + + + /* BUTTONS and PROXIMITY */ + if (buttonbyte& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } + input_report_abs(inputdev, ABS_DISTANCE, val); + + /* Convert buttons, only 4 bits possible */ + val = buttonbyte&0x0F; +#ifdef USE_BUTTONS + for ( i=0;i<5;i++){ + input_report_key(inputdev, BTN_DIGI+i,val&(1<buffer[6]); + + } + } + + /* Everybody gets report ID's */ + input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]); + + /* Sync it up */ + input_sync(inputdev); + + resubmit: + rc = usb_submit_urb(urbinfo, GFP_ATOMIC); + if (rc != 0) { + err("usb_submit_urb failed rc=0x%x",rc); + } + +} + +/* + * The probe routine. This is called when the kernel find the matching USB + * vendor/product. We do the following: + * + * - Allocate mem for a local structure to manage the device + * - Request a HID Report Descriptor from the device and parse it to + * find out the device parameters + * - Create an input device and assign it attributes + * - Allocate an URB so the device can talk to us when the input + * queue is open + */ +static int gtco_probe(struct usb_interface *usbinterface, + const struct usb_device_id *id) +{ + + struct gtco *device = NULL; + char path[PATHLENGTH]; + struct input_dev *inputdev; + struct hid_descriptor *hid_desc; + char *report; + int result=0, retry; + struct usb_endpoint_descriptor *endpoint; + + /* Allocate memory for device structure */ + device = kzalloc(sizeof(struct gtco), GFP_KERNEL); + if (device == NULL) { + err("No more memory"); + return -ENOMEM; + } + + + device->inputdevice = input_allocate_device(); + if (!device->inputdevice){ + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Get pointer to the input device */ + inputdev = device->inputdevice; + + /* Save interface information */ + device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + + + /* Allocate some data for incoming reports */ + device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE, + GFP_KERNEL, &(device->buf_dma)); + if (!device->buffer){ + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Allocate URB for reports */ + device->urbinfo = usb_alloc_urb(0, GFP_KERNEL); + if (!device->urbinfo) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + + /* + * The endpoint is always altsetting 0, we know this since we know + * this device only has one interrupt endpoint + */ + endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + + /* Some debug */ + dbg("gtco # interfaces: %d",usbinterface->num_altsetting); + dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints); + dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass); + dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + dbg("endpoint: we have interrupt endpoint\n"); + + dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen); + + + + /* + * Find the HID descriptor so we can find out the size of the + * HID report descriptor + */ + if (usb_get_extra_descriptor(usbinterface->cur_altsetting, + HID_DEVICE_TYPE,&hid_desc) != 0){ + err("Can't retrieve exta USB descriptor to get hid report descriptor length"); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + return -EIO; + } + + dbg("Extra descriptor success: type:%d len:%d", + hid_desc->bDescriptorType, hid_desc->wDescriptorLength); + + if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Couple of tries to get reply */ + for (retry=0;retry<3;retry++) { + result = usb_control_msg(device->usbdev, + usb_rcvctrlpipe(device->usbdev, 0), + USB_REQ_GET_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_DIR_IN, + (REPORT_DEVICE_TYPE << 8), + 0, /* interface */ + report, + hid_desc->wDescriptorLength, + 5000); /* 5 secs */ + + if (result == hid_desc->wDescriptorLength) + break; + } + + /* If we didn't get the report, fail */ + dbg("usb_control_msg result: :%d", result); + if (result != hid_desc->wDescriptorLength){ + kfree(report); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("Failed to get HID Report Descriptor of size: %d", + hid_desc->wDescriptorLength); + return -EIO; + } + + + /* Now we parse the report */ + parse_hid_report_descriptor(device,report,result); + + /* Now we delete it */ + kfree(report); + + /* Create a device file node */ + usb_make_path(device->usbdev, path, PATHLENGTH); + sprintf(device->usbpath, "%s/input0", path); + + + /* Set Input device functions */ + inputdev->open = gtco_input_open; + inputdev->close = gtco_input_close; + + /* Set input device information */ + inputdev->name = "GTCO_CalComp"; + inputdev->phys = device->usbpath; + inputdev->private = device; + + + /* Now set up all the input device capabilities */ + gtco_setup_caps(inputdev); + + /* Set input device required ID information */ + usb_to_input_id(device->usbdev, &device->inputdevice->id); + inputdev->cdev.dev = &usbinterface->dev; + + /* Setup the URB, it will be posted later on open of input device */ + endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + + usb_fill_int_urb(device->urbinfo, + device->usbdev, + usb_rcvintpipe(device->usbdev, + endpoint->bEndpointAddress), + device->buffer, + REPORT_MAX_SIZE, + gtco_urb_callback, + device, + endpoint->bInterval); + + device->urbinfo->transfer_dma = device->buf_dma; + device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + + /* Save device pointer in USB interface device */ + usb_set_intfdata(usbinterface, device); + + /* All done, now register the input device */ + input_register_device(inputdev); + + info( "gtco driver created usb: %s\n", path); + return 0; + +} + +/* + * This function is a standard USB function called when the USB device + * is disconnected. We will get rid of the URV, de-register the input + * device, and free up allocated memory + */ +static void gtco_disconnect(struct usb_interface *interface) +{ + + /* Grab private device ptr */ + struct gtco *device = usb_get_intfdata (interface); + struct input_dev *inputdev; + + inputdev = device->inputdevice; + + /* Now reverse all the registration stuff */ + if (device) { + input_unregister_device(inputdev); + usb_kill_urb(device->urbinfo); + usb_free_urb(device->urbinfo); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + kfree(device); + } + + info("gtco driver disconnected"); +} + + +/* STANDARD MODULE LOAD ROUTINES */ + +static struct usb_driver gtco_driverinfo_table = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + .owner = THIS_MODULE, +#endif + .name = "gtco", + .id_table = gtco_usbid_table, + .probe = gtco_probe, + .disconnect = gtco_disconnect, +}; +/* + * Register this module with the USB subsystem + */ +static int __init gtco_init(void) +{ + int rc; + rc = usb_register(>co_driverinfo_table); + if (rc) { + err("usb_register() failed rc=0x%x", rc); + } + printk("GTCO usb driver version: %s",GTCO_VERSION); + return rc; +} + +/* + * Deregister this module with the USB subsystem + */ +static void __exit gtco_exit(void) +{ + usb_deregister(>co_driverinfo_table); +} + +module_init (gtco_init); +module_exit (gtco_exit); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From d0532184086906889f4a0cd92eade1f7be49fbac Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 18 Jan 2007 15:06:07 +0100 Subject: USB: autosuspend for usb printer driver this implements autosuspend for usb printers. It compiles and is tested. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 6377db1b446..63e50a1f139 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file) retval = 0; #endif + retval = usb_autopm_get_interface(intf); + if (retval < 0) + goto out; usblp->used = 1; file->private_data = usblp; @@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file) usblp->used = 0; if (usblp->present) { usblp_unlink_urbs(usblp); + usb_autopm_put_interface(usblp->intf); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); mutex_unlock (&usblp_mutex); @@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message) { struct usblp *usblp = usb_get_intfdata (intf); - /* this races against normal access and open */ - mutex_lock (&usblp_mutex); - mutex_lock (&usblp->mut); /* we take no more IO */ usblp->sleeping = 1; usblp_unlink_urbs(usblp); - mutex_unlock (&usblp->mut); - mutex_unlock (&usblp_mutex); return 0; } @@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf) struct usblp *usblp = usb_get_intfdata (intf); int r; - mutex_lock (&usblp_mutex); - mutex_lock (&usblp->mut); - usblp->sleeping = 0; r = handle_bidir (usblp); - mutex_unlock (&usblp->mut); - mutex_unlock (&usblp_mutex); - return r; } @@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = { .suspend = usblp_suspend, .resume = usblp_resume, .id_table = usblp_ids, + .supports_autosuspend = 1, }; static int __init usblp_init(void) -- cgit v1.2.3 From 1d619f128ba911cd3e6d6ad3475f146eb92f5c27 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Sun, 21 Jan 2007 19:45:59 -0200 Subject: USB: switch ehci-hcd to new polling scheme Switch ehci-hcd to use the new polling scheme, which reports root hub status changes via the interrupt handler, in an asynchronous fashion. Doing so disables polling for status changes (whose handler is rh_timer_func). Tested on a Geode GX machine, which is now capable of running at =~ 5 timer interrupts per second (in the -rt tree), resulting in significant power savings. Signed-off-by: Marcelo Tosatti Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 92c62911f57..185721dba42 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -501,6 +501,9 @@ static int ehci_run (struct usb_hcd *hcd) u32 temp; u32 hcc_params; + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + /* EHCI spec section 4.1 */ if ((retval = ehci_reset(ehci)) != 0) { ehci_mem_cleanup(ehci); @@ -574,7 +577,7 @@ static int ehci_run (struct usb_hcd *hcd) static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status; + u32 status, pcd_status = 0; int bh; spin_lock (&ehci->lock); @@ -624,6 +627,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* remote wakeup [4.3.1] */ if (status & STS_PCD) { unsigned i = HCS_N_PORTS (ehci->hcs_params); + pcd_status = status; /* resume root hub? */ if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) @@ -670,6 +674,8 @@ dead: if (bh) ehci_work (ehci); spin_unlock (&ehci->lock); + if (pcd_status & STS_PCD) + usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; } -- cgit v1.2.3 From 629e4427aa817d5c9f11885420abf54b8f5967dc Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 22 Jan 2007 16:08:53 -0500 Subject: EHCI: fix interrupt-driven remote wakeup Now that port status change notifications are interrupt-driven, ehci-hcd needs to tell usbcore when a remote-wakeup resume operation is finished -- we can no longer rely on the core to poll and find out. This patch (as843) uses the root-hub status timer to force a poll after the resume is complete. The patch also changes the test for detecting when the TDRSMDN resume period has expired. It's necessary to use time_after_eq() instead of time_after(), since the polling is triggered precisely by a timer. The same change is made for TDRSTR reset expiration, for consistency. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 50 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 18 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 3cfba69e076..0d83c6df1a3 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -379,8 +379,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ehci->reset_done [i] = 0; if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 - && time_after (jiffies, - ehci->reset_done [i]))) { + && time_after_eq(jiffies, + ehci->reset_done[i]))) { if (i < 7) buf [0] |= 1 << (i + 1); else @@ -554,31 +554,45 @@ static int ehci_hub_control ( status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; /* whoever resumes must GetPortStatus to complete it!! */ - if ((temp & PORT_RESUME) - && time_after (jiffies, - ehci->reset_done [wIndex])) { - status |= 1 << USB_PORT_FEAT_C_SUSPEND; - ehci->reset_done [wIndex] = 0; + if (temp & PORT_RESUME) { - /* stop resume signaling */ - temp = ehci_readl(ehci, status_reg); - ehci_writel(ehci, + /* Remote Wakeup received? */ + if (!ehci->reset_done[wIndex]) { + /* resume signaling for 20 msec */ + ehci->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&ehci_to_hcd(ehci)->rh_timer, + ehci->reset_done[wIndex]); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + ehci->reset_done[wIndex])) { + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + ehci->reset_done[wIndex] = 0; + + /* stop resume signaling */ + temp = ehci_readl(ehci, status_reg); + ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESUME), status_reg); - retval = handshake(ehci, status_reg, + retval = handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - ehci_err (ehci, "port %d resume error %d\n", - wIndex + 1, retval); - goto error; + if (retval != 0) { + ehci_err(ehci, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } /* whoever resets must GetPortStatus to complete it!! */ if ((temp & PORT_RESET) - && time_after (jiffies, - ehci->reset_done [wIndex])) { + && time_after_eq(jiffies, + ehci->reset_done[wIndex])) { status |= 1 << USB_PORT_FEAT_C_RESET; ehci->reset_done [wIndex] = 0; -- cgit v1.2.3 From 1096f780d0b9d6bade2d42bf823e81db3e553abe Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 22 Jan 2007 11:58:34 -0500 Subject: usb-storage: use first bulk endpoints, not last According to the Bulk-Only spec, usb-storage is supposed to use the _first_ bulk-in and bulk-out endpoints it finds, not the _last_. And while we're at it, we ought to test the direction of the interrupt endpoint as well. This patch (as842) makes both changes. Signed-off-by: Alan Stern Cc: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 70644506651..7e7ec29782f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us) struct usb_endpoint_descriptor *ep_int = NULL; /* - * Find the endpoints we need. + * Find the first endpoint of each type we need. * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt is OK (necessary for CBI protocol). + * An optional interrupt-in is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; - /* Is it a BULK endpoint? */ if (usb_endpoint_xfer_bulk(ep)) { - /* BULK in or out? */ - if (usb_endpoint_dir_in(ep)) - ep_in = ep; - else - ep_out = ep; + if (usb_endpoint_dir_in(ep)) { + if (!ep_in) + ep_in = ep; + } else { + if (!ep_out) + ep_out = ep; + } } - /* Is it an interrupt endpoint? */ - else if (usb_endpoint_xfer_int(ep)) { - ep_int = ep; + else if (usb_endpoint_is_int_in(ep)) { + if (!ep_int) + ep_int = ep; } } -- cgit v1.2.3 From 9251644ab33579d80c038b077f78daa23a04fdcd Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 23 Jan 2007 15:55:28 -0500 Subject: usbcore: trivial whitespace fixes This patch (as844) makes some trivial whitespace fixes to a few files in usbcore. Oliver did most of the work and Alan added some tidying up. Signed-off-by: Oliver Neukum Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 98 ++++++++++++++++++++++++------------------------ drivers/usb/core/urb.c | 20 +++++----- drivers/usb/core/usb.c | 96 +++++++++++++++++++++++------------------------ 3 files changed, 107 insertions(+), 107 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 55d8f575206..4eaa0ee8e72 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -16,16 +16,16 @@ /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, \ +static ssize_t show_##field(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ \ - udev = to_usb_device (dev); \ + udev = to_usb_device(dev); \ actconfig = udev->actconfig; \ if (actconfig) \ - return sprintf (buf, format_string, \ + return sprintf(buf, format_string, \ actconfig->desc.field * multiplier); \ else \ return 0; \ @@ -35,9 +35,9 @@ static ssize_t show_##field (struct device *dev, \ usb_actconfig_show(field, multiplier, format_string) \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") -usb_actconfig_attr (bmAttributes, 1, "%2x\n") -usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") +usb_actconfig_attr(bNumInterfaces, 1, "%2d\n") +usb_actconfig_attr(bmAttributes, 1, "%2x\n") +usb_actconfig_attr(bMaxPower, 2, "%3dmA\n") static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) @@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev, struct usb_device *udev; struct usb_host_config *actconfig; - udev = to_usb_device (dev); + udev = to_usb_device(dev); actconfig = udev->actconfig; if ((!actconfig) || (!actconfig->string)) return 0; @@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, struct device_attribute *attr, +set_bConfigurationValue(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct usb_device *udev = to_usb_device (dev); + struct usb_device *udev = to_usb_device(dev); int config, value; - if (sscanf (buf, "%u", &config) != 1 || config > 255) + if (sscanf(buf, "%u", &config) != 1 || config > 255) return -EINVAL; usb_lock_device(udev); - value = usb_set_configuration (udev, config); + value = usb_set_configuration(udev, config); usb_unlock_device(udev); return (value < 0) ? value : count; } @@ -81,7 +81,7 @@ static ssize_t show_##name(struct device *dev, \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ + udev = to_usb_device(dev); \ return sprintf(buf, "%s\n", udev->name); \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); @@ -91,12 +91,12 @@ usb_string_attr(manufacturer); usb_string_attr(serial); static ssize_t -show_speed (struct device *dev, struct device_attribute *attr, char *buf) +show_speed(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; char *speed; - udev = to_usb_device (dev); + udev = to_usb_device(dev); switch (udev->speed) { case USB_SPEED_LOW: @@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf) default: speed = "unknown"; } - return sprintf (buf, "%s\n", speed); + return sprintf(buf, "%s\n", speed); } static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); static ssize_t -show_devnum (struct device *dev, struct device_attribute *attr, char *buf) +show_devnum(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->devnum); + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->devnum); } static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); static ssize_t -show_version (struct device *dev, struct device_attribute *attr, char *buf) +show_version(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; u16 bcdUSB; @@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t -show_maxchild (struct device *dev, struct device_attribute *attr, char *buf) +show_maxchild(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->maxchild); + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->maxchild); } static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, \ + udev = to_usb_device(dev); \ + return sprintf(buf, format_string, \ le16_to_cpu(udev->descriptor.field)); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); @@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, udev->descriptor.field); \ + udev = to_usb_device(dev); \ + return sprintf(buf, format_string, udev->descriptor.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_descriptor_attr (bDeviceClass, "%02x\n") -usb_descriptor_attr (bDeviceSubClass, "%02x\n") -usb_descriptor_attr (bDeviceProtocol, "%02x\n") -usb_descriptor_attr (bNumConfigurations, "%d\n") -usb_descriptor_attr (bMaxPacketSize0, "%d\n") +usb_descriptor_attr(bDeviceClass, "%02x\n") +usb_descriptor_attr(bDeviceSubClass, "%02x\n") +usb_descriptor_attr(bDeviceProtocol, "%02x\n") +usb_descriptor_attr(bNumConfigurations, "%d\n") +usb_descriptor_attr(bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) return retval; if (udev->manufacturer) { - retval = device_create_file (dev, &dev_attr_manufacturer); + retval = device_create_file(dev, &dev_attr_manufacturer); if (retval) goto error; } if (udev->product) { - retval = device_create_file (dev, &dev_attr_product); + retval = device_create_file(dev, &dev_attr_product); if (retval) goto error; } if (udev->serial) { - retval = device_create_file (dev, &dev_attr_serial); + retval = device_create_file(dev, &dev_attr_serial); if (retval) goto error; } @@ -246,7 +246,7 @@ error: return retval; } -void usb_remove_sysfs_dev_files (struct usb_device *udev) +void usb_remove_sysfs_dev_files(struct usb_device *udev) { struct device *dev = &udev->dev; @@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct usb_interface *intf = to_usb_interface (dev); \ + struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf (buf, format_string, \ + return sprintf(buf, format_string, \ intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_intf_attr (bInterfaceNumber, "%02x\n") -usb_intf_attr (bAlternateSetting, "%2d\n") -usb_intf_attr (bNumEndpoints, "%02x\n") -usb_intf_attr (bInterfaceClass, "%02x\n") -usb_intf_attr (bInterfaceSubClass, "%02x\n") -usb_intf_attr (bInterfaceProtocol, "%02x\n") +usb_intf_attr(bInterfaceNumber, "%02x\n") +usb_intf_attr(bAlternateSetting, "%2d\n") +usb_intf_attr(bNumEndpoints, "%02x\n") +usb_intf_attr(bInterfaceClass, "%02x\n") +usb_intf_attr(bInterfaceSubClass, "%02x\n") +usb_intf_attr(bInterfaceProtocol, "%02x\n") static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev, struct usb_device *udev; int len; - intf = to_usb_interface (dev); - udev = interface_to_usbdev (intf); + intf = to_usb_interface(dev); + udev = interface_to_usbdev(intf); len = snprintf(buf, 256, "%s", intf->cur_altsetting->string); if (len < 0) return 0; @@ -384,7 +384,7 @@ error: return retval; } -void usb_remove_sysfs_intf_files (struct usb_interface *intf) +void usb_remove_sysfs_intf_files(struct usb_interface *intf) { usb_remove_intf_ep_files(intf); sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index a4fa3e66c30..94ea9727ff5 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -240,10 +240,10 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * and don't need to duplicate tests */ pipe = urb->pipe; - temp = usb_pipetype (pipe); - is_out = usb_pipeout (pipe); + temp = usb_pipetype(pipe); + is_out = usb_pipeout(pipe); - if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) + if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; /* FIXME there should be a sharable lock protecting us against @@ -252,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * checks get made.) */ - max = usb_maxpacket (dev, pipe, is_out); + max = usb_maxpacket(dev, pipe, is_out); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint (pipe), is_out ? "out" : "in", + usb_pipeendpoint(pipe), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -278,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (urb->number_of_packets <= 0) return -EINVAL; for (n = 0; n < urb->number_of_packets; n++) { - len = urb->iso_frame_desc [n].length; + len = urb->iso_frame_desc[n].length; if (len < 0 || len > max) return -EMSGSIZE; - urb->iso_frame_desc [n].status = -EXDEV; - urb->iso_frame_desc [n].actual_length = 0; + urb->iso_frame_desc[n].status = -EXDEV; + urb->iso_frame_desc[n].actual_length = 0; } } @@ -321,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* fail if submitter gave bogus flags */ if (urb->transfer_flags != orig_flags) { - err ("BOGUS urb flags, %x --> %x", + err("BOGUS urb flags, %x --> %x", orig_flags, urb->transfer_flags); return -EINVAL; } @@ -372,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->interval = temp; } - return usb_hcd_submit_urb (urb, mem_flags); + return usb_hcd_submit_urb(urb, mem_flags); } /*-------------------------------------------------------------------*/ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 02426d0b9a3..3db721cd557 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work) * @parent: hub to which device is connected; null to allocate a root hub * @bus: bus used to access the device * @port1: one-based index of port; ignored for root hubs - * Context: !in_interrupt () + * Context: !in_interrupt() * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) * as stable: bus->busnum changes easily from modprobe order, * cardbus or pci hotplugging, and so on. */ - if (unlikely (!parent)) { - dev->devpath [0] = '0'; + if (unlikely(!parent)) { + dev->devpath[0] = '0'; dev->dev.parent = bus->controller; - sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum); + sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); } else { /* match any labeling on the hubs; it's one-based */ - if (parent->devpath [0] == '0') - snprintf (dev->devpath, sizeof dev->devpath, + if (parent->devpath[0] == '0') + snprintf(dev->devpath, sizeof dev->devpath, "%d", port1); else - snprintf (dev->devpath, sizeof dev->devpath, + snprintf(dev->devpath, sizeof dev->devpath, "%s.%d", parent->devpath, port1); dev->dev.parent = &parent->dev; - sprintf (&dev->dev.bus_id[0], "%d-%s", + sprintf(&dev->dev.bus_id[0], "%d-%s", bus->busnum, dev->devpath); /* hub driver sets up TT records */ @@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev, /* see if this device matches */ if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) && (product_id == le16_to_cpu(dev->descriptor.idProduct))) { - dev_dbg (&dev->dev, "matched this device!\n"); + dev_dbg(&dev->dev, "matched this device!\n"); ret_dev = usb_get_dev(dev); goto exit; } @@ -535,7 +535,7 @@ exit: */ int usb_get_current_frame_number(struct usb_device *dev) { - return usb_hcd_get_frame_number (dev); + return usb_hcd_get_frame_number(dev); } /*-------------------------------------------------------------------*/ @@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, * * When the buffer is no longer used, free it with usb_buffer_free(). */ -void *usb_buffer_alloc ( +void *usb_buffer_alloc( struct usb_device *dev, size_t size, gfp_t mem_flags, @@ -602,7 +602,7 @@ void *usb_buffer_alloc ( { if (!dev || !dev->bus) return NULL; - return hcd_buffer_alloc (dev->bus, size, mem_flags, dma); + return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); } /** @@ -616,7 +616,7 @@ void *usb_buffer_alloc ( * been allocated using usb_buffer_alloc(), and the parameters must match * those provided in that allocation request. */ -void usb_buffer_free ( +void usb_buffer_free( struct usb_device *dev, size_t size, void *addr, @@ -627,7 +627,7 @@ void usb_buffer_free ( return; if (!addr) return; - hcd_buffer_free (dev->bus, size, addr, dma); + hcd_buffer_free(dev->bus, size, addr, dma); } /** @@ -647,7 +647,7 @@ void usb_buffer_free ( * Reverse the effect of this call with usb_buffer_unmap(). */ #if 0 -struct urb *usb_buffer_map (struct urb *urb) +struct urb *usb_buffer_map(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb) return NULL; if (controller->dma_mask) { - urb->transfer_dma = dma_map_single (controller, + urb->transfer_dma = dma_map_single(controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = dma_map_single (controller, + if (usb_pipecontrol(urb->pipe)) + urb->setup_dma = dma_map_single(controller, urb->setup_packet, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); // FIXME generic api broken like pci, can't report errors // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; @@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb) * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) * @urb: urb whose transfer_buffer/setup_packet will be synchronized */ -void usb_buffer_dmasync (struct urb *urb) +void usb_buffer_dmasync(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb) return; if (controller->dma_mask) { - dma_sync_single (controller, + dma_sync_single(controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - dma_sync_single (controller, + if (usb_pipecontrol(urb->pipe)) + dma_sync_single(controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); } } @@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb) * Reverses the effect of usb_buffer_map(). */ #if 0 -void usb_buffer_unmap (struct urb *urb) +void usb_buffer_unmap(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb) return; if (controller->dma_mask) { - dma_unmap_single (controller, + dma_unmap_single(controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - dma_unmap_single (controller, + if (usb_pipecontrol(urb->pipe)) + dma_unmap_single(controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); } urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP @@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, struct device *controller; if (!dev - || usb_pipecontrol (pipe) + || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) return -1; // FIXME generic api broken like pci, can't report errors - return dma_map_sg (controller, sg, nents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + return dma_map_sg(controller, sg, nents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, || !controller->dma_mask) return; - dma_sync_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_sync_sg(controller, sg, n_hw_ents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif @@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, || !controller->dma_mask) return; - dma_unmap_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_unmap_sg(controller, sg, n_hw_ents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ @@ -871,7 +871,7 @@ static int __init usb_init(void) { int retval; if (nousb) { - pr_info ("%s: USB support disabled\n", usbcore_name); + pr_info("%s: USB support disabled\n", usbcore_name); return 0; } @@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); -EXPORT_SYMBOL (usb_buffer_alloc); -EXPORT_SYMBOL (usb_buffer_free); +EXPORT_SYMBOL(usb_buffer_alloc); +EXPORT_SYMBOL(usb_buffer_free); #if 0 -EXPORT_SYMBOL (usb_buffer_map); -EXPORT_SYMBOL (usb_buffer_dmasync); -EXPORT_SYMBOL (usb_buffer_unmap); +EXPORT_SYMBOL(usb_buffer_map); +EXPORT_SYMBOL(usb_buffer_dmasync); +EXPORT_SYMBOL(usb_buffer_unmap); #endif -EXPORT_SYMBOL (usb_buffer_map_sg); +EXPORT_SYMBOL(usb_buffer_map_sg); #if 0 -EXPORT_SYMBOL (usb_buffer_dmasync_sg); +EXPORT_SYMBOL(usb_buffer_dmasync_sg); #endif -EXPORT_SYMBOL (usb_buffer_unmap_sg); +EXPORT_SYMBOL(usb_buffer_unmap_sg); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 1a68f71d4fe71426a5c9703591e068241c03f896 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 25 Jan 2007 11:17:41 +0100 Subject: USB: a bit more coding style cleanup I was sitting in a train threatened to be blocked by ice. I took this as a hint to do some more boring work for the common good. Here's a bit more for coding style. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 36 ++++++++++++++++++------------------ drivers/usb/core/devices.c | 14 +++++++------- 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index c3915dc2860..ead2475406b 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = { * * Call hcd_buffer_destroy() to clean up after using those pools. */ -int hcd_buffer_create (struct usb_hcd *hcd) +int hcd_buffer_create(struct usb_hcd *hcd) { - char name [16]; + char name[16]; int i, size; if (!hcd->self.controller->dma_mask) @@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd) for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (!(size = pool_max [i])) continue; - snprintf (name, sizeof name, "buffer-%d", size); - hcd->pool [i] = dma_pool_create (name, hcd->self.controller, + snprintf(name, sizeof name, "buffer-%d", size); + hcd->pool[i] = dma_pool_create(name, hcd->self.controller, size, size, 0); if (!hcd->pool [i]) { - hcd_buffer_destroy (hcd); + hcd_buffer_destroy(hcd); return -ENOMEM; } } @@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd) * * This frees the buffer pools created by hcd_buffer_create(). */ -void hcd_buffer_destroy (struct usb_hcd *hcd) +void hcd_buffer_destroy(struct usb_hcd *hcd) { int i; for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool [i]; + struct dma_pool *pool = hcd->pool[i]; if (pool) { - dma_pool_destroy (pool); + dma_pool_destroy(pool); hcd->pool[i] = NULL; } } @@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) * better sharing and to leverage mm/slab.c intelligence. */ -void *hcd_buffer_alloc ( - struct usb_bus *bus, +void *hcd_buffer_alloc( + struct usb_bus *bus, size_t size, gfp_t mem_flags, dma_addr_t *dma @@ -110,18 +110,18 @@ void *hcd_buffer_alloc ( /* some USB hosts just use PIO */ if (!bus->controller->dma_mask) { *dma = ~(dma_addr_t) 0; - return kmalloc (size, mem_flags); + return kmalloc(size, mem_flags); } for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) - return dma_pool_alloc (hcd->pool [i], mem_flags, dma); + return dma_pool_alloc(hcd->pool [i], mem_flags, dma); } - return dma_alloc_coherent (hcd->self.controller, size, dma, 0); + return dma_alloc_coherent(hcd->self.controller, size, dma, 0); } -void hcd_buffer_free ( - struct usb_bus *bus, +void hcd_buffer_free( + struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma @@ -134,15 +134,15 @@ void hcd_buffer_free ( return; if (!bus->controller->dma_mask) { - kfree (addr); + kfree(addr); return; } for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) { - dma_pool_free (hcd->pool [i], addr, dma); + dma_pool_free(hcd->pool [i], addr, dma); return; } } - dma_free_coherent (hcd->self.controller, size, addr, dma); + dma_free_coherent(hcd->self.controller, size, addr, dma); } diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 1ff429c37d5..a47c30b2d76 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -164,10 +164,10 @@ static const char *class_decode(const int class) for (ix = 0; clas_info[ix].class != -1; ix++) if (clas_info[ix].class == class) break; - return (clas_info[ix].class_name); + return clas_info[ix].class_name; } -static char *usb_dump_endpoint_descriptor ( +static char *usb_dump_endpoint_descriptor( int speed, char *start, char *end, @@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor ( break; case USB_ENDPOINT_XFER_INT: type = "Int."; - if (speed == USB_SPEED_HIGH) { + if (speed == USB_SPEED_HIGH) interval = 1 << (desc->bInterval - 1); - } else + else interval = desc->bInterval; break; default: /* "can't happen" */ @@ -347,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb if (start > end) return start; - start += sprintf (start, format_device1, + start += sprintf(start, format_device1, bcdUSB >> 8, bcdUSB & 0xff, desc->bDeviceClass, class_decode (desc->bDeviceClass), @@ -367,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb /* * Dump the different strings that this device holds. */ -static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev) +static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev) { if (start > end) return start; @@ -399,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) if (start > end) return start; - start = usb_dump_device_strings (start, end, dev); + start = usb_dump_device_strings(start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (start > end) -- cgit v1.2.3 From 9da88d78bcb5610a4bb9e0e10dfb31cc9b4fdb1b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 25 Jan 2007 16:15:24 -0800 Subject: USB: remove duplicate device id from visor As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 3 --- drivers/usb/serial/visor.h | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 02cd6f7a2d6..2f59ff226e2 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), @@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 765118d83fb..4ce6f62a6f3 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -32,7 +32,6 @@ #define PALM_TUNGSTEN_T_ID 0x0060 #define PALM_TREO_650 0x0061 #define PALM_TUNGSTEN_Z_ID 0x0031 -#define PALM_ZIRE31_ID 0x0061 #define PALM_ZIRE_ID 0x0070 #define PALM_M100_ID 0x0080 -- cgit v1.2.3 From 210b1975795d4661127144365a889a7a4f2cf1fa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 25 Jan 2007 16:15:24 -0800 Subject: USB: remove duplicate device id from ftdi_sio As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 - drivers/usb/serial/ftdi_sio.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 35cad4249e5..4695952b647 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 40dd394de58..7eff1c03ba8 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -364,7 +364,6 @@ * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices * and I'm not entirely sure which are used by which. */ -#define FTDI_4N_GALAXY_DE_0_PID 0x8372 #define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 #define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 -- cgit v1.2.3 From 33c6b7e99fb043b7ae7d3deafb552a179a29b489 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 25 Jan 2007 16:15:24 -0800 Subject: USB: remove duplicate device id from keyspan As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/keyspan.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 2dc8964916f..c6830cbdc6d 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -229,7 +229,6 @@ struct ezusb_hex_record { #define keyspan_usa28_product_id 0x010f #define keyspan_usa28x_product_id 0x0110 #define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 #define keyspan_usa49w_product_id 0x010a #define keyspan_usa49wlc_product_id 0x012a @@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, { } /* Terminating entry */ @@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { } /* Terminating entry */ }; -- cgit v1.2.3 From ab6c41a498cd76085ce45ec407f5fe25968058a6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 25 Jan 2007 16:15:24 -0800 Subject: USB: remove duplicate device id from usb_storage As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f0fe29c1241..f49a62fc32d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1325,13 +1325,6 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -/* Reported by Jan Mate */ -UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, - "Sony Ericsson", - "P990i", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - /* Reported by Kevin Cernekee * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. -- cgit v1.2.3 From 72401339b545a8a0a66411c5a2486f602447d924 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Feb 2007 16:05:32 +0000 Subject: [PATCH] ps3 usb missed the addition of new argument to ps3_alloc_io_irq() Acked-by: Geoff Levand Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/host/ehci-ps3.c | 2 +- drivers/usb/host/ohci-ps3.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 371f194a9d3..4d781a2a980 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -104,7 +104,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 69d948b4a70..62283a3926d 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -107,7 +107,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", -- cgit v1.2.3 From 53ebb3b8264a77b6214f7a405300de8c24a12554 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Feb 2007 16:39:55 +0000 Subject: [PATCH] trivial usb endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/net/gl620a.c | 26 ++++++++++++-------------- drivers/usb/serial/cp2101.c | 8 ++++---- 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index a6f0f4d934d..31e5fe363fd 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -70,12 +70,12 @@ (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) struct gl_packet { - u32 packet_length; + __le32 packet_length; char packet_data [1]; }; struct gl_header { - u32 packet_count; + __le32 packet_count; struct gl_packet packets; }; @@ -85,15 +85,14 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) struct gl_packet *packet; struct sk_buff *gl_skb; u32 size; + u32 count; header = (struct gl_header *) skb->data; // get the packet count of the received skb - le32_to_cpus(&header->packet_count); - if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) - || (header->packet_count < 0)) { - dbg("genelink: invalid received packet count %d", - header->packet_count); + count = le32_to_cpu(header->packet_count); + if (count > GL_MAX_TRANSMIT_PACKETS) { + dbg("genelink: invalid received packet count %u", count); return 0; } @@ -103,7 +102,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) // decrement the length for the packet count size 4 bytes skb_pull(skb, 4); - while (header->packet_count > 1) { + while (count > 1) { // get the packet length size = le32_to_cpu(packet->packet_length); @@ -124,9 +123,8 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } // advance to the next packet - packet = (struct gl_packet *) - &packet->packet_data [size]; - header->packet_count--; + packet = (struct gl_packet *)&packet->packet_data[size]; + count--; // shift the data pointer to the next gl_packet skb_pull(skb, size + 4); @@ -149,8 +147,8 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) int length = skb->len; int headroom = skb_headroom(skb); int tailroom = skb_tailroom(skb); - u32 *packet_count; - u32 *packet_len; + __le32 *packet_count; + __le32 *packet_len; // FIXME: magic numbers, bleech padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; @@ -172,7 +170,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) } // attach the packet count to the header - packet_count = (u32 *) skb_push(skb, (4 + 4*1)); + packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); packet_len = packet_count + 1; *packet_count = cpu_to_le32(1); diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 06b4fffc189..3ec24870bca 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -170,13 +170,13 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kcalloc(length, sizeof(u32), GFP_KERNEL); + buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; @@ -216,13 +216,13 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kmalloc(length * sizeof(u32), GFP_KERNEL); + buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); -- cgit v1.2.3 From 68f50e52554a0a55dfe2e3fdf659ee0569d73c3f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Feb 2007 16:40:00 +0000 Subject: [PATCH] hci_{read,write}l() does force casts to wrong type for no reason readl() et.al. expect iomem pointer, so WTF force-cast it to normal one??? Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/usb/host/ehci.h | 12 ++++++------ drivers/usb/host/ohci.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index ec0da0343be..46fa57a520d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -677,10 +677,10 @@ static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO return ehci_big_endian_mmio(ehci) ? - readl_be((__force u32 *)regs) : - readl((__force u32 *)regs); + readl_be(regs) : + readl(regs); #else - return readl((__force u32 *)regs); + return readl(regs); #endif } @@ -689,10 +689,10 @@ static inline void ehci_writel (const struct ehci_hcd *ehci, { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO ehci_big_endian_mmio(ehci) ? - writel_be(val, (__force u32 *)regs) : - writel(val, (__force u32 *)regs); + writel_be(val, regs) : + writel(val, regs); #else - writel(val, (__force u32 *)regs); + writel(val, regs); #endif } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 0dafcda3729..c2b5ecfe5e9 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -507,10 +507,10 @@ static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, { #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO return big_endian_mmio(ohci) ? - readl_be ((__force u32 *)regs) : - readl ((__force u32 *)regs); + readl_be (regs) : + readl (regs); #else - return readl ((__force u32 *)regs); + return readl (regs); #endif } @@ -519,10 +519,10 @@ static inline void _ohci_writel (const struct ohci_hcd *ohci, { #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO big_endian_mmio(ohci) ? - writel_be (val, (__force u32 *)regs) : - writel (val, (__force u32 *)regs); + writel_be (val, regs) : + writel (val, regs); #else - writel (val, (__force u32 *)regs); + writel (val, regs); #endif } -- cgit v1.2.3