diff --git a/[refs] b/[refs] index b04b002c6dfa..8355a2ff4c45 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 80618fa83a34a26199fa99cfd06476a81ddf57df +refs/heads/master: 3ee86dcdd273aa91cb9b4fe1e3d4f69035750a12 diff --git a/trunk/Documentation/ABI/testing/sysfs-class-uwb_rc b/trunk/Documentation/ABI/testing/sysfs-class-uwb_rc index 6a5fd072849d..a0d18dbeb7a9 100644 --- a/trunk/Documentation/ABI/testing/sysfs-class-uwb_rc +++ b/trunk/Documentation/ABI/testing/sysfs-class-uwb_rc @@ -32,16 +32,14 @@ Contact: linux-usb@vger.kernel.org Description: Write: - + [] - to force a specific channel to be used when beaconing, - or, if is -1, to prohibit beaconing. If - is 0, then the default channel selection - algorithm will be used. Valid channels depends on the - radio controller's supported band groups. + to start beaconing on a specific channel, or stop + beaconing if is -1. Valid channels depends + on the radio controller's supported band groups. - Reading returns the currently active channel, or -1 if - the radio controller is not beaconing. + may be used to try and join a specific + beacon group if more than one was found during a scan. What: /sys/class/uwb_rc/uwbN/scan Date: July 2008 diff --git a/trunk/Documentation/filesystems/devpts.txt b/trunk/Documentation/filesystems/devpts.txt deleted file mode 100644 index 68dffd87f9b7..000000000000 --- a/trunk/Documentation/filesystems/devpts.txt +++ /dev/null @@ -1,132 +0,0 @@ - -To support containers, we now allow multiple instances of devpts filesystem, -such that indices of ptys allocated in one instance are independent of indices -allocated in other instances of devpts. - -To preserve backward compatibility, this support for multiple instances is -enabled only if: - - - CONFIG_DEVPTS_MULTIPLE_INSTANCES=y, and - - '-o newinstance' mount option is specified while mounting devpts - -IOW, devpts now supports both single-instance and multi-instance semantics. - -If CONFIG_DEVPTS_MULTIPLE_INSTANCES=n, there is no change in behavior and -this referred to as the "legacy" mode. In this mode, the new mount options -(-o newinstance and -o ptmxmode) will be ignored with a 'bogus option' message -on console. - -If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and devpts is mounted without the -'newinstance' option (as in current start-up scripts) the new mount binds -to the initial kernel mount of devpts. This mode is referred to as the -'single-instance' mode and the current, single-instance semantics are -preserved, i.e PTYs are common across the system. - -The only difference between this single-instance mode and the legacy mode -is the presence of new, '/dev/pts/ptmx' node with permissions 0000, which -can safely be ignored. - -If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and 'newinstance' option is specified, -the mount is considered to be in the multi-instance mode and a new instance -of the devpts fs is created. Any ptys created in this instance are independent -of ptys in other instances of devpts. Like in the single-instance mode, the -/dev/pts/ptmx node is present. To effectively use the multi-instance mode, -open of /dev/ptmx must be a redirected to '/dev/pts/ptmx' using a symlink or -bind-mount. - -Eg: A container startup script could do the following: - - $ chmod 0666 /dev/pts/ptmx - $ rm /dev/ptmx - $ ln -s pts/ptmx /dev/ptmx - $ ns_exec -cm /bin/bash - - # We are now in new container - - $ umount /dev/pts - $ mount -t devpts -o newinstance lxcpts /dev/pts - $ sshd -p 1234 - -where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs -/bin/bash in the child process. A pty created by the sshd is not visible in -the original mount of /dev/pts. - -User-space changes ------------------- - -In multi-instance mode (i.e '-o newinstance' mount option is specified at least -once), following user-space issues should be noted. - -1. If -o newinstance mount option is never used, /dev/pts/ptmx can be ignored - and no change is needed to system-startup scripts. - -2. To effectively use multi-instance mode (i.e -o newinstance is specified) - administrators or startup scripts should "redirect" open of /dev/ptmx to - /dev/pts/ptmx using either a bind mount or symlink. - - $ mount -t devpts -o newinstance devpts /dev/pts - - followed by either - - $ rm /dev/ptmx - $ ln -s pts/ptmx /dev/ptmx - $ chmod 666 /dev/pts/ptmx - or - $ mount -o bind /dev/pts/ptmx /dev/ptmx - -3. The '/dev/ptmx -> pts/ptmx' symlink is the preferred method since it - enables better error-reporting and treats both single-instance and - multi-instance mounts similarly. - - But this method requires that system-startup scripts set the mode of - /dev/pts/ptmx correctly (default mode is 0000). The scripts can set the - mode by, either - - - adding ptmxmode mount option to devpts entry in /etc/fstab, or - - using 'chmod 0666 /dev/pts/ptmx' - -4. If multi-instance mode mount is needed for containers, but the system - startup scripts have not yet been updated, container-startup scripts - should bind mount /dev/ptmx to /dev/pts/ptmx to avoid breaking single- - instance mounts. - - Or, in general, container-startup scripts should use: - - mount -t devpts -o newinstance -o ptmxmode=0666 devpts /dev/pts - if [ ! -L /dev/ptmx ]; then - mount -o bind /dev/pts/ptmx /dev/ptmx - fi - - When all devpts mounts are multi-instance, /dev/ptmx can permanently be - a symlink to pts/ptmx and the bind mount can be ignored. - -5. A multi-instance mount that is not accompanied by the /dev/ptmx to - /dev/pts/ptmx redirection would result in an unusable/unreachable pty. - - mount -t devpts -o newinstance lxcpts /dev/pts - - immediately followed by: - - open("/dev/ptmx") - - would create a pty, say /dev/pts/7, in the initial kernel mount. - But /dev/pts/7 would be invisible in the new mount. - -6. The permissions for /dev/pts/ptmx node should be specified when mounting - /dev/pts, using the '-o ptmxmode=%o' mount option (default is 0000). - - mount -t devpts -o newinstance -o ptmxmode=0644 devpts /dev/pts - - The permissions can be later be changed as usual with 'chmod'. - - chmod 666 /dev/pts/ptmx - -7. A mount of devpts without the 'newinstance' option results in binding to - initial kernel mount. This behavior while preserving legacy semantics, - does not provide strict isolation in a container environment. i.e by - mounting devpts without the 'newinstance' option, a container could - get visibility into the 'host' or root container's devpts. - - To workaround this and have strict isolation, all mounts of devpts, - including the mount in the root container, should use the newinstance - option. diff --git a/trunk/Documentation/usb/wusb-cbaf b/trunk/Documentation/usb/wusb-cbaf index 426ddaaef96f..2e78b70f3adc 100644 --- a/trunk/Documentation/usb/wusb-cbaf +++ b/trunk/Documentation/usb/wusb-cbaf @@ -80,6 +80,12 @@ case $1 in start) for dev in ${2:-$hdevs} do + uwb_rc=$(readlink -f $dev/uwb_rc) + if cat $uwb_rc/beacon | grep -q -- "-1" + then + echo 13 0 > $uwb_rc/beacon + echo I: started beaconing on ch 13 on $(basename $uwb_rc) >&2 + fi echo $host_CHID > $dev/wusb_chid echo I: started host $(basename $dev) >&2 done @@ -89,6 +95,9 @@ case $1 in do echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid echo I: stopped host $(basename $dev) >&2 + uwb_rc=$(readlink -f $dev/uwb_rc) + echo -1 | cat > $uwb_rc/beacon + echo I: stopped beaconing on $(basename $uwb_rc) >&2 done ;; set-chid) diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 3148de29afa7..ceb32ee51f9d 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2049,12 +2049,6 @@ M: mikulas@artax.karlin.mff.cuni.cz W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained -HSO 3G Modem Driver (hso.c) -P: Denis Joseph Barrow -M: d.barow@option.com -W: http://www.pharscape.org -S: Maintained - HTCPEN TOUCHSCREEN DRIVER P: Pau Oliva Fora M: pof@eslack.org @@ -2641,13 +2635,13 @@ W: http://www.hansenpartnership.com/voyager S: Maintained LINUX FOR POWERPC (32-BIT AND 64-BIT) -P: Benjamin Herrenschmidt -M: benh@kernel.crashing.org P: Paul Mackerras M: paulus@samba.org +P: Benjamin Herrenschmidt +M: benh@kernel.crashing.org W: http://www.penguinppc.org/ L: linuxppc-dev@ozlabs.org -T: git kernel.org:/pub/scm/linux/kernel/git/benh/powerpc.git +T: git kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc.git S: Supported LINUX FOR POWER MACINTOSH diff --git a/trunk/arch/x86/mm/init_32.c b/trunk/arch/x86/mm/init_32.c index f99a6c6c432e..8655b5bb0963 100644 --- a/trunk/arch/x86/mm/init_32.c +++ b/trunk/arch/x86/mm/init_32.c @@ -435,12 +435,8 @@ static void __init set_highmem_pages_init(void) #endif /* !CONFIG_NUMA */ #else -static inline void permanent_kmaps_init(pgd_t *pgd_base) -{ -} -static inline void set_highmem_pages_init(void) -{ -} +# define permanent_kmaps_init(pgd_base) do { } while (0) +# define set_highmem_pages_init() do { } while (0) #endif /* CONFIG_HIGHMEM */ void __init native_pagetable_setup_start(pgd_t *base) diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig index 1697043119bd..c602b547cc6e 100644 --- a/trunk/drivers/char/Kconfig +++ b/trunk/drivers/char/Kconfig @@ -190,7 +190,7 @@ config DIGIEPCA config ESPSERIAL tristate "Hayes ESP serial port support" - depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API && BROKEN + depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API help This is a driver which supports Hayes ESP serial ports. Both single port cards and multiport cards are supported. Make sure to read @@ -443,17 +443,6 @@ config UNIX98_PTYS All modern Linux systems use the Unix98 ptys. Say Y unless you're on an embedded system and want to conserve memory. -config DEVPTS_MULTIPLE_INSTANCES - bool "Support multiple instances of devpts" - depends on UNIX98_PTYS - default n - ---help--- - Enable support for multiple instances of devpts filesystem. - If you want to have isolated PTY namespaces (eg: in containers), - say Y here. Otherwise, say N. If enabled, each mount of devpts - filesystem with the '-o newinstance' option will create an - independent PTY namespace. - config LEGACY_PTYS bool "Legacy (BSD) PTY support" default y diff --git a/trunk/drivers/char/amiserial.c b/trunk/drivers/char/amiserial.c index 4e0cfdeab146..b97aebd7aeb8 100644 --- a/trunk/drivers/char/amiserial.c +++ b/trunk/drivers/char/amiserial.c @@ -170,7 +170,7 @@ static __inline__ void rtsdtr_ctrl(int bits) */ static void rs_stop(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_stop")) @@ -190,7 +190,7 @@ static void rs_stop(struct tty_struct *tty) static void rs_start(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_start")) @@ -861,7 +861,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) static void rs_flush_chars(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) @@ -934,7 +934,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count static int rs_write_room(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_write_room")) return 0; @@ -943,7 +943,7 @@ static int rs_write_room(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) return 0; @@ -952,7 +952,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) @@ -969,7 +969,7 @@ static void rs_flush_buffer(struct tty_struct *tty) */ static void rs_send_xchar(struct tty_struct *tty, char ch) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_send_char")) @@ -1004,7 +1004,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) */ static void rs_throttle(struct tty_struct * tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1029,7 +1029,7 @@ static void rs_throttle(struct tty_struct * tty) static void rs_unthrottle(struct tty_struct * tty) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1194,7 +1194,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value) static int rs_tiocmget(struct tty_struct *tty, struct file *file) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned char control, status; unsigned long flags; @@ -1217,7 +1217,7 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file) static int rs_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_ioctl")) @@ -1244,7 +1244,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, */ static int rs_break(struct tty_struct *tty, int break_state) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_break")) @@ -1264,7 +1264,7 @@ static int rs_break(struct tty_struct *tty, int break_state) static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct icount; void __user *argp = (void __user *)arg; @@ -1368,7 +1368,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct async_struct *info = tty->driver_data; + struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; unsigned int cflag = tty->termios->c_cflag; @@ -1428,7 +1428,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) */ static void rs_close(struct tty_struct *tty, struct file * filp) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *state; unsigned long flags; @@ -1523,7 +1523,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long orig_jiffies, char_time; int lsr; @@ -1587,7 +1587,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) */ static void rs_hangup(struct tty_struct *tty) { - struct async_struct * info = tty->driver_data; + struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *state = info->state; if (serial_paranoia_check(info, tty->name, "rs_hangup")) diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c index 6a59f72a9c21..5e5b1dc1a0a7 100644 --- a/trunk/drivers/char/cyclades.c +++ b/trunk/drivers/char/cyclades.c @@ -5010,7 +5010,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, if (nchan == 0) { dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " "Serial-Modules\n"); - goto err_unmap; + return -EIO; } } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { struct RUNTIME_9060 __iomem *ctl_addr; diff --git a/trunk/drivers/char/epca.c b/trunk/drivers/char/epca.c index 39ad820b2350..cf2461d34e5f 100644 --- a/trunk/drivers/char/epca.c +++ b/trunk/drivers/char/epca.c @@ -69,9 +69,7 @@ static int invalid_lilo_config; /* * The ISA boards do window flipping into the same spaces so its only sane with - * a single lock. It's still pretty efficient. This lock guards the hardware - * and the tty_port lock guards the kernel side stuff like use counts. Take - * this lock inside the port lock if you must take both. + * a single lock. It's still pretty efficient. */ static DEFINE_SPINLOCK(epca_lock); @@ -158,12 +156,14 @@ static struct channel *verifyChannel(struct tty_struct *); static void pc_sched_event(struct channel *, int); static void epca_error(int, char *); static void pc_close(struct tty_struct *, struct file *); -static void shutdown(struct channel *, struct tty_struct *tty); +static void shutdown(struct channel *); static void pc_hangup(struct tty_struct *); static int pc_write_room(struct tty_struct *); static int pc_chars_in_buffer(struct tty_struct *); static void pc_flush_buffer(struct tty_struct *); static void pc_flush_chars(struct tty_struct *); +static int block_til_ready(struct tty_struct *, struct file *, + struct channel *); static int pc_open(struct tty_struct *, struct file *); static void post_fep_init(unsigned int crd); static void epcapoll(unsigned long); @@ -173,7 +173,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned); static unsigned termios2digi_i(struct channel *ch, unsigned); static unsigned termios2digi_c(struct channel *ch, unsigned); static void epcaparam(struct tty_struct *, struct channel *); -static void receive_data(struct channel *, struct tty_struct *tty); +static void receive_data(struct channel *); static int pc_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static int info_ioctl(struct tty_struct *, struct file *, @@ -392,7 +392,7 @@ static struct channel *verifyChannel(struct tty_struct *tty) * through tty->driver_data this should catch it. */ if (tty) { - struct channel *ch = tty->driver_data; + struct channel *ch = (struct channel *)tty->driver_data; if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) { if (ch->magic == EPCA_MAGIC) return ch; @@ -419,34 +419,76 @@ static void epca_error(int line, char *msg) static void pc_close(struct tty_struct *tty, struct file *filp) { struct channel *ch; - struct tty_port *port; + unsigned long flags; /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ ch = verifyChannel(tty); - if (ch == NULL) - return; - port = &ch->port; + if (ch != NULL) { + spin_lock_irqsave(&epca_lock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&epca_lock, flags); + return; + } + if (ch->port.count-- > 1) { + /* Begin channel is open more than once */ + /* + * Return without doing anything. Someone might still + * be using the channel. + */ + spin_unlock_irqrestore(&epca_lock, flags); + return; + } + /* Port open only once go ahead with shutdown & reset */ + BUG_ON(ch->port.count < 0); - if (tty_port_close_start(port, tty, filp) == 0) - return; + /* + * Let the rest of the driver know the channel is being closed. + * This becomes important if an open is attempted before close + * is finished. + */ + ch->port.flags |= ASYNC_CLOSING; + tty->closing = 1; - pc_flush_buffer(tty); - shutdown(ch, tty); + spin_unlock_irqrestore(&epca_lock, flags); + + if (ch->port.flags & ASYNC_INITIALIZED) { + /* Setup an event to indicate when the + transmit buffer empties */ + setup_empty_event(tty, ch); + /* 30 seconds timeout */ + tty_wait_until_sent(tty, 3000); + } + pc_flush_buffer(tty); - tty_port_close_end(port, tty); - ch->event = 0; /* FIXME: review ch->event locking */ - tty_port_tty_set(port, NULL); + tty_ldisc_flush(tty); + shutdown(ch); + + spin_lock_irqsave(&epca_lock, flags); + tty->closing = 0; + ch->event = 0; + ch->port.tty = NULL; + spin_unlock_irqrestore(&epca_lock, flags); + + if (ch->port.blocked_open) { + if (ch->close_delay) + msleep_interruptible(jiffies_to_msecs(ch->close_delay)); + wake_up_interruptible(&ch->port.open_wait); + } + ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | + ASYNC_CLOSING); + wake_up_interruptible(&ch->port.close_wait); + } } -static void shutdown(struct channel *ch, struct tty_struct *tty) +static void shutdown(struct channel *ch) { unsigned long flags; + struct tty_struct *tty; struct board_chan __iomem *bc; - struct tty_port *port = &ch->port; - if (!(port->flags & ASYNC_INITIALIZED)) + if (!(ch->port.flags & ASYNC_INITIALIZED)) return; spin_lock_irqsave(&epca_lock, flags); @@ -461,6 +503,7 @@ static void shutdown(struct channel *ch, struct tty_struct *tty) */ if (bc) writeb(0, &bc->idata); + tty = ch->port.tty; /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */ if (tty->termios->c_cflag & HUPCL) { @@ -474,26 +517,32 @@ static void shutdown(struct channel *ch, struct tty_struct *tty) * will have to reinitialized. Set a flag to indicate this. */ /* Prevent future Digi programmed interrupts from coming active */ - port->flags &= ~ASYNC_INITIALIZED; + ch->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&epca_lock, flags); } static void pc_hangup(struct tty_struct *tty) { struct channel *ch; - /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ ch = verifyChannel(tty); if (ch != NULL) { + unsigned long flags; + pc_flush_buffer(tty); tty_ldisc_flush(tty); - shutdown(ch, tty); + shutdown(ch); - ch->event = 0; /* FIXME: review locking of ch->event */ - tty_port_hangup(&ch->port); + spin_lock_irqsave(&epca_lock, flags); + ch->port.tty = NULL; + ch->event = 0; + ch->port.count = 0; + ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); + spin_unlock_irqrestore(&epca_lock, flags); + wake_up_interruptible(&ch->port.open_wait); } } @@ -737,22 +786,100 @@ static void pc_flush_chars(struct tty_struct *tty) } } -static int epca_carrier_raised(struct tty_port *port) +static int block_til_ready(struct tty_struct *tty, + struct file *filp, struct channel *ch) { - struct channel *ch = container_of(port, struct channel, port); - if (ch->imodem & ch->dcd) - return 1; - return 0; -} + DECLARE_WAITQUEUE(wait, current); + int retval, do_clocal = 0; + unsigned long flags; -static void epca_raise_dtr_rts(struct tty_port *port) -{ + if (tty_hung_up_p(filp)) { + if (ch->port.flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + return retval; + } + + /* + * If the device is in the middle of being closed, then block until + * it's done, and then try again. + */ + if (ch->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&ch->port.close_wait); + + if (ch->port.flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + if (filp->f_flags & O_NONBLOCK) { + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + ch->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* Block waiting for the carrier detect and the line to become free */ + + retval = 0; + add_wait_queue(&ch->port.open_wait, &wait); + + spin_lock_irqsave(&epca_lock, flags); + /* We dec count so that pc_close will know when to free things */ + if (!tty_hung_up_p(filp)) + ch->port.count--; + ch->port.blocked_open++; + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(ch->port.flags & ASYNC_INITIALIZED)) { + if (ch->port.flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(ch->port.flags & ASYNC_CLOSING) && + (do_clocal || (ch->imodem & ch->dcd))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + spin_unlock_irqrestore(&epca_lock, flags); + /* + * Allow someone else to be scheduled. We will occasionally go + * through this loop until one of the above conditions change. + * The below schedule call will allow other processes to enter + * and prevent this loop from hogging the cpu. + */ + schedule(); + spin_lock_irqsave(&epca_lock, flags); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&ch->port.open_wait, &wait); + if (!tty_hung_up_p(filp)) + ch->port.count++; + ch->port.blocked_open--; + + spin_unlock_irqrestore(&epca_lock, flags); + + if (retval) + return retval; + + ch->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; } static int pc_open(struct tty_struct *tty, struct file *filp) { struct channel *ch; - struct tty_port *port; unsigned long flags; int line, retval, boardnum; struct board_chan __iomem *bc; @@ -763,7 +890,6 @@ static int pc_open(struct tty_struct *tty, struct file *filp) return -ENODEV; ch = &digi_channels[line]; - port = &ch->port; boardnum = ch->boardnum; /* Check status of board configured in system. */ @@ -800,24 +926,22 @@ static int pc_open(struct tty_struct *tty, struct file *filp) return -ENODEV; } - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&epca_lock, flags); /* * Every time a channel is opened, increment a counter. This is * necessary because we do not wish to flush and shutdown the channel * until the last app holding the channel open, closes it. */ - port->count++; + ch->port.count++; /* * Set a kernel structures pointer to our local channel structure. This * way we can get to it when passed only a tty struct. */ tty->driver_data = ch; - port->tty = tty; /* * If this is the first time the channel has been opened, initialize * the tty->termios struct otherwise let pc_close handle it. */ - spin_lock(&epca_lock); globalwinon(ch); ch->statusflags = 0; @@ -832,33 +956,31 @@ static int pc_open(struct tty_struct *tty, struct file *filp) writew(head, &bc->rout); /* Set the channels associated tty structure */ + ch->port.tty = tty; /* * The below routine generally sets up parity, baud, flow control * issues, etc.... It effect both control flags and input flags. */ epcaparam(tty, ch); + ch->port.flags |= ASYNC_INITIALIZED; memoff(ch); - spin_unlock(&epca_lock); - port->flags |= ASYNC_INITIALIZED; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&epca_lock, flags); - retval = tty_port_block_til_ready(port, tty, filp); + retval = block_til_ready(tty, filp, ch); if (retval) return retval; /* * Set this again in case a hangup set it to zero while this open() was * waiting for the line... */ - spin_lock_irqsave(&port->lock, flags); - port->tty = tty; - spin_lock(&epca_lock); + spin_lock_irqsave(&epca_lock, flags); + ch->port.tty = tty; globalwinon(ch); /* Enable Digi Data events */ writeb(1, &bc->idata); memoff(ch); - spin_unlock(&epca_lock); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&epca_lock, flags); return 0; } @@ -894,11 +1016,8 @@ static void __exit epca_module_exit(void) } ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { - struct tty_struct *tty = tty_port_tty_get(&ch->port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } + if (ch && ch->port.tty) + tty_hangup(ch->port.tty); } } pci_unregister_driver(&epca_driver); @@ -923,11 +1042,6 @@ static const struct tty_operations pc_ops = { .break_ctl = pc_send_break }; -static const struct tty_port_operations epca_port_ops = { - .carrier_raised = epca_carrier_raised, - .raise_dtr_rts = epca_raise_dtr_rts, -}; - static int info_open(struct tty_struct *tty, struct file *filp) { return 0; @@ -1263,7 +1377,6 @@ static void post_fep_init(unsigned int crd) u16 tseg, rseg; tty_port_init(&ch->port); - ch->port.ops = &epca_port_ops; ch->brdchan = bc; ch->mailbox = gd; INIT_WORK(&ch->tqueue, do_softint); @@ -1315,7 +1428,7 @@ static void post_fep_init(unsigned int crd) ch->boardnum = crd; ch->channelnum = i; ch->magic = EPCA_MAGIC; - tty_port_tty_set(&ch->port, NULL); + ch->port.tty = NULL; if (shrinkmem) { fepcmd(ch, SETBUFFER, 32, 0, 0, 0); @@ -1397,7 +1510,7 @@ static void post_fep_init(unsigned int crd) ch->fepstartca = 0; ch->fepstopca = 0; - ch->port.close_delay = 50; + ch->close_delay = 50; spin_unlock_irqrestore(&epca_lock, flags); } @@ -1509,16 +1622,15 @@ static void doevent(int crd) if (bc == NULL) goto next; - tty = tty_port_tty_get(&ch->port); if (event & DATA_IND) { /* Begin DATA_IND */ - receive_data(ch, tty); + receive_data(ch); assertgwinon(ch); } /* End DATA_IND */ /* else *//* Fix for DCD transition missed bug */ if (event & MODEMCHG_IND) { /* A modem signal change has been indicated */ ch->imodem = mstat; - if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) { + if (ch->port.flags & ASYNC_CHECK_CD) { /* We are now receiving dcd */ if (mstat & ch->dcd) wake_up_interruptible(&ch->port.open_wait); @@ -1526,6 +1638,7 @@ static void doevent(int crd) pc_sched_event(ch, EPCA_EVENT_HANGUP); } } + tty = ch->port.tty; if (tty) { if (event & BREAK_IND) { /* A break has been indicated */ @@ -1545,7 +1658,6 @@ static void doevent(int crd) tty_wakeup(tty); } } - tty_kref_put(tty); } next: globalwinon(ch); @@ -1765,9 +1877,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) * that the driver will wait on carrier detect. */ if (ts->c_cflag & CLOCAL) - clear_bit(ASYNC_CHECK_CD, &ch->port.flags); + ch->port.flags &= ~ASYNC_CHECK_CD; else - set_bit(ASYNC_CHECK_CD, &ch->port.flags); + ch->port.flags |= ASYNC_CHECK_CD; mval = ch->m_dtr | ch->m_rts; } /* End CBAUD not detected */ iflag = termios2digi_i(ch, ts->c_iflag); @@ -1840,10 +1952,11 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) } /* Caller holds lock */ -static void receive_data(struct channel *ch, struct tty_struct *tty) +static void receive_data(struct channel *ch) { unchar *rptr; struct ktermios *ts = NULL; + struct tty_struct *tty; struct board_chan __iomem *bc; int dataToRead, wrapgap, bytesAvailable; unsigned int tail, head; @@ -1856,6 +1969,7 @@ static void receive_data(struct channel *ch, struct tty_struct *tty) globalwinon(ch); if (ch->statusflags & RXSTOPPED) return; + tty = ch->port.tty; if (tty) ts = tty->termios; bc = ch->brdchan; @@ -1915,7 +2029,7 @@ static void receive_data(struct channel *ch, struct tty_struct *tty) globalwinon(ch); writew(tail, &bc->rout); /* Must be called with global data */ - tty_schedule_flip(tty); + tty_schedule_flip(ch->port.tty); } static int info_ioctl(struct tty_struct *tty, struct file *file, @@ -1983,7 +2097,7 @@ static int info_ioctl(struct tty_struct *tty, struct file *file, static int pc_tiocmget(struct tty_struct *tty, struct file *file) { - struct channel *ch = tty->driver_data; + struct channel *ch = (struct channel *) tty->driver_data; struct board_chan __iomem *bc; unsigned int mstat, mflag = 0; unsigned long flags; @@ -2017,7 +2131,7 @@ static int pc_tiocmget(struct tty_struct *tty, struct file *file) static int pc_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct channel *ch = tty->driver_data; + struct channel *ch = (struct channel *) tty->driver_data; unsigned long flags; if (!ch) @@ -2064,7 +2178,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file, unsigned int mflag, mstat; unsigned char startc, stopc; struct board_chan __iomem *bc; - struct channel *ch = tty->driver_data; + struct channel *ch = (struct channel *) tty->driver_data; void __user *argp = (void __user *)arg; if (ch) @@ -2238,16 +2352,15 @@ static void do_softint(struct work_struct *work) struct channel *ch = container_of(work, struct channel, tqueue); /* Called in response to a modem change event */ if (ch && ch->magic == EPCA_MAGIC) { - struct tty_struct *tty = tty_port_tty_get(&ch->port);; + struct tty_struct *tty = ch->port.tty; if (tty && tty->driver_data) { if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { tty_hangup(tty); wake_up_interruptible(&ch->port.open_wait); - clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags); + ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; } } - tty_kref_put(tty); } } @@ -2360,7 +2473,7 @@ static void pc_unthrottle(struct tty_struct *tty) static int pc_send_break(struct tty_struct *tty, int msec) { - struct channel *ch = tty->driver_data; + struct channel *ch = (struct channel *) tty->driver_data; unsigned long flags; if (msec == -1) diff --git a/trunk/drivers/char/esp.c b/trunk/drivers/char/esp.c index 45ec263ec012..7f077c0097f6 100644 --- a/trunk/drivers/char/esp.c +++ b/trunk/drivers/char/esp.c @@ -2054,15 +2054,6 @@ static void esp_hangup(struct tty_struct *tty) wake_up_interruptible(&info->port.open_wait); } -static int esp_carrier_raised(struct tty_port *port) -{ - struct esp_struct *info = container_of(port, struct esp_struct, port); - serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); - if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) - return 1; - return 0; -} - /* * ------------------------------------------------------------ * esp_open() and friends @@ -2075,19 +2066,17 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, int retval; int do_clocal = 0; unsigned long flags; - int cd; - struct tty_port *port = &info->port; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (tty_hung_up_p(filp) || - (port->flags & ASYNC_CLOSING)) { - if (port->flags & ASYNC_CLOSING) - interruptible_sleep_on(&port->close_wait); + (info->port.flags & ASYNC_CLOSING)) { + if (info->port.flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->port.close_wait); #ifdef SERIAL_DO_RESTART - if (port->flags & ASYNC_HUP_NOTIFY) + if (info->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -2102,7 +2091,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2112,20 +2101,20 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n", - info->line, port->count); + info->line, info->port.count); #endif spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) - port->count--; - port->blocked_open++; + info->port.count--; + info->port.blocked_open++; while (1) { if ((tty->termios->c_cflag & CBAUD)) { unsigned int scratch; @@ -2140,9 +2129,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { + !(info->port.flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (port->flags & ASYNC_HUP_NOTIFY) + if (info->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -2152,9 +2141,11 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, break; } - cd = tty_port_carrier_raised(port); + serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); + if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) + do_clocal = 1; - if (!(port->flags & ASYNC_CLOSING) && + if (!(info->port.flags & ASYNC_CLOSING) && (do_clocal)) break; if (signal_pending(current)) { @@ -2163,25 +2154,25 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n", - info->line, port->count); + info->line, info->port.count); #endif spin_unlock_irqrestore(&info->lock, flags); schedule(); spin_lock_irqsave(&info->lock, flags); } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; + info->port.count++; + info->port.blocked_open--; spin_unlock_irqrestore(&info->lock, flags); #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n", - info->line, port->count); + info->line, info->port.count); #endif if (retval) return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2338,10 +2329,6 @@ static const struct tty_operations esp_ops = { .tiocmset = esp_tiocmset, }; -static const struct tty_port_operations esp_port_ops = { - .esp_carrier_raised, -}; - /* * The serial driver boot-time initialization code! */ @@ -2428,8 +2415,6 @@ static int __init espserial_init(void) offset = 0; do { - tty_port_init(&info->port); - info->port.ops = &esp_port_ops; info->io_port = esp[i] + offset; info->irq = irq[i]; info->line = (i * 8) + (offset / 8); @@ -2452,6 +2437,8 @@ static int __init espserial_init(void) info->config.flow_off = flow_off; info->config.pio_threshold = pio_threshold; info->next_port = ports; + init_waitqueue_head(&info->port.open_wait); + init_waitqueue_head(&info->port.close_wait); init_waitqueue_head(&info->delta_msr_wait); init_waitqueue_head(&info->break_wait); ports = info; diff --git a/trunk/drivers/char/generic_serial.c b/trunk/drivers/char/generic_serial.c index 9e4e569dc00d..c6090f84a2e4 100644 --- a/trunk/drivers/char/generic_serial.c +++ b/trunk/drivers/char/generic_serial.c @@ -376,8 +376,7 @@ static void gs_shutdown_port (struct gs_port *port) void gs_hangup(struct tty_struct *tty) { - struct gs_port *port; - unsigned long flags; + struct gs_port *port; func_enter (); @@ -387,11 +386,9 @@ void gs_hangup(struct tty_struct *tty) return; gs_shutdown_port (port); - spin_lock_irqsave(&port->port.lock, flags); port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE); port->port.tty = NULL; port->port.count = 0; - spin_unlock_irqrestore(&port->port.lock, flags); wake_up_interruptible(&port->port.open_wait); func_exit (); @@ -400,8 +397,7 @@ void gs_hangup(struct tty_struct *tty) int gs_block_til_ready(void *port_, struct file * filp) { - struct gs_port *gp = port_; - struct tty_port *port = &gp->port; + struct gs_port *port = port_; DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -413,16 +409,16 @@ int gs_block_til_ready(void *port_, struct file * filp) if (!port) return 0; - tty = port->tty; + tty = port->port.tty; gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -436,7 +432,7 @@ int gs_block_til_ready(void *port_, struct file * filp) */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; + port->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -448,34 +444,34 @@ int gs_block_til_ready(void *port_, struct file * filp) /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, port->port.count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&port->port.open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->driver_lock, flags); if (!tty_hung_up_p(filp)) { - port->count--; + port->port.count--; } - port->blocked_open++; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->driver_lock, flags); + port->port.blocked_open++; while (1) { - CD = tty_port_carrier_raised(port); + CD = port->rd->get_CD (port); gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); set_current_state (TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) + !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CLOSING) && + if (!(port->port.flags & ASYNC_CLOSING) && (do_clocal || CD)) break; gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", @@ -487,20 +483,19 @@ int gs_block_til_ready(void *port_, struct file * filp) schedule(); } gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", - port->blocked_open); + port->port.blocked_open); set_current_state (TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); - - spin_lock_irqsave(&port->lock, flags); + remove_wait_queue(&port->port.open_wait, &wait); if (!tty_hung_up_p(filp)) { - port->count++; + port->port.count++; } - port->blocked_open--; - if (retval == 0) - port->flags |= ASYNC_NORMAL_ACTIVE; - spin_unlock_irqrestore(&port->lock, flags); + port->port.blocked_open--; + if (retval) + return retval; + + port->port.flags |= ASYNC_NORMAL_ACTIVE; func_exit (); - return retval; + return 0; } @@ -511,7 +506,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) func_enter (); - port = tty->driver_data; + port = (struct gs_port *) tty->driver_data; if (!port) return; @@ -521,10 +516,10 @@ void gs_close(struct tty_struct * tty, struct file * filp) port->port.tty = tty; } - spin_lock_irqsave(&port->port.lock, flags); + spin_lock_irqsave(&port->driver_lock, flags); if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&port->port.lock, flags); + spin_unlock_irqrestore(&port->driver_lock, flags); if (port->rd->hungup) port->rd->hungup (port); func_exit (); @@ -543,7 +538,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) if (port->port.count) { gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count); - spin_unlock_irqrestore(&port->port.lock, flags); + spin_unlock_irqrestore(&port->driver_lock, flags); func_exit (); return; } @@ -564,10 +559,8 @@ void gs_close(struct tty_struct * tty, struct file * filp) * line status register. */ - spin_lock_irqsave(&port->driver_lock, flags); port->rd->disable_rx_interrupts (port); spin_unlock_irqrestore(&port->driver_lock, flags); - spin_unlock_irqrestore(&port->port.lock, flags); /* close has no way of returning "EINTR", so discard return value */ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) @@ -580,25 +573,20 @@ void gs_close(struct tty_struct * tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; - spin_lock_irqsave(&port->driver_lock, flags); port->event = 0; port->rd->close (port); port->rd->shutdown_port (port); - spin_unlock_irqrestore(&port->driver_lock, flags); - - spin_lock_irqsave(&port->port.lock, flags); port->port.tty = NULL; if (port->port.blocked_open) { if (port->close_delay) { - spin_unlock_irqrestore(&port->port.lock, flags); + spin_unlock_irqrestore(&port->driver_lock, flags); msleep_interruptible(jiffies_to_msecs(port->close_delay)); - spin_lock_irqsave(&port->port.lock, flags); + spin_lock_irqsave(&port->driver_lock, flags); } wake_up_interruptible(&port->port.open_wait); } port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); - spin_unlock_irqrestore(&port->port.lock, flags); wake_up_interruptible(&port->port.close_wait); func_exit (); diff --git a/trunk/drivers/char/hvc_console.c b/trunk/drivers/char/hvc_console.c index 5a8a4c28c867..0587b66d6fc7 100644 --- a/trunk/drivers/char/hvc_console.c +++ b/trunk/drivers/char/hvc_console.c @@ -529,7 +529,7 @@ static void hvc_set_winsz(struct work_struct *work) tty = tty_kref_get(hp->tty); spin_unlock_irqrestore(&hp->lock, hvc_flags); - tty_do_resize(tty, &ws); + tty_do_resize(tty, tty, &ws); tty_kref_put(tty); } diff --git a/trunk/drivers/char/hvsi.c b/trunk/drivers/char/hvsi.c index 406f8742a260..af055287271a 100644 --- a/trunk/drivers/char/hvsi.c +++ b/trunk/drivers/char/hvsi.c @@ -997,14 +997,14 @@ static void hvsi_write_worker(struct work_struct *work) static int hvsi_write_room(struct tty_struct *tty) { - struct hvsi_struct *hp = tty->driver_data; + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; return N_OUTBUF - hp->n_outbuf; } static int hvsi_chars_in_buffer(struct tty_struct *tty) { - struct hvsi_struct *hp = tty->driver_data; + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; return hp->n_outbuf; } @@ -1070,7 +1070,7 @@ static int hvsi_write(struct tty_struct *tty, */ static void hvsi_throttle(struct tty_struct *tty) { - struct hvsi_struct *hp = tty->driver_data; + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; pr_debug("%s\n", __func__); @@ -1079,7 +1079,7 @@ static void hvsi_throttle(struct tty_struct *tty) static void hvsi_unthrottle(struct tty_struct *tty) { - struct hvsi_struct *hp = tty->driver_data; + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; unsigned long flags; int shouldflip = 0; @@ -1100,7 +1100,7 @@ static void hvsi_unthrottle(struct tty_struct *tty) static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) { - struct hvsi_struct *hp = tty->driver_data; + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; hvsi_get_mctrl(hp); return hp->mctrl; @@ -1109,7 +1109,7 @@ static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct hvsi_struct *hp = tty->driver_data; + struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; unsigned long flags; uint16_t new_mctrl; diff --git a/trunk/drivers/char/i8k.c b/trunk/drivers/char/i8k.c index fc8cf7ac7f2b..b60d425ce8d1 100644 --- a/trunk/drivers/char/i8k.c +++ b/trunk/drivers/char/i8k.c @@ -485,21 +485,7 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "MP061"), }, }, - { - .ident = "Dell Precision", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Precision"), - }, - }, - { - .ident = "Dell Vostro", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"), - }, - }, - { } + { } }; /* diff --git a/trunk/drivers/char/isicom.c b/trunk/drivers/char/isicom.c index 24aa6e88e223..04e4549299ba 100644 --- a/trunk/drivers/char/isicom.c +++ b/trunk/drivers/char/isicom.c @@ -328,13 +328,11 @@ static inline void drop_rts(struct isi_port *port) } /* card->lock MUST NOT be held */ - -static void isicom_raise_dtr_rts(struct tty_port *port) +static inline void raise_dtr_rts(struct isi_port *port) { - struct isi_port *ip = container_of(port, struct isi_port, port); - struct isi_board *card = ip->card; + struct isi_board *card = port->card; unsigned long base = card->base; - u16 channel = ip->channel; + u16 channel = port->channel; if (!lock_card(card)) return; @@ -342,7 +340,7 @@ static void isicom_raise_dtr_rts(struct tty_port *port) outw(0x8000 | (channel << card->shift_count) | 0x02, base); outw(0x0f04, base); InterruptTheCard(base); - ip->status |= (ISI_DTR | ISI_RTS); + port->status |= (ISI_DTR | ISI_RTS); unlock_card(card); } @@ -832,10 +830,80 @@ static int isicom_setup_port(struct tty_struct *tty) return 0; } -static int isicom_carrier_raised(struct tty_port *port) +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct isi_port *port) { - struct isi_port *ip = container_of(port, struct isi_port, port); - return (ip->status & ISI_DCD)?1 : 0; + struct isi_board *card = port->card; + int do_clocal = 0, retval; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + + /* block if port is in the process of being closed */ + + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { + pr_dbg("block_til_ready: close in progress.\n"); + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + /* if non-blocking mode is set ... */ + + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + pr_dbg("block_til_ready: non-block mode.\n"); + port->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (C_CLOCAL(tty)) + do_clocal = 1; + + /* block waiting for DCD to be asserted, and while + callout dev is busy */ + retval = 0; + add_wait_queue(&port->port.open_wait, &wait); + + spin_lock_irqsave(&card->card_lock, flags); + if (!tty_hung_up_p(filp)) + port->port.count--; + port->port.blocked_open++; + spin_unlock_irqrestore(&card->card_lock, flags); + + while (1) { + raise_dtr_rts(port); + + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->port.flags & ASYNC_CLOSING) && + (do_clocal || (port->status & ISI_DCD))) { + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->port.open_wait, &wait); + spin_lock_irqsave(&card->card_lock, flags); + if (!tty_hung_up_p(filp)) + port->port.count++; + port->port.blocked_open--; + spin_unlock_irqrestore(&card->card_lock, flags); + if (retval) + return retval; + port->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; } static int isicom_open(struct tty_struct *tty, struct file *filp) @@ -864,13 +932,12 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) isicom_setup_board(card); - /* FIXME: locking on port.count etc */ port->port.count++; tty->driver_data = port; tty_port_tty_set(&port->port, tty); error = isicom_setup_port(tty); if (error == 0) - error = tty_port_block_til_ready(&port->port, tty, filp); + error = block_til_ready(tty, filp, port); return error; } @@ -945,30 +1012,76 @@ static void isicom_flush_buffer(struct tty_struct *tty) static void isicom_close(struct tty_struct *tty, struct file *filp) { - struct isi_port *ip = tty->driver_data; - struct tty_port *port = &ip->port; + struct isi_port *port = tty->driver_data; struct isi_board *card; unsigned long flags; - BUG_ON(!ip); + if (!port) + return; + card = port->card; + if (isicom_paranoia_check(port, tty->name, "isicom_close")) + return; + + pr_dbg("Close start!!!.\n"); + + spin_lock_irqsave(&card->card_lock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&card->card_lock, flags); + return; + } + + if (tty->count == 1 && port->port.count != 1) { + printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port " + "count tty->count = 1 port count = %d.\n", + card->base, port->port.count); + port->port.count = 1; + } + if (--port->port.count < 0) { + printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port " + "count for channel%d = %d", card->base, port->channel, + port->port.count); + port->port.count = 0; + } - card = ip->card; - if (isicom_paranoia_check(ip, tty->name, "isicom_close")) + if (port->port.count) { + spin_unlock_irqrestore(&card->card_lock, flags); return; + } + port->port.flags |= ASYNC_CLOSING; + tty->closing = 1; + spin_unlock_irqrestore(&card->card_lock, flags); + if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->port.closing_wait); /* indicate to the card that no more data can be received on this port */ spin_lock_irqsave(&card->card_lock, flags); - if (port->flags & ASYNC_INITIALIZED) { - card->port_status &= ~(1 << ip->channel); + if (port->port.flags & ASYNC_INITIALIZED) { + card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); } - isicom_shutdown_port(ip); + isicom_shutdown_port(port); spin_unlock_irqrestore(&card->card_lock, flags); isicom_flush_buffer(tty); - - tty_port_close_end(port, tty); + tty_ldisc_flush(tty); + + spin_lock_irqsave(&card->card_lock, flags); + tty->closing = 0; + + if (port->port.blocked_open) { + spin_unlock_irqrestore(&card->card_lock, flags); + if (port->port.close_delay) { + pr_dbg("scheduling until time out.\n"); + msleep_interruptible( + jiffies_to_msecs(port->port.close_delay)); + } + spin_lock_irqsave(&card->card_lock, flags); + wake_up_interruptible(&port->port.open_wait); + } + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + wake_up_interruptible(&port->port.close_wait); + spin_unlock_irqrestore(&card->card_lock, flags); } /* write et all */ @@ -1307,7 +1420,10 @@ static void isicom_hangup(struct tty_struct *tty) isicom_shutdown_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); - tty_port_hangup(&port->port); + port->port.count = 0; + port->port.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_tty_set(&port->port, NULL); + wake_up_interruptible(&port->port.open_wait); } @@ -1336,11 +1452,6 @@ static const struct tty_operations isicom_ops = { .break_ctl = isicom_send_break, }; -static const struct tty_port_operations isicom_port_ops = { - .carrier_raised = isicom_carrier_raised, - .raise_dtr_rts = isicom_raise_dtr_rts, -}; - static int __devinit reset_card(struct pci_dev *pdev, const unsigned int card, unsigned int *signature) { @@ -1683,7 +1794,6 @@ static int __init isicom_init(void) spin_lock_init(&isi_card[idx].card_lock); for (channel = 0; channel < 16; channel++, port++) { tty_port_init(&port->port); - port->port.ops = &isicom_port_ops; port->magic = ISICOM_MAGIC; port->card = &isi_card[idx]; port->channel = channel; diff --git a/trunk/drivers/char/istallion.c b/trunk/drivers/char/istallion.c index 5c3dc6b8411c..4b10770fa937 100644 --- a/trunk/drivers/char/istallion.c +++ b/trunk/drivers/char/istallion.c @@ -151,7 +151,7 @@ static char *stli_drvversion = "5.6.0"; static char *stli_serialname = "ttyE"; static struct tty_driver *stli_serial; -static const struct tty_port_operations stli_port_ops; + #define STLI_TXBUFSIZE 4096 @@ -626,6 +626,8 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp); static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp); static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); +static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, + struct stliport *portp, struct file *filp); static int stli_setport(struct tty_struct *tty); static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); @@ -767,7 +769,7 @@ static int stli_parsebrd(struct stlconf *confp, char **argp) break; } if (i == ARRAY_SIZE(stli_brdstr)) { - printk(KERN_WARNING "istallion: unknown board name, %s?\n", argp[0]); + printk("STALLION: unknown board name, %s?\n", argp[0]); return 0; } @@ -785,7 +787,6 @@ static int stli_open(struct tty_struct *tty, struct file *filp) { struct stlibrd *brdp; struct stliport *portp; - struct tty_port *port; unsigned int minordev, brdnr, portnr; int rc; @@ -807,19 +808,30 @@ static int stli_open(struct tty_struct *tty, struct file *filp) return -ENODEV; if (portp->devnr < 1) return -ENODEV; - port = &portp->port; + + +/* + * Check if this port is in the middle of closing. If so then wait + * until it is closed then return error status based on flag settings. + * The sleep here does not need interrupt protection since the wakeup + * for it is done with the same context. + */ + if (portp->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->port.close_wait); + if (portp->port.flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + return -ERESTARTSYS; + } /* * On the first open of the device setup the port hardware, and * initialize the per port data structure. Since initializing the port * requires several commands to the board we will need to wait for any * other open that is already initializing the port. - * - * Review - locking */ - tty_port_tty_set(port, tty); + tty_port_tty_set(&portp->port, tty); tty->driver_data = portp; - port->count++; + portp->port.count++; wait_event_interruptible(portp->raw_wait, !test_bit(ST_INITIALIZING, &portp->state)); @@ -829,8 +841,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { set_bit(ST_INITIALIZING, &portp->state); if ((rc = stli_initopen(tty, brdp, portp)) >= 0) { - /* Locking */ - port->flags |= ASYNC_INITIALIZED; + portp->port.flags |= ASYNC_INITIALIZED; clear_bit(TTY_IO_ERROR, &tty->flags); } clear_bit(ST_INITIALIZING, &portp->state); @@ -838,7 +849,31 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if (rc < 0) return rc; } - return tty_port_block_til_ready(&portp->port, tty, filp); + +/* + * Check if this port is in the middle of closing. If so then wait + * until it is closed then return error status, based on flag settings. + * The sleep here does not need interrupt protection since the wakeup + * for it is done with the same context. + */ + if (portp->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->port.close_wait); + if (portp->port.flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + return -ERESTARTSYS; + } + +/* + * Based on type of open being done check if it can overlap with any + * previous opens still in effect. If we are a normal serial device + * then also we might have to wait for carrier. + */ + if (!(filp->f_flags & O_NONBLOCK)) { + if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0) + return rc; + } + portp->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; } /*****************************************************************************/ @@ -847,16 +882,25 @@ static void stli_close(struct tty_struct *tty, struct file *filp) { struct stlibrd *brdp; struct stliport *portp; - struct tty_port *port; unsigned long flags; portp = tty->driver_data; if (portp == NULL) return; - port = &portp->port; - if (tty_port_close_start(port, tty, filp) == 0) + spin_lock_irqsave(&stli_lock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&stli_lock, flags); + return; + } + if ((tty->count == 1) && (portp->port.count != 1)) + portp->port.count = 1; + if (portp->port.count-- > 1) { + spin_unlock_irqrestore(&stli_lock, flags); return; + } + + portp->port.flags |= ASYNC_CLOSING; /* * May want to wait for data to drain before closing. The BUSY flag @@ -864,19 +908,15 @@ static void stli_close(struct tty_struct *tty, struct file *filp) * updated by messages from the slave - indicating when all chars * really have drained. */ - spin_lock_irqsave(&stli_lock, flags); if (tty == stli_txcooktty) stli_flushchars(tty); + tty->closing = 1; spin_unlock_irqrestore(&stli_lock, flags); - /* We end up doing this twice for the moment. This needs looking at - eventually. Note we still use portp->closing_wait as a result */ if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, portp->closing_wait); - /* FIXME: port locking here needs attending to */ - port->flags &= ~ASYNC_INITIALIZED; - + portp->port.flags &= ~ASYNC_INITIALIZED; brdp = stli_brds[portp->brdnr]; stli_rawclose(brdp, portp, 0, 0); if (tty->termios->c_cflag & HUPCL) { @@ -894,8 +934,17 @@ static void stli_close(struct tty_struct *tty, struct file *filp) set_bit(ST_DOFLUSHRX, &portp->state); stli_flushbuffer(tty); - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); + tty->closing = 0; + tty_port_tty_set(&portp->port, NULL); + + if (portp->openwaitcnt) { + if (portp->close_delay) + msleep_interruptible(jiffies_to_msecs(portp->close_delay)); + wake_up_interruptible(&portp->port.open_wait); + } + + portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&portp->port.close_wait); } /*****************************************************************************/ @@ -1134,22 +1183,61 @@ static int stli_setport(struct tty_struct *tty) /*****************************************************************************/ -static int stli_carrier_raised(struct tty_port *port) -{ - struct stliport *portp = container_of(port, struct stliport, port); - return (portp->sigs & TIOCM_CD) ? 1 : 0; -} +/* + * Possibly need to wait for carrier (DCD signal) to come high. Say + * maybe because if we are clocal then we don't need to wait... + */ -static void stli_raise_dtr_rts(struct tty_port *port) +static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, + struct stliport *portp, struct file *filp) { - struct stliport *portp = container_of(port, struct stliport, port); - struct stlibrd *brdp = stli_brds[portp->brdnr]; - stli_mkasysigs(&portp->asig, 1, 1); - if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0) < 0) - printk(KERN_WARNING "istallion: dtr raise failed.\n"); -} + unsigned long flags; + int rc, doclocal; + + rc = 0; + doclocal = 0; + if (tty->termios->c_cflag & CLOCAL) + doclocal++; + + spin_lock_irqsave(&stli_lock, flags); + portp->openwaitcnt++; + if (! tty_hung_up_p(filp)) + portp->port.count--; + spin_unlock_irqrestore(&stli_lock, flags); + + for (;;) { + stli_mkasysigs(&portp->asig, 1, 1); + if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, + &portp->asig, sizeof(asysigs_t), 0)) < 0) + break; + if (tty_hung_up_p(filp) || + ((portp->port.flags & ASYNC_INITIALIZED) == 0)) { + if (portp->port.flags & ASYNC_HUP_NOTIFY) + rc = -EBUSY; + else + rc = -ERESTARTSYS; + break; + } + if (((portp->port.flags & ASYNC_CLOSING) == 0) && + (doclocal || (portp->sigs & TIOCM_CD))) { + break; + } + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&portp->port.open_wait); + } + + spin_lock_irqsave(&stli_lock, flags); + if (! tty_hung_up_p(filp)) + portp->port.count++; + portp->openwaitcnt--; + spin_unlock_irqrestore(&stli_lock, flags); + + return rc; +} /*****************************************************************************/ @@ -1462,7 +1550,7 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s sio.irq = 0; sio.flags = portp->port.flags; sio.baud_base = portp->baud_base; - sio.close_delay = portp->port.close_delay; + sio.close_delay = portp->close_delay; sio.closing_wait = portp->closing_wait; sio.custom_divisor = portp->custom_divisor; sio.xmit_fifo_size = 0; @@ -1494,7 +1582,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s return -EFAULT; if (!capable(CAP_SYS_ADMIN)) { if ((sio.baud_base != portp->baud_base) || - (sio.close_delay != portp->port.close_delay) || + (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != (portp->port.flags & ~ASYNC_USR_MASK))) return -EPERM; @@ -1503,7 +1591,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK); portp->baud_base = sio.baud_base; - portp->port.close_delay = sio.close_delay; + portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; @@ -1733,7 +1821,6 @@ static void stli_hangup(struct tty_struct *tty) { struct stliport *portp; struct stlibrd *brdp; - struct tty_port *port; unsigned long flags; portp = tty->driver_data; @@ -1744,11 +1831,8 @@ static void stli_hangup(struct tty_struct *tty) brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return; - port = &portp->port; - spin_lock_irqsave(&port->lock, flags); - port->flags &= ~ASYNC_INITIALIZED; - spin_unlock_irqrestore(&port->lock, flags); + portp->port.flags &= ~ASYNC_INITIALIZED; if (!test_bit(ST_CLOSING, &portp->state)) stli_rawclose(brdp, portp, 0, 0); @@ -1769,9 +1853,12 @@ static void stli_hangup(struct tty_struct *tty) clear_bit(ST_TXBUSY, &portp->state); clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); + tty_port_tty_set(&portp->port, NULL); + portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; + portp->port.count = 0; spin_unlock_irqrestore(&stli_lock, flags); - tty_port_hangup(port); + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -2045,7 +2132,7 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne unsigned char __iomem *bits; if (test_bit(ST_CMDING, &portp->state)) { - printk(KERN_ERR "istallion: command already busy, cmd=%x!\n", + printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n", (int) cmd); return; } @@ -2605,17 +2692,16 @@ static int stli_initports(struct stlibrd *brdp) for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) { portp = kzalloc(sizeof(struct stliport), GFP_KERNEL); if (!portp) { - printk(KERN_WARNING "istallion: failed to allocate port structure\n"); + printk("STALLION: failed to allocate port structure\n"); continue; } tty_port_init(&portp->port); - portp->port.ops = &stli_port_ops; portp->magic = STLI_PORTMAGIC; portp->portnr = i; portp->brdnr = brdp->brdnr; portp->panelnr = panelnr; portp->baud_base = STL_BAUDBASE; - portp->port.close_delay = STL_CLOSEDELAY; + portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; init_waitqueue_head(&portp->port.open_wait); init_waitqueue_head(&portp->port.close_wait); @@ -2672,7 +2758,7 @@ static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offse unsigned char val; if (offset > brdp->memsize) { - printk(KERN_ERR "istallion: shared memory pointer=%x out of " + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " "range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr); ptr = NULL; @@ -2746,7 +2832,7 @@ static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long off unsigned char val; if (offset > brdp->memsize) { - printk(KERN_ERR "istallion: shared memory pointer=%x out of " + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " "range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr); ptr = NULL; @@ -2798,7 +2884,7 @@ static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long off unsigned char val; if (offset > brdp->memsize) { - printk(KERN_ERR "istallion: shared memory pointer=%x out of " + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " "range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr); ptr = NULL; @@ -2843,7 +2929,7 @@ static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long of unsigned char val; if (offset > brdp->memsize) { - printk(KERN_ERR "istallion: shared memory pointer=%x out of " + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " "range at line=%d(%d), board=%d\n", (int) offset, line, __LINE__, brdp->brdnr); ptr = NULL; @@ -2908,7 +2994,7 @@ static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offse void __iomem *ptr; if (offset > brdp->memsize) { - printk(KERN_ERR "istallion: shared memory pointer=%x out of " + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " "range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr); ptr = NULL; @@ -2974,7 +3060,7 @@ static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offs unsigned char val; if (offset > brdp->memsize) { - printk(KERN_ERR "istallion: shared memory pointer=%x out of " + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " "range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr); ptr = NULL; @@ -3413,7 +3499,7 @@ static int stli_startbrd(struct stlibrd *brdp) #endif if (nrdevs < (brdp->nrports + 1)) { - printk(KERN_ERR "istallion: slave failed to allocate memory for " + printk(KERN_ERR "STALLION: slave failed to allocate memory for " "all devices, devices=%d\n", nrdevs); brdp->nrports = nrdevs - 1; } @@ -3423,13 +3509,13 @@ static int stli_startbrd(struct stlibrd *brdp) brdp->bitsize = (nrdevs + 7) / 8; memoff = readl(&hdrp->memp); if (memoff > brdp->memsize) { - printk(KERN_ERR "istallion: corrupted shared memory region?\n"); + printk(KERN_ERR "STALLION: corrupted shared memory region?\n"); rc = -EIO; goto stli_donestartup; } memp = (cdkmem_t __iomem *) EBRDGETMEMPTR(brdp, memoff); if (readw(&memp->dtype) != TYP_ASYNCTRL) { - printk(KERN_ERR "istallion: no slave control device found\n"); + printk(KERN_ERR "STALLION: no slave control device found\n"); goto stli_donestartup; } memp++; @@ -3514,7 +3600,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp) retval = stli_initonb(brdp); break; default: - printk(KERN_ERR "istallion: board=%d is unknown board " + printk(KERN_ERR "STALLION: board=%d is unknown board " "type=%d\n", brdp->brdnr, brdp->brdtype); retval = -ENODEV; } @@ -3523,7 +3609,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp) return retval; stli_initports(brdp); - printk(KERN_INFO "istallion: %s found, board=%d io=%x mem=%x " + printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x " "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr, brdp->nrpanels, brdp->nrports); @@ -3617,7 +3703,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp) if (! foundit) { brdp->memaddr = 0; brdp->membase = NULL; - printk(KERN_ERR "istallion: failed to probe shared memory " + printk(KERN_ERR "STALLION: failed to probe shared memory " "region for %s in EISA slot=%d\n", stli_brdnames[brdp->brdtype], (brdp->iobase >> 12)); return -ENODEV; @@ -3762,7 +3848,7 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev, mutex_lock(&stli_brdslock); brdnr = stli_getbrdnr(); if (brdnr < 0) { - printk(KERN_INFO "istallion: too many boards found, " + printk(KERN_INFO "STALLION: too many boards found, " "maximum supported %d\n", STL_MAXBRDS); mutex_unlock(&stli_brdslock); retval = -EIO; @@ -3834,7 +3920,7 @@ static struct stlibrd *stli_allocbrd(void) brdp = kzalloc(sizeof(struct stlibrd), GFP_KERNEL); if (!brdp) { - printk(KERN_ERR "istallion: failed to allocate memory " + printk(KERN_ERR "STALLION: failed to allocate memory " "(size=%Zd)\n", sizeof(struct stlibrd)); return NULL; } @@ -4432,11 +4518,6 @@ static const struct tty_operations stli_ops = { .tiocmset = stli_tiocmset, }; -static const struct tty_port_operations stli_port_ops = { - .carrier_raised = stli_carrier_raised, - .raise_dtr_rts = stli_raise_dtr_rts, -}; - /*****************************************************************************/ /* * Loadable module initialization stuff. @@ -4473,7 +4554,7 @@ static int __init istallion_module_init(void) stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL); if (!stli_txcookbuf) { - printk(KERN_ERR "istallion: failed to allocate memory " + printk(KERN_ERR "STALLION: failed to allocate memory " "(size=%d)\n", STLI_TXBUFSIZE); retval = -ENOMEM; goto err; @@ -4498,7 +4579,7 @@ static int __init istallion_module_init(void) retval = tty_register_driver(stli_serial); if (retval) { - printk(KERN_ERR "istallion: failed to register serial driver\n"); + printk(KERN_ERR "STALLION: failed to register serial driver\n"); goto err_ttyput; } @@ -4512,7 +4593,7 @@ static int __init istallion_module_init(void) */ retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem); if (retval) { - printk(KERN_ERR "istallion: failed to register serial memory " + printk(KERN_ERR "STALLION: failed to register serial memory " "device\n"); goto err_deinit; } diff --git a/trunk/drivers/char/moxa.c b/trunk/drivers/char/moxa.c index 8b0da97d5293..12d327a2c9ba 100644 --- a/trunk/drivers/char/moxa.c +++ b/trunk/drivers/char/moxa.c @@ -206,7 +206,6 @@ static void moxa_poll(unsigned long); static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); static void moxa_setup_empty_event(struct tty_struct *); static void moxa_shut_down(struct tty_struct *); -static int moxa_carrier_raised(struct tty_port *); /* * moxa board interface functions: */ @@ -406,10 +405,6 @@ static const struct tty_operations moxa_ops = { .tiocmset = moxa_tiocmset, }; -static const struct tty_port_operations moxa_port_ops = { - .carrier_raised = moxa_carrier_raised, -}; - static struct tty_driver *moxaDriver; static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); static DEFINE_SPINLOCK(moxa_lock); @@ -831,7 +826,6 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) { tty_port_init(&p->port); - p->port.ops = &moxa_port_ops; p->type = PORT_16550A; p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; } @@ -1121,27 +1115,15 @@ static void moxa_close_port(struct tty_struct *tty) tty_port_tty_set(&ch->port, NULL); } -static int moxa_carrier_raised(struct tty_port *port) -{ - struct moxa_port *ch = container_of(port, struct moxa_port, port); - int dcd; - - spin_lock_bh(&moxa_lock); - dcd = ch->DCDState; - spin_unlock_bh(&moxa_lock); - return dcd; -} - static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, struct moxa_port *ch) { - struct tty_port *port = &ch->port; DEFINE_WAIT(wait); int retval = 0; u8 dcd; while (1) { - prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp)) { #ifdef SERIAL_DO_RESTART retval = -ERESTARTSYS; @@ -1150,7 +1132,9 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, #endif break; } - dcd = tty_port_carrier_raised(port); + spin_lock_bh(&moxa_lock); + dcd = ch->DCDState; + spin_unlock_bh(&moxa_lock); if (dcd) break; @@ -1160,7 +1144,7 @@ static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, } schedule(); } - finish_wait(&port->open_wait, &wait); + finish_wait(&ch->port.open_wait, &wait); return retval; } diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c index 402c9f217f83..047766915411 100644 --- a/trunk/drivers/char/mxser.c +++ b/trunk/drivers/char/mxser.c @@ -541,21 +541,74 @@ static unsigned char mxser_get_msr(int baseaddr, int mode, int port) return status; } -static int mxser_carrier_raised(struct tty_port *port) +static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, + struct mxser_port *port) { - struct mxser_port *mp = container_of(port, struct mxser_port, port); - return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0; -} - -static void mxser_raise_dtr_rts(struct tty_port *port) -{ - struct mxser_port *mp = container_of(port, struct mxser_port, port); + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; unsigned long flags; - spin_lock_irqsave(&mp->slock, flags); - outb(inb(mp->ioaddr + UART_MCR) | - UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); - spin_unlock_irqrestore(&mp->slock, flags); + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + test_bit(TTY_IO_ERROR, &tty->flags)) { + port->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->port.count is dropped by one, so that + * mxser_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->port.open_wait, &wait); + + spin_lock_irqsave(&port->slock, flags); + if (!tty_hung_up_p(filp)) + port->port.count--; + spin_unlock_irqrestore(&port->slock, flags); + port->port.blocked_open++; + while (1) { + spin_lock_irqsave(&port->slock, flags); + outb(inb(port->ioaddr + UART_MCR) | + UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR); + spin_unlock_irqrestore(&port->slock, flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->port.flags & ASYNC_CLOSING) && + (do_clocal || + (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->port.open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->port.count++; + port->port.blocked_open--; + if (retval) + return retval; + port->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; } static int mxser_set_baud(struct tty_struct *tty, long newspd) @@ -1034,14 +1087,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) /* * Start up serial port */ - spin_lock_irqsave(&info->port.lock, flags); + spin_lock_irqsave(&info->slock, flags); info->port.count++; - spin_unlock_irqrestore(&info->port.lock, flags); + spin_unlock_irqrestore(&info->slock, flags); retval = mxser_startup(tty); if (retval) return retval; - retval = tty_port_block_til_ready(&info->port, tty, filp); + retval = mxser_block_til_ready(tty, filp, info); if (retval) return retval; @@ -1080,26 +1133,57 @@ static void mxser_flush_buffer(struct tty_struct *tty) static void mxser_close(struct tty_struct *tty, struct file *filp) { struct mxser_port *info = tty->driver_data; - struct tty_port *port = &info->port; unsigned long timeout; + unsigned long flags; if (tty->index == MXSER_PORTS) return; if (!info) return; - if (tty_port_close_start(port, tty, filp) == 0) - return; + spin_lock_irqsave(&info->slock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&info->slock, flags); + return; + } + if ((tty->count == 1) && (info->port.count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->port.count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_ERR "mxser_close: bad serial port count; " + "tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; + } + if (--info->port.count < 0) { + printk(KERN_ERR "mxser_close: bad serial port count for " + "ttys%d: %d\n", tty->index, info->port.count); + info->port.count = 0; + } + if (info->port.count) { + spin_unlock_irqrestore(&info->slock, flags); + return; + } + info->port.flags |= ASYNC_CLOSING; + spin_unlock_irqrestore(&info->slock, flags); /* * Save the termios structure, since this port may have * separate termios for callout and dialin. - * - * FIXME: Can this go ? */ if (info->port.flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->port.closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1125,12 +1209,19 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) } } mxser_shutdown(tty); + mxser_flush_buffer(tty); + tty_ldisc_flush(tty); + + tty->closing = 0; + tty_port_tty_set(&info->port, NULL); + if (info->port.blocked_open) { + if (info->port.close_delay) + schedule_timeout_interruptible(info->port.close_delay); + wake_up_interruptible(&info->port.open_wait); + } - /* Right now the tty_port set is done outside of the close_end helper - as we don't yet have everyone using refcounts */ - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); } static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -2055,7 +2146,10 @@ static void mxser_hangup(struct tty_struct *tty) mxser_flush_buffer(tty); mxser_shutdown(tty); - tty_port_hangup(&info->port); + info->port.count = 0; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_tty_set(&info->port, NULL); + wake_up_interruptible(&info->port.open_wait); } /* @@ -2355,11 +2449,6 @@ static const struct tty_operations mxser_ops = { .tiocmset = mxser_tiocmset, }; -struct tty_port_operations mxser_port_ops = { - .carrier_raised = mxser_carrier_raised, - .raise_dtr_rts = mxser_raise_dtr_rts, -}; - /* * The MOXA Smartio/Industio serial driver boot-time initialization code! */ @@ -2393,7 +2482,6 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, for (i = 0; i < brd->info->nports; i++) { info = &brd->ports[i]; tty_port_init(&info->port); - info->port.ops = &mxser_port_ops; info->board = brd; info->stop_rx = 0; info->ldisc_stop_rx = 0; diff --git a/trunk/drivers/char/n_r3964.c b/trunk/drivers/char/n_r3964.c index d2e93e343226..4a8215a89ad3 100644 --- a/trunk/drivers/char/n_r3964.c +++ b/trunk/drivers/char/n_r3964.c @@ -1003,7 +1003,7 @@ static int r3964_open(struct tty_struct *tty) static void r3964_close(struct tty_struct *tty) { - struct r3964_info *pInfo = tty->disc_data; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; struct r3964_client_info *pClient, *pNext; struct r3964_message *pMsg; struct r3964_block_header *pHeader, *pNextHeader; @@ -1058,7 +1058,7 @@ static void r3964_close(struct tty_struct *tty) static ssize_t r3964_read(struct tty_struct *tty, struct file *file, unsigned char __user * buf, size_t nr) { - struct r3964_info *pInfo = tty->disc_data; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; struct r3964_client_info *pClient; struct r3964_message *pMsg; struct r3964_client_message theMsg; @@ -1113,7 +1113,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, static ssize_t r3964_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { - struct r3964_info *pInfo = tty->disc_data; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; struct r3964_block_header *pHeader; struct r3964_client_info *pClient; unsigned char *new_data; @@ -1182,7 +1182,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, static int r3964_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct r3964_info *pInfo = tty->disc_data; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; if (pInfo == NULL) return -EINVAL; switch (cmd) { @@ -1216,7 +1216,7 @@ static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, struct poll_table_struct *wait) { - struct r3964_info *pInfo = tty->disc_data; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; struct r3964_client_info *pClient; struct r3964_message *pMsg = NULL; unsigned long flags; @@ -1241,7 +1241,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { - struct r3964_info *pInfo = tty->disc_data; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; const unsigned char *p; char *f, flags = 0; int i; diff --git a/trunk/drivers/char/n_tty.c b/trunk/drivers/char/n_tty.c index f6f0e4ec2b51..efbfe9612658 100644 --- a/trunk/drivers/char/n_tty.c +++ b/trunk/drivers/char/n_tty.c @@ -47,8 +47,8 @@ #include #include #include -#include +#include #include /* number of characters left in xmit buffer before select has we have room */ @@ -62,17 +62,6 @@ #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ #define TTY_THRESHOLD_UNTHROTTLE 128 -/* - * Special byte codes used in the echo buffer to represent operations - * or special handling of characters. Bytes in the echo buffer that - * are not part of such special blocks are treated as normal character - * codes. - */ -#define ECHO_OP_START 0xff -#define ECHO_OP_MOVE_BACK_COL 0x80 -#define ECHO_OP_SET_CANON_COL 0x81 -#define ECHO_OP_ERASE_TAB 0x82 - static inline unsigned char *alloc_buf(void) { gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; @@ -180,7 +169,6 @@ static void check_unthrottle(struct tty_struct *tty) * * Locking: tty_read_lock for read fields. */ - static void reset_buffer_flags(struct tty_struct *tty) { unsigned long flags; @@ -188,11 +176,6 @@ static void reset_buffer_flags(struct tty_struct *tty) spin_lock_irqsave(&tty->read_lock, flags); tty->read_head = tty->read_tail = tty->read_cnt = 0; spin_unlock_irqrestore(&tty->read_lock, flags); - - mutex_lock(&tty->echo_lock); - tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0; - mutex_unlock(&tty->echo_lock); - tty->canon_head = tty->canon_data = tty->erasing = 0; memset(&tty->read_flags, 0, sizeof tty->read_flags); n_tty_set_room(tty); @@ -283,118 +266,89 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) } /** - * do_output_char - output one character + * opost - output post processor * @c: character (or partial unicode symbol) * @tty: terminal device - * @space: space available in tty driver write buffer - * - * This is a helper function that handles one output character - * (including special characters like TAB, CR, LF, etc.), - * putting the results in the tty driver's write buffer. * - * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY - * and NLDLY. They simply aren't relevant in the world today. - * If you ever need them, add them here. - * - * Returns the number of bytes of buffer space used or -1 if - * no space left. + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. Note that Linux currently + * ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't + * relevant in the world today. If you ever need them, add them here. * - * Locking: should be called under the output_lock to protect - * the column state and space left in the buffer + * Called from both the receive and transmit sides and can be called + * re-entrantly. Relies on lock_kernel() for tty->column state. */ -static int do_output_char(unsigned char c, struct tty_struct *tty, int space) +static int opost(unsigned char c, struct tty_struct *tty) { - int spaces; + int space, spaces; + space = tty_write_room(tty); if (!space) return -1; - switch (c) { - case '\n': - if (O_ONLRET(tty)) - tty->column = 0; - if (O_ONLCR(tty)) { - if (space < 2) - return -1; - tty->canon_column = tty->column = 0; - tty_put_char(tty, '\r'); - tty_put_char(tty, c); - return 2; - } - tty->canon_column = tty->column; - break; - case '\r': - if (O_ONOCR(tty) && tty->column == 0) - return 0; - if (O_OCRNL(tty)) { - c = '\n'; + lock_kernel(); + if (O_OPOST(tty)) { + switch (c) { + case '\n': if (O_ONLRET(tty)) - tty->canon_column = tty->column = 0; + tty->column = 0; + if (O_ONLCR(tty)) { + if (space < 2) { + unlock_kernel(); + return -1; + } + tty_put_char(tty, '\r'); + tty->column = 0; + } + tty->canon_column = tty->column; break; - } - tty->canon_column = tty->column = 0; - break; - case '\t': - spaces = 8 - (tty->column & 7); - if (O_TABDLY(tty) == XTABS) { - if (space < spaces) - return -1; + case '\r': + if (O_ONOCR(tty) && tty->column == 0) { + unlock_kernel(); + return 0; + } + if (O_OCRNL(tty)) { + c = '\n'; + if (O_ONLRET(tty)) + tty->canon_column = tty->column = 0; + break; + } + tty->canon_column = tty->column = 0; + break; + case '\t': + spaces = 8 - (tty->column & 7); + if (O_TABDLY(tty) == XTABS) { + if (space < spaces) { + unlock_kernel(); + return -1; + } + tty->column += spaces; + tty->ops->write(tty, " ", spaces); + unlock_kernel(); + return 0; + } tty->column += spaces; - tty->ops->write(tty, " ", spaces); - return spaces; - } - tty->column += spaces; - break; - case '\b': - if (tty->column > 0) - tty->column--; - break; - default: - if (!iscntrl(c)) { + break; + case '\b': + if (tty->column > 0) + tty->column--; + break; + default: if (O_OLCUC(tty)) c = toupper(c); - if (!is_continuation(c, tty)) + if (!iscntrl(c) && !is_continuation(c, tty)) tty->column++; + break; } - break; } - tty_put_char(tty, c); - return 1; -} - -/** - * process_output - output post processor - * @c: character (or partial unicode symbol) - * @tty: terminal device - * - * Perform OPOST processing. Returns -1 when the output device is - * full and the character must be retried. - * - * Locking: output_lock to protect column state and space left - * (also, this is called from n_tty_write under the - * tty layer write lock) - */ - -static int process_output(unsigned char c, struct tty_struct *tty) -{ - int space, retval; - - mutex_lock(&tty->output_lock); - - space = tty_write_room(tty); - retval = do_output_char(c, tty, space); - - mutex_unlock(&tty->output_lock); - if (retval < 0) - return -1; - else - return 0; + unlock_kernel(); + return 0; } /** - * process_output_block - block post processor + * opost_block - block postprocess * @tty: terminal device * @inbuf: user buffer * @nr: number of bytes @@ -404,32 +358,26 @@ static int process_output(unsigned char c, struct tty_struct *tty) * the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * - * Locking: output_lock to protect column state and space left - * (also, this is called from n_tty_write under the - * tty layer write lock) + * Called from n_tty_write under the tty layer write lock. Relies + * on lock_kernel for the tty->column state. */ -static ssize_t process_output_block(struct tty_struct *tty, - const unsigned char *buf, unsigned int nr) +static ssize_t opost_block(struct tty_struct *tty, + const unsigned char *buf, unsigned int nr) { int space; int i; const unsigned char *cp; - mutex_lock(&tty->output_lock); - space = tty_write_room(tty); - if (!space) { - mutex_unlock(&tty->output_lock); + if (!space) return 0; - } if (nr > space) nr = space; + lock_kernel(); for (i = 0, cp = buf; i < nr; i++, cp++) { - unsigned char c = *cp; - - switch (c) { + switch (*cp) { case '\n': if (O_ONLRET(tty)) tty->column = 0; @@ -451,403 +399,54 @@ static ssize_t process_output_block(struct tty_struct *tty, tty->column--; break; default: - if (!iscntrl(c)) { - if (O_OLCUC(tty)) - goto break_out; - if (!is_continuation(c, tty)) - tty->column++; - } + if (O_OLCUC(tty)) + goto break_out; + if (!iscntrl(*cp)) + tty->column++; break; } } break_out: - i = tty->ops->write(tty, buf, i); - - mutex_unlock(&tty->output_lock); - return i; -} - -/** - * process_echoes - write pending echo characters - * @tty: terminal device - * - * Write previously buffered echo (and other ldisc-generated) - * characters to the tty. - * - * Characters generated by the ldisc (including echoes) need to - * be buffered because the driver's write buffer can fill during - * heavy program output. Echoing straight to the driver will - * often fail under these conditions, causing lost characters and - * resulting mismatches of ldisc state information. - * - * Since the ldisc state must represent the characters actually sent - * to the driver at the time of the write, operations like certain - * changes in column state are also saved in the buffer and executed - * here. - * - * A circular fifo buffer is used so that the most recent characters - * are prioritized. Also, when control characters are echoed with a - * prefixed "^", the pair is treated atomically and thus not separated. - * - * Locking: output_lock to protect column state and space left, - * echo_lock to protect the echo buffer - */ - -static void process_echoes(struct tty_struct *tty) -{ - int space, nr; - unsigned char c; - unsigned char *cp, *buf_end; - - if (!tty->echo_cnt) - return; - - mutex_lock(&tty->output_lock); - mutex_lock(&tty->echo_lock); - - space = tty_write_room(tty); - - buf_end = tty->echo_buf + N_TTY_BUF_SIZE; - cp = tty->echo_buf + tty->echo_pos; - nr = tty->echo_cnt; - while (nr > 0) { - c = *cp; - if (c == ECHO_OP_START) { - unsigned char op; - unsigned char *opp; - int no_space_left = 0; - - /* - * If the buffer byte is the start of a multi-byte - * operation, get the next byte, which is either the - * op code or a control character value. - */ - opp = cp + 1; - if (opp == buf_end) - opp -= N_TTY_BUF_SIZE; - op = *opp; - - switch (op) { - unsigned int num_chars, num_bs; - - case ECHO_OP_ERASE_TAB: - if (++opp == buf_end) - opp -= N_TTY_BUF_SIZE; - num_chars = *opp; - - /* - * Determine how many columns to go back - * in order to erase the tab. - * This depends on the number of columns - * used by other characters within the tab - * area. If this (modulo 8) count is from - * the start of input rather than from a - * previous tab, we offset by canon column. - * Otherwise, tab spacing is normal. - */ - if (!(num_chars & 0x80)) - num_chars += tty->canon_column; - num_bs = 8 - (num_chars & 7); - - if (num_bs > space) { - no_space_left = 1; - break; - } - space -= num_bs; - while (num_bs--) { - tty_put_char(tty, '\b'); - if (tty->column > 0) - tty->column--; - } - cp += 3; - nr -= 3; - break; - - case ECHO_OP_SET_CANON_COL: - tty->canon_column = tty->column; - cp += 2; - nr -= 2; - break; - - case ECHO_OP_MOVE_BACK_COL: - if (tty->column > 0) - tty->column--; - cp += 2; - nr -= 2; - break; - - case ECHO_OP_START: - /* This is an escaped echo op start code */ - if (!space) { - no_space_left = 1; - break; - } - tty_put_char(tty, ECHO_OP_START); - tty->column++; - space--; - cp += 2; - nr -= 2; - break; - - default: - if (iscntrl(op)) { - if (L_ECHOCTL(tty)) { - /* - * Ensure there is enough space - * for the whole ctrl pair. - */ - if (space < 2) { - no_space_left = 1; - break; - } - tty_put_char(tty, '^'); - tty_put_char(tty, op ^ 0100); - tty->column += 2; - space -= 2; - } else { - if (!space) { - no_space_left = 1; - break; - } - tty_put_char(tty, op); - space--; - } - } - /* - * If above falls through, this was an - * undefined op. - */ - cp += 2; - nr -= 2; - } - - if (no_space_left) - break; - } else { - int retval; - - retval = do_output_char(c, tty, space); - if (retval < 0) - break; - space -= retval; - cp += 1; - nr -= 1; - } - - /* When end of circular buffer reached, wrap around */ - if (cp >= buf_end) - cp -= N_TTY_BUF_SIZE; - } - - if (nr == 0) { - tty->echo_pos = 0; - tty->echo_cnt = 0; - tty->echo_overrun = 0; - } else { - int num_processed = tty->echo_cnt - nr; - tty->echo_pos += num_processed; - tty->echo_pos &= N_TTY_BUF_SIZE - 1; - tty->echo_cnt = nr; - if (num_processed > 0) - tty->echo_overrun = 0; - } - - mutex_unlock(&tty->echo_lock); - mutex_unlock(&tty->output_lock); - if (tty->ops->flush_chars) tty->ops->flush_chars(tty); + i = tty->ops->write(tty, buf, i); + unlock_kernel(); + return i; } -/** - * add_echo_byte - add a byte to the echo buffer - * @c: unicode byte to echo - * @tty: terminal device - * - * Add a character or operation byte to the echo buffer. - * - * Should be called under the echo lock to protect the echo buffer. - */ - -static void add_echo_byte(unsigned char c, struct tty_struct *tty) -{ - int new_byte_pos; - - if (tty->echo_cnt == N_TTY_BUF_SIZE) { - /* Circular buffer is already at capacity */ - new_byte_pos = tty->echo_pos; - - /* - * Since the buffer start position needs to be advanced, - * be sure to step by a whole operation byte group. - */ - if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) { - if (tty->echo_buf[(tty->echo_pos + 1) & - (N_TTY_BUF_SIZE - 1)] == - ECHO_OP_ERASE_TAB) { - tty->echo_pos += 3; - tty->echo_cnt -= 2; - } else { - tty->echo_pos += 2; - tty->echo_cnt -= 1; - } - } else { - tty->echo_pos++; - } - tty->echo_pos &= N_TTY_BUF_SIZE - 1; - - tty->echo_overrun = 1; - } else { - new_byte_pos = tty->echo_pos + tty->echo_cnt; - new_byte_pos &= N_TTY_BUF_SIZE - 1; - tty->echo_cnt++; - } - - tty->echo_buf[new_byte_pos] = c; -} - -/** - * echo_move_back_col - add operation to move back a column - * @tty: terminal device - * - * Add an operation to the echo buffer to move back one column. - * - * Locking: echo_lock to protect the echo buffer - */ - -static void echo_move_back_col(struct tty_struct *tty) -{ - mutex_lock(&tty->echo_lock); - - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty); - - mutex_unlock(&tty->echo_lock); -} - -/** - * echo_set_canon_col - add operation to set the canon column - * @tty: terminal device - * - * Add an operation to the echo buffer to set the canon column - * to the current column. - * - * Locking: echo_lock to protect the echo buffer - */ - -static void echo_set_canon_col(struct tty_struct *tty) -{ - mutex_lock(&tty->echo_lock); - - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_SET_CANON_COL, tty); - - mutex_unlock(&tty->echo_lock); -} - -/** - * echo_erase_tab - add operation to erase a tab - * @num_chars: number of character columns already used - * @after_tab: true if num_chars starts after a previous tab - * @tty: terminal device - * - * Add an operation to the echo buffer to erase a tab. - * - * Called by the eraser function, which knows how many character - * columns have been used since either a previous tab or the start - * of input. This information will be used later, along with - * canon column (if applicable), to go back the correct number - * of columns. - * - * Locking: echo_lock to protect the echo buffer - */ - -static void echo_erase_tab(unsigned int num_chars, int after_tab, - struct tty_struct *tty) -{ - mutex_lock(&tty->echo_lock); - - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_ERASE_TAB, tty); - - /* We only need to know this modulo 8 (tab spacing) */ - num_chars &= 7; - - /* Set the high bit as a flag if num_chars is after a previous tab */ - if (after_tab) - num_chars |= 0x80; - - add_echo_byte(num_chars, tty); - - mutex_unlock(&tty->echo_lock); -} /** - * echo_char_raw - echo a character raw + * echo_char - echo characters * @c: unicode byte to echo * @tty: terminal device * * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. * - * This variant does not treat control characters specially. - * - * Locking: echo_lock to protect the echo buffer - */ - -static void echo_char_raw(unsigned char c, struct tty_struct *tty) -{ - mutex_lock(&tty->echo_lock); - - if (c == ECHO_OP_START) { - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_START, tty); - } else { - add_echo_byte(c, tty); - } - - mutex_unlock(&tty->echo_lock); -} - -/** - * echo_char - echo a character - * @c: unicode byte to echo - * @tty: terminal device - * - * Echo user input back onto the screen. This must be called only when - * L_ECHO(tty) is true. Called from the driver receive_buf path. - * - * This variant tags control characters to be possibly echoed as - * as "^X" (where X is the letter representing the control char). - * - * Locking: echo_lock to protect the echo buffer + * Relies on BKL for tty column locking */ static void echo_char(unsigned char c, struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); - - if (c == ECHO_OP_START) { - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_START, tty); - } else { - if (iscntrl(c) && c != '\t') - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(c, tty); - } - - mutex_unlock(&tty->echo_lock); + if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { + tty_put_char(tty, '^'); + tty_put_char(tty, c ^ 0100); + tty->column += 2; + } else + opost(c, tty); } /** - * finish_erasing - complete erase + * finsh_erasing - complete erase * @tty: tty doing the erase + * + * Relies on BKL for tty column locking */ - static inline void finish_erasing(struct tty_struct *tty) { if (tty->erasing) { - echo_char_raw('/', tty); + tty_put_char(tty, '/'); + tty->column++; tty->erasing = 0; } } @@ -861,7 +460,7 @@ static inline void finish_erasing(struct tty_struct *tty) * present in the stream from the driver layer. Handles the complexities * of UTF-8 multibyte symbols. * - * Locking: read_lock for tty buffers + * Locking: read_lock for tty buffers, BKL for column/erasing state */ static void eraser(unsigned char c, struct tty_struct *tty) @@ -872,7 +471,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) /* FIXME: locking needed ? */ if (tty->read_head == tty->canon_head) { - /* process_output('\a', tty); */ /* what do you think? */ + /* opost('\a', tty); */ /* what do you think? */ return; } if (c == ERASE_CHAR(tty)) @@ -898,7 +497,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) echo_char(KILL_CHAR(tty), tty); /* Add a newline if ECHOK is on and ECHOKE is off. */ if (L_ECHOK(tty)) - echo_char_raw('\n', tty); + opost('\n', tty); return; } kill_type = KILL; @@ -934,61 +533,67 @@ static void eraser(unsigned char c, struct tty_struct *tty) if (L_ECHO(tty)) { if (L_ECHOPRT(tty)) { if (!tty->erasing) { - echo_char_raw('\\', tty); + tty_put_char(tty, '\\'); + tty->column++; tty->erasing = 1; } /* if cnt > 1, output a multi-byte character */ echo_char(c, tty); while (--cnt > 0) { head = (head+1) & (N_TTY_BUF_SIZE-1); - echo_char_raw(tty->read_buf[head], tty); - echo_move_back_col(tty); + tty_put_char(tty, tty->read_buf[head]); } } else if (kill_type == ERASE && !L_ECHOE(tty)) { echo_char(ERASE_CHAR(tty), tty); } else if (c == '\t') { - unsigned int num_chars = 0; - int after_tab = 0; - unsigned long tail = tty->read_head; - - /* - * Count the columns used for characters - * since the start of input or after a - * previous tab. - * This info is used to go back the correct - * number of columns. - */ - while (tail != tty->canon_head) { - tail = (tail-1) & (N_TTY_BUF_SIZE-1); + unsigned int col = tty->canon_column; + unsigned long tail = tty->canon_head; + + /* Find the column of the last char. */ + while (tail != tty->read_head) { c = tty->read_buf[tail]; - if (c == '\t') { - after_tab = 1; - break; - } else if (iscntrl(c)) { + if (c == '\t') + col = (col | 7) + 1; + else if (iscntrl(c)) { if (L_ECHOCTL(tty)) - num_chars += 2; - } else if (!is_continuation(c, tty)) { - num_chars++; - } + col += 2; + } else if (!is_continuation(c, tty)) + col++; + tail = (tail+1) & (N_TTY_BUF_SIZE-1); + } + + /* should never happen */ + if (tty->column > 0x80000000) + tty->column = 0; + + /* Now backup to that column. */ + while (tty->column > col) { + /* Can't use opost here. */ + tty_put_char(tty, '\b'); + if (tty->column > 0) + tty->column--; } - echo_erase_tab(num_chars, after_tab, tty); } else { if (iscntrl(c) && L_ECHOCTL(tty)) { - echo_char_raw('\b', tty); - echo_char_raw(' ', tty); - echo_char_raw('\b', tty); + tty_put_char(tty, '\b'); + tty_put_char(tty, ' '); + tty_put_char(tty, '\b'); + if (tty->column > 0) + tty->column--; } if (!iscntrl(c) || L_ECHOCTL(tty)) { - echo_char_raw('\b', tty); - echo_char_raw(' ', tty); - echo_char_raw('\b', tty); + tty_put_char(tty, '\b'); + tty_put_char(tty, ' '); + tty_put_char(tty, '\b'); + if (tty->column > 0) + tty->column--; } } } if (kill_type == ERASE) break; } - if (tty->read_head == tty->canon_head && L_ECHO(tty)) + if (tty->read_head == tty->canon_head) finish_erasing(tty); } @@ -1107,7 +712,6 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { unsigned long flags; - int parmrk; if (tty->raw) { put_tty_queue(c, tty); @@ -1117,21 +721,18 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) - c = tolower(c); + c=tolower(c); if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && - I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) && - c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) { + ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) || + c == INTR_CHAR(tty) || c == QUIT_CHAR(tty) || c == SUSP_CHAR(tty))) start_tty(tty); - process_echoes(tty); - } if (tty->closing) { if (I_IXON(tty)) { - if (c == START_CHAR(tty)) { + if (c == START_CHAR(tty)) start_tty(tty); - process_echoes(tty); - } else if (c == STOP_CHAR(tty)) + else if (c == STOP_CHAR(tty)) stop_tty(tty); } return; @@ -1144,23 +745,19 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) * up. */ if (!test_bit(c, tty->process_char_map) || tty->lnext) { + finish_erasing(tty); tty->lnext = 0; - parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; - if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { - /* beep if no space */ - if (L_ECHO(tty)) - process_output('\a', tty); - return; - } if (L_ECHO(tty)) { - finish_erasing(tty); + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + tty_put_char(tty, '\a'); /* beep if no space */ + return; + } /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) - echo_set_canon_col(tty); + tty->canon_column = tty->column; echo_char(c, tty); - process_echoes(tty); } - if (parmrk) + if (I_PARMRK(tty) && c == (unsigned char) '\377') put_tty_queue(c, tty); put_tty_queue(c, tty); return; @@ -1169,7 +766,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (I_IXON(tty)) { if (c == START_CHAR(tty)) { start_tty(tty); - process_echoes(tty); return; } if (c == STOP_CHAR(tty)) { @@ -1190,6 +786,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (c == SUSP_CHAR(tty)) { send_signal: /* + * Echo character, and then send the signal. * Note that we do not use isig() here because we want * the order to be: * 1) flush, 2) echo, 3) signal @@ -1198,12 +795,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) n_tty_flush_buffer(tty); tty_driver_flush_buffer(tty); } - if (I_IXON(tty)) - start_tty(tty); - if (L_ECHO(tty)) { + if (L_ECHO(tty)) echo_char(c, tty); - process_echoes(tty); - } if (tty->pgrp) kill_pgrp(tty->pgrp, signal, 1); return; @@ -1222,7 +815,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { eraser(c, tty); - process_echoes(tty); return; } if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { @@ -1230,9 +822,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (L_ECHO(tty)) { finish_erasing(tty); if (L_ECHOCTL(tty)) { - echo_char_raw('^', tty); - echo_char_raw('\b', tty); - process_echoes(tty); + tty_put_char(tty, '^'); + tty_put_char(tty, '\b'); } } return; @@ -1243,29 +834,22 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) finish_erasing(tty); echo_char(c, tty); - echo_char_raw('\n', tty); + opost('\n', tty); while (tail != tty->read_head) { echo_char(tty->read_buf[tail], tty); tail = (tail+1) & (N_TTY_BUF_SIZE-1); } - process_echoes(tty); return; } if (c == '\n') { - if (tty->read_cnt >= N_TTY_BUF_SIZE) { - if (L_ECHO(tty)) - process_output('\a', tty); - return; - } if (L_ECHO(tty) || L_ECHONL(tty)) { - echo_char_raw('\n', tty); - process_echoes(tty); + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) + tty_put_char(tty, '\a'); + opost('\n', tty); } goto handle_newline; } if (c == EOF_CHAR(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE) - return; if (tty->canon_head != tty->read_head) set_bit(TTY_PUSH, &tty->flags); c = __DISABLED_CHAR; @@ -1273,28 +857,22 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) } if ((c == EOL_CHAR(tty)) || (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { - parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) - ? 1 : 0; - if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) { - if (L_ECHO(tty)) - process_output('\a', tty); - return; - } /* * XXX are EOL_CHAR and EOL2_CHAR echoed?!? */ if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) + tty_put_char(tty, '\a'); /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) - echo_set_canon_col(tty); + tty->canon_column = tty->column; echo_char(c, tty); - process_echoes(tty); } /* * XXX does PARMRK doubling happen for * EOL_CHAR and EOL2_CHAR? */ - if (parmrk) + if (I_PARMRK(tty) && c == (unsigned char) '\377') put_tty_queue(c, tty); handle_newline: @@ -1311,27 +889,23 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) } } - parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; - if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { - /* beep if no space */ - if (L_ECHO(tty)) - process_output('\a', tty); - return; - } + finish_erasing(tty); if (L_ECHO(tty)) { - finish_erasing(tty); + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + tty_put_char(tty, '\a'); /* beep if no space */ + return; + } if (c == '\n') - echo_char_raw('\n', tty); + opost('\n', tty); else { /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) - echo_set_canon_col(tty); + tty->canon_column = tty->column; echo_char(c, tty); } - process_echoes(tty); } - if (parmrk) + if (I_PARMRK(tty) && c == (unsigned char) '\377') put_tty_queue(c, tty); put_tty_queue(c, tty); @@ -1349,11 +923,10 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) static void n_tty_write_wakeup(struct tty_struct *tty) { - /* Write out any echoed characters that are still pending */ - process_echoes(tty); - - if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) + if (tty->fasync) { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); kill_fasync(&tty->fasync, SIGIO, POLL_OUT); + } } /** @@ -1561,10 +1134,6 @@ static void n_tty_close(struct tty_struct *tty) free_buf(tty->read_buf); tty->read_buf = NULL; } - if (tty->echo_buf) { - free_buf(tty->echo_buf); - tty->echo_buf = NULL; - } } /** @@ -1582,19 +1151,13 @@ static int n_tty_open(struct tty_struct *tty) if (!tty) return -EINVAL; - /* These are ugly. Currently a malloc failure here can panic */ + /* This one is ugly. Currently a malloc failure here can panic */ if (!tty->read_buf) { tty->read_buf = alloc_buf(); if (!tty->read_buf) return -ENOMEM; } - if (!tty->echo_buf) { - tty->echo_buf = alloc_buf(); - if (!tty->echo_buf) - return -ENOMEM; - } memset(tty->read_buf, 0, N_TTY_BUF_SIZE); - memset(tty->echo_buf, 0, N_TTY_BUF_SIZE); reset_buffer_flags(tty); tty->column = 0; n_tty_set_termios(tty, NULL); @@ -1924,23 +1487,16 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, * @buf: userspace buffer pointer * @nr: size of I/O * - * Write function of the terminal device. This is serialized with + * Write function of the terminal device. This is serialized with * respect to other write callers but not to termios changes, reads - * and other such events. Since the receive code will echo characters, - * thus calling driver write methods, the output_lock is used in - * the output processing functions called here as well as in the - * echo processing function to protect the column state and space - * left in the buffer. + * and other such events. We must be careful with N_TTY as the receive + * code will echo characters, thus calling driver write methods. * * This code must be sure never to sleep through a hangup. - * - * Locking: output_lock to protect column state and space left - * (note that the process_output*() functions take this - * lock themselves) */ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) + const unsigned char *buf, size_t nr) { const unsigned char *b = buf; DECLARE_WAITQUEUE(wait, current); @@ -1954,9 +1510,6 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, return retval; } - /* Write out any echoed characters that are still pending */ - process_echoes(tty); - add_wait_queue(&tty->write_wait, &wait); while (1) { set_current_state(TASK_INTERRUPTIBLE); @@ -1970,7 +1523,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, } if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) { while (nr > 0) { - ssize_t num = process_output_block(tty, b, nr); + ssize_t num = opost_block(tty, b, nr); if (num < 0) { if (num == -EAGAIN) break; @@ -1982,7 +1535,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, if (nr == 0) break; c = *b; - if (process_output(c, tty) < 0) + if (opost(c, tty) < 0) break; b++; nr--; } @@ -2012,8 +1565,6 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, break_out: __set_current_state(TASK_RUNNING); remove_wait_queue(&tty->write_wait, &wait); - if (b - buf != nr && tty->fasync) - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); return (b - buf) ? b - buf : retval; } @@ -2112,3 +1663,4 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup }; + diff --git a/trunk/drivers/char/nozomi.c b/trunk/drivers/char/nozomi.c index d6102b644b55..9a34a1935283 100644 --- a/trunk/drivers/char/nozomi.c +++ b/trunk/drivers/char/nozomi.c @@ -353,7 +353,6 @@ struct ctrl_ul { /* This holds all information that is needed regarding a port */ struct port { - struct tty_port port; u8 update_flow_control; struct ctrl_ul ctrl_ul; struct ctrl_dl ctrl_dl; @@ -366,6 +365,8 @@ struct port { u8 toggle_ul; u16 token_dl; + struct tty_struct *tty; + int tty_open_count; /* mutex to ensure one access patch to this port */ struct mutex tty_sem; wait_queue_head_t tty_wait; @@ -787,14 +788,14 @@ static void disable_transmit_dl(enum port_type port, struct nozomi *dc) * Return 1 - send buffer to card and ack. * Return 0 - don't ack, don't send buffer to card. */ -static int send_data(enum port_type index, struct nozomi *dc) +static int send_data(enum port_type index, const struct nozomi *dc) { u32 size = 0; - struct port *port = &dc->port[index]; + const struct port *port = &dc->port[index]; const u8 toggle = port->toggle_ul; void __iomem *addr = port->ul_addr[toggle]; const u32 ul_size = port->ul_size[toggle]; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->tty; /* Get data from tty and place in buf for now */ size = __kfifo_get(port->fifo_ul, dc->send_buf, @@ -802,7 +803,6 @@ static int send_data(enum port_type index, struct nozomi *dc) if (size == 0) { DBG4("No more data to send, disable link:"); - tty_kref_put(tty); return 0; } @@ -815,7 +815,6 @@ static int send_data(enum port_type index, struct nozomi *dc) if (tty) tty_wakeup(tty); - tty_kref_put(tty); return 1; } @@ -827,7 +826,7 @@ static int receive_data(enum port_type index, struct nozomi *dc) u32 offset = 4; struct port *port = &dc->port[index]; void __iomem *addr = port->dl_addr[port->toggle_dl]; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->tty; int i; if (unlikely(!tty)) { @@ -871,7 +870,7 @@ static int receive_data(enum port_type index, struct nozomi *dc) } set_bit(index, &dc->flip); - tty_kref_put(tty); + return 1; } @@ -1277,15 +1276,9 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) exit_handler: spin_unlock(&dc->spin_mutex); - for (a = 0; a < NOZOMI_MAX_PORTS; a++) { - struct tty_struct *tty; - if (test_and_clear_bit(a, &dc->flip)) { - tty = tty_port_tty_get(&dc->port[a].port); - if (tty) - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - } + for (a = 0; a < NOZOMI_MAX_PORTS; a++) + if (test_and_clear_bit(a, &dc->flip)) + tty_flip_buffer_push(dc->port[a].tty); return IRQ_HANDLED; none: spin_unlock(&dc->spin_mutex); @@ -1460,10 +1453,12 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, for (i = 0; i < MAX_PORT; i++) { mutex_init(&dc->port[i].tty_sem); - tty_port_init(&dc->port[i].port); + dc->port[i].tty_open_count = 0; + dc->port[i].tty = NULL; tty_register_device(ntty_driver, dc->index_start + i, &pdev->dev); } + return 0; err_free_sbuf: @@ -1487,16 +1482,14 @@ static void __devexit tty_exit(struct nozomi *dc) flush_scheduled_work(); - for (i = 0; i < MAX_PORT; ++i) { - struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); - if (tty && list_empty(&tty->hangup_work.entry)) - tty_hangup(tty); - tty_kref_put(tty); - } - /* Racy below - surely should wait for scheduled work to be done or - complete off a hangup method ? */ + for (i = 0; i < MAX_PORT; ++i) + if (dc->port[i].tty && \ + list_empty(&dc->port[i].tty->hangup_work.entry)) + tty_hangup(dc->port[i].tty); + while (dc->open_ttys) msleep(1); + for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) tty_unregister_device(ntty_driver, i); } @@ -1586,22 +1579,23 @@ static int ntty_open(struct tty_struct *tty, struct file *file) if (mutex_lock_interruptible(&port->tty_sem)) return -ERESTARTSYS; - port->port.count++; + port->tty_open_count++; dc->open_ttys++; /* Enable interrupt downlink for channel */ - if (port->port.count == 1) { - /* FIXME: is this needed now ? */ + if (port->tty_open_count == 1) { tty->low_latency = 1; tty->driver_data = port; - tty_port_tty_set(&port->port, tty); + port->tty = tty; DBG1("open: %d", port->token_dl); spin_lock_irqsave(&dc->spin_mutex, flags); dc->last_ier = dc->last_ier | port->token_dl; writew(dc->last_ier, dc->reg_ier); spin_unlock_irqrestore(&dc->spin_mutex, flags); } + mutex_unlock(&port->tty_sem); + return 0; } @@ -1612,30 +1606,31 @@ static int ntty_open(struct tty_struct *tty, struct file *file) static void ntty_close(struct tty_struct *tty, struct file *file) { struct nozomi *dc = get_dc_by_tty(tty); - struct port *nport = tty->driver_data; - struct tty_port *port = &nport->port; + struct port *port = tty->driver_data; unsigned long flags; - if (!dc || !nport) + if (!dc || !port) return; - /* Users cannot interrupt a close */ - mutex_lock(&nport->tty_sem); + if (mutex_lock_interruptible(&port->tty_sem)) + return; - WARN_ON(!port->count); + if (!port->tty_open_count) + goto exit; dc->open_ttys--; - port->count--; - tty_port_tty_set(port, NULL); + port->tty_open_count--; - if (port->count == 0) { - DBG1("close: %d", nport->token_dl); + if (port->tty_open_count == 0) { + DBG1("close: %d", port->token_dl); spin_lock_irqsave(&dc->spin_mutex, flags); - dc->last_ier &= ~(nport->token_dl); + dc->last_ier &= ~(port->token_dl); writew(dc->last_ier, dc->reg_ier); spin_unlock_irqrestore(&dc->spin_mutex, flags); } - mutex_unlock(&nport->tty_sem); + +exit: + mutex_unlock(&port->tty_sem); } /* @@ -1665,7 +1660,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, return -EAGAIN; } - if (unlikely(!port->port.count)) { + if (unlikely(!port->tty_open_count)) { DBG1(" "); goto exit; } @@ -1715,7 +1710,7 @@ static int ntty_write_room(struct tty_struct *tty) if (!mutex_trylock(&port->tty_sem)) return 0; - if (!port->port.count) + if (!port->tty_open_count) goto exit; room = port->fifo_ul->size - __kfifo_len(port->fifo_ul); @@ -1871,7 +1866,7 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty) goto exit_in_buffer; } - if (unlikely(!port->port.count)) { + if (unlikely(!port->tty_open_count)) { dev_err(&dc->pdev->dev, "No tty open?\n"); rval = -ENODEV; goto exit_in_buffer; diff --git a/trunk/drivers/char/pcmcia/synclink_cs.c b/trunk/drivers/char/pcmcia/synclink_cs.c index dc073e167abc..4d64a02612a4 100644 --- a/trunk/drivers/char/pcmcia/synclink_cs.c +++ b/trunk/drivers/char/pcmcia/synclink_cs.c @@ -138,15 +138,20 @@ struct _input_signal_events { */ typedef struct _mgslpc_info { - struct tty_port port; void *if_ptr; /* General purpose pointer (used by SPPP) */ int magic; + int flags; + int count; /* count of opens */ int line; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ struct mgsl_icount icount; + struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ + int blocked_open; /* # of blocked opens */ unsigned char read_status_mask; unsigned char ignore_status_mask; @@ -165,6 +170,9 @@ typedef struct _mgslpc_info { int rx_buf_count; /* total number of rx buffers */ int rx_frame_count; /* number of full rx buffers */ + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t status_event_wait_q; wait_queue_head_t event_wait_q; struct timer_list tx_timer; /* HDLC transmit timeout timer */ @@ -367,7 +375,7 @@ static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short static void rx_start(MGSLPC_INFO *info); static void rx_stop(MGSLPC_INFO *info); -static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty); +static void tx_start(MGSLPC_INFO *info); static void tx_stop(MGSLPC_INFO *info); static void tx_set_idle(MGSLPC_INFO *info); @@ -381,8 +389,7 @@ static void async_mode(MGSLPC_INFO *info); static void tx_timeout(unsigned long context); -static int carrier_raised(struct tty_port *port); -static void raise_dtr_rts(struct tty_port *port); +static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); #if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) @@ -403,7 +410,7 @@ static void release_resources(MGSLPC_INFO *info); static void mgslpc_add_device(MGSLPC_INFO *info); static void mgslpc_remove_device(MGSLPC_INFO *info); -static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty); +static bool rx_get_frame(MGSLPC_INFO *info); static void rx_reset_buffers(MGSLPC_INFO *info); static int rx_alloc_buffers(MGSLPC_INFO *info); static void rx_free_buffers(MGSLPC_INFO *info); @@ -414,7 +421,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id); * Bottom half interrupt handlers */ static void bh_handler(struct work_struct *work); -static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty); +static void bh_transmit(MGSLPC_INFO *info); static void bh_status(MGSLPC_INFO *info); /* @@ -425,10 +432,10 @@ static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); -static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty); +static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params); static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); static int set_txidle(MGSLPC_INFO *info, int idle_mode); -static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty); +static int set_txenable(MGSLPC_INFO *info, int enable); static int tx_abort(MGSLPC_INFO *info); static int set_rxenable(MGSLPC_INFO *info, int enable); static int wait_events(MGSLPC_INFO *info, int __user *mask); @@ -467,7 +474,7 @@ static struct tty_driver *serial_driver; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 -static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty); +static void mgslpc_change_params(MGSLPC_INFO *info); static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); /* PCMCIA prototypes */ @@ -510,11 +517,6 @@ static void ldisc_receive_buf(struct tty_struct *tty, } } -static const struct tty_port_operations mgslpc_port_ops = { - .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts -}; - static int mgslpc_probe(struct pcmcia_device *link) { MGSLPC_INFO *info; @@ -530,12 +532,12 @@ static int mgslpc_probe(struct pcmcia_device *link) } info->magic = MGSLPC_MAGIC; - tty_port_init(&info->port); - info->port.ops = &mgslpc_port_ops; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; - info->port.close_delay = 5*HZ/10; - info->port.closing_wait = 30*HZ; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->lock); @@ -782,7 +784,7 @@ static void tx_release(struct tty_struct *tty) spin_lock_irqsave(&info->lock,flags); if (!info->tx_enabled) - tx_start(info, tty); + tx_start(info); spin_unlock_irqrestore(&info->lock,flags); } @@ -821,7 +823,6 @@ static int bh_action(MGSLPC_INFO *info) static void bh_handler(struct work_struct *work) { MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); - struct tty_struct *tty; int action; if (!info) @@ -832,7 +833,6 @@ static void bh_handler(struct work_struct *work) __FILE__,__LINE__,info->device_name); info->bh_running = true; - tty = tty_port_tty_get(&info->port); while((action = bh_action(info)) != 0) { @@ -844,10 +844,10 @@ static void bh_handler(struct work_struct *work) switch (action) { case BH_RECEIVE: - while(rx_get_frame(info, tty)); + while(rx_get_frame(info)); break; case BH_TRANSMIT: - bh_transmit(info, tty); + bh_transmit(info); break; case BH_STATUS: bh_status(info); @@ -859,14 +859,14 @@ static void bh_handler(struct work_struct *work) } } - tty_kref_put(tty); if (debug_level >= DEBUG_LEVEL_BH) printk( "%s(%d):bh_handler(%s) exit\n", __FILE__,__LINE__,info->device_name); } -static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty) +static void bh_transmit(MGSLPC_INFO *info) { + struct tty_struct *tty = info->tty; if (debug_level >= DEBUG_LEVEL_BH) printk("bh_transmit() entry on %s\n", info->device_name); @@ -945,11 +945,12 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) issue_command(info, CHA, CMD_RXFIFO); } -static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty) +static void rx_ready_async(MGSLPC_INFO *info, int tcd) { unsigned char data, status, flag; int fifo_count; int work = 0; + struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; if (tcd) { @@ -1012,7 +1013,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty) } -static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) +static void tx_done(MGSLPC_INFO *info) { if (!info->tx_active) return; @@ -1041,7 +1042,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) else #endif { - if (tty->stopped || tty->hw_stopped) { + if (info->tty->stopped || info->tty->hw_stopped) { tx_stop(info); return; } @@ -1049,7 +1050,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) } } -static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) +static void tx_ready(MGSLPC_INFO *info) { unsigned char fifo_count = 32; int c; @@ -1061,7 +1062,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) if (!info->tx_active) return; } else { - if (tty->stopped || tty->hw_stopped) { + if (info->tty->stopped || info->tty->hw_stopped) { tx_stop(info); return; } @@ -1098,7 +1099,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) } } -static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) +static void cts_change(MGSLPC_INFO *info) { get_signals(info); if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1111,14 +1112,14 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if (info->port.flags & ASYNC_CTS_FLOW) { - if (tty->hw_stopped) { + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { if (info->serial_signals & SerialSignal_CTS) { if (debug_level >= DEBUG_LEVEL_ISR) printk("CTS tx start..."); - if (tty) - tty->hw_stopped = 0; - tx_start(info, tty); + if (info->tty) + info->tty->hw_stopped = 0; + tx_start(info); info->pending_bh |= BH_TRANSMIT; return; } @@ -1126,8 +1127,8 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) if (!(info->serial_signals & SerialSignal_CTS)) { if (debug_level >= DEBUG_LEVEL_ISR) printk("CTS tx stop..."); - if (tty) - tty->hw_stopped = 1; + if (info->tty) + info->tty->hw_stopped = 1; tx_stop(info); } } @@ -1135,7 +1136,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) info->pending_bh |= BH_STATUS; } -static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty) +static void dcd_change(MGSLPC_INFO *info) { get_signals(info); if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1157,17 +1158,17 @@ static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if (info->port.flags & ASYNC_CHECK_CD) { + if (info->flags & ASYNC_CHECK_CD) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s CD now %s...", info->device_name, (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); if (info->serial_signals & SerialSignal_DCD) - wake_up_interruptible(&info->port.open_wait); + wake_up_interruptible(&info->open_wait); else { if (debug_level >= DEBUG_LEVEL_ISR) printk("doing serial hangup..."); - if (tty) - tty_hangup(tty); + if (info->tty) + tty_hangup(info->tty); } } info->pending_bh |= BH_STATUS; @@ -1213,7 +1214,6 @@ static void ri_change(MGSLPC_INFO *info) static irqreturn_t mgslpc_isr(int dummy, void *dev_id) { MGSLPC_INFO *info = dev_id; - struct tty_struct *tty; unsigned short isr; unsigned char gis, pis; int count=0; @@ -1224,8 +1224,6 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) if (!(info->p_dev->_locked)) return IRQ_HANDLED; - tty = tty_port_tty_get(&info->port); - spin_lock(&info->lock); while ((gis = read_reg(info, CHA + GIS))) { @@ -1241,9 +1239,9 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) if (gis & (BIT1 + BIT0)) { isr = read_reg16(info, CHB + ISR); if (isr & IRQ_DCD) - dcd_change(info, tty); + dcd_change(info); if (isr & IRQ_CTS) - cts_change(info, tty); + cts_change(info); } if (gis & (BIT3 + BIT2)) { @@ -1260,8 +1258,8 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) } if (isr & IRQ_BREAK_ON) { info->icount.brk++; - if (info->port.flags & ASYNC_SAK) - do_SAK(tty); + if (info->flags & ASYNC_SAK) + do_SAK(info->tty); } if (isr & IRQ_RXTIME) { issue_command(info, CHA, CMD_RXFIFO_READ); @@ -1270,7 +1268,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) if (info->params.mode == MGSL_MODE_HDLC) rx_ready_hdlc(info, isr & IRQ_RXEOM); else - rx_ready_async(info, isr & IRQ_RXEOM, tty); + rx_ready_async(info, isr & IRQ_RXEOM); } /* transmit IRQs */ @@ -1279,14 +1277,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) info->icount.txabort++; else info->icount.txunder++; - tx_done(info, tty); + tx_done(info); } else if (isr & IRQ_ALLSENT) { info->icount.txok++; - tx_done(info, tty); + tx_done(info); } else if (isr & IRQ_TXFIFO) - tx_ready(info, tty); + tx_ready(info); } if (gis & BIT7) { pis = read_reg(info, CHA + PIS); @@ -1310,7 +1308,6 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) } spin_unlock(&info->lock); - tty_kref_put(tty); if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):mgslpc_isr(%d)exit.\n", @@ -1321,14 +1318,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) /* Initialize and start device. */ -static int startup(MGSLPC_INFO * info, struct tty_struct *tty) +static int startup(MGSLPC_INFO * info) { int retval = 0; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name); - if (info->port.flags & ASYNC_INITIALIZED) + if (info->flags & ASYNC_INITIALIZED) return 0; if (!info->tx_buf) { @@ -1355,30 +1352,30 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty) retval = adapter_test(info); if ( retval ) { - if (capable(CAP_SYS_ADMIN) && tty) - set_bit(TTY_IO_ERROR, &tty->flags); + if (capable(CAP_SYS_ADMIN) && info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); release_resources(info); return retval; } /* program hardware for current parameters */ - mgslpc_change_params(info, tty); + mgslpc_change_params(info); - if (tty) - clear_bit(TTY_IO_ERROR, &tty->flags); + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->port.flags |= ASYNC_INITIALIZED; + info->flags |= ASYNC_INITIALIZED; return 0; } /* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware */ -static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) +static void shutdown(MGSLPC_INFO * info) { unsigned long flags; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!(info->flags & ASYNC_INITIALIZED)) return; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1405,7 +1402,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) /* TODO:disable interrupts instead of reset to preserve signal states */ reset_device(info); - if (!tty || tty->termios->c_cflag & HUPCL) { + if (!info->tty || info->tty->termios->c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -1414,13 +1411,13 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) release_resources(info); - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); - info->port.flags &= ~ASYNC_INITIALIZED; + info->flags &= ~ASYNC_INITIALIZED; } -static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) +static void mgslpc_program_hw(MGSLPC_INFO *info) { unsigned long flags; @@ -1446,7 +1443,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); get_signals(info); - if (info->netcount || (tty && (tty->termios->c_cflag & CREAD))) + if (info->netcount || info->tty->termios->c_cflag & CREAD) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -1454,19 +1451,19 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) /* Reconfigure adapter based on new parameters */ -static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) +static void mgslpc_change_params(MGSLPC_INFO *info) { unsigned cflag; int bits_per_char; - if (!tty || !tty->termios) + if (!info->tty || !info->tty->termios) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); - cflag = tty->termios->c_cflag; + cflag = info->tty->termios->c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -1513,7 +1510,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) * current data rate. */ if (info->params.data_rate <= 460800) { - info->params.data_rate = tty_get_baud_rate(tty); + info->params.data_rate = tty_get_baud_rate(info->tty); } if ( info->params.data_rate ) { @@ -1523,24 +1520,24 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) - info->port.flags |= ASYNC_CTS_FLOW; + info->flags |= ASYNC_CTS_FLOW; else - info->port.flags &= ~ASYNC_CTS_FLOW; + info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->port.flags &= ~ASYNC_CHECK_CD; + info->flags &= ~ASYNC_CHECK_CD; else - info->port.flags |= ASYNC_CHECK_CD; + info->flags |= ASYNC_CHECK_CD; /* process tty input control flags */ info->read_status_mask = 0; - if (I_INPCK(tty)) + if (I_INPCK(info->tty)) info->read_status_mask |= BIT7 | BIT6; - if (I_IGNPAR(tty)) + if (I_IGNPAR(info->tty)) info->ignore_status_mask |= BIT7 | BIT6; - mgslpc_program_hw(info, tty); + mgslpc_program_hw(info); } /* Add a character to the transmit buffer @@ -1600,7 +1597,7 @@ static void mgslpc_flush_chars(struct tty_struct *tty) spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) - tx_start(info, tty); + tx_start(info); spin_unlock_irqrestore(&info->lock,flags); } @@ -1662,7 +1659,7 @@ static int mgslpc_write(struct tty_struct * tty, if (info->tx_count && !tty->stopped && !tty->hw_stopped) { spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) - tx_start(info, tty); + tx_start(info); spin_unlock_irqrestore(&info->lock,flags); } cleanup: @@ -1767,7 +1764,7 @@ static void mgslpc_send_xchar(struct tty_struct *tty, char ch) if (ch) { spin_lock_irqsave(&info->lock,flags); if (!info->tx_enabled) - tx_start(info, tty); + tx_start(info); spin_unlock_irqrestore(&info->lock,flags); } } @@ -1865,7 +1862,7 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) * * Returns: 0 if success, otherwise error code */ -static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty) +static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params) { unsigned long flags; MGSL_PARAMS tmp_params; @@ -1886,7 +1883,7 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); spin_unlock_irqrestore(&info->lock,flags); - mgslpc_change_params(info, tty); + mgslpc_change_params(info); return 0; } @@ -1947,7 +1944,7 @@ static int set_interface(MGSLPC_INFO * info, int if_mode) return 0; } -static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty) +static int set_txenable(MGSLPC_INFO * info, int enable) { unsigned long flags; @@ -1957,7 +1954,7 @@ static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty) spin_lock_irqsave(&info->lock,flags); if (enable) { if (!info->tx_enabled) - tx_start(info, tty); + tx_start(info); } else { if (info->tx_enabled) tx_stop(info); @@ -2266,11 +2263,6 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - int error; - struct mgsl_icount cnow; /* kernel counter temps */ - struct serial_icounter_struct __user *p_cuser; /* user space */ - void __user *argp = (void __user *)arg; - unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, @@ -2285,11 +2277,22 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, return -EIO; } + return ioctl_common(info, cmd, arg); +} + +static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) +{ + int error; + struct mgsl_icount cnow; /* kernel counter temps */ + struct serial_icounter_struct __user *p_cuser; /* user space */ + void __user *argp = (void __user *)arg; + unsigned long flags; + switch (cmd) { case MGSL_IOCGPARAMS: return get_params(info, argp); case MGSL_IOCSPARAMS: - return set_params(info, argp, tty); + return set_params(info, argp); case MGSL_IOCGTXIDLE: return get_txidle(info, argp); case MGSL_IOCSTXIDLE: @@ -2299,7 +2302,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, case MGSL_IOCSIF: return set_interface(info,(int)arg); case MGSL_IOCTXENABLE: - return set_txenable(info,(int)arg, tty); + return set_txenable(info,(int)arg); case MGSL_IOCRXENABLE: return set_rxenable(info,(int)arg); case MGSL_IOCTXABORT: @@ -2366,7 +2369,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term == RELEVANT_IFLAG(old_termios->c_iflag))) return; - mgslpc_change_params(info, tty); + mgslpc_change_params(info); /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && @@ -2401,34 +2404,81 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term static void mgslpc_close(struct tty_struct *tty, struct file * filp) { MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - struct tty_port *port = &info->port; if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", - __FILE__,__LINE__, info->device_name, port->count); + __FILE__,__LINE__, info->device_name, info->count); + + if (!info->count) + return; - WARN_ON(!port->count); + if (tty_hung_up_p(filp)) + goto cleanup; + + if ((tty->count == 1) && (info->count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + printk("mgslpc_close: bad refcount; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } - if (tty_port_close_start(port, tty, filp) == 0) + info->count--; + + /* if at least one open remaining, leave hardware active */ + if (info->count) goto cleanup; - if (port->flags & ASYNC_INITIALIZED) + info->flags |= ASYNC_CLOSING; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgslpc_close(%s) calling tty_wait_until_sent\n", + __FILE__,__LINE__, info->device_name ); + tty_wait_until_sent(tty, info->closing_wait); + } + + if (info->flags & ASYNC_INITIALIZED) mgslpc_wait_until_sent(tty, info->timeout); mgslpc_flush_buffer(tty); tty_ldisc_flush(tty); - shutdown(info, tty); - - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); + + shutdown(info); + + tty->closing = 0; + info->tty = NULL; + + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs(info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + + wake_up_interruptible(&info->close_wait); + cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, port->count); + tty->driver->name, info->count); } /* Wait until the transmitter is empty. @@ -2448,7 +2498,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent")) return; - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!(info->flags & ASYNC_INITIALIZED)) goto exit; orig_jiffies = jiffies; @@ -2509,40 +2559,120 @@ static void mgslpc_hangup(struct tty_struct *tty) return; mgslpc_flush_buffer(tty); - shutdown(info, tty); - tty_port_hangup(&info->port); + shutdown(info); + + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->tty = NULL; + + wake_up_interruptible(&info->open_wait); } -static int carrier_raised(struct tty_port *port) +/* Block the current process until the specified port + * is ready to be opened. + */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, + MGSLPC_INFO *info) { - MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); - unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + int retval; + bool do_clocal = false; + bool extra_count = false; + unsigned long flags; - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready on %s\n", + __FILE__,__LINE__, tty->driver->name ); - if (info->serial_signals & SerialSignal_DCD) - return 1; - return 0; -} + if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + /* nonblock mode is set or port is not enabled */ + /* just verify that callout device is not active */ + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } -static void raise_dtr_rts(struct tty_port *port) -{ - MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); - unsigned long flags; + if (tty->termios->c_cflag & CLOCAL) + do_clocal = true; - spin_lock_irqsave(&info->lock,flags); - info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); -} + /* Wait for carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * mgslpc_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready before block on %s count=%d\n", + __FILE__,__LINE__, tty->driver->name, info->count ); + + spin_lock_irqsave(&info->lock, flags); + if (!tty_hung_up_p(filp)) { + extra_count = true; + info->count--; + } + spin_unlock_irqrestore(&info->lock, flags); + info->blocked_open++; + + while (1) { + if ((tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->lock,flags); + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + set_current_state(TASK_INTERRUPTIBLE); + + if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ + retval = (info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + if (!(info->flags & ASYNC_CLOSING) && + (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready blocking on %s count=%d\n", + __FILE__,__LINE__, tty->driver->name, info->count ); + + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + + if (extra_count) + info->count++; + info->blocked_open--; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready after blocking on %s count=%d\n", + __FILE__,__LINE__, tty->driver->name, info->count ); + + if (!retval) + info->flags |= ASYNC_NORMAL_ACTIVE; + + return retval; +} static int mgslpc_open(struct tty_struct *tty, struct file * filp) { MGSLPC_INFO *info; - struct tty_port *port; int retval, line; unsigned long flags; @@ -2561,24 +2691,23 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) return -ENODEV; - port = &info->port; tty->driver_data = info; - tty_port_tty_set(port, tty); + info->tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, port->count); + __FILE__,__LINE__,tty->driver->name, info->count); /* If port is closing, signal caller to try again */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){ - if (port->flags & ASYNC_CLOSING) - interruptible_sleep_on(&port->close_wait); - retval = ((port->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + retval = ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); goto cleanup; } - tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { @@ -2586,19 +2715,17 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } - spin_lock(&port->lock); - port->count++; - spin_unlock(&port->lock); + info->count++; spin_unlock_irqrestore(&info->netlock, flags); - if (port->count == 1) { + if (info->count == 1) { /* 1st open on this device, init hardware */ - retval = startup(info, tty); + retval = startup(info); if (retval < 0) goto cleanup; } - retval = tty_port_block_til_ready(&info->port, tty, filp); + retval = block_til_ready(tty, filp, info); if (retval) { if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready(%s) returned %d\n", @@ -2612,6 +2739,13 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) retval = 0; cleanup: + if (retval) { + if (tty->count == 1) + info->tty = NULL; /* tty layer will release tty struct */ + if(info->count) + info->count--; + } + return retval; } @@ -3366,7 +3500,7 @@ static void rx_start(MGSLPC_INFO *info) info->rx_enabled = true; } -static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty) +static void tx_start(MGSLPC_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):tx_start(%s)\n", @@ -3390,11 +3524,11 @@ static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty) if (info->params.mode == MGSL_MODE_ASYNC) { if (!info->tx_active) { info->tx_active = true; - tx_ready(info, tty); + tx_ready(info); } } else { info->tx_active = true; - tx_ready(info, tty); + tx_ready(info); mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); } @@ -3715,12 +3849,13 @@ static void rx_reset_buffers(MGSLPC_INFO *info) * * Returns true if frame returned, otherwise false */ -static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty) +static bool rx_get_frame(MGSLPC_INFO *info) { unsigned short status; RXBUF *buf; unsigned int framesize = 0; unsigned long flags; + struct tty_struct *tty = info->tty; bool return_frame = false; if (info->rx_frame_count == 0) @@ -3940,11 +4075,7 @@ static void tx_timeout(unsigned long context) hdlcdev_tx_done(info); else #endif - { - struct tty_struct *tty = tty_port_tty_get(&info->port); - bh_transmit(info, tty); - tty_kref_put(tty); - } + bh_transmit(info); } #if SYNCLINK_GENERIC_HDLC @@ -3963,12 +4094,11 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { MGSLPC_INFO *info = dev_to_port(dev); - struct tty_struct *tty; unsigned char new_encoding; unsigned short new_crctype; /* return error if TTY interface open */ - if (info->port.count) + if (info->count) return -EBUSY; switch (encoding) @@ -3993,11 +4123,8 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, info->params.crc_type = new_crctype; /* if network interface up, reprogram hardware */ - if (info->netcount) { - tty = tty_port_tty_get(&info->port); - mgslpc_program_hw(info, tty); - tty_kref_put(tty); - } + if (info->netcount) + mgslpc_program_hw(info); return 0; } @@ -4038,11 +4165,8 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) /* start hardware transmitter if necessary */ spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) { - struct tty_struct *tty = tty_port_tty_get(&info->port); - tx_start(info, tty); - tty_kref_put(tty); - } + if (!info->tx_active) + tx_start(info); spin_unlock_irqrestore(&info->lock,flags); return 0; @@ -4059,7 +4183,6 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) static int hdlcdev_open(struct net_device *dev) { MGSLPC_INFO *info = dev_to_port(dev); - struct tty_struct *tty; int rc; unsigned long flags; @@ -4072,7 +4195,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { + if (info->count != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -4080,19 +4203,17 @@ static int hdlcdev_open(struct net_device *dev) info->netcount=1; spin_unlock_irqrestore(&info->netlock, flags); - tty = tty_port_tty_get(&info->port); /* claim resources and init adapter */ - if ((rc = startup(info, tty)) != 0) { - tty_kref_put(tty); + if ((rc = startup(info)) != 0) { spin_lock_irqsave(&info->netlock, flags); info->netcount=0; spin_unlock_irqrestore(&info->netlock, flags); return rc; } + /* assert DTR and RTS, apply hardware settings */ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; - mgslpc_program_hw(info, tty); - tty_kref_put(tty); + mgslpc_program_hw(info); /* enable network layer transmit */ dev->trans_start = jiffies; @@ -4120,7 +4241,6 @@ static int hdlcdev_open(struct net_device *dev) static int hdlcdev_close(struct net_device *dev) { MGSLPC_INFO *info = dev_to_port(dev); - struct tty_struct *tty = tty_port_tty_get(&info->port); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -4129,8 +4249,8 @@ static int hdlcdev_close(struct net_device *dev) netif_stop_queue(dev); /* shutdown adapter and release resources */ - shutdown(info, tty); - tty_kref_put(tty); + shutdown(info); + hdlc_close(dev); spin_lock_irqsave(&info->netlock, flags); @@ -4161,7 +4281,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); /* return error if TTY interface open */ - if (info->port.count) + if (info->count) return -EBUSY; if (cmd != SIOCWANDEV) @@ -4234,11 +4354,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) info->params.clock_speed = 0; /* if network interface up, reprogram hardware */ - if (info->netcount) { - struct tty_struct *tty = tty_port_tty_get(&info->port); - mgslpc_program_hw(info, tty); - tty_kref_put(tty); - } + if (info->netcount) + mgslpc_program_hw(info); return 0; default: diff --git a/trunk/drivers/char/pty.c b/trunk/drivers/char/pty.c index 112a6ba9a96f..6d4582712b1f 100644 --- a/trunk/drivers/char/pty.c +++ b/trunk/drivers/char/pty.c @@ -5,6 +5,8 @@ * * Added support for a Unix98-style ptmx device. * -- C. Scott Ananian , 14-Jan-1998 + * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to + * waiting writers -- Sapan Bhatia * * When reading this code see also fs/devpts. In particular note that the * driver_data field is used by the devpts side as a binding to the devpts @@ -215,6 +217,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp) clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); retval = 0; out: return retval; @@ -227,55 +230,6 @@ static void pty_set_termios(struct tty_struct *tty, tty->termios->c_cflag |= (CS8 | CREAD); } -/** - * pty_do_resize - resize event - * @tty: tty being resized - * @real_tty: real tty (not the same as tty if using a pty/tty pair) - * @rows: rows (character) - * @cols: cols (character) - * - * Update the termios variables and send the neccessary signals to - * peform a terminal resize correctly - */ - -int pty_resize(struct tty_struct *tty, struct winsize *ws) -{ - struct pid *pgrp, *rpgrp; - unsigned long flags; - struct tty_struct *pty = tty->link; - - /* For a PTY we need to lock the tty side */ - mutex_lock(&tty->termios_mutex); - if (!memcmp(ws, &tty->winsize, sizeof(*ws))) - goto done; - - /* Get the PID values and reference them so we can - avoid holding the tty ctrl lock while sending signals. - We need to lock these individually however. */ - - spin_lock_irqsave(&tty->ctrl_lock, flags); - pgrp = get_pid(tty->pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - - spin_lock_irqsave(&pty->ctrl_lock, flags); - rpgrp = get_pid(pty->pgrp); - spin_unlock_irqrestore(&pty->ctrl_lock, flags); - - if (pgrp) - kill_pgrp(pgrp, SIGWINCH, 1); - if (rpgrp != pgrp && rpgrp) - kill_pgrp(rpgrp, SIGWINCH, 1); - - put_pid(pgrp); - put_pid(rpgrp); - - tty->winsize = *ws; - pty->winsize = *ws; /* Never used so will go away soon */ -done: - mutex_unlock(&tty->termios_mutex); - return 0; -} - static int pty_install(struct tty_driver *driver, struct tty_struct *tty) { struct tty_struct *o_tty; @@ -336,7 +290,6 @@ static const struct tty_operations pty_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .resize = pty_resize }; /* Traditional BSD devices */ @@ -366,7 +319,6 @@ static const struct tty_operations pty_ops_bsd = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_bsd_ioctl, - .resize = pty_resize }; static void __init legacy_pty_init(void) @@ -609,8 +561,7 @@ static const struct tty_operations ptm_unix98_ops = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, - .shutdown = pty_unix98_shutdown, - .resize = pty_resize + .shutdown = pty_unix98_shutdown }; static const struct tty_operations pty_unix98_ops = { diff --git a/trunk/drivers/char/rio/rio_linux.c b/trunk/drivers/char/rio/rio_linux.c index 2e8a6eed34be..a8f68a3f14dd 100644 --- a/trunk/drivers/char/rio/rio_linux.c +++ b/trunk/drivers/char/rio/rio_linux.c @@ -173,7 +173,7 @@ static void rio_disable_tx_interrupts(void *ptr); static void rio_enable_tx_interrupts(void *ptr); static void rio_disable_rx_interrupts(void *ptr); static void rio_enable_rx_interrupts(void *ptr); -static int rio_carrier_raised(struct tty_port *port); +static int rio_get_CD(void *ptr); static void rio_shutdown_port(void *ptr); static int rio_set_real_termios(void *ptr); static void rio_hungup(void *ptr); @@ -224,6 +224,7 @@ static struct real_driver rio_real_driver = { rio_enable_tx_interrupts, rio_disable_rx_interrupts, rio_enable_rx_interrupts, + rio_get_CD, rio_shutdown_port, rio_set_real_termios, rio_chars_in_buffer, @@ -475,9 +476,9 @@ static void rio_enable_rx_interrupts(void *ptr) /* Jeez. Isn't this simple? */ -static int rio_carrier_raised(struct tty_port *port) +static int rio_get_CD(void *ptr) { - struct Port *PortP = container_of(port, struct Port, gs.port); + struct Port *PortP = ptr; int rv; func_enter(); @@ -796,9 +797,16 @@ static int rio_init_drivers(void) return 1; } -static const struct tty_port_operations rio_port_ops = { - .carrier_raised = rio_carrier_raised, -}; + +static void *ckmalloc(int size) +{ + void *p; + + p = kzalloc(size, GFP_KERNEL); + return p; +} + + static int rio_init_datastructures(void) { @@ -818,30 +826,33 @@ static int rio_init_datastructures(void) #define TMIO_SZ sizeof(struct termios *) rio_dprintk(RIO_DEBUG_INIT, "getting : %Zd %Zd %Zd %Zd %Zd bytes\n", RI_SZ, RIO_HOSTS * HOST_SZ, RIO_PORTS * PORT_SZ, RIO_PORTS * TMIO_SZ, RIO_PORTS * TMIO_SZ); - if (!(p = kzalloc(RI_SZ, GFP_KERNEL))) + if (!(p = ckmalloc(RI_SZ))) goto free0; - if (!(p->RIOHosts = kzalloc(RIO_HOSTS * HOST_SZ, GFP_KERNEL))) + if (!(p->RIOHosts = ckmalloc(RIO_HOSTS * HOST_SZ))) goto free1; - if (!(p->RIOPortp = kzalloc(RIO_PORTS * PORT_SZ, GFP_KERNEL))) + if (!(p->RIOPortp = ckmalloc(RIO_PORTS * PORT_SZ))) goto free2; p->RIOConf = RIOConf; rio_dprintk(RIO_DEBUG_INIT, "Got : %p %p %p\n", p, p->RIOHosts, p->RIOPortp); #if 1 for (i = 0; i < RIO_PORTS; i++) { - port = p->RIOPortp[i] = kzalloc(sizeof(struct Port), GFP_KERNEL); + port = p->RIOPortp[i] = ckmalloc(sizeof(struct Port)); if (!port) { goto free6; } rio_dprintk(RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped); - tty_port_init(&port->gs.port); - port->gs.port.ops = &rio_port_ops; port->PortNum = i; port->gs.magic = RIO_MAGIC; port->gs.close_delay = HZ / 2; port->gs.closing_wait = 30 * HZ; port->gs.rd = &rio_real_driver; spin_lock_init(&port->portSem); + /* + * Initializing wait queue + */ + init_waitqueue_head(&port->gs.port.open_wait); + init_waitqueue_head(&port->gs.port.close_wait); } #else /* We could postpone initializing them to when they are configured. */ diff --git a/trunk/drivers/char/riscom8.c b/trunk/drivers/char/riscom8.c index 9af8d74875bc..2c6c8f33d6b4 100644 --- a/trunk/drivers/char/riscom8.c +++ b/trunk/drivers/char/riscom8.c @@ -857,21 +857,98 @@ static void rc_shutdown_port(struct tty_struct *tty, rc_shutdown_board(bp); } -static int carrier_raised(struct tty_port *port) +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct riscom_port *port) { - struct riscom_port *p = container_of(port, struct riscom_port, port); - struct riscom_board *bp = port_Board(p); + DECLARE_WAITQUEUE(wait, current); + struct riscom_board *bp = port_Board(port); + int retval; + int do_clocal = 0; + int CD; unsigned long flags; - int CD; - + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->port.close_wait); + if (port->port.flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + port->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (C_CLOCAL(tty)) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->port.open_wait, &wait); + spin_lock_irqsave(&riscom_lock, flags); - rc_out(bp, CD180_CAR, port_No(p)); - CD = rc_in(bp, CD180_MSVR) & MSVR_CD; - rc_out(bp, CD180_MSVR, MSVR_RTS); - bp->DTR &= ~(1u << port_No(p)); - rc_out(bp, RC_DTR, bp->DTR); + + if (!tty_hung_up_p(filp)) + port->port.count--; + spin_unlock_irqrestore(&riscom_lock, flags); - return CD; + + port->port.blocked_open++; + while (1) { + spin_lock_irqsave(&riscom_lock, flags); + + rc_out(bp, CD180_CAR, port_No(port)); + CD = rc_in(bp, CD180_MSVR) & MSVR_CD; + rc_out(bp, CD180_MSVR, MSVR_RTS); + bp->DTR &= ~(1u << port_No(port)); + rc_out(bp, RC_DTR, bp->DTR); + + spin_unlock_irqrestore(&riscom_lock, flags); + + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(port->port.flags & ASYNC_INITIALIZED)) { + if (port->port.flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->port.flags & ASYNC_CLOSING) && + (do_clocal || CD)) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&port->port.open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->port.count++; + port->port.blocked_open--; + if (retval) + return retval; + + port->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; } static int rc_open(struct tty_struct *tty, struct file *filp) @@ -900,13 +977,13 @@ static int rc_open(struct tty_struct *tty, struct file *filp) error = rc_setup_port(bp, port); if (error == 0) - error = tty_port_block_til_ready(&port->port, tty, filp); + error = block_til_ready(tty, filp, port); return error; } static void rc_flush_buffer(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; if (rc_paranoia_check(port, tty->name, "rc_flush_buffer")) @@ -921,7 +998,7 @@ static void rc_flush_buffer(struct tty_struct *tty) static void rc_close(struct tty_struct *tty, struct file *filp) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *) tty->driver_data; struct riscom_board *bp; unsigned long flags; unsigned long timeout; @@ -929,19 +1006,40 @@ static void rc_close(struct tty_struct *tty, struct file *filp) if (!port || rc_paranoia_check(port, tty->name, "close")) return; + spin_lock_irqsave(&riscom_lock, flags); + + if (tty_hung_up_p(filp)) + goto out; + bp = port_Board(port); - - if (tty_port_close_start(&port->port, tty, filp) == 0) - return; - + if ((tty->count == 1) && (port->port.count != 1)) { + printk(KERN_INFO "rc%d: rc_close: bad port count;" + " tty->count is 1, port count is %d\n", + board_No(bp), port->port.count); + port->port.count = 1; + } + if (--port->port.count < 0) { + printk(KERN_INFO "rc%d: rc_close: bad port count " + "for tty%d: %d\n", + board_No(bp), port_No(port), port->port.count); + port->port.count = 0; + } + if (port->port.count) + goto out; + port->port.flags |= ASYNC_CLOSING; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->port.closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ - - spin_lock_irqsave(&riscom_lock, flags); port->IER &= ~IER_RXD; if (port->port.flags & ASYNC_INITIALIZED) { port->IER &= ~IER_TXRDY; @@ -955,24 +1053,33 @@ static void rc_close(struct tty_struct *tty, struct file *filp) */ timeout = jiffies + HZ; while (port->IER & IER_TXEMPTY) { - spin_unlock_irqrestore(&riscom_lock, flags); msleep_interruptible(jiffies_to_msecs(port->timeout)); - spin_lock_irqsave(&riscom_lock, flags); if (time_after(jiffies, timeout)) break; } } rc_shutdown_port(tty, bp, port); rc_flush_buffer(tty); - spin_unlock_irqrestore(&riscom_lock, flags); + tty_ldisc_flush(tty); + + tty->closing = 0; + port->port.tty = NULL; + if (port->port.blocked_open) { + if (port->port.close_delay) + msleep_interruptible(jiffies_to_msecs(port->port.close_delay)); + wake_up_interruptible(&port->port.open_wait); + } + port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->port.close_wait); - tty_port_close_end(&port->port, tty); +out: + spin_unlock_irqrestore(&riscom_lock, flags); } static int rc_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; int c, total = 0; unsigned long flags; @@ -1015,7 +1122,7 @@ static int rc_write(struct tty_struct *tty, static int rc_put_char(struct tty_struct *tty, unsigned char ch) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; int ret = 0; @@ -1039,7 +1146,7 @@ static int rc_put_char(struct tty_struct *tty, unsigned char ch) static void rc_flush_chars(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; if (rc_paranoia_check(port, tty->name, "rc_flush_chars")) @@ -1059,7 +1166,7 @@ static void rc_flush_chars(struct tty_struct *tty) static int rc_write_room(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; int ret; if (rc_paranoia_check(port, tty->name, "rc_write_room")) @@ -1073,7 +1180,7 @@ static int rc_write_room(struct tty_struct *tty) static int rc_chars_in_buffer(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer")) return 0; @@ -1083,7 +1190,7 @@ static int rc_chars_in_buffer(struct tty_struct *tty) static int rc_tiocmget(struct tty_struct *tty, struct file *file) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned char status; unsigned int result; @@ -1113,7 +1220,7 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file) static int rc_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; struct riscom_board *bp; @@ -1145,7 +1252,7 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, static int rc_send_break(struct tty_struct *tty, int length) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp = port_Board(port); unsigned long flags; @@ -1238,7 +1345,7 @@ static int rc_get_serial_info(struct riscom_port *port, static int rc_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; void __user *argp = (void __user *)arg; int retval; @@ -1264,7 +1371,7 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp, static void rc_throttle(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; @@ -1286,7 +1393,7 @@ static void rc_throttle(struct tty_struct *tty) static void rc_unthrottle(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; @@ -1308,7 +1415,7 @@ static void rc_unthrottle(struct tty_struct *tty) static void rc_stop(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; @@ -1326,7 +1433,7 @@ static void rc_stop(struct tty_struct *tty) static void rc_start(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; @@ -1347,9 +1454,8 @@ static void rc_start(struct tty_struct *tty) static void rc_hangup(struct tty_struct *tty) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; - unsigned long flags; if (rc_paranoia_check(port, tty->name, "rc_hangup")) return; @@ -1357,18 +1463,16 @@ static void rc_hangup(struct tty_struct *tty) bp = port_Board(port); rc_shutdown_port(tty, bp, port); - spin_lock_irqsave(&port->port.lock, flags); port->port.count = 0; port->port.flags &= ~ASYNC_NORMAL_ACTIVE; port->port.tty = NULL; wake_up_interruptible(&port->port.open_wait); - spin_unlock_irqrestore(&port->port.lock, flags); } static void rc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct riscom_port *port = tty->driver_data; + struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; if (rc_paranoia_check(port, tty->name, "rc_set_termios")) @@ -1406,11 +1510,6 @@ static const struct tty_operations riscom_ops = { .break_ctl = rc_send_break, }; -static const struct tty_port_operations riscom_port_ops = { - .carrier_raised = carrier_raised, -}; - - static int __init rc_init_drivers(void) { int error; @@ -1442,7 +1541,6 @@ static int __init rc_init_drivers(void) memset(rc_port, 0, sizeof(rc_port)); for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { tty_port_init(&rc_port[i].port); - rc_port[i].port.ops = &riscom_port_ops; rc_port[i].magic = RISCOM8_MAGIC; } return 0; diff --git a/trunk/drivers/char/rocket.c b/trunk/drivers/char/rocket.c index f59fc5cea067..584d791e84a6 100644 --- a/trunk/drivers/char/rocket.c +++ b/trunk/drivers/char/rocket.c @@ -135,7 +135,6 @@ static int rcktpt_type[NUM_BOARDS]; static int is_PCI[NUM_BOARDS]; static rocketModel_t rocketModel[NUM_BOARDS]; static int max_board; -static const struct tty_port_operations rocket_port_ops; /* * The following arrays define the interrupt bits corresponding to each AIOP. @@ -436,15 +435,15 @@ static void rp_do_transmit(struct r_port *info) #endif if (!info) return; - tty = tty_port_tty_get(&info->port); - - if (tty == NULL) { - printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__); + if (!info->port.tty) { + printk(KERN_WARNING "rp: WARNING %s called with " + "info->port.tty==NULL\n", __func__); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); return; } spin_lock_irqsave(&info->slock, flags); + tty = info->port.tty; info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); /* Loop sending data to FIFO until done or FIFO full */ @@ -478,7 +477,6 @@ static void rp_do_transmit(struct r_port *info) } spin_unlock_irqrestore(&info->slock, flags); - tty_kref_put(tty); #ifdef ROCKET_DEBUG_INTR printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head, @@ -500,18 +498,18 @@ static void rp_handle_port(struct r_port *info) if (!info) return; - if ((info->port.flags & ASYNC_INITIALIZED) == 0) { + if ((info->flags & ROCKET_INITIALIZED) == 0) { printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " "info->flags & NOT_INIT\n"); return; } - tty = tty_port_tty_get(&info->port); - if (!tty) { + if (!info->port.tty) { printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " - "tty==NULL\n"); + "info->port.tty==NULL\n"); return; } cp = &info->channel; + tty = info->port.tty; IntMask = sGetChanIntID(cp) & info->intmask; #ifdef ROCKET_DEBUG_INTR @@ -543,7 +541,6 @@ static void rp_handle_port(struct r_port *info) printk(KERN_INFO "DSR change...\n"); } #endif - tty_kref_put(tty); } /* @@ -652,8 +649,9 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) info->board = board; info->aiop = aiop; info->chan = chan; - tty_port_init(&info->port); - info->port.ops = &rocket_port_ops; + info->port.closing_wait = 3000; + info->port.close_delay = 50; + init_waitqueue_head(&info->port.open_wait); init_completion(&info->close_wait); info->flags &= ~ROCKET_MODE_MASK; switch (pc104[board][line]) { @@ -712,7 +710,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) * Configures a rocketport port according to its termio settings. Called from * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. */ -static void configure_r_port(struct tty_struct *tty, struct r_port *info, +static void configure_r_port(struct r_port *info, struct ktermios *old_termios) { unsigned cflag; @@ -720,7 +718,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, unsigned rocketMode; int bits, baud, divisor; CHANNEL_t *cp; - struct ktermios *t = tty->termios; + struct ktermios *t = info->port.tty->termios; cp = &info->channel; cflag = t->c_cflag; @@ -753,7 +751,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, } /* baud rate */ - baud = tty_get_baud_rate(tty); + baud = tty_get_baud_rate(info->port.tty); if (!baud) baud = 9600; divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; @@ -771,7 +769,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, sSetBaud(cp, divisor); /* FIXME: Should really back compute a baud rate from the divisor */ - tty_encode_baud_rate(tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; @@ -796,15 +794,15 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, * Handle software flow control in the board */ #ifdef ROCKET_SOFT_FLOW - if (I_IXON(tty)) { + if (I_IXON(info->port.tty)) { sEnTxSoftFlowCtl(cp); - if (I_IXANY(tty)) { + if (I_IXANY(info->port.tty)) { sEnIXANY(cp); } else { sDisIXANY(cp); } - sSetTxXONChar(cp, START_CHAR(tty)); - sSetTxXOFFChar(cp, STOP_CHAR(tty)); + sSetTxXONChar(cp, START_CHAR(info->port.tty)); + sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty)); } else { sDisTxSoftFlowCtl(cp); sDisIXANY(cp); @@ -816,24 +814,24 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, * Set up ignore/read mask words */ info->read_status_mask = STMRCVROVRH | 0xFF; - if (I_INPCK(tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= STMFRAMEH | STMPARITYH; - if (I_BRKINT(tty) || I_PARMRK(tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= STMBREAKH; /* * Characters to ignore */ info->ignore_status_mask = 0; - if (I_IGNPAR(tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= STMFRAMEH | STMPARITYH; - if (I_IGNBRK(tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= STMBREAKH; /* * If we're ignoring parity and break indicators, * ignore overruns too. (For real raw support). */ - if (I_IGNPAR(tty)) + if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= STMRCVROVRH; } @@ -866,17 +864,106 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, } } -static int carrier_raised(struct tty_port *port) +/* info->port.count is considered critical, protected by spinlocks. */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct r_port *info) { - struct r_port *info = container_of(port, struct r_port, port); - return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; -} + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; -static void raise_dtr_rts(struct tty_port *port) -{ - struct r_port *info = container_of(port, struct r_port, port); - sSetDTR(&info->channel); - sSetRTS(&info->channel); + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp)) + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); + if (info->flags & ROCKET_CLOSING) { + if (wait_for_completion_interruptible(&info->close_wait)) + return -ERESTARTSYS; + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= ROCKET_NORMAL_ACTIVE; + return 0; + } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become free. While we are in + * this loop, info->port.count is dropped by one, so that rp_close() knows when to free things. + * We restore it upon exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->port.open_wait, &wait); +#ifdef ROCKET_DEBUG_OPEN + printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->port.count); +#endif + spin_lock_irqsave(&info->slock, flags); + +#ifdef ROCKET_DISABLE_SIMUSAGE + info->flags |= ROCKET_NORMAL_ACTIVE; +#else + if (!tty_hung_up_p(filp)) { + extra_count = 1; + info->port.count--; + } +#endif + info->port.blocked_open++; + + spin_unlock_irqrestore(&info->slock, flags); + + while (1) { + if (tty->termios->c_cflag & CBAUD) { + sSetDTR(&info->channel); + sSetRTS(&info->channel); + } + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) { + if (info->flags & ROCKET_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef ROCKET_DEBUG_OPEN + printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", + info->line, info->port.count, info->flags); +#endif + schedule(); /* Don't hold spinlock here, will hang PC */ + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&info->port.open_wait, &wait); + + spin_lock_irqsave(&info->slock, flags); + + if (extra_count) + info->port.count++; + info->port.blocked_open--; + + spin_unlock_irqrestore(&info->slock, flags); + +#ifdef ROCKET_DEBUG_OPEN + printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n", + info->line, info->port.count); +#endif + if (retval) + return retval; + info->flags |= ROCKET_NORMAL_ACTIVE; + return 0; } /* @@ -886,26 +973,24 @@ static void raise_dtr_rts(struct tty_port *port) static int rp_open(struct tty_struct *tty, struct file *filp) { struct r_port *info; - struct tty_port *port; int line = 0, retval; CHANNEL_t *cp; unsigned long page; line = tty->index; - if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL)) + if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL)) return -ENXIO; - port = &info->port; - + page = __get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; - if (port->flags & ASYNC_CLOSING) { + if (info->flags & ROCKET_CLOSING) { retval = wait_for_completion_interruptible(&info->close_wait); free_page(page); if (retval) return retval; - return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } /* @@ -917,9 +1002,9 @@ static int rp_open(struct tty_struct *tty, struct file *filp) info->xmit_buf = (unsigned char *) page; tty->driver_data = info; - tty_port_tty_set(port, tty); + info->port.tty = tty; - if (port->count++ == 0) { + if (info->port.count++ == 0) { atomic_inc(&rp_num_ports_open); #ifdef ROCKET_DEBUG_OPEN @@ -934,7 +1019,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) /* * Info->count is now 1; so it's safe to sleep now. */ - if (!test_bit(ASYNC_INITIALIZED, &port->flags)) { + if ((info->flags & ROCKET_INITIALIZED) == 0) { cp = &info->channel; sSetRxTrigger(cp, TRIG_1); if (sGetChanStatus(cp) & CD_ACT) @@ -958,21 +1043,21 @@ static int rp_open(struct tty_struct *tty, struct file *filp) sEnRxFIFO(cp); sEnTransmit(cp); - set_bit(ASYNC_INITIALIZED, &info->port.flags); + info->flags |= ROCKET_INITIALIZED; /* * Set up the tty->alt_speed kludge */ if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) - tty->alt_speed = 57600; + info->port.tty->alt_speed = 57600; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) - tty->alt_speed = 115200; + info->port.tty->alt_speed = 115200; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) - tty->alt_speed = 230400; + info->port.tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) - tty->alt_speed = 460800; + info->port.tty->alt_speed = 460800; - configure_r_port(tty, info, NULL); + configure_r_port(info, NULL); if (tty->termios->c_cflag & CBAUD) { sSetDTR(cp); sSetRTS(cp); @@ -981,7 +1066,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) /* Starts (or resets) the maint polling loop */ mod_timer(&rocket_timer, jiffies + POLL_PERIOD); - retval = tty_port_block_til_ready(port, tty, filp); + retval = block_til_ready(tty, filp, info); if (retval) { #ifdef ROCKET_DEBUG_OPEN printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); @@ -996,8 +1081,8 @@ static int rp_open(struct tty_struct *tty, struct file *filp) */ static void rp_close(struct tty_struct *tty, struct file *filp) { - struct r_port *info = tty->driver_data; - struct tty_port *port = &info->port; + struct r_port *info = (struct r_port *) tty->driver_data; + unsigned long flags; int timeout; CHANNEL_t *cp; @@ -1008,10 +1093,53 @@ static void rp_close(struct tty_struct *tty, struct file *filp) printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count); #endif - if (tty_port_close_start(port, tty, filp) == 0) + if (tty_hung_up_p(filp)) + return; + spin_lock_irqsave(&info->slock, flags); + + if ((tty->count == 1) && (info->port.count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_WARNING "rp_close: bad serial port count; " + "tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; + } + if (--info->port.count < 0) { + printk(KERN_WARNING "rp_close: bad serial port count for " + "ttyR%d: %d\n", info->line, info->port.count); + info->port.count = 0; + } + if (info->port.count) { + spin_unlock_irqrestore(&info->slock, flags); return; + } + info->flags |= ROCKET_CLOSING; + spin_unlock_irqrestore(&info->slock, flags); cp = &info->channel; + + /* + * Notify the line discpline to only process XON/XOFF characters + */ + tty->closing = 1; + + /* + * If transmission was throttled by the application request, + * just flush the xmit buffer. + */ + if (tty->flow_stopped) + rp_flush_buffer(tty); + + /* + * Wait for the transmit buffer to clear + */ + if (info->port.closing_wait != ROCKET_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->port.closing_wait); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1040,24 +1168,19 @@ static void rp_close(struct tty_struct *tty, struct file *filp) clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - /* We can't yet use tty_port_close_end as the buffer handling in this - driver is a bit different to the usual */ - - if (port->blocked_open) { - if (port->close_delay) { - msleep_interruptible(jiffies_to_msecs(port->close_delay)); + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); } - wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&info->port.open_wait); } else { if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = NULL; } } - info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE); + info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE); tty->closing = 0; - tty_port_tty_set(port, NULL); - wake_up_interruptible(&port->close_wait); complete_all(&info->close_wait); atomic_dec(&rp_num_ports_open); @@ -1072,7 +1195,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp) static void rp_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned cflag; @@ -1090,7 +1213,7 @@ static void rp_set_termios(struct tty_struct *tty, /* Or CMSPAR */ tty->termios->c_cflag &= ~CMSPAR; - configure_r_port(tty, info, old_termios); + configure_r_port(info, old_termios); cp = &info->channel; @@ -1115,7 +1238,7 @@ static void rp_set_termios(struct tty_struct *tty, static int rp_break(struct tty_struct *tty, int break_state) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; unsigned long flags; if (rocket_paranoia_check(info, "rp_break")) @@ -1161,7 +1284,7 @@ static int sGetChanRI(CHANNEL_T * ChP) */ static int rp_tiocmget(struct tty_struct *tty, struct file *file) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *)tty->driver_data; unsigned int control, result, ChanStatus; ChanStatus = sGetChanStatusLo(&info->channel); @@ -1182,7 +1305,7 @@ static int rp_tiocmget(struct tty_struct *tty, struct file *file) static int rp_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *)tty->driver_data; if (set & TIOCM_RTS) info->channel.TxControl[3] |= SET_RTS; @@ -1215,8 +1338,7 @@ static int get_config(struct r_port *info, struct rocket_config __user *retinfo) return 0; } -static int set_config(struct tty_struct *tty, struct r_port *info, - struct rocket_config __user *new_info) +static int set_config(struct r_port *info, struct rocket_config __user *new_info) { struct rocket_config new_serial; @@ -1228,7 +1350,7 @@ static int set_config(struct tty_struct *tty, struct r_port *info, if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); - configure_r_port(tty, info, NULL); + configure_r_port(info, NULL); return 0; } @@ -1237,15 +1359,15 @@ static int set_config(struct tty_struct *tty, struct r_port *info, info->port.closing_wait = new_serial.closing_wait; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) - tty->alt_speed = 57600; + info->port.tty->alt_speed = 57600; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) - tty->alt_speed = 115200; + info->port.tty->alt_speed = 115200; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) - tty->alt_speed = 230400; + info->port.tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) - tty->alt_speed = 460800; + info->port.tty->alt_speed = 460800; - configure_r_port(tty, info, NULL); + configure_r_port(info, NULL); return 0; } @@ -1312,7 +1434,7 @@ static int get_version(struct r_port *info, struct rocket_version __user *retver static int rp_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; void __user *argp = (void __user *)arg; int ret = 0; @@ -1330,7 +1452,7 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file, ret = get_config(info, argp); break; case RCKP_SET_CONFIG: - ret = set_config(tty, info, argp); + ret = set_config(info, argp); break; case RCKP_GET_PORTS: ret = get_ports(info, argp); @@ -1350,7 +1472,7 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file, static void rp_send_xchar(struct tty_struct *tty, char ch) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; if (rocket_paranoia_check(info, "rp_send_xchar")) @@ -1365,7 +1487,7 @@ static void rp_send_xchar(struct tty_struct *tty, char ch) static void rp_throttle(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; #ifdef ROCKET_DEBUG_THROTTLE @@ -1385,7 +1507,7 @@ static void rp_throttle(struct tty_struct *tty) static void rp_unthrottle(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; #ifdef ROCKET_DEBUG_THROTTLE printk(KERN_INFO "unthrottle %s: %d....\n", tty->name, @@ -1412,7 +1534,7 @@ static void rp_unthrottle(struct tty_struct *tty) */ static void rp_stop(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; #ifdef ROCKET_DEBUG_FLOW printk(KERN_INFO "stop %s: %d %d....\n", tty->name, @@ -1428,7 +1550,7 @@ static void rp_stop(struct tty_struct *tty) static void rp_start(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; #ifdef ROCKET_DEBUG_FLOW printk(KERN_INFO "start %s: %d %d....\n", tty->name, @@ -1448,7 +1570,7 @@ static void rp_start(struct tty_struct *tty) */ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long orig_jiffies; int check_time, exit_time; @@ -1505,7 +1627,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) static void rp_hangup(struct tty_struct *tty) { CHANNEL_t *cp; - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; if (rocket_paranoia_check(info, "rp_hangup")) return; @@ -1514,13 +1636,15 @@ static void rp_hangup(struct tty_struct *tty) printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line); #endif rp_flush_buffer(tty); - if (info->port.flags & ASYNC_CLOSING) + if (info->flags & ROCKET_CLOSING) return; if (info->port.count) atomic_dec(&rp_num_ports_open); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - tty_port_hangup(&info->port); + info->port.count = 0; + info->flags &= ~ROCKET_NORMAL_ACTIVE; + info->port.tty = NULL; cp = &info->channel; sDisRxFIFO(cp); @@ -1529,7 +1653,7 @@ static void rp_hangup(struct tty_struct *tty) sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); - info->port.flags &= ~ASYNC_INITIALIZED; + info->flags &= ~ROCKET_INITIALIZED; wake_up_interruptible(&info->port.open_wait); } @@ -1543,7 +1667,7 @@ static void rp_hangup(struct tty_struct *tty) */ static int rp_put_char(struct tty_struct *tty, unsigned char ch) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long flags; @@ -1590,7 +1714,7 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch) static int rp_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; const unsigned char *b; int c, retval = 0; @@ -1640,8 +1764,7 @@ static int rp_write(struct tty_struct *tty, /* Write remaining data into the port's xmit_buf */ while (1) { - /* Hung up ? */ - if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags)) + if (!info->port.tty) /* Seemingly obligatory check... */ goto end; c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); c = min(c, XMIT_BUF_SIZE - info->xmit_head); @@ -1683,7 +1806,7 @@ static int rp_write(struct tty_struct *tty, */ static int rp_write_room(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; int ret; if (rocket_paranoia_check(info, "rp_write_room")) @@ -1704,7 +1827,7 @@ static int rp_write_room(struct tty_struct *tty) */ static int rp_chars_in_buffer(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; if (rocket_paranoia_check(info, "rp_chars_in_buffer")) @@ -1725,7 +1848,7 @@ static int rp_chars_in_buffer(struct tty_struct *tty) */ static void rp_flush_buffer(struct tty_struct *tty) { - struct r_port *info = tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long flags; @@ -2248,11 +2371,6 @@ static const struct tty_operations rocket_ops = { .tiocmset = rp_tiocmset, }; -static const struct tty_port_operations rocket_port_ops = { - .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, -}; - /* * The module "startup" routine; it's run when the module is loaded. */ diff --git a/trunk/drivers/char/rocket.h b/trunk/drivers/char/rocket.h index ec863f35f1a9..a8b09195ebba 100644 --- a/trunk/drivers/char/rocket.h +++ b/trunk/drivers/char/rocket.h @@ -39,7 +39,7 @@ struct rocket_version { /* * Rocketport flags */ -/*#define ROCKET_CALLOUT_NOHUP 0x00000001 */ +#define ROCKET_CALLOUT_NOHUP 0x00000001 #define ROCKET_FORCE_CD 0x00000002 #define ROCKET_HUP_NOTIFY 0x00000004 #define ROCKET_SPLIT_TERMIOS 0x00000008 diff --git a/trunk/drivers/char/rocket_int.h b/trunk/drivers/char/rocket_int.h index 67e0f1e778a2..21f3ff53ba32 100644 --- a/trunk/drivers/char/rocket_int.h +++ b/trunk/drivers/char/rocket_int.h @@ -1162,6 +1162,11 @@ struct r_port { /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +/* Internal flags used only by the rocketport driver */ +#define ROCKET_INITIALIZED 0x80000000 /* Port is active */ +#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */ +#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */ + /* * Assigned major numbers for the Comtrol Rocketport */ diff --git a/trunk/drivers/char/selection.c b/trunk/drivers/char/selection.c index f29fbe9b8ed7..2978a49a172b 100644 --- a/trunk/drivers/char/selection.c +++ b/trunk/drivers/char/selection.c @@ -306,7 +306,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t */ int paste_selection(struct tty_struct *tty) { - struct vc_data *vc = tty->driver_data; + struct vc_data *vc = (struct vc_data *)tty->driver_data; int pasted = 0; unsigned int count; struct tty_ldisc *ld; diff --git a/trunk/drivers/char/ser_a2232.c b/trunk/drivers/char/ser_a2232.c index 33872a219df6..7b0c35207d9b 100644 --- a/trunk/drivers/char/ser_a2232.c +++ b/trunk/drivers/char/ser_a2232.c @@ -122,7 +122,7 @@ static void a2232_disable_tx_interrupts(void *ptr); static void a2232_enable_tx_interrupts(void *ptr); static void a2232_disable_rx_interrupts(void *ptr); static void a2232_enable_rx_interrupts(void *ptr); -static int a2232_carrier_raised(struct tty_port *port); +static int a2232_get_CD(void *ptr); static void a2232_shutdown_port(void *ptr); static int a2232_set_real_termios(void *ptr); static int a2232_chars_in_buffer(void *ptr); @@ -148,6 +148,7 @@ static struct real_driver a2232_real_driver = { a2232_enable_tx_interrupts, a2232_disable_rx_interrupts, a2232_enable_rx_interrupts, + a2232_get_CD, a2232_shutdown_port, a2232_set_real_termios, a2232_chars_in_buffer, @@ -259,10 +260,9 @@ static void a2232_enable_rx_interrupts(void *ptr) port->disable_rx = 0; } -static int a2232_carrier_raised(struct tty_port *port) +static int a2232_get_CD(void *ptr) { - struct a2232_port *ap = container_of(port, struct a2232_port, gs.port); - return ap->cd_status; + return ((struct a2232_port *) ptr)->cd_status; } static void a2232_shutdown_port(void *ptr) @@ -460,14 +460,14 @@ static void a2232_throttle(struct tty_struct *tty) if switched on. So the only thing we can do at this layer here is not taking any characters out of the A2232 buffer any more. */ - struct a2232_port *port = tty->driver_data; + struct a2232_port *port = (struct a2232_port *) tty->driver_data; port->throttle_input = -1; } static void a2232_unthrottle(struct tty_struct *tty) { /* Unthrottle: dual to "throttle()" above. */ - struct a2232_port *port = tty->driver_data; + struct a2232_port *port = (struct a2232_port *) tty->driver_data; port->throttle_input = 0; } @@ -638,10 +638,6 @@ int ch, err, n, p; return IRQ_HANDLED; } -static const struct tty_port_operations a2232_port_ops = { - .carrier_raised = a2232_carrier_raised, -}; - static void a2232_init_portstructs(void) { struct a2232_port *port; @@ -649,8 +645,6 @@ static void a2232_init_portstructs(void) for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) { port = a2232_ports + i; - tty_port_init(&port->gs.port); - port->gs.port.ops = &a2232_port_ops; port->which_a2232 = i/NUMLINES; port->which_port_on_a2232 = i%NUMLINES; port->disable_rx = port->throttle_input = port->cd_status = 0; @@ -658,6 +652,11 @@ static void a2232_init_portstructs(void) port->gs.close_delay = HZ/2; port->gs.closing_wait = 30 * HZ; port->gs.rd = &a2232_real_driver; +#ifdef NEW_WRITE_LOCKING + mutex_init(&(port->gs.port_write_mutex)); +#endif + init_waitqueue_head(&port->gs.port.open_wait); + init_waitqueue_head(&port->gs.port.close_wait); } } diff --git a/trunk/drivers/char/serial167.c b/trunk/drivers/char/serial167.c index f1f24f0ee26f..a8f15e6be594 100644 --- a/trunk/drivers/char/serial167.c +++ b/trunk/drivers/char/serial167.c @@ -315,7 +315,7 @@ u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd) static void cy_stop(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; int channel; unsigned long flags; @@ -337,7 +337,7 @@ static void cy_stop(struct tty_struct *tty) static void cy_start(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; int channel; unsigned long flags; @@ -1062,7 +1062,7 @@ static void config_setup(struct cyclades_port *info) static int cy_put_char(struct tty_struct *tty, unsigned char ch) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_IO @@ -1090,7 +1090,7 @@ static int cy_put_char(struct tty_struct *tty, unsigned char ch) static void cy_flush_chars(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; volatile unsigned char *base_addr = (u_char *) BASE_ADDR; int channel; @@ -1122,7 +1122,7 @@ static void cy_flush_chars(struct tty_struct *tty) */ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; int c, total = 0; @@ -1166,7 +1166,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) static int cy_write_room(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; int ret; #ifdef SERIAL_DEBUG_IO @@ -1183,7 +1183,7 @@ static int cy_write_room(struct tty_struct *tty) static int cy_chars_in_buffer(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; #ifdef SERIAL_DEBUG_IO printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */ @@ -1197,7 +1197,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty) static void cy_flush_buffer(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_IO @@ -1218,7 +1218,7 @@ static void cy_flush_buffer(struct tty_struct *tty) */ static void cy_throttle(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; volatile unsigned char *base_addr = (u_char *) BASE_ADDR; int channel; @@ -1250,7 +1250,7 @@ static void cy_throttle(struct tty_struct *tty) static void cy_unthrottle(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; volatile unsigned char *base_addr = (u_char *) BASE_ADDR; int channel; @@ -1345,7 +1345,7 @@ set_serial_info(struct cyclades_port *info, static int cy_tiocmget(struct tty_struct *tty, struct file *file) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; int channel; volatile unsigned char *base_addr = (u_char *) BASE_ADDR; unsigned long flags; @@ -1369,7 +1369,7 @@ static int cy_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; int channel; volatile unsigned char *base_addr = (u_char *) BASE_ADDR; unsigned long flags; @@ -1532,7 +1532,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; int ret_val = 0; void __user *argp = (void __user *)arg; @@ -1607,7 +1607,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; #ifdef SERIAL_DEBUG_OTHER printk("cy_set_termios %s\n", tty->name); @@ -1631,7 +1631,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void cy_close(struct tty_struct *tty, struct file *filp) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; /* CP('C'); */ #ifdef SERIAL_DEBUG_OTHER @@ -1698,7 +1698,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp) */ void cy_hangup(struct tty_struct *tty) { - struct cyclades_port *info = tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; #ifdef SERIAL_DEBUG_OTHER printk("cy_hangup %s\n", tty->name); /* */ diff --git a/trunk/drivers/char/specialix.c b/trunk/drivers/char/specialix.c index 3c67c3d83de9..a16b94f12eb2 100644 --- a/trunk/drivers/char/specialix.c +++ b/trunk/drivers/char/specialix.c @@ -1450,7 +1450,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp) static void sx_flush_buffer(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board *bp; @@ -1472,7 +1472,7 @@ static void sx_flush_buffer(struct tty_struct *tty) static void sx_close(struct tty_struct *tty, struct file *filp) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned long flags; unsigned long timeout; @@ -1585,7 +1585,7 @@ static void sx_close(struct tty_struct *tty, struct file *filp) static int sx_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; int c, total = 0; unsigned long flags; @@ -1637,7 +1637,7 @@ static int sx_write(struct tty_struct *tty, static int sx_put_char(struct tty_struct *tty, unsigned char ch) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board *bp; @@ -1676,7 +1676,7 @@ static int sx_put_char(struct tty_struct *tty, unsigned char ch) static void sx_flush_chars(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board *bp = port_Board(port); @@ -1703,7 +1703,7 @@ static void sx_flush_chars(struct tty_struct *tty) static int sx_write_room(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; int ret; func_enter(); @@ -1724,7 +1724,7 @@ static int sx_write_room(struct tty_struct *tty) static int sx_chars_in_buffer(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; func_enter(); @@ -1738,7 +1738,7 @@ static int sx_chars_in_buffer(struct tty_struct *tty) static int sx_tiocmget(struct tty_struct *tty, struct file *file) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned char status; unsigned int result; @@ -1780,7 +1780,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file) static int sx_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board *bp; @@ -1820,7 +1820,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file, static int sx_send_break(struct tty_struct *tty, int length) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp = port_Board(port); unsigned long flags; @@ -1931,7 +1931,7 @@ static int sx_get_serial_info(struct specialix_port *port, static int sx_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; void __user *argp = (void __user *)arg; func_enter(); @@ -1959,7 +1959,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp, static void sx_throttle(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned long flags; @@ -2004,7 +2004,7 @@ static void sx_throttle(struct tty_struct *tty) static void sx_unthrottle(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned long flags; @@ -2045,7 +2045,7 @@ static void sx_unthrottle(struct tty_struct *tty) static void sx_stop(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned long flags; @@ -2072,7 +2072,7 @@ static void sx_stop(struct tty_struct *tty) static void sx_start(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned long flags; @@ -2100,7 +2100,7 @@ static void sx_start(struct tty_struct *tty) static void sx_hangup(struct tty_struct *tty) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; struct specialix_board *bp; unsigned long flags; @@ -2135,7 +2135,7 @@ static void sx_hangup(struct tty_struct *tty) static void sx_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct specialix_port *port = tty->driver_data; + struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board *bp; diff --git a/trunk/drivers/char/stallion.c b/trunk/drivers/char/stallion.c index e1e0dd89ac9a..963b03fb29e5 100644 --- a/trunk/drivers/char/stallion.c +++ b/trunk/drivers/char/stallion.c @@ -130,8 +130,6 @@ static char stl_unwanted[SC26198_RXFIFOSIZE]; static DEFINE_MUTEX(stl_brdslock); static struct stlbrd *stl_brds[STL_MAXBRDS]; -static const struct tty_port_operations stl_port_ops; - /* * Per board state flags. Used with the state field of the board struct. * Not really much here! @@ -409,6 +407,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns static int stl_brdinit(struct stlbrd *brdp); static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp); static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); +static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp); /* * CD1400 uart specific handling functions. @@ -704,9 +703,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp) { struct stlport *portp; struct stlbrd *brdp; - struct tty_port *port; unsigned int minordev, brdnr, panelnr; - int portnr; + int portnr, rc; pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name); @@ -717,7 +715,6 @@ static int stl_open(struct tty_struct *tty, struct file *filp) brdp = stl_brds[brdnr]; if (brdp == NULL) return -ENODEV; - minordev = MINOR2PORT(minordev); for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) { if (brdp->panels[panelnr] == NULL) @@ -734,17 +731,16 @@ static int stl_open(struct tty_struct *tty, struct file *filp) portp = brdp->panels[panelnr]->ports[portnr]; if (portp == NULL) return -ENODEV; - port = &portp->port; /* * On the first open of the device setup the port hardware, and * initialize the per port data structure. */ - tty_port_tty_set(port, tty); + tty_port_tty_set(&portp->port, tty); tty->driver_data = portp; - port->count++; + portp->port.count++; - if ((port->flags & ASYNC_INITIALIZED) == 0) { + if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { if (!portp->tx.buf) { portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); if (!portp->tx.buf) @@ -758,24 +754,91 @@ static int stl_open(struct tty_struct *tty, struct file *filp) stl_enablerxtx(portp, 1, 1); stl_startrxtx(portp, 1, 0); clear_bit(TTY_IO_ERROR, &tty->flags); - port->flags |= ASYNC_INITIALIZED; + portp->port.flags |= ASYNC_INITIALIZED; + } + +/* + * Check if this port is in the middle of closing. If so then wait + * until it is closed then return error status, based on flag settings. + * The sleep here does not need interrupt protection since the wakeup + * for it is done with the same context. + */ + if (portp->port.flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->port.close_wait); + if (portp->port.flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + return -ERESTARTSYS; } - return tty_port_block_til_ready(port, tty, filp); + +/* + * Based on type of open being done check if it can overlap with any + * previous opens still in effect. If we are a normal serial device + * then also we might have to wait for carrier. + */ + if (!(filp->f_flags & O_NONBLOCK)) + if ((rc = stl_waitcarrier(tty, portp, filp)) != 0) + return rc; + + portp->port.flags |= ASYNC_NORMAL_ACTIVE; + + return 0; } /*****************************************************************************/ -static int stl_carrier_raised(struct tty_port *port) -{ - struct stlport *portp = container_of(port, struct stlport, port); - return (portp->sigs & TIOCM_CD) ? 1 : 0; -} +/* + * Possibly need to wait for carrier (DCD signal) to come high. Say + * maybe because if we are clocal then we don't need to wait... + */ -static void stl_raise_dtr_rts(struct tty_port *port) +static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, + struct file *filp) { - struct stlport *portp = container_of(port, struct stlport, port); - /* Takes brd_lock internally */ - stl_setsignals(portp, 1, 1); + unsigned long flags; + int rc, doclocal; + + pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp); + + rc = 0; + doclocal = 0; + + spin_lock_irqsave(&stallion_lock, flags); + + if (tty->termios->c_cflag & CLOCAL) + doclocal++; + + portp->openwaitcnt++; + if (! tty_hung_up_p(filp)) + portp->port.count--; + + for (;;) { + /* Takes brd_lock internally */ + stl_setsignals(portp, 1, 1); + if (tty_hung_up_p(filp) || + ((portp->port.flags & ASYNC_INITIALIZED) == 0)) { + if (portp->port.flags & ASYNC_HUP_NOTIFY) + rc = -EBUSY; + else + rc = -ERESTARTSYS; + break; + } + if (((portp->port.flags & ASYNC_CLOSING) == 0) && + (doclocal || (portp->sigs & TIOCM_CD))) + break; + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + /* FIXME */ + interruptible_sleep_on(&portp->port.open_wait); + } + + if (! tty_hung_up_p(filp)) + portp->port.count++; + portp->openwaitcnt--; + spin_unlock_irqrestore(&stallion_lock, flags); + + return rc; } /*****************************************************************************/ @@ -827,29 +890,47 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) static void stl_close(struct tty_struct *tty, struct file *filp) { struct stlport *portp; - struct tty_port *port; unsigned long flags; pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp); portp = tty->driver_data; - BUG_ON(portp == NULL); - - port = &portp->port; + if (portp == NULL) + return; - if (tty_port_close_start(port, tty, filp) == 0) + spin_lock_irqsave(&stallion_lock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&stallion_lock, flags); + return; + } + if ((tty->count == 1) && (portp->port.count != 1)) + portp->port.count = 1; + if (portp->port.count-- > 1) { + spin_unlock_irqrestore(&stallion_lock, flags); return; + } + + portp->port.count = 0; + portp->port.flags |= ASYNC_CLOSING; + /* * May want to wait for any data to drain before closing. The BUSY * flag keeps track of whether we are still sending or not - it is * very accurate for the cd1400, not quite so for the sc26198. * (The sc26198 has no "end-of-data" interrupt only empty FIFO) */ + tty->closing = 1; + + spin_unlock_irqrestore(&stallion_lock, flags); + + if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, portp->closing_wait); stl_waituntilsent(tty, (HZ / 2)); - spin_lock_irqsave(&port->lock, flags); + + spin_lock_irqsave(&stallion_lock, flags); portp->port.flags &= ~ASYNC_INITIALIZED; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&stallion_lock, flags); stl_disableintrs(portp); if (tty->termios->c_cflag & HUPCL) @@ -863,9 +944,20 @@ static void stl_close(struct tty_struct *tty, struct file *filp) portp->tx.head = NULL; portp->tx.tail = NULL; } + set_bit(TTY_IO_ERROR, &tty->flags); + tty_ldisc_flush(tty); - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); + tty->closing = 0; + tty_port_tty_set(&portp->port, NULL); + + if (portp->openwaitcnt) { + if (portp->close_delay) + msleep_interruptible(jiffies_to_msecs(portp->close_delay)); + wake_up_interruptible(&portp->port.open_wait); + } + + portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&portp->port.close_wait); } /*****************************************************************************/ @@ -1313,20 +1405,14 @@ static void stl_stop(struct tty_struct *tty) static void stl_hangup(struct tty_struct *tty) { struct stlport *portp; - struct tty_port *port; - unsigned long flags; pr_debug("stl_hangup(tty=%p)\n", tty); portp = tty->driver_data; if (portp == NULL) return; - port = &portp->port; - - spin_lock_irqsave(&port->lock, flags); - port->flags &= ~ASYNC_INITIALIZED; - spin_unlock_irqrestore(&port->lock, flags); + portp->port.flags &= ~ASYNC_INITIALIZED; stl_disableintrs(portp); if (tty->termios->c_cflag & HUPCL) stl_setsignals(portp, 0, 0); @@ -1340,7 +1426,10 @@ static void stl_hangup(struct tty_struct *tty) portp->tx.head = NULL; portp->tx.tail = NULL; } - tty_port_hangup(port); + tty_port_tty_set(&portp->port, NULL); + portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; + portp->port.count = 0; + wake_up_interruptible(&portp->port.open_wait); } /*****************************************************************************/ @@ -1687,7 +1776,6 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) break; } tty_port_init(&portp->port); - portp->port.ops = &stl_port_ops; portp->magic = STL_PORTMAGIC; portp->portnr = i; portp->brdnr = panelp->brdnr; @@ -2571,11 +2659,6 @@ static const struct tty_operations stl_ops = { .tiocmset = stl_tiocmset, }; -static const struct tty_port_operations stl_port_ops = { - .carrier_raised = stl_carrier_raised, - .raise_dtr_rts = stl_raise_dtr_rts, -}; - /*****************************************************************************/ /* CD1400 HARDWARE FUNCTIONS */ /*****************************************************************************/ diff --git a/trunk/drivers/char/sx.c b/trunk/drivers/char/sx.c index b60be7b0decf..ba4e86281fbf 100644 --- a/trunk/drivers/char/sx.c +++ b/trunk/drivers/char/sx.c @@ -279,7 +279,7 @@ static void sx_disable_tx_interrupts(void *ptr); static void sx_enable_tx_interrupts(void *ptr); static void sx_disable_rx_interrupts(void *ptr); static void sx_enable_rx_interrupts(void *ptr); -static int sx_carrier_raised(struct tty_port *port); +static int sx_get_CD(void *ptr); static void sx_shutdown_port(void *ptr); static int sx_set_real_termios(void *ptr); static void sx_close(void *ptr); @@ -360,6 +360,7 @@ static struct real_driver sx_real_driver = { sx_enable_tx_interrupts, sx_disable_rx_interrupts, sx_enable_rx_interrupts, + sx_get_CD, sx_shutdown_port, sx_set_real_termios, sx_chars_in_buffer, @@ -790,7 +791,7 @@ static int sx_getsignals(struct sx_port *port) sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) " "%02x/%02x\n", (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0, - port->c_dcd, tty_port_carrier_raised(&port->gs.port), + port->c_dcd, sx_get_CD(port), sx_read_channel_byte(port, hi_ip), sx_read_channel_byte(port, hi_state)); @@ -1189,7 +1190,7 @@ static inline void sx_check_modem_signals(struct sx_port *port) hi_state = sx_read_channel_byte(port, hi_state); sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n", - port->c_dcd, tty_port_carrier_raised(&port->gs.port)); + port->c_dcd, sx_get_CD(port)); if (hi_state & ST_BREAK) { hi_state &= ~ST_BREAK; @@ -1201,11 +1202,11 @@ static inline void sx_check_modem_signals(struct sx_port *port) hi_state &= ~ST_DCD; sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n"); sx_write_channel_byte(port, hi_state, hi_state); - c_dcd = tty_port_carrier_raised(&port->gs.port); + c_dcd = sx_get_CD(port); sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd); if (c_dcd != port->c_dcd) { port->c_dcd = c_dcd; - if (tty_port_carrier_raised(&port->gs.port)) { + if (sx_get_CD(port)) { /* DCD went UP */ if ((sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) && @@ -1414,10 +1415,13 @@ static void sx_enable_rx_interrupts(void *ptr) } /* Jeez. Isn't this simple? */ -static int sx_carrier_raised(struct tty_port *port) +static int sx_get_CD(void *ptr) { - struct sx_port *sp = container_of(port, struct sx_port, gs.port); - return ((sx_read_channel_byte(sp, hi_ip) & IP_DCD) != 0); + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte(port, hi_ip) & IP_DCD) != 0); } /* Jeez. Isn't this simple? */ @@ -1532,7 +1536,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp) } /* tty->low_latency = 1; */ - port->c_dcd = sx_carrier_raised(&port->gs.port); + port->c_dcd = sx_get_CD(port); sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd); func_exit(); @@ -1941,7 +1945,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp, static void sx_throttle(struct tty_struct *tty) { - struct sx_port *port = tty->driver_data; + struct sx_port *port = (struct sx_port *)tty->driver_data; func_enter2(); /* If the port is using any type of input flow @@ -1955,7 +1959,7 @@ static void sx_throttle(struct tty_struct *tty) static void sx_unthrottle(struct tty_struct *tty) { - struct sx_port *port = tty->driver_data; + struct sx_port *port = (struct sx_port *)tty->driver_data; func_enter2(); /* Always unthrottle even if flow control is not enabled on @@ -2350,10 +2354,6 @@ static const struct tty_operations sx_ops = { .tiocmset = sx_tiocmset, }; -static const struct tty_port_operations sx_port_ops = { - .carrier_raised = sx_carrier_raised, -}; - static int sx_init_drivers(void) { int error; @@ -2410,7 +2410,6 @@ static int sx_init_portstructs(int nboards, int nports) for (j = 0; j < boards[i].nports; j++) { sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j); tty_port_init(&port->gs.port); - port->gs.port.ops = &sx_port_ops; port->gs.magic = SX_MAGIC; port->gs.close_delay = HZ / 2; port->gs.closing_wait = 30 * HZ; diff --git a/trunk/drivers/char/synclink.c b/trunk/drivers/char/synclink.c index b8063d4cad32..500f5176b6ba 100644 --- a/trunk/drivers/char/synclink.c +++ b/trunk/drivers/char/synclink.c @@ -977,7 +977,7 @@ static void ldisc_receive_buf(struct tty_struct *tty, */ static void mgsl_stop(struct tty_struct *tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (mgsl_paranoia_check(info, tty->name, "mgsl_stop")) @@ -1000,7 +1000,7 @@ static void mgsl_stop(struct tty_struct *tty) */ static void mgsl_start(struct tty_struct *tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (mgsl_paranoia_check(info, tty->name, "mgsl_start")) @@ -2057,7 +2057,7 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch) */ static void mgsl_flush_chars(struct tty_struct *tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) @@ -2109,7 +2109,7 @@ static int mgsl_write(struct tty_struct * tty, const unsigned char *buf, int count) { int c, ret = 0; - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) @@ -2232,7 +2232,7 @@ static int mgsl_write(struct tty_struct * tty, */ static int mgsl_write_room(struct tty_struct *tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; int ret; if (mgsl_paranoia_check(info, tty->name, "mgsl_write_room")) @@ -2267,7 +2267,7 @@ static int mgsl_write_room(struct tty_struct *tty) */ static int mgsl_chars_in_buffer(struct tty_struct *tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_chars_in_buffer(%s)\n", @@ -2301,7 +2301,7 @@ static int mgsl_chars_in_buffer(struct tty_struct *tty) */ static void mgsl_flush_buffer(struct tty_struct *tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2329,7 +2329,7 @@ static void mgsl_flush_buffer(struct tty_struct *tty) */ static void mgsl_send_xchar(struct tty_struct *tty, char ch) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2358,7 +2358,7 @@ static void mgsl_send_xchar(struct tty_struct *tty, char ch) */ static void mgsl_throttle(struct tty_struct * tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2388,7 +2388,7 @@ static void mgsl_throttle(struct tty_struct * tty) */ static void mgsl_unthrottle(struct tty_struct * tty) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2841,7 +2841,7 @@ static int modem_input_wait(struct mgsl_struct *info,int arg) */ static int tiocmget(struct tty_struct *tty, struct file *file) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned int result; unsigned long flags; @@ -2867,7 +2867,7 @@ static int tiocmget(struct tty_struct *tty, struct file *file) static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2898,7 +2898,7 @@ static int tiocmset(struct tty_struct *tty, struct file *file, */ static int mgsl_break(struct tty_struct *tty, int break_state) { - struct mgsl_struct * info = tty->driver_data; + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2932,7 +2932,7 @@ static int mgsl_break(struct tty_struct *tty, int break_state) static int mgsl_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct mgsl_struct * info = tty->driver_data; + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; int ret; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3042,7 +3042,7 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne */ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct mgsl_struct *info = tty->driver_data; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3096,7 +3096,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio */ static void mgsl_close(struct tty_struct *tty, struct file * filp) { - struct mgsl_struct * info = tty->driver_data; + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; if (mgsl_paranoia_check(info, tty->name, "mgsl_close")) return; @@ -3104,18 +3104,70 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) entry, count=%d\n", __FILE__,__LINE__, info->device_name, info->port.count); + + if (!info->port.count) + return; - if (tty_port_close_start(&info->port, tty, filp) == 0) + if (tty_hung_up_p(filp)) goto cleanup; + if ((tty->count == 1) && (info->port.count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->port.count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + printk("mgsl_close: bad refcount; tty->count is 1, " + "info->port.count is %d\n", info->port.count); + info->port.count = 1; + } + + info->port.count--; + + /* if at least one open remaining, leave hardware active */ + if (info->port.count) + goto cleanup; + + info->port.flags |= ASYNC_CLOSING; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sent\n", + __FILE__,__LINE__, info->device_name ); + tty_wait_until_sent(tty, info->port.closing_wait); + } + if (info->port.flags & ASYNC_INITIALIZED) mgsl_wait_until_sent(tty, info->timeout); + mgsl_flush_buffer(tty); + tty_ldisc_flush(tty); + shutdown(info); - - tty_port_close_end(&info->port, tty); + + tty->closing = 0; info->port.tty = NULL; + + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); + } + wake_up_interruptible(&info->port.open_wait); + } + + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + + wake_up_interruptible(&info->port.close_wait); + cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__, @@ -3136,7 +3188,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) */ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) { - struct mgsl_struct * info = tty->driver_data; + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; unsigned long orig_jiffies, char_time; if (!info ) @@ -3209,7 +3261,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) */ static void mgsl_hangup(struct tty_struct *tty) { - struct mgsl_struct * info = tty->driver_data; + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_hangup(%s)\n", @@ -3229,35 +3281,6 @@ static void mgsl_hangup(struct tty_struct *tty) } /* end of mgsl_hangup() */ -/* - * carrier_raised() - * - * Return true if carrier is raised - */ - -static int carrier_raised(struct tty_port *port) -{ - unsigned long flags; - struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); - - spin_lock_irqsave(&info->irq_spinlock, flags); - usc_get_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock, flags); - return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; -} - -static void raise_dtr_rts(struct tty_port *port) -{ - struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); -} - - /* block_til_ready() * * Block the current process until the specified port @@ -3279,8 +3302,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, bool do_clocal = false; bool extra_count = false; unsigned long flags; - int dcd; - struct tty_port *port = &info->port; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready on %s\n", @@ -3288,7 +3309,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -3297,42 +3318,50 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * mgsl_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready before block on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); spin_lock_irqsave(&info->irq_spinlock, flags); if (!tty_hung_up_p(filp)) { extra_count = true; - port->count--; + info->port.count--; } spin_unlock_irqrestore(&info->irq_spinlock, flags); - port->blocked_open++; + info->port.blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) - tty_port_raise_dtr_rts(port); + if (tty->termios->c_cflag & CBAUD) { + spin_lock_irqsave(&info->irq_spinlock,flags); + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ - retval = (port->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ + retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } - dcd = tty_port_carrier_raised(&info->port); + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_get_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); - if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd)) + if (!(info->port.flags & ASYNC_CLOSING) && + (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; + } if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -3341,25 +3370,24 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); - /* FIXME: Racy on hangup during close wait */ if (extra_count) - port->count++; - port->blocked_open--; + info->port.count++; + info->port.blocked_open--; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready after blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return retval; @@ -4276,12 +4304,6 @@ static void mgsl_add_device( struct mgsl_struct *info ) } /* end of mgsl_add_device() */ -static const struct tty_port_operations mgsl_port_ops = { - .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, -}; - - /* mgsl_allocate_device() * * Allocate and initialize a device instance structure @@ -4300,7 +4322,6 @@ static struct mgsl_struct* mgsl_allocate_device(void) printk("Error can't allocate device instance data\n"); } else { tty_port_init(&info->port); - info->port.ops = &mgsl_port_ops; info->magic = MGSL_MAGIC; INIT_WORK(&info->task, mgsl_bh_handler); info->max_frame_size = 4096; diff --git a/trunk/drivers/char/synclink_gt.c b/trunk/drivers/char/synclink_gt.c index 53544e21f191..08911ed66494 100644 --- a/trunk/drivers/char/synclink_gt.c +++ b/trunk/drivers/char/synclink_gt.c @@ -720,9 +720,44 @@ static void close(struct tty_struct *tty, struct file *filp) return; DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count)); - if (tty_port_close_start(&info->port, tty, filp) == 0) + if (!info->port.count) + return; + + if (tty_hung_up_p(filp)) + goto cleanup; + + if ((tty->count == 1) && (info->port.count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->port.count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + DBGERR(("%s close: bad refcount; tty->count=1, " + "info->port.count=%d\n", info->device_name, info->port.count)); + info->port.count = 1; + } + + info->port.count--; + + /* if at least one open remaining, leave hardware active */ + if (info->port.count) goto cleanup; + info->port.flags |= ASYNC_CLOSING; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { + DBGINFO(("%s call tty_wait_until_sent\n", info->device_name)); + tty_wait_until_sent(tty, info->port.closing_wait); + } + if (info->port.flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); flush_buffer(tty); @@ -730,8 +765,20 @@ static void close(struct tty_struct *tty, struct file *filp) shutdown(info); - tty_port_close_end(&info->port, tty); + tty->closing = 0; info->port.tty = NULL; + + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); + } + wake_up_interruptible(&info->port.open_wait); + } + + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + + wake_up_interruptible(&info->port.close_wait); + cleanup: DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count)); } @@ -3085,29 +3132,6 @@ static int tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int carrier_raised(struct tty_port *port) -{ - unsigned long flags; - struct slgt_info *info = container_of(port, struct slgt_info, port); - - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - return (info->signals & SerialSignal_DCD) ? 1 : 0; -} - -static void raise_dtr_rts(struct tty_port *port) -{ - unsigned long flags; - struct slgt_info *info = container_of(port, struct slgt_info, port); - - spin_lock_irqsave(&info->lock,flags); - info->signals |= SerialSignal_RTS + SerialSignal_DTR; - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); -} - - /* * block current process until the device is ready to open */ @@ -3119,14 +3143,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, bool do_clocal = false; bool extra_count = false; unsigned long flags; - int cd; - struct tty_port *port = &info->port; DBGINFO(("%s block_til_ready\n", tty->driver->name)); if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -3135,38 +3157,46 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = true; - port->count--; + info->port.count--; } spin_unlock_irqrestore(&info->lock, flags); - port->blocked_open++; + info->port.blocked_open++; while (1) { - if ((tty->termios->c_cflag & CBAUD)) - tty_port_raise_dtr_rts(port); + if ((tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->lock,flags); + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ - retval = (port->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ + retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } - cd = tty_port_carrier_raised(port); + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); - if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd )) + if (!(info->port.flags & ASYNC_CLOSING) && + (do_clocal || (info->signals & SerialSignal_DCD)) ) { break; + } if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -3178,14 +3208,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (extra_count) - port->count++; - port->blocked_open--; + info->port.count++; + info->port.blocked_open--; if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); return retval; @@ -3414,11 +3444,6 @@ static void add_device(struct slgt_info *info) #endif } -static const struct tty_port_operations slgt_port_ops = { - .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, -}; - /* * allocate device instance structure, return NULL on failure */ @@ -3433,7 +3458,6 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev driver_name, adapter_num, port_num)); } else { tty_port_init(&info->port); - info->port.ops = &slgt_port_ops; info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; diff --git a/trunk/drivers/char/synclinkmp.c b/trunk/drivers/char/synclinkmp.c index 7b0c5b2dd263..6bdb44f7bec2 100644 --- a/trunk/drivers/char/synclinkmp.c +++ b/trunk/drivers/char/synclinkmp.c @@ -558,7 +558,6 @@ static void release_resources(SLMP_INFO *info); static int startup(SLMP_INFO *info); static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info); -static int carrier_raised(struct tty_port *port); static void shutdown(SLMP_INFO *info); static void program_hw(SLMP_INFO *info); static void change_params(SLMP_INFO *info); @@ -801,7 +800,7 @@ static int open(struct tty_struct *tty, struct file *filp) */ static void close(struct tty_struct *tty, struct file *filp) { - SLMP_INFO * info = tty->driver_data; + SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; if (sanity_check(info, tty->name, "close")) return; @@ -810,18 +809,70 @@ static void close(struct tty_struct *tty, struct file *filp) printk("%s(%d):%s close() entry, count=%d\n", __FILE__,__LINE__, info->device_name, info->port.count); - if (tty_port_close_start(&info->port, tty, filp) == 0) + if (!info->port.count) + return; + + if (tty_hung_up_p(filp)) goto cleanup; - + + if ((tty->count == 1) && (info->port.count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->port.count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + printk("%s(%d):%s close: bad refcount; tty->count is 1, " + "info->port.count is %d\n", + __FILE__,__LINE__, info->device_name, info->port.count); + info->port.count = 1; + } + + info->port.count--; + + /* if at least one open remaining, leave hardware active */ + if (info->port.count) + goto cleanup; + + info->port.flags |= ASYNC_CLOSING; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s close() calling tty_wait_until_sent\n", + __FILE__,__LINE__, info->device_name ); + tty_wait_until_sent(tty, info->port.closing_wait); + } + if (info->port.flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); flush_buffer(tty); + tty_ldisc_flush(tty); + shutdown(info); - tty_port_close_end(&info->port, tty); + tty->closing = 0; info->port.tty = NULL; + + if (info->port.blocked_open) { + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs(info->port.close_delay)); + } + wake_up_interruptible(&info->port.open_wait); + } + + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + + wake_up_interruptible(&info->port.close_wait); + cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, @@ -833,7 +884,7 @@ static void close(struct tty_struct *tty, struct file *filp) */ static void hangup(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s hangup()\n", @@ -856,7 +907,7 @@ static void hangup(struct tty_struct *tty) */ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -909,7 +960,7 @@ static int write(struct tty_struct *tty, const unsigned char *buf, int count) { int c, ret = 0; - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -987,7 +1038,7 @@ static int write(struct tty_struct *tty, */ static int put_char(struct tty_struct *tty, unsigned char ch) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; int ret = 0; @@ -1024,7 +1075,7 @@ static int put_char(struct tty_struct *tty, unsigned char ch) */ static void send_xchar(struct tty_struct *tty, char ch) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1048,7 +1099,7 @@ static void send_xchar(struct tty_struct *tty, char ch) */ static void wait_until_sent(struct tty_struct *tty, int timeout) { - SLMP_INFO * info = tty->driver_data; + SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; unsigned long orig_jiffies, char_time; if (!info ) @@ -1115,7 +1166,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) */ static int write_room(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; int ret; if (sanity_check(info, tty->name, "write_room")) @@ -1142,7 +1193,7 @@ static int write_room(struct tty_struct *tty) */ static void flush_chars(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) @@ -1181,7 +1232,7 @@ static void flush_chars(struct tty_struct *tty) */ static void flush_buffer(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1203,7 +1254,7 @@ static void flush_buffer(struct tty_struct *tty) */ static void tx_hold(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "tx_hold")) @@ -1223,7 +1274,7 @@ static void tx_hold(struct tty_struct *tty) */ static void tx_release(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "tx_release")) @@ -1253,7 +1304,7 @@ static void tx_release(struct tty_struct *tty) static int do_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; int error; struct mgsl_icount cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ @@ -1464,7 +1515,7 @@ static int read_proc(char *page, char **start, off_t off, int count, */ static int chars_in_buffer(struct tty_struct *tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; if (sanity_check(info, tty->name, "chars_in_buffer")) return 0; @@ -1480,7 +1531,7 @@ static int chars_in_buffer(struct tty_struct *tty) */ static void throttle(struct tty_struct * tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1505,7 +1556,7 @@ static void throttle(struct tty_struct * tty) */ static void unthrottle(struct tty_struct * tty) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1536,7 +1587,7 @@ static void unthrottle(struct tty_struct * tty) static int set_break(struct tty_struct *tty, int break_state) { unsigned char RegValue; - SLMP_INFO * info = tty->driver_data; + SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3218,7 +3269,7 @@ static int modem_input_wait(SLMP_INFO *info,int arg) */ static int tiocmget(struct tty_struct *tty, struct file *file) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned int result; unsigned long flags; @@ -3244,7 +3295,7 @@ static int tiocmget(struct tty_struct *tty, struct file *file) static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - SLMP_INFO *info = tty->driver_data; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3267,28 +3318,7 @@ static int tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int carrier_raised(struct tty_port *port) -{ - SLMP_INFO *info = container_of(port, SLMP_INFO, port); - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; -} - -static void raise_dtr_rts(struct tty_port *port) -{ - SLMP_INFO *info = container_of(port, SLMP_INFO, port); - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); -} /* Block the current process until the specified port is ready to open. */ @@ -3300,8 +3330,6 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, bool do_clocal = false; bool extra_count = false; unsigned long flags; - int cd; - struct tty_port *port = &info->port; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready()\n", @@ -3310,7 +3338,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ /* just verify that callout device is not active */ - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -3319,42 +3347,50 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that + * this loop, info->port.count is dropped by one, so that * close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() before block, count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = true; - port->count--; + info->port.count--; } spin_unlock_irqrestore(&info->lock, flags); - port->blocked_open++; + info->port.blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) - tty_port_raise_dtr_rts(port); + if ((tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->lock,flags); + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ - retval = (port->flags & ASYNC_HUP_NOTIFY) ? + if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){ + retval = (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } - cd = tty_port_carrier_raised(port); + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); - if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd)) + if (!(info->port.flags & ASYNC_CLOSING) && + (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; + } if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -3363,24 +3399,24 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); if (extra_count) - port->count++; - port->blocked_open--; + info->port.count++; + info->port.blocked_open--; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() after, count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, info->port.count ); if (!retval) - port->flags |= ASYNC_NORMAL_ACTIVE; + info->port.flags |= ASYNC_NORMAL_ACTIVE; return retval; } @@ -3746,11 +3782,6 @@ static void add_device(SLMP_INFO *info) #endif } -static const struct tty_port_operations port_ops = { - .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, -}; - /* Allocate and initialize a device instance structure * * Return Value: pointer to SLMP_INFO if success, otherwise NULL @@ -3767,7 +3798,6 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) __FILE__,__LINE__, adapter_num, port_num); } else { tty_port_init(&info->port); - info->port.ops = &port_ops; info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; @@ -3910,7 +3940,6 @@ static const struct tty_operations ops = { .tiocmset = tiocmset, }; - static void synclinkmp_cleanup(void) { int rc; diff --git a/trunk/drivers/char/tty_io.c b/trunk/drivers/char/tty_io.c index d33e5ab06177..db15f9ba7c0b 100644 --- a/trunk/drivers/char/tty_io.c +++ b/trunk/drivers/char/tty_io.c @@ -1111,7 +1111,9 @@ void tty_write_message(struct tty_struct *tty, char *msg) * Locks the line discipline as required * Writes to the tty driver are serialized by the atomic_write_lock * and are then processed in chunks to the device. The line discipline - * write method will not be invoked in parallel for each device. + * write method will not be involked in parallel for each device + * The line discipline write method is called under the big + * kernel lock for historical reasons. New code should not rely on this. */ static ssize_t tty_write(struct file *file, const char __user *buf, @@ -1211,7 +1213,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p) * be held until the 'fast-open' is also done. Will change once we * have refcounting in the driver and per driver locking */ -static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, +struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct inode *inode, int idx) { struct tty_struct *tty; @@ -2048,6 +2050,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) /** * tty_do_resize - resize event * @tty: tty being resized + * @real_tty: real tty (not the same as tty if using a pty/tty pair) * @rows: rows (character) * @cols: cols (character) * @@ -2055,34 +2058,41 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) * peform a terminal resize correctly */ -int tty_do_resize(struct tty_struct *tty, struct winsize *ws) +int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws) { - struct pid *pgrp; + struct pid *pgrp, *rpgrp; unsigned long flags; - /* Lock the tty */ - mutex_lock(&tty->termios_mutex); - if (!memcmp(ws, &tty->winsize, sizeof(*ws))) + /* For a PTY we need to lock the tty side */ + mutex_lock(&real_tty->termios_mutex); + if (!memcmp(ws, &real_tty->winsize, sizeof(*ws))) goto done; /* Get the PID values and reference them so we can avoid holding the tty ctrl lock while sending signals */ spin_lock_irqsave(&tty->ctrl_lock, flags); pgrp = get_pid(tty->pgrp); + rpgrp = get_pid(real_tty->pgrp); spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (pgrp) kill_pgrp(pgrp, SIGWINCH, 1); + if (rpgrp != pgrp && rpgrp) + kill_pgrp(rpgrp, SIGWINCH, 1); + put_pid(pgrp); + put_pid(rpgrp); tty->winsize = *ws; + real_tty->winsize = *ws; done: - mutex_unlock(&tty->termios_mutex); + mutex_unlock(&real_tty->termios_mutex); return 0; } /** * tiocswinsz - implement window size set ioctl - * @tty; tty side of tty + * @tty; tty * @arg: user buffer for result * * Copies the user idea of the window size to the kernel. Traditionally @@ -2095,16 +2105,17 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws) * then calls into the default method. */ -static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) +static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize __user *arg) { struct winsize tmp_ws; if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; if (tty->ops->resize) - return tty->ops->resize(tty, &tmp_ws); + return tty->ops->resize(tty, real_tty, &tmp_ws); else - return tty_do_resize(tty, &tmp_ws); + return tty_do_resize(tty, real_tty, &tmp_ws); } /** @@ -2529,7 +2540,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGWINSZ: return tiocgwinsz(real_tty, p); case TIOCSWINSZ: - return tiocswinsz(real_tty, p); + return tiocswinsz(tty, real_tty, p); case TIOCCONS: return real_tty != tty ? -EINVAL : tioccons(file); case FIONBIO: @@ -2774,8 +2785,6 @@ void initialize_tty_struct(struct tty_struct *tty, INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); - mutex_init(&tty->output_lock); - mutex_init(&tty->echo_lock); spin_lock_init(&tty->read_lock); spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); diff --git a/trunk/drivers/char/tty_ldisc.c b/trunk/drivers/char/tty_ldisc.c index 7a84b406a952..f307f135cbfb 100644 --- a/trunk/drivers/char/tty_ldisc.c +++ b/trunk/drivers/char/tty_ldisc.c @@ -316,7 +316,8 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) { /* wait_event is a macro */ wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); - WARN_ON(tty->ldisc.refcount == 0); + if (tty->ldisc.refcount == 0) + printk(KERN_ERR "tty_ldisc_ref_wait\n"); return &tty->ldisc; } @@ -375,17 +376,15 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref); * @tty: terminal to activate ldisc on * * Set the TTY_LDISC flag when the line discipline can be called - * again. Do necessary wakeups for existing sleepers. Clear the LDISC - * changing flag to indicate any ldisc change is now over. + * again. Do necessary wakeups for existing sleepers. * - * Note: nobody should set the TTY_LDISC bit except via this function. - * Clearing directly is allowed. + * Note: nobody should set this bit except via this function. Clearing + * directly is allowed. */ void tty_ldisc_enable(struct tty_struct *tty) { set_bit(TTY_LDISC, &tty->flags); - clear_bit(TTY_LDISC_CHANGING, &tty->flags); wake_up(&tty_ldisc_wait); } @@ -497,14 +496,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) * reference to the line discipline. The TTY_LDISC bit * prevents anyone taking a reference once it is clear. * We need the lock to avoid racing reference takers. - * - * We must clear the TTY_LDISC bit here to avoid a livelock - * with a userspace app continually trying to use the tty in - * parallel to the change and re-referencing the tty. */ - clear_bit(TTY_LDISC, &tty->flags); - if (o_tty) - clear_bit(TTY_LDISC, &o_tty->flags); spin_lock_irqsave(&tty_ldisc_lock, flags); if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { @@ -536,7 +528,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) * If the TTY_LDISC bit is set, then we are racing against * another ldisc change */ - if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { + if (!test_bit(TTY_LDISC, &tty->flags)) { struct tty_ldisc *ld; spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(new_ldisc.ops); @@ -544,14 +536,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_ldisc_deref(ld); goto restart; } - /* - * This flag is used to avoid two parallel ldisc changes. Once - * open and close are fine grained locked this may work better - * as a mutex shared with the open/close/hup paths - */ - set_bit(TTY_LDISC_CHANGING, &tty->flags); + + clear_bit(TTY_LDISC, &tty->flags); if (o_tty) - set_bit(TTY_LDISC_CHANGING, &o_tty->flags); + clear_bit(TTY_LDISC, &o_tty->flags); spin_unlock_irqrestore(&tty_ldisc_lock, flags); /* diff --git a/trunk/drivers/char/tty_port.c b/trunk/drivers/char/tty_port.c index 9b8004c72686..c8f8024cb40e 100644 --- a/trunk/drivers/char/tty_port.c +++ b/trunk/drivers/char/tty_port.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -95,227 +94,3 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&port->lock, flags); } EXPORT_SYMBOL(tty_port_tty_set); - -/** - * tty_port_hangup - hangup helper - * @port: tty port - * - * Perform port level tty hangup flag and count changes. Drop the tty - * reference. - */ - -void tty_port_hangup(struct tty_port *port) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; - if (port->tty) - tty_kref_put(port->tty); - port->tty = NULL; - spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&port->open_wait); -} -EXPORT_SYMBOL(tty_port_hangup); - -/** - * tty_port_carrier_raised - carrier raised check - * @port: tty port - * - * Wrapper for the carrier detect logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. - */ - -int tty_port_carrier_raised(struct tty_port *port) -{ - if (port->ops->carrier_raised == NULL) - return 1; - return port->ops->carrier_raised(port); -} -EXPORT_SYMBOL(tty_port_carrier_raised); - -/** - * tty_port_raise_dtr_rts - Riase DTR/RTS - * @port: tty port - * - * Wrapper for the DTR/RTS raise logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. - */ - -void tty_port_raise_dtr_rts(struct tty_port *port) -{ - if (port->ops->raise_dtr_rts) - port->ops->raise_dtr_rts(port); -} -EXPORT_SYMBOL(tty_port_raise_dtr_rts); - -/** - * tty_port_block_til_ready - Waiting logic for tty open - * @port: the tty port being opened - * @tty: the tty device being bound - * @filp: the file pointer of the opener - * - * Implement the core POSIX/SuS tty behaviour when opening a tty device. - * Handles: - * - hangup (both before and during) - * - non blocking open - * - rts/dtr/dcd - * - signals - * - port flags and counts - * - * The passed tty_port must implement the carrier_raised method if it can - * do carrier detect and the raise_dtr_rts method if it supports software - * management of these lines. Note that the dtr/rts raise is done each - * iteration as a hangup may have previously dropped them while we wait. - */ - -int tty_port_block_til_ready(struct tty_port *port, - struct tty_struct *tty, struct file *filp) -{ - int do_clocal = 0, retval; - unsigned long flags; - DECLARE_WAITQUEUE(wait, current); - int cd; - - /* block if port is in the process of being closed */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; - } - - /* if non-blocking mode is set we can pass directly to open unless - the port has just hung up or is in another error state */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (C_CLOCAL(tty)) - do_clocal = 1; - - /* Block waiting until we can proceed. We may need to wait for the - carrier, but we must also wait for any close that is in progress - before the next open may complete */ - - retval = 0; - add_wait_queue(&port->open_wait, &wait); - - /* The port lock protects the port counts */ - spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count--; - port->blocked_open++; - spin_unlock_irqrestore(&port->lock, flags); - - while (1) { - /* Indicate we are open */ - if (tty->termios->c_cflag & CBAUD) - tty_port_raise_dtr_rts(port); - - set_current_state(TASK_INTERRUPTIBLE); - /* Check for a hangup or uninitialised port. Return accordingly */ - if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; - break; - } - /* Probe the carrier. For devices with no carrier detect this - will always return true */ - cd = tty_port_carrier_raised(port); - if (!(port->flags & ASYNC_CLOSING) && - (do_clocal || cd)) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); - - /* Update counts. A parallel hangup will have set count to zero and - we must not mess that up further */ - spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - if (retval == 0) - port->flags |= ASYNC_NORMAL_ACTIVE; - spin_unlock_irqrestore(&port->lock, flags); - return 0; - -} -EXPORT_SYMBOL(tty_port_block_til_ready); - -int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&port->lock, flags); - return 0; - } - - if( tty->count == 1 && port->count != 1) { - printk(KERN_WARNING - "tty_port_close_start: tty->count = 1 port count = %d.\n", - port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_WARNING "tty_port_close_start: count = %d\n", - port->count); - port->count = 0; - } - - if (port->count) { - spin_unlock_irqrestore(&port->lock, flags); - return 0; - } - port->flags |= ASYNC_CLOSING; - tty->closing = 1; - spin_unlock_irqrestore(&port->lock, flags); - /* Don't block on a stalled port, just pull the chain */ - if (tty->flow_stopped) - tty_driver_flush_buffer(tty); - if (port->flags & ASYNC_INITIALIZED && - port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, port->closing_wait); - return 1; -} -EXPORT_SYMBOL(tty_port_close_start); - -void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) -{ - unsigned long flags; - - tty_ldisc_flush(tty); - - spin_lock_irqsave(&port->lock, flags); - tty->closing = 0; - - if (port->blocked_open) { - spin_unlock_irqrestore(&port->lock, flags); - if (port->close_delay) { - msleep_interruptible( - jiffies_to_msecs(port->close_delay)); - } - spin_lock_irqsave(&port->lock, flags); - wake_up_interruptible(&port->open_wait); - } - port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL(tty_port_close_end); diff --git a/trunk/drivers/char/vme_scc.c b/trunk/drivers/char/vme_scc.c index 0e8234bd0e19..1718b3c481db 100644 --- a/trunk/drivers/char/vme_scc.c +++ b/trunk/drivers/char/vme_scc.c @@ -69,7 +69,7 @@ static void scc_disable_tx_interrupts(void * ptr); static void scc_enable_tx_interrupts(void * ptr); static void scc_disable_rx_interrupts(void * ptr); static void scc_enable_rx_interrupts(void * ptr); -static int scc_carrier_raised(struct tty_port *port); +static int scc_get_CD(void * ptr); static void scc_shutdown_port(void * ptr); static int scc_set_real_termios(void *ptr); static void scc_hungup(void *ptr); @@ -100,6 +100,7 @@ static struct real_driver scc_real_driver = { scc_enable_tx_interrupts, scc_disable_rx_interrupts, scc_enable_rx_interrupts, + scc_get_CD, scc_shutdown_port, scc_set_real_termios, scc_chars_in_buffer, @@ -128,10 +129,6 @@ static const struct tty_operations scc_ops = { .break_ctl = scc_break_ctl, }; -static const struct tty_port_operations scc_port_ops = { - .carrier_raised = scc_carrier_raised, -}; - /*---------------------------------------------------------------------------- * vme_scc_init() and support functions *---------------------------------------------------------------------------*/ @@ -179,8 +176,6 @@ static void scc_init_portstructs(void) for (i = 0; i < 2; i++) { port = scc_ports + i; - tty_port_init(&port->gs.port); - port->gs.port.ops = &scc_port_ops; port->gs.magic = SCC_MAGIC; port->gs.close_delay = HZ/2; port->gs.closing_wait = 30 * HZ; @@ -629,10 +624,10 @@ static void scc_enable_rx_interrupts(void *ptr) } -static int scc_carrier_raised(struct tty_port *port) +static int scc_get_CD(void *ptr) { - struct scc_port *sc = container_of(port, struct scc_port, gs.port); - unsigned channel = sc->channel; + struct scc_port *port = ptr; + unsigned channel = port->channel; return !!(scc_last_status_reg[channel] & SR_DCD); } @@ -643,7 +638,7 @@ static void scc_shutdown_port(void *ptr) struct scc_port *port = ptr; port->gs.port.flags &= ~ GS_ACTIVE; - if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) { + if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) { scc_setsignals (port, 0, 0); } } @@ -784,7 +779,7 @@ static void scc_setsignals(struct scc_port *port, int dtr, int rts) static void scc_send_xchar(struct tty_struct *tty, char ch) { - struct scc_port *port = tty->driver_data; + struct scc_port *port = (struct scc_port *)tty->driver_data; port->x_char = ch; if (ch) @@ -901,7 +896,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp) return retval; } - port->c_dcd = tty_port_carrier_raised(&port->gs.port); + port->c_dcd = scc_get_CD (port); scc_enable_rx_interrupts(port); @@ -911,7 +906,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp) static void scc_throttle (struct tty_struct * tty) { - struct scc_port *port = tty->driver_data; + struct scc_port *port = (struct scc_port *)tty->driver_data; unsigned long flags; SCC_ACCESS_INIT(port); @@ -927,7 +922,7 @@ static void scc_throttle (struct tty_struct * tty) static void scc_unthrottle (struct tty_struct * tty) { - struct scc_port *port = tty->driver_data; + struct scc_port *port = (struct scc_port *)tty->driver_data; unsigned long flags; SCC_ACCESS_INIT(port); @@ -950,7 +945,7 @@ static int scc_ioctl(struct tty_struct *tty, struct file *file, static int scc_break_ctl(struct tty_struct *tty, int break_state) { - struct scc_port *port = tty->driver_data; + struct scc_port *port = (struct scc_port *)tty->driver_data; unsigned long flags; SCC_ACCESS_INIT(port); diff --git a/trunk/drivers/char/vt.c b/trunk/drivers/char/vt.c index 80014213fb53..008176edbd64 100644 --- a/trunk/drivers/char/vt.c +++ b/trunk/drivers/char/vt.c @@ -819,8 +819,8 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, * ctrl_lock of the tty IFF a tty is passed. */ -static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, - unsigned int cols, unsigned int lines) +static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct vc_data *vc, unsigned int cols, unsigned int lines) { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned int old_cols, old_rows, old_row_size, old_screen_size; @@ -932,7 +932,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, ws.ws_row = vc->vc_rows; ws.ws_col = vc->vc_cols; ws.ws_ypixel = vc->vc_scan_lines; - tty_do_resize(tty, &ws); + tty_do_resize(tty, real_tty, &ws); } if (CON_IS_VISIBLE(vc)) @@ -954,12 +954,13 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) { - return vc_do_resize(vc->vc_tty, vc, cols, rows); + return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows); } /** * vt_resize - resize a VT * @tty: tty to resize + * @real_tty: tty if a pty/tty pair * @ws: winsize attributes * * Resize a virtual terminal. This is called by the tty layer as we @@ -970,13 +971,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) * termios_mutex and the tty ctrl_lock in that order. */ -int vt_resize(struct tty_struct *tty, struct winsize *ws) +int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws) { struct vc_data *vc = tty->driver_data; int ret; acquire_console_sem(); - ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row); + ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row); release_console_sem(); return ret; } @@ -2677,7 +2679,7 @@ static int con_write_room(struct tty_struct *tty) { if (tty->stopped) return 0; - return 32768; /* No limit, really; we're not buffering */ + return 4096; /* No limit, really; we're not buffering */ } static int con_chars_in_buffer(struct tty_struct *tty) diff --git a/trunk/drivers/char/vt_ioctl.c b/trunk/drivers/char/vt_ioctl.c index a2dee0eb6dad..8944ce508e2f 100644 --- a/trunk/drivers/char/vt_ioctl.c +++ b/trunk/drivers/char/vt_ioctl.c @@ -366,7 +366,7 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct vc_data *vc = tty->driver_data; + struct vc_data *vc = (struct vc_data *)tty->driver_data; struct console_font_op op; /* used in multiple places here */ struct kbd_struct * kbd; unsigned int console; diff --git a/trunk/drivers/ide/tx4938ide.c b/trunk/drivers/ide/tx4938ide.c index 13b63e7fa353..0bb8b0ce456e 100644 --- a/trunk/drivers/ide/tx4938ide.c +++ b/trunk/drivers/ide/tx4938ide.c @@ -216,16 +216,16 @@ static const struct ide_tp_ops tx4938ide_tp_ops = { #endif /* __BIG_ENDIAN */ static const struct ide_port_ops tx4938ide_port_ops = { - .set_pio_mode = tx4938ide_set_pio_mode, + .set_pio_mode = tx4938ide_set_pio_mode, }; static const struct ide_port_info tx4938ide_port_info __initdata = { - .port_ops = &tx4938ide_port_ops, + .port_ops = &tx4938ide_port_ops, #ifdef __BIG_ENDIAN - .tp_ops = &tx4938ide_tp_ops, + .tp_ops = &tx4938ide_tp_ops, #endif - .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO5, + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO5, }; static int __init tx4938ide_probe(struct platform_device *pdev) diff --git a/trunk/drivers/ide/tx4939ide.c b/trunk/drivers/ide/tx4939ide.c index 97cd9e0f66f6..65cd09773a02 100644 --- a/trunk/drivers/ide/tx4939ide.c +++ b/trunk/drivers/ide/tx4939ide.c @@ -623,33 +623,33 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { #endif /* __LITTLE_ENDIAN */ static const struct ide_port_ops tx4939ide_port_ops = { - .set_pio_mode = tx4939ide_set_pio_mode, - .set_dma_mode = tx4939ide_set_dma_mode, - .clear_irq = tx4939ide_clear_irq, - .cable_detect = tx4939ide_cable_detect, + .set_pio_mode = tx4939ide_set_pio_mode, + .set_dma_mode = tx4939ide_set_dma_mode, + .clear_irq = tx4939ide_clear_irq, + .cable_detect = tx4939ide_cable_detect, }; static const struct ide_dma_ops tx4939ide_dma_ops = { - .dma_host_set = tx4939ide_dma_host_set, - .dma_setup = tx4939ide_dma_setup, - .dma_exec_cmd = ide_dma_exec_cmd, - .dma_start = ide_dma_start, - .dma_end = tx4939ide_dma_end, - .dma_test_irq = tx4939ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timeout = ide_dma_timeout, + .dma_host_set = tx4939ide_dma_host_set, + .dma_setup = tx4939ide_dma_setup, + .dma_exec_cmd = ide_dma_exec_cmd, + .dma_start = ide_dma_start, + .dma_end = tx4939ide_dma_end, + .dma_test_irq = tx4939ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timeout = ide_dma_timeout, }; static const struct ide_port_info tx4939ide_port_info __initdata = { - .init_hwif = tx4939ide_init_hwif, - .init_dma = tx4939ide_init_dma, - .port_ops = &tx4939ide_port_ops, - .dma_ops = &tx4939ide_dma_ops, - .tp_ops = &tx4939ide_tp_ops, - .host_flags = IDE_HFLAG_MMIO, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, + .init_hwif = tx4939ide_init_hwif, + .init_dma = tx4939ide_init_dma, + .port_ops = &tx4939ide_port_ops, + .dma_ops = &tx4939ide_dma_ops, + .tp_ops = &tx4939ide_tp_ops, + .host_flags = IDE_HFLAG_MMIO, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, }; static int __init tx4939ide_probe(struct platform_device *pdev) diff --git a/trunk/drivers/net/usb/hso.c b/trunk/drivers/net/usb/hso.c index c4918b86ed19..9f7896a25f1b 100644 --- a/trunk/drivers/net/usb/hso.c +++ b/trunk/drivers/net/usb/hso.c @@ -3,8 +3,6 @@ * Driver for Option High Speed Mobile Devices. * * Copyright (C) 2008 Option International - * Filip Aben - * Denis Joseph Barrow * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) * * Copyright (C) 2008 Greg Kroah-Hartman @@ -41,11 +39,8 @@ * port is opened, as this have a huge impact on the network port * throughput. * - * Interface 2: Standard modem interface - circuit switched interface, this - * can be used to make a standard ppp connection however it - * should not be used in conjunction with the IP network interface - * enabled for USB performance reasons i.e. if using this set - * ideally disable_net=1. + * Interface 2: Standard modem interface - circuit switched interface, should + * not be used. * *****************************************************************************/ @@ -68,8 +63,6 @@ #include #include #include -#include -#include #define DRIVER_VERSION "1.2" @@ -189,41 +182,6 @@ enum rx_ctrl_state{ RX_PENDING }; -#define BM_REQUEST_TYPE (0xa1) -#define B_NOTIFICATION (0x20) -#define W_VALUE (0x0) -#define W_INDEX (0x2) -#define W_LENGTH (0x2) - -#define B_OVERRUN (0x1<<6) -#define B_PARITY (0x1<<5) -#define B_FRAMING (0x1<<4) -#define B_RING_SIGNAL (0x1<<3) -#define B_BREAK (0x1<<2) -#define B_TX_CARRIER (0x1<<1) -#define B_RX_CARRIER (0x1<<0) - -struct hso_serial_state_notification { - u8 bmRequestType; - u8 bNotification; - u16 wValue; - u16 wIndex; - u16 wLength; - u16 UART_state_bitmap; -} __attribute__((packed)); - -struct hso_tiocmget { - struct mutex mutex; - wait_queue_head_t waitq; - int intr_completed; - struct usb_endpoint_descriptor *endp; - struct urb *urb; - struct hso_serial_state_notification serial_state_notification; - u16 prev_UART_state_bitmap; - struct uart_icount icount; -}; - - struct hso_serial { struct hso_device *parent; int magic; @@ -261,7 +219,6 @@ struct hso_serial { spinlock_t serial_lock; int (*write_data) (struct hso_serial *serial); - struct hso_tiocmget *tiocmget; /* Hacks required to get flow control * working on the serial receive buffers * so as not to drop characters on the floor. @@ -348,7 +305,7 @@ static void async_get_intf(struct work_struct *data); static void async_put_intf(struct work_struct *data); static int hso_put_activity(struct hso_device *hso_dev); static int hso_get_activity(struct hso_device *hso_dev); -static void tiocmget_intr_callback(struct urb *urb); + /*****************************************************************************/ /* Helping functions */ /*****************************************************************************/ @@ -405,6 +362,8 @@ static struct tty_driver *tty_drv; static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; static spinlock_t serial_table_lock; +static struct ktermios *hso_serial_termios[HSO_SERIAL_TTY_MINORS]; +static struct ktermios *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS]; static const s32 default_port_spec[] = { HSO_INTF_MUX | HSO_PORT_NETWORK, @@ -1050,11 +1009,23 @@ static void read_bulk_callback(struct urb *urb) /* Serial driver functions */ -static void hso_init_termios(struct ktermios *termios) +static void _hso_serial_set_termios(struct tty_struct *tty, + struct ktermios *old) { + struct hso_serial *serial = get_serial_by_tty(tty); + struct ktermios *termios; + + if ((!tty) || (!tty->termios) || (!serial)) { + printk(KERN_ERR "%s: no tty structures", __func__); + return; + } + + D4("port %d", serial->minor); + /* * The default requirements for this device are: */ + termios = tty->termios; termios->c_iflag &= ~(IGNBRK /* disable ignore break */ | BRKINT /* disable break causes interrupt */ @@ -1086,38 +1057,15 @@ static void hso_init_termios(struct ktermios *termios) termios->c_cflag |= CS8; /* character size 8 bits */ /* baud rate 115200 */ - tty_termios_encode_baud_rate(termios, 115200, 115200); -} - -static void _hso_serial_set_termios(struct tty_struct *tty, - struct ktermios *old) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - struct ktermios *termios; - - if (!serial) { - printk(KERN_ERR "%s: no tty structures", __func__); - return; - } - - D4("port %d", serial->minor); + tty_encode_baud_rate(serial->tty, 115200, 115200); /* - * Fix up unsupported bits + * Force low_latency on; otherwise the pushes are scheduled; + * this is bad as it opens up the possibility of dropping bytes + * on the floor. We don't want to drop bytes on the floor. :) */ - termios = tty->termios; - termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ - - termios->c_cflag &= - ~(CSIZE /* no size */ - | PARENB /* disable parity bit */ - | CBAUD /* clear current baud rate */ - | CBAUDEX); /* clear current buad rate */ - - termios->c_cflag |= CS8; /* character size 8 bits */ - - /* baud rate 115200 */ - tty_encode_baud_rate(tty, 115200, 115200); + serial->tty->low_latency = 1; + return; } static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) @@ -1280,7 +1228,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) /* sanity check */ if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { - WARN_ON(1); tty->driver_data = NULL; D1("Failed to open port"); return -ENODEV; @@ -1295,10 +1242,8 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) kref_get(&serial->parent->ref); /* setup */ - spin_lock_irq(&serial->serial_lock); tty->driver_data = serial; - serial->tty = tty_kref_get(tty); - spin_unlock_irq(&serial->serial_lock); + serial->tty = tty; /* check for port already opened, if not set the termios */ serial->open_count++; @@ -1340,10 +1285,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) D1("Closing serial port"); - /* Open failed, no close cleanup required */ - if (serial == NULL) - return; - mutex_lock(&serial->parent->mutex); usb_gone = serial->parent->usb_gone; @@ -1356,13 +1297,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) kref_put(&serial->parent->ref, hso_serial_ref_free); if (serial->open_count <= 0) { serial->open_count = 0; - spin_lock_irq(&serial->serial_lock); - if (serial->tty == tty) { + if (serial->tty) { serial->tty->driver_data = NULL; serial->tty = NULL; - tty_kref_put(tty); } - spin_unlock_irq(&serial->serial_lock); if (!usb_gone) hso_stop_serial_device(serial->parent); tasklet_kill(&serial->unthrottle_tasklet); @@ -1462,217 +1400,25 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty) return chars; } -int tiocmget_submit_urb(struct hso_serial *serial, - struct hso_tiocmget *tiocmget, - struct usb_device *usb) -{ - int result; - - if (serial->parent->usb_gone) - return -ENODEV; - usb_fill_int_urb(tiocmget->urb, usb, - usb_rcvintpipe(usb, - tiocmget->endp-> - bEndpointAddress & 0x7F), - &tiocmget->serial_state_notification, - sizeof(struct hso_serial_state_notification), - tiocmget_intr_callback, serial, - tiocmget->endp->bInterval); - result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC); - if (result) { - dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__, - result); - } - return result; - -} - -static void tiocmget_intr_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - struct hso_tiocmget *tiocmget; - int status = urb->status; - u16 UART_state_bitmap, prev_UART_state_bitmap; - struct uart_icount *icount; - struct hso_serial_state_notification *serial_state_notification; - struct usb_device *usb; - - /* Sanity checks */ - if (!serial) - return; - if (status) { - log_usb_status(status, __func__); - return; - } - tiocmget = serial->tiocmget; - if (!tiocmget) - return; - usb = serial->parent->usb; - serial_state_notification = &tiocmget->serial_state_notification; - if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || - serial_state_notification->bNotification != B_NOTIFICATION || - le16_to_cpu(serial_state_notification->wValue) != W_VALUE || - le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || - le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { - dev_warn(&usb->dev, - "hso received invalid serial state notification\n"); - DUMP(serial_state_notification, - sizeof(hso_serial_state_notifation)) - } else { - - UART_state_bitmap = le16_to_cpu(serial_state_notification-> - UART_state_bitmap); - prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap; - icount = &tiocmget->icount; - spin_lock(&serial->serial_lock); - if ((UART_state_bitmap & B_OVERRUN) != - (prev_UART_state_bitmap & B_OVERRUN)) - icount->parity++; - if ((UART_state_bitmap & B_PARITY) != - (prev_UART_state_bitmap & B_PARITY)) - icount->parity++; - if ((UART_state_bitmap & B_FRAMING) != - (prev_UART_state_bitmap & B_FRAMING)) - icount->frame++; - if ((UART_state_bitmap & B_RING_SIGNAL) && - !(prev_UART_state_bitmap & B_RING_SIGNAL)) - icount->rng++; - if ((UART_state_bitmap & B_BREAK) != - (prev_UART_state_bitmap & B_BREAK)) - icount->brk++; - if ((UART_state_bitmap & B_TX_CARRIER) != - (prev_UART_state_bitmap & B_TX_CARRIER)) - icount->dsr++; - if ((UART_state_bitmap & B_RX_CARRIER) != - (prev_UART_state_bitmap & B_RX_CARRIER)) - icount->dcd++; - tiocmget->prev_UART_state_bitmap = UART_state_bitmap; - spin_unlock(&serial->serial_lock); - tiocmget->intr_completed = 1; - wake_up_interruptible(&tiocmget->waitq); - } - memset(serial_state_notification, 0, - sizeof(struct hso_serial_state_notification)); - tiocmget_submit_urb(serial, - tiocmget, - serial->parent->usb); -} - -/* - * next few functions largely stolen from drivers/serial/serial_core.c - */ -/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ -static int -hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) -{ - DECLARE_WAITQUEUE(wait, current); - struct uart_icount cprev, cnow; - struct hso_tiocmget *tiocmget; - int ret; - - tiocmget = serial->tiocmget; - if (!tiocmget) - return -ENOENT; - /* - * note the counters on entry - */ - spin_lock_irq(&serial->serial_lock); - memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - add_wait_queue(&tiocmget->waitq, &wait); - for (;;) { - spin_lock_irq(&serial->serial_lock); - memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - set_current_state(TASK_INTERRUPTIBLE); - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) { - ret = 0; - break; - } - schedule(); - /* see if a signal did it */ - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - cprev = cnow; - } - current->state = TASK_RUNNING; - remove_wait_queue(&tiocmget->waitq, &wait); - - return ret; -} - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int hso_get_count(struct hso_serial *serial, - struct serial_icounter_struct __user *icnt) -{ - struct serial_icounter_struct icount; - struct uart_icount cnow; - struct hso_tiocmget *tiocmget = serial->tiocmget; - - if (!tiocmget) - return -ENOENT; - spin_lock_irq(&serial->serial_lock); - memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; - - return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; -} - static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) { - int retval; + unsigned int value; struct hso_serial *serial = get_serial_by_tty(tty); - struct hso_tiocmget *tiocmget; - u16 UART_state_bitmap; + unsigned long flags; /* sanity check */ if (!serial) { D1("no tty structures"); return -EINVAL; } - spin_lock_irq(&serial->serial_lock); - retval = ((serial->rts_state) ? TIOCM_RTS : 0) | + + spin_lock_irqsave(&serial->serial_lock, flags); + value = ((serial->rts_state) ? TIOCM_RTS : 0) | ((serial->dtr_state) ? TIOCM_DTR : 0); - tiocmget = serial->tiocmget; - if (tiocmget) { + spin_unlock_irqrestore(&serial->serial_lock, flags); - UART_state_bitmap = le16_to_cpu( - tiocmget->prev_UART_state_bitmap); - if (UART_state_bitmap & B_RING_SIGNAL) - retval |= TIOCM_RNG; - if (UART_state_bitmap & B_RX_CARRIER) - retval |= TIOCM_CD; - if (UART_state_bitmap & B_TX_CARRIER) - retval |= TIOCM_DSR; - } - spin_unlock_irq(&serial->serial_lock); - return retval; + return value; } static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, @@ -1714,32 +1460,6 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, USB_CTRL_SET_TIMEOUT); } -static int hso_serial_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - void __user *uarg = (void __user *)arg; - int ret = 0; - D4("IOCTL cmd: %d, arg: %ld", cmd, arg); - - if (!serial) - return -ENODEV; - switch (cmd) { - case TIOCMIWAIT: - ret = hso_wait_modem_status(serial, arg); - break; - - case TIOCGICOUNT: - ret = hso_get_count(serial, uarg); - break; - default: - ret = -ENOIOCTLCMD; - break; - } - return ret; -} - - /* starts a transmit */ static void hso_kick_transmit(struct hso_serial *serial) { @@ -1933,7 +1653,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) { struct hso_serial *serial = urb->context; int status = urb->status; - struct tty_struct *tty; /* sanity check */ if (!serial) { @@ -1943,18 +1662,14 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) spin_lock(&serial->serial_lock); serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); spin_unlock(&serial->serial_lock); if (status) { log_usb_status(status, __func__); - tty_kref_put(tty); return; } hso_put_activity(serial->parent); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (serial->tty) + tty_wakeup(serial->tty); hso_kick_transmit(serial); D1(" "); @@ -1991,7 +1706,6 @@ static void ctrl_callback(struct urb *urb) struct hso_serial *serial = urb->context; struct usb_ctrlrequest *req; int status = urb->status; - struct tty_struct *tty; /* sanity check */ if (!serial) @@ -1999,11 +1713,9 @@ static void ctrl_callback(struct urb *urb) spin_lock(&serial->serial_lock); serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); spin_unlock(&serial->serial_lock); if (status) { log_usb_status(status, __func__); - tty_kref_put(tty); return; } @@ -2022,31 +1734,25 @@ static void ctrl_callback(struct urb *urb) spin_unlock(&serial->serial_lock); } else { hso_put_activity(serial->parent); - if (tty) - tty_wakeup(tty); + if (serial->tty) + tty_wakeup(serial->tty); /* response to a write command */ hso_kick_transmit(serial); } - tty_kref_put(tty); } /* handle RX data for serial port */ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) { - struct tty_struct *tty; + struct tty_struct *tty = serial->tty; int write_length_remaining = 0; int curr_write_len; - /* Sanity check */ if (urb == NULL || serial == NULL) { D1("serial = NULL"); return -2; } - spin_lock(&serial->serial_lock); - tty = tty_kref_get(serial->tty); - spin_unlock(&serial->serial_lock); - /* Push data to tty */ if (tty) { write_length_remaining = urb->actual_length - @@ -2068,7 +1774,6 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) serial->curr_rx_urb_offset = 0; serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; } - tty_kref_put(tty); return write_length_remaining; } @@ -2217,10 +1922,7 @@ static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) serial->shared_int->use_count++; mutex_unlock(&serial->shared_int->shared_int_lock); } - if (serial->tiocmget) - tiocmget_submit_urb(serial, - serial->tiocmget, - serial->parent->usb); + return result; } @@ -2228,7 +1930,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) { int i; struct hso_serial *serial = dev2ser(hso_dev); - struct hso_tiocmget *tiocmget; if (!serial) return -ENODEV; @@ -2257,11 +1958,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) } mutex_unlock(&serial->shared_int->shared_int_lock); } - tiocmget = serial->tiocmget; - if (tiocmget) { - wake_up_interruptible(&tiocmget->waitq); - usb_kill_urb(tiocmget->urb); - } return 0; } @@ -2608,20 +2304,6 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface) return NULL; } -static void hso_free_tiomget(struct hso_serial *serial) -{ - struct hso_tiocmget *tiocmget = serial->tiocmget; - if (tiocmget) { - kfree(tiocmget); - if (tiocmget->urb) { - usb_free_urb(tiocmget->urb); - tiocmget->urb = NULL; - } - serial->tiocmget = NULL; - - } -} - /* Frees an AT channel ( goes for both mux and non-mux ) */ static void hso_free_serial_device(struct hso_device *hso_dev) { @@ -2640,7 +2322,6 @@ static void hso_free_serial_device(struct hso_device *hso_dev) else mutex_unlock(&serial->shared_int->shared_int_lock); } - hso_free_tiomget(serial); kfree(serial); hso_free_device(hso_dev); } @@ -2652,7 +2333,6 @@ static struct hso_device *hso_create_bulk_serial_device( struct hso_device *hso_dev; struct hso_serial *serial; int num_urbs; - struct hso_tiocmget *tiocmget; hso_dev = hso_create_device(interface, port); if (!hso_dev) @@ -2665,27 +2345,8 @@ static struct hso_device *hso_create_bulk_serial_device( serial->parent = hso_dev; hso_dev->port_data.dev_serial = serial; - if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) { + if (port & HSO_PORT_MODEM) num_urbs = 2; - serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), - GFP_KERNEL); - /* it isn't going to break our heart if serial->tiocmget - * allocation fails don't bother checking this. - */ - if (serial->tiocmget) { - tiocmget = serial->tiocmget; - tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); - if (tiocmget->urb) { - mutex_init(&tiocmget->mutex); - init_waitqueue_head(&tiocmget->waitq); - tiocmget->endp = hso_get_ep( - interface, - USB_ENDPOINT_XFER_INT, - USB_DIR_IN); - } else - hso_free_tiomget(serial); - } - } else num_urbs = 1; @@ -2721,7 +2382,6 @@ static struct hso_device *hso_create_bulk_serial_device( exit2: hso_serial_common_free(serial); exit: - hso_free_tiomget(serial); kfree(serial); hso_free_device(hso_dev); return NULL; @@ -3126,20 +2786,15 @@ static void hso_serial_ref_free(struct kref *ref) static void hso_free_interface(struct usb_interface *interface) { struct hso_serial *hso_dev; - struct tty_struct *tty; int i; for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == interface)) { hso_dev = dev2ser(serial_table[i]); - spin_lock_irq(&hso_dev->serial_lock); - tty = tty_kref_get(hso_dev->tty); - spin_unlock_irq(&hso_dev->serial_lock); - if (tty) - tty_hangup(tty); + if (hso_dev->tty) + tty_hangup(hso_dev->tty); mutex_lock(&hso_dev->parent->mutex); - tty_kref_put(tty); hso_dev->parent->usb_gone = 1; mutex_unlock(&hso_dev->parent->mutex); kref_put(&serial_table[i]->ref, hso_serial_ref_free); @@ -3232,7 +2887,6 @@ static const struct tty_operations hso_serial_ops = { .close = hso_serial_close, .write = hso_serial_write, .write_room = hso_serial_write_room, - .ioctl = hso_serial_ioctl, .set_termios = hso_serial_set_termios, .chars_in_buffer = hso_serial_chars_in_buffer, .tiocmget = hso_serial_tiocmget, @@ -3285,7 +2939,9 @@ static int __init hso_init(void) tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->init_termios = tty_std_termios; - hso_init_termios(&tty_drv->init_termios); + tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tty_drv->termios = hso_serial_termios; + tty_drv->termios_locked = hso_serial_termios_locked; tty_set_operations(tty_drv, &hso_serial_ops); /* register the tty driver */ diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index daa00567bc44..303272af386e 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -279,13 +279,6 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, - [PORT_OCTEON] = { - .name = "OCTEON", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, }; #if defined (CONFIG_SERIAL_8250_AU1X00) @@ -310,16 +303,16 @@ static const u8 au_io_out_map[] = { }; /* sane hardware needs no mapping */ -static inline int map_8250_in_reg(struct uart_port *p, int offset) +static inline int map_8250_in_reg(struct uart_8250_port *up, int offset) { - if (p->iotype != UPIO_AU) + if (up->port.iotype != UPIO_AU) return offset; return au_io_in_map[offset]; } -static inline int map_8250_out_reg(struct uart_port *p, int offset) +static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) { - if (p->iotype != UPIO_AU) + if (up->port.iotype != UPIO_AU) return offset; return au_io_out_map[offset]; } @@ -348,16 +341,16 @@ static const u8 [UART_SCR] = 0x2c }; -static inline int map_8250_in_reg(struct uart_port *p, int offset) +static inline int map_8250_in_reg(struct uart_8250_port *up, int offset) { - if (p->iotype != UPIO_RM9000) + if (up->port.iotype != UPIO_RM9000) return offset; return regmap_in[offset]; } -static inline int map_8250_out_reg(struct uart_port *p, int offset) +static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) { - if (p->iotype != UPIO_RM9000) + if (up->port.iotype != UPIO_RM9000) return offset; return regmap_out[offset]; } @@ -370,170 +363,108 @@ static inline int map_8250_out_reg(struct uart_port *p, int offset) #endif -static unsigned int hub6_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - return inb(p->iobase + 1); -} - -static void hub6_serial_out(struct uart_port *p, int offset, int value) +static unsigned int serial_in(struct uart_8250_port *up, int offset) { - offset = map_8250_out_reg(p, offset) << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - outb(value, p->iobase + 1); -} - -static unsigned int mem_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return readb(p->membase + offset); -} + unsigned int tmp; + offset = map_8250_in_reg(up, offset) << up->port.regshift; -static void mem_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - writeb(value, p->membase + offset); -} + switch (up->port.iotype) { + case UPIO_HUB6: + outb(up->port.hub6 - 1 + offset, up->port.iobase); + return inb(up->port.iobase + 1); -static void mem32_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - writel(value, p->membase + offset); -} + case UPIO_MEM: + case UPIO_DWAPB: + return readb(up->port.membase + offset); -static unsigned int mem32_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return readl(p->membase + offset); -} + case UPIO_RM9000: + case UPIO_MEM32: + return readl(up->port.membase + offset); #ifdef CONFIG_SERIAL_8250_AU1X00 -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return __raw_readl(p->membase + offset); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - __raw_writel(value, p->membase + offset); -} + case UPIO_AU: + return __raw_readl(up->port.membase + offset); #endif -static unsigned int tsi_serial_in(struct uart_port *p, int offset) -{ - unsigned int tmp; - offset = map_8250_in_reg(p, offset) << p->regshift; - if (offset == UART_IIR) { - tmp = readl(p->membase + (UART_IIR & ~3)); - return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ - } else - return readb(p->membase + offset); -} - -static void tsi_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - if (!((offset == UART_IER) && (value & UART_IER_UUE))) - writeb(value, p->membase + offset); -} + case UPIO_TSI: + if (offset == UART_IIR) { + tmp = readl(up->port.membase + (UART_IIR & ~3)); + return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ + } else + return readb(up->port.membase + offset); -static void dwapb_serial_out(struct uart_port *p, int offset, int value) -{ - int save_offset = offset; - offset = map_8250_out_reg(p, offset) << p->regshift; - /* Save the LCR value so it can be re-written when a - * Busy Detect interrupt occurs. */ - if (save_offset == UART_LCR) { - struct uart_8250_port *up = (struct uart_8250_port *)p; - up->lcr = value; + default: + return inb(up->port.iobase + offset); } - writeb(value, p->membase + offset); - /* Read the IER to ensure any interrupt is cleared before - * returning from ISR. */ - if (save_offset == UART_TX || save_offset == UART_IER) - value = p->serial_in(p, UART_IER); } -static unsigned int io_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return inb(p->iobase + offset); -} - -static void io_serial_out(struct uart_port *p, int offset, int value) +static void +serial_out(struct uart_8250_port *up, int offset, int value) { - offset = map_8250_out_reg(p, offset) << p->regshift; - outb(value, p->iobase + offset); -} + /* Save the offset before it's remapped */ + int save_offset = offset; + offset = map_8250_out_reg(up, offset) << up->port.regshift; -static void set_io_from_upio(struct uart_port *p) -{ - switch (p->iotype) { + switch (up->port.iotype) { case UPIO_HUB6: - p->serial_in = hub6_serial_in; - p->serial_out = hub6_serial_out; + outb(up->port.hub6 - 1 + offset, up->port.iobase); + outb(value, up->port.iobase + 1); break; case UPIO_MEM: - p->serial_in = mem_serial_in; - p->serial_out = mem_serial_out; + writeb(value, up->port.membase + offset); break; case UPIO_RM9000: case UPIO_MEM32: - p->serial_in = mem32_serial_in; - p->serial_out = mem32_serial_out; + writel(value, up->port.membase + offset); break; #ifdef CONFIG_SERIAL_8250_AU1X00 case UPIO_AU: - p->serial_in = au_serial_in; - p->serial_out = au_serial_out; + __raw_writel(value, up->port.membase + offset); break; #endif case UPIO_TSI: - p->serial_in = tsi_serial_in; - p->serial_out = tsi_serial_out; + if (!((offset == UART_IER) && (value & UART_IER_UUE))) + writeb(value, up->port.membase + offset); break; case UPIO_DWAPB: - p->serial_in = mem_serial_in; - p->serial_out = dwapb_serial_out; + /* Save the LCR value so it can be re-written when a + * Busy Detect interrupt occurs. */ + if (save_offset == UART_LCR) + up->lcr = value; + writeb(value, up->port.membase + offset); + /* Read the IER to ensure any interrupt is cleared before + * returning from ISR. */ + if (save_offset == UART_TX || save_offset == UART_IER) + value = serial_in(up, UART_IER); break; default: - p->serial_in = io_serial_in; - p->serial_out = io_serial_out; - break; + outb(value, up->port.iobase + offset); } } static void serial_out_sync(struct uart_8250_port *up, int offset, int value) { - struct uart_port *p = &up->port; - switch (p->iotype) { + switch (up->port.iotype) { case UPIO_MEM: case UPIO_MEM32: #ifdef CONFIG_SERIAL_8250_AU1X00 case UPIO_AU: #endif case UPIO_DWAPB: - p->serial_out(p, offset, value); - p->serial_in(p, UART_LCR); /* safe, no side-effects */ + serial_out(up, offset, value); + serial_in(up, UART_LCR); /* safe, no side-effects */ break; default: - p->serial_out(p, offset, value); + serial_out(up, offset, value); } } -#define serial_in(up, offset) \ - (up->port.serial_in(&(up)->port, (offset))) -#define serial_out(up, offset, value) \ - (up->port.serial_out(&(up)->port, (offset), (value))) /* * We used to support using pause I/O for certain machines. We * haven't supported this for a while, but just in case it's badly @@ -2645,7 +2576,6 @@ static void __init serial8250_isa_init_ports(void) up->port.membase = old_serial_port[i].iomem_base; up->port.iotype = old_serial_port[i].io_type; up->port.regshift = old_serial_port[i].iomem_reg_shift; - set_io_from_upio(&up->port); if (share_irqs) up->port.flags |= UPF_SHARE_IRQ; } @@ -2822,30 +2752,12 @@ static struct uart_driver serial8250_reg = { */ int __init early_serial_setup(struct uart_port *port) { - struct uart_port *p; - if (port->line >= ARRAY_SIZE(serial8250_ports)) return -ENODEV; serial8250_isa_init_ports(); - p = &serial8250_ports[port->line].port; - p->iobase = port->iobase; - p->membase = port->membase; - p->irq = port->irq; - p->uartclk = port->uartclk; - p->fifosize = port->fifosize; - p->regshift = port->regshift; - p->iotype = port->iotype; - p->flags = port->flags; - p->mapbase = port->mapbase; - p->private_data = port->private_data; - - set_io_from_upio(p); - if (port->serial_in) - p->serial_in = port->serial_in; - if (port->serial_out) - p->serial_out = port->serial_out; - + serial8250_ports[port->line].port = *port; + serial8250_ports[port->line].port.ops = &serial8250_pops; return 0; } @@ -2910,9 +2822,6 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.mapbase = p->mapbase; port.hub6 = p->hub6; port.private_data = p->private_data; - port.type = p->type; - port.serial_in = p->serial_in; - port.serial_out = p->serial_out; port.dev = &dev->dev; if (share_irqs) port.flags |= UPF_SHARE_IRQ; @@ -3067,20 +2976,6 @@ int serial8250_register_port(struct uart_port *port) if (port->dev) uart->port.dev = port->dev; - if (port->flags & UPF_FIXED_TYPE) { - uart->port.type = port->type; - uart->port.fifosize = uart_config[port->type].fifo_size; - uart->capabilities = uart_config[port->type].flags; - uart->tx_loadsz = uart_config[port->type].tx_loadsz; - } - - set_io_from_upio(&uart->port); - /* Possibly override default I/O functions. */ - if (port->serial_in) - uart->port.serial_in = port->serial_in; - if (port->serial_out) - uart->port.serial_out = port->serial_out; - ret = uart_add_one_port(&serial8250_reg, &uart->port); if (ret == 0) ret = uart->port.line; diff --git a/trunk/drivers/serial/8250_pci.c b/trunk/drivers/serial/8250_pci.c index c088146b7513..5450a0e5ecdb 100644 --- a/trunk/drivers/serial/8250_pci.c +++ b/trunk/drivers/serial/8250_pci.c @@ -42,8 +42,7 @@ struct pci_serial_quirk { u32 subvendor; u32 subdevice; int (*init)(struct pci_dev *dev); - int (*setup)(struct serial_private *, - const struct pciserial_board *, + int (*setup)(struct serial_private *, struct pciserial_board *, struct uart_port *, int); void (*exit)(struct pci_dev *dev); }; @@ -108,7 +107,7 @@ setup_port(struct serial_private *priv, struct uart_port *port, * ADDI-DATA GmbH communication cards */ static int addidata_apci7800_setup(struct serial_private *priv, - const struct pciserial_board *board, + struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; @@ -135,7 +134,7 @@ static int addidata_apci7800_setup(struct serial_private *priv, * Not that ugly ;) -- HW */ static int -afavlab_setup(struct serial_private *priv, const struct pciserial_board *board, +afavlab_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -189,9 +188,8 @@ static int pci_hp_diva_init(struct pci_dev *dev) * some serial ports are supposed to be hidden on certain models. */ static int -pci_hp_diva_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) +pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board, + struct uart_port *port, int idx) { unsigned int offset = board->first_offset; unsigned int bar = FL_GET_BASE(board->flags); @@ -308,7 +306,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev) /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */ static int -sbs_setup(struct serial_private *priv, const struct pciserial_board *board, +sbs_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -465,7 +463,7 @@ static int pci_siig_init(struct pci_dev *dev) } static int pci_siig_setup(struct serial_private *priv, - const struct pciserial_board *board, + struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0; @@ -536,8 +534,7 @@ static int pci_timedia_init(struct pci_dev *dev) * Ugh, this is ugly as all hell --- TYT */ static int -pci_timedia_setup(struct serial_private *priv, - const struct pciserial_board *board, +pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; @@ -571,7 +568,7 @@ pci_timedia_setup(struct serial_private *priv, */ static int titan_400l_800l_setup(struct serial_private *priv, - const struct pciserial_board *board, + struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -740,41 +737,8 @@ static void __devexit pci_ite887x_exit(struct pci_dev *dev) release_region(ioport, ITE_887x_IOSIZE); } -/* - * Oxford Semiconductor Inc. - * Check that device is part of the Tornado range of devices, then determine - * the number of ports available on the device. - */ -static int pci_oxsemi_tornado_init(struct pci_dev *dev) -{ - u8 __iomem *p; - unsigned long deviceID; - unsigned int number_uarts = 0; - - /* OxSemi Tornado devices are all 0xCxxx */ - if (dev->vendor == PCI_VENDOR_ID_OXSEMI && - (dev->device & 0xF000) != 0xC000) - return 0; - - p = pci_iomap(dev, 0, 5); - if (p == NULL) - return -ENOMEM; - - deviceID = ioread32(p); - /* Tornado device */ - if (deviceID == 0x07000200) { - number_uarts = ioread8(p + 4); - printk(KERN_DEBUG - "%d ports detected on Oxford PCI Express device\n", - number_uarts); - } - pci_iounmap(dev, p); - return number_uarts; -} - static int -pci_default_setup(struct serial_private *priv, - const struct pciserial_board *board, +pci_default_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset, maxnr; @@ -1053,25 +1017,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .init = pci_netmos_init, .setup = pci_default_setup, }, - /* - * For Oxford Semiconductor and Mainpine - */ - { - .vendor = PCI_VENDOR_ID_OXSEMI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_MAINPINE, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, - }, /* * Default "match everything" terminator entry */ @@ -1103,7 +1048,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) } static inline int get_pci_irq(struct pci_dev *dev, - const struct pciserial_board *board) + struct pciserial_board *board) { if (board->flags & FL_NOIRQ) return 0; @@ -1898,8 +1843,8 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) } static inline int -serial_pci_matches(const struct pciserial_board *board, - const struct pciserial_board *guessed) +serial_pci_matches(struct pciserial_board *board, + struct pciserial_board *guessed) { return board->num_ports == guessed->num_ports && @@ -1909,14 +1854,54 @@ serial_pci_matches(const struct pciserial_board *board, board->first_offset == guessed->first_offset; } +/* + * Oxford Semiconductor Inc. + * Check that device is part of the Tornado range of devices, then determine + * the number of ports available on the device. + */ +static int pci_oxsemi_tornado_init(struct pci_dev *dev, struct pciserial_board *board) +{ + u8 __iomem *p; + unsigned long deviceID; + unsigned int number_uarts; + + /* OxSemi Tornado devices are all 0xCxxx */ + if (dev->vendor == PCI_VENDOR_ID_OXSEMI && + (dev->device & 0xF000) != 0xC000) + return 0; + + p = pci_iomap(dev, 0, 5); + if (p == NULL) + return -ENOMEM; + + deviceID = ioread32(p); + /* Tornado device */ + if (deviceID == 0x07000200) { + number_uarts = ioread8(p + 4); + board->num_ports = number_uarts; + printk(KERN_DEBUG + "%d ports detected on Oxford PCI Express device\n", + number_uarts); + } + pci_iounmap(dev, p); + return 0; +} + struct serial_private * -pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) +pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) { struct uart_port serial_port; struct serial_private *priv; struct pci_serial_quirk *quirk; int rc, nr_ports, i; + /* + * Find number of ports on board + */ + if (dev->vendor == PCI_VENDOR_ID_OXSEMI || + dev->vendor == PCI_VENDOR_ID_MAINPINE) + pci_oxsemi_tornado_init(dev, board); + nr_ports = board->num_ports; /* @@ -2043,8 +2028,7 @@ static int __devinit pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { struct serial_private *priv; - const struct pciserial_board *board; - struct pciserial_board tmp; + struct pciserial_board *board, tmp; int rc; if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { @@ -2071,7 +2055,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) * We matched one of our class entries. Try to * determine the parameters of this board. */ - rc = serial_pci_guess_board(dev, &tmp); + rc = serial_pci_guess_board(dev, board); if (rc) goto disable; } else { @@ -2287,9 +2271,6 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_460800 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_115200 }, @@ -2390,9 +2371,6 @@ static struct pci_device_id serial_pci_tbl[] = { * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html). * For now just used the hex ID 0x950a. */ - { PCI_VENDOR_ID_OXSEMI, 0x950a, - PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0, - pbn_b0_2_115200 }, { PCI_VENDOR_ID_OXSEMI, 0x950a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_1130000 }, diff --git a/trunk/drivers/serial/bfin_5xx.c b/trunk/drivers/serial/bfin_5xx.c index 318d69dce8e1..569f0e2476c6 100644 --- a/trunk/drivers/serial/bfin_5xx.c +++ b/trunk/drivers/serial/bfin_5xx.c @@ -22,8 +22,7 @@ #include #include -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) +#ifdef CONFIG_KGDB_UART #include #include #endif @@ -46,16 +45,6 @@ static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - -# ifndef CONFIG_SERIAL_BFIN_PIO -# error KGDB only support UART in PIO mode. -# endif - -static int kgdboc_port_line; -static int kgdboc_break_enabled; -#endif /* * Setup for console. Argument comes from the menuconfig */ @@ -73,17 +62,13 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart); static void bfin_serial_mctrl_check(struct bfin_serial_port *uart); -static void bfin_serial_reset_irda(struct uart_port *port); - /* * interrupts are disabled on entry */ static void bfin_serial_stop_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -#ifdef CONFIG_SERIAL_BFIN_DMA struct circ_buf *xmit = &uart->port.info->xmit; -#endif while (!(UART_GET_LSR(uart) & TEMT)) cpu_relax(); @@ -109,14 +94,6 @@ static void bfin_serial_stop_tx(struct uart_port *port) static void bfin_serial_start_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - struct tty_struct *tty = uart->port.info->port.tty; - - /* - * To avoid losting RX interrupt, we reset IR function - * before sending data. - */ - if (tty->termios->c_line == N_IRDA) - bfin_serial_reset_irda(port); #ifdef CONFIG_SERIAL_BFIN_DMA if (uart->tx_done) @@ -133,7 +110,9 @@ static void bfin_serial_start_tx(struct uart_port *port) static void bfin_serial_stop_rx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - +#ifdef CONFIG_KGDB_UART + if (uart->port.line != CONFIG_KGDB_UART_PORT) +#endif UART_CLEAR_IER(uart, ERBFI); } @@ -144,6 +123,49 @@ static void bfin_serial_enable_ms(struct uart_port *port) { } +#ifdef CONFIG_KGDB_UART +static int kgdb_entry_state; + +void kgdb_put_debug_char(int chr) +{ + struct bfin_serial_port *uart; + + if (CONFIG_KGDB_UART_PORT < 0 + || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) + uart = &bfin_serial_ports[0]; + else + uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; + + while (!(UART_GET_LSR(uart) & THRE)) { + SSYNC(); + } + + UART_CLEAR_DLAB(uart); + UART_PUT_CHAR(uart, (unsigned char)chr); + SSYNC(); +} + +int kgdb_get_debug_char(void) +{ + struct bfin_serial_port *uart; + unsigned char chr; + + if (CONFIG_KGDB_UART_PORT < 0 + || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) + uart = &bfin_serial_ports[0]; + else + uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; + + while(!(UART_GET_LSR(uart) & DR)) { + SSYNC(); + } + UART_CLEAR_DLAB(uart); + chr = UART_GET_CHAR(uart); + SSYNC(); + + return chr; +} +#endif #if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO) # define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold) @@ -156,7 +178,7 @@ static void bfin_serial_enable_ms(struct uart_port *port) #ifdef CONFIG_SERIAL_BFIN_PIO static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = NULL; + struct tty_struct *tty = uart->port.info->port.tty; unsigned int status, ch, flg; static struct timeval anomaly_start = { .tv_sec = 0 }; @@ -166,18 +188,27 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) ch = UART_GET_CHAR(uart); uart->port.icount.rx++; -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - if (kgdb_connected && kgdboc_port_line == uart->port.line) - if (ch == 0x3) {/* Ctrl + C */ - kgdb_breakpoint(); +#ifdef CONFIG_KGDB_UART + if (uart->port.line == CONFIG_KGDB_UART_PORT) { + struct pt_regs *regs = get_irq_regs(); + if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */ + kgdb_breakkey_pressed(regs); + return; + } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */ + kgdb_entry_state = 1; + } else if (kgdb_entry_state == 1 && ch == 'q') { + kgdb_entry_state = 0; + kgdb_breakkey_pressed(regs); + return; + } else if (ch == 0x3) {/* Ctrl + C */ + kgdb_entry_state = 0; + kgdb_breakkey_pressed(regs); return; + } else { + kgdb_entry_state = 0; } - - if (!uart->port.info || !uart->port.info->tty) - return; + } #endif - tty = uart->port.info->tty; if (ANOMALY_05000363) { /* The BF533 (and BF561) family of processors have a nice anomaly @@ -219,7 +250,6 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) return; known_good_char: - status &= ~BI; anomaly_start.tv_sec = 0; } } @@ -415,9 +445,7 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { - int x_pos, pos, flags; - - spin_lock_irqsave(&uart->port.lock, flags); + int x_pos, pos; uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); @@ -435,8 +463,6 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock_irqrestore(&uart->port.lock, flags); - mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } @@ -471,9 +497,10 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); - bfin_serial_dma_rx_chars(uart); spin_unlock(&uart->port.lock); + mod_timer(&(uart->rx_dma_timer), jiffies); + return IRQ_HANDLED; } #endif @@ -603,16 +630,16 @@ static int bfin_serial_startup(struct uart_port *port) uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer)); #else -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled) - kgdboc_break_enabled = 0; - else { -# endif if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, "BFIN_UART_RX", uart)) { +# ifdef CONFIG_KGDB_UART + if (uart->port.line != CONFIG_KGDB_UART_PORT) { +# endif printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); return -EBUSY; +# ifdef CONFIG_KGDB_UART + } +# endif } if (request_irq @@ -658,10 +685,6 @@ static int bfin_serial_startup(struct uart_port *port) } } # endif -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - } -# endif #endif UART_SET_IER(uart, ERBFI); return 0; @@ -692,6 +715,9 @@ static void bfin_serial_shutdown(struct uart_port *port) default: break; }; +#endif +#ifdef CONFIG_KGDB_UART + if (uart->port.line != CONFIG_KGDB_UART_PORT) #endif free_irq(uart->port.irq, uart); free_irq(uart->port.irq+1, uart); @@ -861,65 +887,6 @@ static void bfin_serial_set_ldisc(struct uart_port *port) } } -#ifdef CONFIG_CONSOLE_POLL -static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - - while (!(UART_GET_LSR(uart) & THRE)) - cpu_relax(); - - UART_CLEAR_DLAB(uart); - UART_PUT_CHAR(uart, (unsigned char)chr); -} - -static int bfin_serial_poll_get_char(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned char chr; - - while (!(UART_GET_LSR(uart) & DR)) - cpu_relax(); - - UART_CLEAR_DLAB(uart); - chr = UART_GET_CHAR(uart); - - return chr; -} -#endif - -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) -static void bfin_kgdboc_port_shutdown(struct uart_port *port) -{ - if (kgdboc_break_enabled) { - kgdboc_break_enabled = 0; - bfin_serial_shutdown(port); - } -} - -static int bfin_kgdboc_port_startup(struct uart_port *port) -{ - kgdboc_port_line = port->line; - kgdboc_break_enabled = !bfin_serial_startup(port); - return 0; -} -#endif - -static void bfin_serial_reset_irda(struct uart_port *port) -{ - int line = port->line; - unsigned short val; - - val = UART_GET_GCTL(&bfin_serial_ports[line]); - val &= ~(IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); - SSYNC(); - val |= (IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); - SSYNC(); -} - static struct uart_ops bfin_serial_pops = { .tx_empty = bfin_serial_tx_empty, .set_mctrl = bfin_serial_set_mctrl, @@ -938,15 +905,6 @@ static struct uart_ops bfin_serial_pops = { .request_port = bfin_serial_request_port, .config_port = bfin_serial_config_port, .verify_port = bfin_serial_verify_port, -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - .kgdboc_port_startup = bfin_kgdboc_port_startup, - .kgdboc_port_shutdown = bfin_kgdboc_port_shutdown, -#endif -#ifdef CONFIG_CONSOLE_POLL - .poll_put_char = bfin_serial_poll_put_char, - .poll_get_char = bfin_serial_poll_get_char, -#endif }; static void __init bfin_serial_init_ports(void) @@ -992,7 +950,7 @@ static void __init bfin_serial_init_ports(void) } -#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +#ifdef CONFIG_SERIAL_BFIN_CONSOLE /* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. @@ -1036,20 +994,24 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, } pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); } +#endif +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) static struct uart_driver bfin_serial_reg; static int __init bfin_serial_console_setup(struct console *co, char *options) { struct bfin_serial_port *uart; +# ifdef CONFIG_SERIAL_BFIN_CONSOLE int baud = 57600; int bits = 8; int parity = 'n'; -# ifdef CONFIG_SERIAL_BFIN_CTSRTS +# ifdef CONFIG_SERIAL_BFIN_CTSRTS int flow = 'r'; -# else +# else int flow = 'n'; +# endif # endif /* @@ -1061,12 +1023,16 @@ bfin_serial_console_setup(struct console *co, char *options) co->index = 0; uart = &bfin_serial_ports[co->index]; +# ifdef CONFIG_SERIAL_BFIN_CONSOLE if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else bfin_serial_console_get_options(uart, &baud, &parity, &bits); return uart_set_options(&uart->port, co, baud, parity, bits, flow); +# else + return 0; +# endif } #endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || defined (CONFIG_EARLY_PRINTK) */ @@ -1110,7 +1076,10 @@ static int __init bfin_serial_rs_console_init(void) { bfin_serial_init_ports(); register_console(&bfin_serial_console); - +#ifdef CONFIG_KGDB_UART + kgdb_entry_state = 0; + init_kgdb_uart(); +#endif return 0; } console_initcall(bfin_serial_rs_console_init); @@ -1175,7 +1144,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, return &bfin_early_serial_console; } -#endif /* CONFIG_EARLY_PRINTK */ +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ static struct uart_driver bfin_serial_reg = { .owner = THIS_MODULE, @@ -1266,6 +1235,10 @@ static struct platform_driver bfin_serial_driver = { static int __init bfin_serial_init(void) { int ret; +#ifdef CONFIG_KGDB_UART + struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; + struct ktermios t; +#endif pr_info("Serial: Blackfin serial driver\n"); @@ -1279,6 +1252,21 @@ static int __init bfin_serial_init(void) uart_unregister_driver(&bfin_serial_reg); } } +#ifdef CONFIG_KGDB_UART + if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) { + request_irq(uart->port.irq, bfin_serial_rx_int, + IRQF_DISABLED, "BFIN_UART_RX", uart); + pr_info("Request irq for kgdb uart port\n"); + UART_SET_IER(uart, ERBFI); + SSYNC(); + t.c_cflag = CS8|B57600; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = CONFIG_KGDB_UART_PORT; + bfin_serial_set_termios(&uart->port, &t, &t); + } +#endif return ret; } @@ -1288,7 +1276,6 @@ static void __exit bfin_serial_exit(void) uart_unregister_driver(&bfin_serial_reg); } - module_init(bfin_serial_init); module_exit(bfin_serial_exit); diff --git a/trunk/drivers/serial/bfin_sport_uart.c b/trunk/drivers/serial/bfin_sport_uart.c index 529c0ff7952c..dd8564d25051 100644 --- a/trunk/drivers/serial/bfin_sport_uart.c +++ b/trunk/drivers/serial/bfin_sport_uart.c @@ -99,7 +99,7 @@ static void sport_stop_tx(struct uart_port *port); static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) { - pr_debug("%s value:%x\n", __func__, value); + pr_debug("%s value:%x\n", __FUNCTION__, value); /* Place a Start and Stop bit */ __asm__ volatile ( "R2 = b#01111111100;\n\t" @@ -110,7 +110,7 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) :"=r"(value) :"0"(value) :"R2", "R3"); - pr_debug("%s value:%x\n", __func__, value); + pr_debug("%s value:%x\n", __FUNCTION__, value); SPORT_PUT_TX(up, value); } @@ -120,7 +120,7 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up) unsigned int value, extract; value = SPORT_GET_RX32(up); - pr_debug("%s value:%x\n", __func__, value); + pr_debug("%s value:%x\n", __FUNCTION__, value); /* Extract 8 bits data */ __asm__ volatile ( @@ -151,12 +151,12 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) /* Set TCR1 and TCR2 */ SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); SPORT_PUT_TCR2(up, 10); - pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); + pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); /* Set RCR1 and RCR2 */ SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK)); SPORT_PUT_RCR2(up, 28); - pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); + pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); tclkdiv = sclk/(2 * baud_rate) - 1; tfsdiv = 12; @@ -166,7 +166,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) SPORT_PUT_RCLKDIV(up, rclkdiv); SSYNC(); pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n", - __func__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv); + __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv); return 0; } @@ -231,7 +231,7 @@ static int sport_startup(struct uart_port *port) char buffer[20]; int retval; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); memset(buffer, 20, '\0'); snprintf(buffer, 20, "%s rx", up->name); retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up); @@ -320,7 +320,7 @@ static unsigned int sport_tx_empty(struct uart_port *port) unsigned int stat; stat = SPORT_GET_STAT(up); - pr_debug("%s stat:%04x\n", __func__, stat); + pr_debug("%s stat:%04x\n", __FUNCTION__, stat); if (stat & TXHRE) { return TIOCSER_TEMT; } else @@ -329,13 +329,13 @@ static unsigned int sport_tx_empty(struct uart_port *port) static unsigned int sport_get_mctrl(struct uart_port *port) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR); } static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); } static void sport_stop_tx(struct uart_port *port) @@ -343,7 +343,7 @@ static void sport_stop_tx(struct uart_port *port) struct sport_uart_port *up = (struct sport_uart_port *)port; unsigned int stat; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); stat = SPORT_GET_STAT(up); while(!(stat & TXHRE)) { @@ -366,21 +366,21 @@ static void sport_start_tx(struct uart_port *port) { struct sport_uart_port *up = (struct sport_uart_port *)port; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); /* Write data into SPORT FIFO before enable SPROT to transmit */ sport_uart_tx_chars(up); /* Enable transmit, then an interrupt will generated */ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); SSYNC(); - pr_debug("%s exit\n", __func__); + pr_debug("%s exit\n", __FUNCTION__); } static void sport_stop_rx(struct uart_port *port) { struct sport_uart_port *up = (struct sport_uart_port *)port; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); /* Disable sport to stop rx */ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); SSYNC(); @@ -388,19 +388,19 @@ static void sport_stop_rx(struct uart_port *port) static void sport_enable_ms(struct uart_port *port) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); } static void sport_break_ctl(struct uart_port *port, int break_state) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); } static void sport_shutdown(struct uart_port *port) { struct sport_uart_port *up = (struct sport_uart_port *)port; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); /* Disable sport */ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); @@ -421,7 +421,7 @@ static void sport_shutdown(struct uart_port *port) static void sport_set_termios(struct uart_port *port, struct termios *termios, struct termios *old) { - pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); + pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag); uart_update_timeout(port, CS8 ,port->uartclk); } @@ -429,18 +429,18 @@ static const char *sport_type(struct uart_port *port) { struct sport_uart_port *up = (struct sport_uart_port *)port; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); return up->name; } static void sport_release_port(struct uart_port *port) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); } static int sport_request_port(struct uart_port *port) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); return 0; } @@ -448,13 +448,13 @@ static void sport_config_port(struct uart_port *port, int flags) { struct sport_uart_port *up = (struct sport_uart_port *)port; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); up->port.type = PORT_BFIN_SPORT; } static int sport_verify_port(struct uart_port *port, struct serial_struct *ser) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); return 0; } @@ -527,7 +527,7 @@ static int sport_uart_suspend(struct platform_device *dev, pm_message_t state) { struct sport_uart_port *sport = platform_get_drvdata(dev); - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); if (sport) uart_suspend_port(&sport_uart_reg, &sport->port); @@ -538,7 +538,7 @@ static int sport_uart_resume(struct platform_device *dev) { struct sport_uart_port *sport = platform_get_drvdata(dev); - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); if (sport) uart_resume_port(&sport_uart_reg, &sport->port); @@ -547,7 +547,7 @@ static int sport_uart_resume(struct platform_device *dev) static int sport_uart_probe(struct platform_device *dev) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); sport_uart_ports[dev->id].port.dev = &dev->dev; uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port); platform_set_drvdata(dev, &sport_uart_ports[dev->id]); @@ -559,7 +559,7 @@ static int sport_uart_remove(struct platform_device *dev) { struct sport_uart_port *sport = platform_get_drvdata(dev); - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); platform_set_drvdata(dev, NULL); if (sport) @@ -582,7 +582,7 @@ static int __init sport_uart_init(void) { int ret; - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); ret = uart_register_driver(&sport_uart_reg); if (ret != 0) { printk(KERN_ERR "Failed to register %s:%d\n", @@ -597,13 +597,13 @@ static int __init sport_uart_init(void) } - pr_debug("%s exit\n", __func__); + pr_debug("%s exit\n", __FUNCTION__); return ret; } static void __exit sport_uart_exit(void) { - pr_debug("%s enter\n", __func__); + pr_debug("%s enter\n", __FUNCTION__); platform_driver_unregister(&sport_uart_driver); uart_unregister_driver(&sport_uart_reg); } diff --git a/trunk/drivers/serial/jsm/jsm_tty.c b/trunk/drivers/serial/jsm/jsm_tty.c index 3547558d2caf..a697914ae3d0 100644 --- a/trunk/drivers/serial/jsm/jsm_tty.c +++ b/trunk/drivers/serial/jsm/jsm_tty.c @@ -272,7 +272,7 @@ static void jsm_tty_close(struct uart_port *port) jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; - ts = port->info->port.tty->termios; + ts = channel->uart_port.info->port.tty->termios; channel->ch_flags &= ~(CH_STOPI); diff --git a/trunk/drivers/serial/serial_core.c b/trunk/drivers/serial/serial_core.c index dc68b7e0c930..874786a11fe9 100644 --- a/trunk/drivers/serial/serial_core.c +++ b/trunk/drivers/serial/serial_core.c @@ -50,7 +50,7 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#define uart_users(state) ((state)->count + (state)->info.port.blocked_open) +#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->port.blocked_open : 0)) #ifdef CONFIG_SERIAL_CORE_CONSOLE #define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) @@ -94,7 +94,7 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; - if (!uart_circ_empty(&state->info.xmit) && state->info.xmit.buf && + if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf && !tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); } @@ -113,7 +113,7 @@ static void uart_start(struct tty_struct *tty) static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - tty_wakeup(state->info.port.tty); + tty_wakeup(state->info->port.tty); } static inline void @@ -139,7 +139,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) */ static int uart_startup(struct uart_state *state, int init_hw) { - struct uart_info *info = &state->info; + struct uart_info *info = state->info; struct uart_port *port = state->port; unsigned long page; int retval = 0; @@ -212,15 +212,14 @@ static int uart_startup(struct uart_state *state, int init_hw) */ static void uart_shutdown(struct uart_state *state) { - struct uart_info *info = &state->info; + struct uart_info *info = state->info; struct uart_port *port = state->port; - struct tty_struct *tty = info->port.tty; /* * Set the TTY IO error marker */ - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); if (info->flags & UIF_INITIALIZED) { info->flags &= ~UIF_INITIALIZED; @@ -228,7 +227,7 @@ static void uart_shutdown(struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (!tty || (tty->termios->c_cflag & HUPCL)) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* @@ -428,7 +427,7 @@ EXPORT_SYMBOL(uart_get_divisor); static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { - struct tty_struct *tty = state->info.port.tty; + struct tty_struct *tty = state->info->port.tty; struct uart_port *port = state->port; struct ktermios *termios; @@ -445,14 +444,14 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios) * Set flags based on termios cflag */ if (termios->c_cflag & CRTSCTS) - state->info.flags |= UIF_CTS_FLOW; + state->info->flags |= UIF_CTS_FLOW; else - state->info.flags &= ~UIF_CTS_FLOW; + state->info->flags &= ~UIF_CTS_FLOW; if (termios->c_cflag & CLOCAL) - state->info.flags &= ~UIF_CHECK_CD; + state->info->flags &= ~UIF_CHECK_CD; else - state->info.flags |= UIF_CHECK_CD; + state->info->flags |= UIF_CHECK_CD; port->ops->set_termios(port, termios, old_termios); } @@ -480,7 +479,7 @@ static int uart_put_char(struct tty_struct *tty, unsigned char ch) { struct uart_state *state = tty->driver_data; - return __uart_put_char(state->port, &state->info.xmit, ch); + return __uart_put_char(state->port, &state->info->xmit, ch); } static void uart_flush_chars(struct tty_struct *tty) @@ -501,13 +500,13 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count) * This means you called this function _after_ the port was * closed. No cookie for you. */ - if (!state) { + if (!state || !state->info) { WARN_ON(1); return -EL3HLT; } port = state->port; - circ = &state->info.xmit; + circ = &state->info->xmit; if (!circ->buf) return 0; @@ -538,7 +537,7 @@ static int uart_write_room(struct tty_struct *tty) int ret; spin_lock_irqsave(&state->port->lock, flags); - ret = uart_circ_chars_free(&state->info.xmit); + ret = uart_circ_chars_free(&state->info->xmit); spin_unlock_irqrestore(&state->port->lock, flags); return ret; } @@ -550,7 +549,7 @@ static int uart_chars_in_buffer(struct tty_struct *tty) int ret; spin_lock_irqsave(&state->port->lock, flags); - ret = uart_circ_chars_pending(&state->info.xmit); + ret = uart_circ_chars_pending(&state->info->xmit); spin_unlock_irqrestore(&state->port->lock, flags); return ret; } @@ -565,7 +564,7 @@ static void uart_flush_buffer(struct tty_struct *tty) * This means you called this function _after_ the port was * closed. No cookie for you. */ - if (!state) { + if (!state || !state->info) { WARN_ON(1); return; } @@ -574,7 +573,7 @@ static void uart_flush_buffer(struct tty_struct *tty) pr_debug("uart_flush_buffer(%d) called\n", tty->index); spin_lock_irqsave(&port->lock, flags); - uart_circ_clear(&state->info.xmit); + uart_circ_clear(&state->info->xmit); if (port->ops->flush_buffer) port->ops->flush_buffer(port); spin_unlock_irqrestore(&port->lock, flags); @@ -838,15 +837,15 @@ static int uart_set_info(struct uart_state *state, state->closing_wait = closing_wait; if (new_serial.xmit_fifo_size) port->fifosize = new_serial.xmit_fifo_size; - if (state->info.port.tty) - state->info.port.tty->low_latency = + if (state->info->port.tty) + state->info->port.tty->low_latency = (port->flags & UPF_LOW_LATENCY) ? 1 : 0; check_and_exit: retval = 0; if (port->type == PORT_UNKNOWN) goto exit; - if (state->info.flags & UIF_INITIALIZED) { + if (state->info->flags & UIF_INITIALIZED) { if (((old_flags ^ port->flags) & UPF_SPD_MASK) || old_custom_divisor != port->custom_divisor) { /* @@ -859,7 +858,7 @@ static int uart_set_info(struct uart_state *state, printk(KERN_NOTICE "%s sets custom speed on %s. This " "is deprecated.\n", current->comm, - tty_name(state->info.port.tty, buf)); + tty_name(state->info->port.tty, buf)); } uart_change_speed(state, NULL); } @@ -890,8 +889,8 @@ static int uart_get_lsr_info(struct uart_state *state, * interrupt happens). */ if (port->x_char || - ((uart_circ_chars_pending(&state->info.xmit) > 0) && - !state->info.port.tty->stopped && !state->info.port.tty->hw_stopped)) + ((uart_circ_chars_pending(&state->info->xmit) > 0) && + !state->info->port.tty->stopped && !state->info->port.tty->hw_stopped)) result &= ~TIOCSER_TEMT; return put_user(result, value); @@ -1018,7 +1017,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) port->ops->enable_ms(port); spin_unlock_irq(&port->lock); - add_wait_queue(&state->info.delta_msr_wait, &wait); + add_wait_queue(&state->info->delta_msr_wait, &wait); for (;;) { spin_lock_irq(&port->lock); memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); @@ -1046,7 +1045,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) } current->state = TASK_RUNNING; - remove_wait_queue(&state->info.delta_msr_wait, &wait); + remove_wait_queue(&state->info->delta_msr_wait, &wait); return ret; } @@ -1242,7 +1241,7 @@ static void uart_set_termios(struct tty_struct *tty, */ if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->port.open_wait); + wake_up_interruptible(&state->info->port.open_wait); #endif } @@ -1304,7 +1303,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts. */ - if (state->info.flags & UIF_INITIALIZED) { + if (state->info->flags & UIF_INITIALIZED) { unsigned long flags; spin_lock_irqsave(&port->lock, flags); port->ops->stop_rx(port); @@ -1323,9 +1322,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - state->info.port.tty = NULL; + state->info->port.tty = NULL; - if (state->info.port.blocked_open) { + if (state->info->port.blocked_open) { if (state->close_delay) msleep_interruptible(state->close_delay); } else if (!uart_console(port)) { @@ -1335,8 +1334,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) /* * Wake up anyone trying to open this port. */ - state->info.flags &= ~UIF_NORMAL_ACTIVE; - wake_up_interruptible(&state->info.port.open_wait); + state->info->flags &= ~UIF_NORMAL_ACTIVE; + wake_up_interruptible(&state->info->port.open_wait); done: mutex_unlock(&state->mutex); @@ -1410,20 +1409,19 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) static void uart_hangup(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_info *info = &state->info; BUG_ON(!kernel_locked()); pr_debug("uart_hangup(%d)\n", state->port->line); mutex_lock(&state->mutex); - if (info->flags & UIF_NORMAL_ACTIVE) { + if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) { uart_flush_buffer(tty); uart_shutdown(state); state->count = 0; - info->flags &= ~UIF_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->port.open_wait); - wake_up_interruptible(&info->delta_msr_wait); + state->info->flags &= ~UIF_NORMAL_ACTIVE; + state->info->port.tty = NULL; + wake_up_interruptible(&state->info->port.open_wait); + wake_up_interruptible(&state->info->delta_msr_wait); } mutex_unlock(&state->mutex); } @@ -1436,7 +1434,7 @@ static void uart_hangup(struct tty_struct *tty) */ static void uart_update_termios(struct uart_state *state) { - struct tty_struct *tty = state->info.port.tty; + struct tty_struct *tty = state->info->port.tty; struct uart_port *port = state->port; if (uart_console(port) && port->cons->cflag) { @@ -1471,7 +1469,7 @@ static int uart_block_til_ready(struct file *filp, struct uart_state *state) { DECLARE_WAITQUEUE(wait, current); - struct uart_info *info = &state->info; + struct uart_info *info = state->info; struct uart_port *port = state->port; unsigned int mctrl; @@ -1565,6 +1563,28 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) ret = -ENXIO; goto err_unlock; } + + /* BKL: RACE HERE - LEAK */ + /* We should move this into the uart_state structure and kill off + this whole complexity */ + if (!state->info) { + state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL); + if (state->info) { + init_waitqueue_head(&state->info->port.open_wait); + init_waitqueue_head(&state->info->delta_msr_wait); + + /* + * Link the info into the other structures. + */ + state->port->info = state->info; + + tasklet_init(&state->info->tlet, uart_tasklet_action, + (unsigned long)state); + } else { + ret = -ENOMEM; + goto err_unlock; + } + } return state; err_unlock: @@ -1621,10 +1641,9 @@ static int uart_open(struct tty_struct *tty, struct file *filp) * Any failures from here onwards should not touch the count. */ tty->driver_data = state; - state->port->info = &state->info; tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty->alt_speed = 0; - state->info.port.tty = tty; + state->info->port.tty = tty; /* * If the port is in the middle of closing, bail out now. @@ -1657,8 +1676,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp) /* * If this is the first open to succeed, adjust things to suit. */ - if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) { - state->info.flags |= UIF_NORMAL_ACTIVE; + if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) { + state->info->flags |= UIF_NORMAL_ACTIVE; uart_update_termios(state); } @@ -2009,11 +2028,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) } port->suspended = 1; - if (state->info.flags & UIF_INITIALIZED) { + if (state->info && state->info->flags & UIF_INITIALIZED) { const struct uart_ops *ops = port->ops; int tries; - state->info.flags = (state->info.flags & ~UIF_INITIALIZED) + state->info->flags = (state->info->flags & ~UIF_INITIALIZED) | UIF_SUSPENDED; spin_lock_irq(&port->lock); @@ -2088,15 +2107,15 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) /* * If that's unset, use the tty termios setting. */ - if (state->info.port.tty && termios.c_cflag == 0) - termios = *state->info.port.tty->termios; + if (state->info && state->info->port.tty && termios.c_cflag == 0) + termios = *state->info->port.tty->termios; uart_change_pm(state, 0); port->ops->set_termios(port, &termios, NULL); console_start(port->cons); } - if (state->info.flags & UIF_SUSPENDED) { + if (state->info && state->info->flags & UIF_SUSPENDED) { const struct uart_ops *ops = port->ops; int ret; @@ -2111,7 +2130,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) ops->set_mctrl(port, port->mctrl); ops->start_tx(port); spin_unlock_irq(&port->lock); - state->info.flags |= UIF_INITIALIZED; + state->info->flags |= UIF_INITIALIZED; } else { /* * Failed to resume - maybe hardware went away? @@ -2121,7 +2140,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) uart_shutdown(state); } - state->info.flags &= ~UIF_SUSPENDED; + state->info->flags &= ~UIF_SUSPENDED; } mutex_unlock(&state->mutex); @@ -2179,14 +2198,11 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, * Now do the auto configuration stuff. Note that config_port * is expected to claim the resources and map the port for us. */ - flags = 0; + flags = UART_CONFIG_TYPE; if (port->flags & UPF_AUTO_IRQ) flags |= UART_CONFIG_IRQ; if (port->flags & UPF_BOOT_AUTOCONF) { - if (!(port->flags & UPF_FIXED_TYPE)) { - port->type = PORT_UNKNOWN; - flags |= UART_CONFIG_TYPE; - } + port->type = PORT_UNKNOWN; port->ops->config_port(port, flags); } @@ -2367,12 +2383,8 @@ int uart_register_driver(struct uart_driver *drv) state->close_delay = 500; /* .5 seconds */ state->closing_wait = 30000; /* 30 seconds */ - mutex_init(&state->mutex); - tty_port_init(&state->info.port); - init_waitqueue_head(&state->info.delta_msr_wait); - tasklet_init(&state->info.tlet, uart_tasklet_action, - (unsigned long)state); + mutex_init(&state->mutex); } retval = tty_register_driver(normal); @@ -2443,7 +2455,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) state->pm_state = -1; port->cons = drv->cons; - port->info = &state->info; + port->info = state->info; /* * If this port is a console, then the spinlock is already @@ -2515,10 +2527,17 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) */ tty_unregister_device(drv->tty_driver, port->line); - info = &state->info; + info = state->info; if (info && info->port.tty) tty_vhangup(info->port.tty); + /* + * All users of this port should now be disconnected from + * this driver, and the port shut down. We should be the + * only thread fiddling with this port from now on. + */ + state->info = NULL; + /* * Free the port IO and memory resources, if any. */ @@ -2533,8 +2552,10 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) /* * Kill the tasklet, and free resources. */ - if (info) + if (info) { tasklet_kill(&info->tlet); + kfree(info); + } state->port = NULL; mutex_unlock(&port_mutex); diff --git a/trunk/drivers/usb/host/hwa-hc.c b/trunk/drivers/usb/host/hwa-hc.c index 8582236e4cad..64be4d88df11 100644 --- a/trunk/drivers/usb/host/hwa-hc.c +++ b/trunk/drivers/usb/host/hwa-hc.c @@ -54,6 +54,7 @@ * DWA). */ #include +#include #include #include #include @@ -62,12 +63,16 @@ #include "../wusbcore/wa-hc.h" #include "../wusbcore/wusbhc.h" +#define D_LOCAL 0 +#include + struct hwahc { struct wusbhc wusbhc; /* has to be 1st */ struct wahc wa; + u8 buffer[16]; /* for misc usb transactions */ }; -/* +/** * FIXME should be wusbhc * * NOTE: we need to cache the Cluster ID because later...there is no @@ -121,6 +126,7 @@ static int hwahc_op_reset(struct usb_hcd *usb_hcd) struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); struct device *dev = &hwahc->wa.usb_iface->dev; + d_fnstart(4, dev, "(hwahc %p)\n", hwahc); mutex_lock(&wusbhc->mutex); wa_nep_disarm(&hwahc->wa); result = __wa_set_feature(&hwahc->wa, WA_RESET); @@ -128,6 +134,7 @@ static int hwahc_op_reset(struct usb_hcd *usb_hcd) dev_err(dev, "error commanding HC to reset: %d\n", result); goto error_unlock; } + d_printf(3, dev, "reset: waiting for device to change state\n"); result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0); if (result < 0) { dev_err(dev, "error waiting for HC to reset: %d\n", result); @@ -135,6 +142,7 @@ static int hwahc_op_reset(struct usb_hcd *usb_hcd) } error_unlock: mutex_unlock(&wusbhc->mutex); + d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); return result; } @@ -147,9 +155,15 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) int result; struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); + struct device *dev = &hwahc->wa.usb_iface->dev; + /* Set up a Host Info WUSB Information Element */ + d_fnstart(4, dev, "(hwahc %p)\n", hwahc); result = -ENOSPC; mutex_lock(&wusbhc->mutex); + /* Start the numbering from the top so that the bottom + * range of the unauth addr space is used for devices, + * the top for HCs; use 0xfe - RC# */ addr = wusb_cluster_id_get(); if (addr == 0) goto error_cluster_id_get; @@ -157,14 +171,22 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) if (result < 0) goto error_set_cluster_id; + result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); + if (result < 0) { + dev_err(dev, "cannot listen to notifications: %d\n", result); + goto error_stop; + } usb_hcd->uses_new_polling = 1; usb_hcd->poll_rh = 1; usb_hcd->state = HC_STATE_RUNNING; result = 0; out: mutex_unlock(&wusbhc->mutex); + d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); return result; +error_stop: + __wa_stop(&hwahc->wa); error_set_cluster_id: wusb_cluster_id_put(wusbhc->cluster_id); error_cluster_id_get: @@ -172,6 +194,39 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) } +/* + * FIXME: break this function up + */ +static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) +{ + int result; + struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); + struct device *dev = &hwahc->wa.usb_iface->dev; + + /* Set up a Host Info WUSB Information Element */ + d_fnstart(4, dev, "(hwahc %p)\n", hwahc); + result = -ENOSPC; + + result = __wa_set_feature(&hwahc->wa, WA_ENABLE); + if (result < 0) { + dev_err(dev, "error commanding HC to start: %d\n", result); + goto error_stop; + } + result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); + if (result < 0) { + dev_err(dev, "error waiting for HC to start: %d\n", result); + goto error_stop; + } + result = 0; +out: + d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); + return result; + +error_stop: + result = __wa_clear_feature(&hwahc->wa, WA_ENABLE); + goto out; +} + static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) { struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); @@ -191,6 +246,18 @@ static int hwahc_op_resume(struct usb_hcd *usb_hcd) return -ENOSYS; } +static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc) +{ + int result; + struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); + struct device *dev = &hwahc->wa.usb_iface->dev; + + d_fnstart(4, dev, "(hwahc %p)\n", hwahc); + /* Nothing for now */ + d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); + return; +} + /* * No need to abort pipes, as when this is called, all the children * has been disconnected and that has done it [through @@ -199,11 +266,21 @@ static int hwahc_op_resume(struct usb_hcd *usb_hcd) */ static void hwahc_op_stop(struct usb_hcd *usb_hcd) { + int result; struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); + struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); + struct wahc *wa = &hwahc->wa; + struct device *dev = &wa->usb_iface->dev; + d_fnstart(4, dev, "(hwahc %p)\n", hwahc); mutex_lock(&wusbhc->mutex); + wusbhc_stop(wusbhc); + wa_nep_disarm(&hwahc->wa); + result = __wa_stop(&hwahc->wa); wusb_cluster_id_put(wusbhc->cluster_id); mutex_unlock(&wusbhc->mutex); + d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); + return; } static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd) @@ -248,54 +325,6 @@ static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd, rpipe_ep_disable(&hwahc->wa, ep); } -static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) -{ - int result; - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct device *dev = &hwahc->wa.usb_iface->dev; - - result = __wa_set_feature(&hwahc->wa, WA_ENABLE); - if (result < 0) { - dev_err(dev, "error commanding HC to start: %d\n", result); - goto error_stop; - } - result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); - if (result < 0) { - dev_err(dev, "error waiting for HC to start: %d\n", result); - goto error_stop; - } - result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "cannot listen to notifications: %d\n", result); - goto error_stop; - } - return result; - -error_stop: - __wa_clear_feature(&hwahc->wa, WA_ENABLE); - return result; -} - -static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay) -{ - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - int ret; - - ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_CHAN_STOP, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - delay * 1000, - iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); - if (ret == 0) - msleep(delay); - - wa_nep_disarm(&hwahc->wa); - __wa_stop(&hwahc->wa); -} - /* * Set the UWB MAS allocation for the WUSB cluster * @@ -552,11 +581,11 @@ static int wa_fill_descr(struct wahc *wa) itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); while (itr_size >= sizeof(*hdr)) { hdr = (struct usb_descriptor_header *) itr; - dev_dbg(dev, "Extra device descriptor: " - "type %02x/%u bytes @ %zu (%zu left)\n", - hdr->bDescriptorType, hdr->bLength, - (itr - usb_dev->rawdescriptors[actconfig_idx]), - itr_size); + d_printf(3, dev, "Extra device descriptor: " + "type %02x/%u bytes @ %zu (%zu left)\n", + hdr->bDescriptorType, hdr->bLength, + (itr - usb_dev->rawdescriptors[actconfig_idx]), + itr_size); if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER) goto found; itr += hdr->bLength; @@ -765,6 +794,7 @@ static void hwahc_destroy(struct hwahc *hwahc) { struct wusbhc *wusbhc = &hwahc->wusbhc; + d_fnstart(1, NULL, "(hwahc %p)\n", hwahc); mutex_lock(&wusbhc->mutex); __wa_destroy(&hwahc->wa); wusbhc_destroy(&hwahc->wusbhc); @@ -774,6 +804,7 @@ static void hwahc_destroy(struct hwahc *hwahc) usb_put_intf(hwahc->wa.usb_iface); usb_put_dev(hwahc->wa.usb_dev); mutex_unlock(&wusbhc->mutex); + d_fnend(1, NULL, "(hwahc %p) = void\n", hwahc); } static void hwahc_init(struct hwahc *hwahc) @@ -790,6 +821,7 @@ static int hwahc_probe(struct usb_interface *usb_iface, struct hwahc *hwahc; struct device *dev = &usb_iface->dev; + d_fnstart(4, dev, "(%p, %p)\n", usb_iface, id); result = -ENOMEM; usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa"); if (usb_hcd == NULL) { @@ -816,6 +848,7 @@ static int hwahc_probe(struct usb_interface *usb_iface, dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result); goto error_wusbhc_b_create; } + d_fnend(4, dev, "(%p, %p) = 0\n", usb_iface, id); return 0; error_wusbhc_b_create: @@ -825,6 +858,7 @@ static int hwahc_probe(struct usb_interface *usb_iface, error_hwahc_create: usb_put_hcd(usb_hcd); error_alloc: + d_fnend(4, dev, "(%p, %p) = %d\n", usb_iface, id, result); return result; } @@ -838,12 +872,16 @@ static void hwahc_disconnect(struct usb_interface *usb_iface) wusbhc = usb_hcd_to_wusbhc(usb_hcd); hwahc = container_of(wusbhc, struct hwahc, wusbhc); + d_fnstart(1, NULL, "(hwahc %p [usb_iface %p])\n", hwahc, usb_iface); wusbhc_b_destroy(&hwahc->wusbhc); usb_remove_hcd(usb_hcd); hwahc_destroy(hwahc); usb_put_hcd(usb_hcd); + d_fnend(1, NULL, "(hwahc %p [usb_iface %p]) = void\n", hwahc, + usb_iface); } +/** USB device ID's that we handle */ static struct usb_device_id hwahc_id_table[] = { /* FIXME: use class labels for this */ { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, @@ -860,7 +898,18 @@ static struct usb_driver hwahc_driver = { static int __init hwahc_driver_init(void) { - return usb_register(&hwahc_driver); + int result; + result = usb_register(&hwahc_driver); + if (result < 0) { + printk(KERN_ERR "WA-CDS: Cannot register USB driver: %d\n", + result); + goto error_usb_register; + } + return 0; + +error_usb_register: + return result; + } module_init(hwahc_driver_init); diff --git a/trunk/drivers/usb/host/whci/Kbuild b/trunk/drivers/usb/host/whci/Kbuild index 11e5040b8337..26a3871ea0f9 100644 --- a/trunk/drivers/usb/host/whci/Kbuild +++ b/trunk/drivers/usb/host/whci/Kbuild @@ -2,7 +2,6 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o whci-hcd-y := \ asl.o \ - debug.o \ hcd.o \ hw.o \ init.o \ diff --git a/trunk/drivers/usb/host/whci/asl.c b/trunk/drivers/usb/host/whci/asl.c index 577c0d29849d..4d7078e50572 100644 --- a/trunk/drivers/usb/host/whci/asl.c +++ b/trunk/drivers/usb/host/whci/asl.c @@ -19,11 +19,32 @@ #include #include #include +#define D_LOCAL 0 +#include #include "../../wusbcore/wusbhc.h" #include "whcd.h" +#if D_LOCAL >= 4 +static void dump_asl(struct whc *whc, const char *tag) +{ + struct device *dev = &whc->umc->dev; + struct whc_qset *qset; + + d_printf(4, dev, "ASL %s\n", tag); + + list_for_each_entry(qset, &whc->async_list, list_node) { + dump_qset(qset, dev); + } +} +#else +static inline void dump_asl(struct whc *whc, const char *tag) +{ +} +#endif + + static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, struct whc_qset **next, struct whc_qset **prev) { @@ -158,26 +179,11 @@ void asl_stop(struct whc *whc) 1000, "stop ASL"); } -/** - * asl_update - request an ASL update and wait for the hardware to be synced - * @whc: the WHCI HC - * @wusbcmd: WUSBCMD value to start the update. - * - * If the WUSB HC is inactive (i.e., the ASL is stopped) then the - * update must be skipped as the hardware may not respond to update - * requests. - */ void asl_update(struct whc *whc, uint32_t wusbcmd) { - struct wusbhc *wusbhc = &whc->wusbhc; - - mutex_lock(&wusbhc->mutex); - if (wusbhc->active) { - whc_write_wusbcmd(whc, wusbcmd, wusbcmd); - wait_event(whc->async_list_wq, - (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); - } - mutex_unlock(&wusbhc->mutex); + whc_write_wusbcmd(whc, wusbcmd, wusbcmd); + wait_event(whc->async_list_wq, + (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); } /** @@ -196,6 +202,8 @@ void scan_async_work(struct work_struct *work) spin_lock_irq(&whc->lock); + dump_asl(whc, "before processing"); + /* * Transerve the software list backwards so new qsets can be * safely inserted into the ASL without making it non-circular. @@ -209,6 +217,8 @@ void scan_async_work(struct work_struct *work) update |= process_qset(whc, qset); } + dump_asl(whc, "after processing"); + spin_unlock_irq(&whc->lock); if (update) { diff --git a/trunk/drivers/usb/host/whci/debug.c b/trunk/drivers/usb/host/whci/debug.c deleted file mode 100644 index cf2d45946c57..000000000000 --- a/trunk/drivers/usb/host/whci/debug.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Wireless Host Controller (WHC) debug. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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, see . - */ -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -struct whc_dbg { - struct dentry *di_f; - struct dentry *asl_f; - struct dentry *pzl_f; -}; - -void qset_print(struct seq_file *s, struct whc_qset *qset) -{ - struct whc_std *std; - struct urb *urb = NULL; - int i; - - seq_printf(s, "qset %08x\n", (u32)qset->qset_dma); - seq_printf(s, " -> %08x\n", (u32)qset->qh.link); - seq_printf(s, " info: %08x %08x %08x\n", - qset->qh.info1, qset->qh.info2, qset->qh.info3); - seq_printf(s, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count); - seq_printf(s, " TD: sts: %08x opts: %08x\n", - qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); - - for (i = 0; i < WHCI_QSET_TD_MAX; i++) { - seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", - i == qset->td_start ? 'S' : ' ', - i == qset->td_end ? 'E' : ' ', - i, qset->qtd[i].status, qset->qtd[i].options, - (u32)qset->qtd[i].page_list_ptr); - } - seq_printf(s, " ntds: %d\n", qset->ntds); - list_for_each_entry(std, &qset->stds, list_node) { - if (urb != std->urb) { - urb = std->urb; - seq_printf(s, " urb %p transferred: %d bytes\n", urb, - urb->actual_length); - } - if (std->qtd) - seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n", - std->qtd - &qset->qtd[0], - std->len, std->num_pointers ? - (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); - else - seq_printf(s, " sTD[-]: %zd bytes @ %08x\n", - std->len, std->num_pointers ? - (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); - } -} - -static int di_print(struct seq_file *s, void *p) -{ - struct whc *whc = s->private; - char buf[72]; - int d; - - for (d = 0; d < whc->n_devices; d++) { - struct di_buf_entry *di = &whc->di_buf[d]; - - bitmap_scnprintf(buf, sizeof(buf), - (unsigned long *)di->availability_info, UWB_NUM_MAS); - - seq_printf(s, "DI[%d]\n", d); - seq_printf(s, " availability: %s\n", buf); - seq_printf(s, " %c%c key idx: %d dev addr: %d\n", - (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', - (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', - (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, - (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); - } - return 0; -} - -static int asl_print(struct seq_file *s, void *p) -{ - struct whc *whc = s->private; - struct whc_qset *qset; - - list_for_each_entry(qset, &whc->async_list, list_node) { - qset_print(s, qset); - } - - return 0; -} - -static int pzl_print(struct seq_file *s, void *p) -{ - struct whc *whc = s->private; - struct whc_qset *qset; - int period; - - for (period = 0; period < 5; period++) { - seq_printf(s, "Period %d\n", period); - list_for_each_entry(qset, &whc->periodic_list[period], list_node) { - qset_print(s, qset); - } - } - return 0; -} - -static int di_open(struct inode *inode, struct file *file) -{ - return single_open(file, di_print, inode->i_private); -} - -static int asl_open(struct inode *inode, struct file *file) -{ - return single_open(file, asl_print, inode->i_private); -} - -static int pzl_open(struct inode *inode, struct file *file) -{ - return single_open(file, pzl_print, inode->i_private); -} - -static struct file_operations di_fops = { - .open = di_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static struct file_operations asl_fops = { - .open = asl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static struct file_operations pzl_fops = { - .open = pzl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -void whc_dbg_init(struct whc *whc) -{ - if (whc->wusbhc.pal.debugfs_dir == NULL) - return; - - whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL); - if (whc->dbg == NULL) - return; - - whc->dbg->di_f = debugfs_create_file("di", 0444, - whc->wusbhc.pal.debugfs_dir, whc, - &di_fops); - whc->dbg->asl_f = debugfs_create_file("asl", 0444, - whc->wusbhc.pal.debugfs_dir, whc, - &asl_fops); - whc->dbg->pzl_f = debugfs_create_file("pzl", 0444, - whc->wusbhc.pal.debugfs_dir, whc, - &pzl_fops); -} - -void whc_dbg_clean_up(struct whc *whc) -{ - if (whc->dbg) { - debugfs_remove(whc->dbg->pzl_f); - debugfs_remove(whc->dbg->asl_f); - debugfs_remove(whc->dbg->di_f); - kfree(whc->dbg); - } -} diff --git a/trunk/drivers/usb/host/whci/hcd.c b/trunk/drivers/usb/host/whci/hcd.c index 1569afd6245b..ef3ad4dca945 100644 --- a/trunk/drivers/usb/host/whci/hcd.c +++ b/trunk/drivers/usb/host/whci/hcd.c @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include #include @@ -91,6 +92,8 @@ static void whc_stop(struct usb_hcd *usb_hcd) mutex_lock(&wusbhc->mutex); + wusbhc_stop(wusbhc); + /* stop HC */ le_writel(0, whc->base + WUSBINTR); whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); @@ -273,8 +276,6 @@ static int whc_probe(struct umc_dev *umc) goto error_wusbhc_b_create; } - whc_dbg_init(whc); - return 0; error_wusbhc_b_create: @@ -298,7 +299,6 @@ static void whc_remove(struct umc_dev *umc) struct whc *whc = wusbhc_to_whc(wusbhc); if (usb_hcd) { - whc_dbg_clean_up(whc); wusbhc_b_destroy(wusbhc); usb_remove_hcd(usb_hcd); wusbhc_destroy(wusbhc); diff --git a/trunk/drivers/usb/host/whci/hw.c b/trunk/drivers/usb/host/whci/hw.c index d498e7203217..ac86e59c1225 100644 --- a/trunk/drivers/usb/host/whci/hw.c +++ b/trunk/drivers/usb/host/whci/hw.c @@ -50,7 +50,6 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) unsigned long flags; dma_addr_t dma_addr; int t; - int ret = 0; mutex_lock(&whc->mutex); @@ -62,8 +61,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", le_readl(whc->base + WUSBGENCMDSTS), le_readl(whc->base + WUSBGENCMDPARAMS)); - ret = -ETIMEDOUT; - goto out; + return -ETIMEDOUT; } if (addr) { @@ -82,8 +80,8 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) whc->base + WUSBGENCMDSTS); spin_unlock_irqrestore(&whc->lock, flags); -out: + mutex_unlock(&whc->mutex); - return ret; + return 0; } diff --git a/trunk/drivers/usb/host/whci/int.c b/trunk/drivers/usb/host/whci/int.c index 6aae70028101..fce01174aa9b 100644 --- a/trunk/drivers/usb/host/whci/int.c +++ b/trunk/drivers/usb/host/whci/int.c @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include #include diff --git a/trunk/drivers/usb/host/whci/pzl.c b/trunk/drivers/usb/host/whci/pzl.c index 2ae5abf69a6a..8d62df0c330b 100644 --- a/trunk/drivers/usb/host/whci/pzl.c +++ b/trunk/drivers/usb/host/whci/pzl.c @@ -19,11 +19,35 @@ #include #include #include +#define D_LOCAL 0 +#include #include "../../wusbcore/wusbhc.h" #include "whcd.h" +#if D_LOCAL >= 4 +static void dump_pzl(struct whc *whc, const char *tag) +{ + struct device *dev = &whc->umc->dev; + struct whc_qset *qset; + int period = 0; + + d_printf(4, dev, "PZL %s\n", tag); + + for (period = 0; period < 5; period++) { + d_printf(4, dev, "Period %d\n", period); + list_for_each_entry(qset, &whc->periodic_list[period], list_node) { + dump_qset(qset, dev); + } + } +} +#else +static inline void dump_pzl(struct whc *whc, const char *tag) +{ +} +#endif + static void update_pzl_pointers(struct whc *whc, int period, u64 addr) { switch (period) { @@ -171,26 +195,11 @@ void pzl_stop(struct whc *whc) 1000, "stop PZL"); } -/** - * pzl_update - request a PZL update and wait for the hardware to be synced - * @whc: the WHCI HC - * @wusbcmd: WUSBCMD value to start the update. - * - * If the WUSB HC is inactive (i.e., the PZL is stopped) then the - * update must be skipped as the hardware may not respond to update - * requests. - */ void pzl_update(struct whc *whc, uint32_t wusbcmd) { - struct wusbhc *wusbhc = &whc->wusbhc; - - mutex_lock(&wusbhc->mutex); - if (wusbhc->active) { - whc_write_wusbcmd(whc, wusbcmd, wusbcmd); - wait_event(whc->periodic_list_wq, - (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); - } - mutex_unlock(&wusbhc->mutex); + whc_write_wusbcmd(whc, wusbcmd, wusbcmd); + wait_event(whc->periodic_list_wq, + (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); } static void update_pzl_hw_view(struct whc *whc) @@ -226,6 +235,8 @@ void scan_periodic_work(struct work_struct *work) spin_lock_irq(&whc->lock); + dump_pzl(whc, "before processing"); + for (period = 4; period >= 0; period--) { list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { if (!qset->in_hw_list) @@ -237,6 +248,8 @@ void scan_periodic_work(struct work_struct *work) if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) update_pzl_hw_view(whc); + dump_pzl(whc, "after processing"); + spin_unlock_irq(&whc->lock); if (update) { diff --git a/trunk/drivers/usb/host/whci/qset.c b/trunk/drivers/usb/host/whci/qset.c index 7be74314ee12..0420037d2e18 100644 --- a/trunk/drivers/usb/host/whci/qset.c +++ b/trunk/drivers/usb/host/whci/qset.c @@ -24,6 +24,46 @@ #include "whcd.h" +void dump_qset(struct whc_qset *qset, struct device *dev) +{ + struct whc_std *std; + struct urb *urb = NULL; + int i; + + dev_dbg(dev, "qset %08x\n", (u32)qset->qset_dma); + dev_dbg(dev, " -> %08x\n", (u32)qset->qh.link); + dev_dbg(dev, " info: %08x %08x %08x\n", + qset->qh.info1, qset->qh.info2, qset->qh.info3); + dev_dbg(dev, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count); + dev_dbg(dev, " TD: sts: %08x opts: %08x\n", + qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); + + for (i = 0; i < WHCI_QSET_TD_MAX; i++) { + dev_dbg(dev, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", + i == qset->td_start ? 'S' : ' ', + i == qset->td_end ? 'E' : ' ', + i, qset->qtd[i].status, qset->qtd[i].options, + (u32)qset->qtd[i].page_list_ptr); + } + dev_dbg(dev, " ntds: %d\n", qset->ntds); + list_for_each_entry(std, &qset->stds, list_node) { + if (urb != std->urb) { + urb = std->urb; + dev_dbg(dev, " urb %p transferred: %d bytes\n", urb, + urb->actual_length); + } + if (std->qtd) + dev_dbg(dev, " sTD[%td]: %zu bytes @ %08x\n", + std->qtd - &qset->qtd[0], + std->len, std->num_pointers ? + (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); + else + dev_dbg(dev, " sTD[-]: %zd bytes @ %08x\n", + std->len, std->num_pointers ? + (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); + } +} + struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) { struct whc_qset *qset; diff --git a/trunk/drivers/usb/host/whci/whcd.h b/trunk/drivers/usb/host/whci/whcd.h index 0f3540f04f53..1d2a53bd39fd 100644 --- a/trunk/drivers/usb/host/whci/whcd.h +++ b/trunk/drivers/usb/host/whci/whcd.h @@ -21,7 +21,6 @@ #define __WHCD_H #include -#include #include #include "whci-hc.h" @@ -29,7 +28,6 @@ /* Generic command timeout. */ #define WHC_GENCMD_TIMEOUT_MS 100 -struct whc_dbg; struct whc { struct wusbhc wusbhc; @@ -71,8 +69,6 @@ struct whc { struct list_head periodic_removed_list; wait_queue_head_t periodic_list_wq; struct work_struct periodic_work; - - struct whc_dbg *dbg; }; #define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) @@ -140,7 +136,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); /* wusb.c */ int whc_wusbhc_start(struct wusbhc *wusbhc); -void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay); +void whc_wusbhc_stop(struct wusbhc *wusbhc); int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, u8 handle, struct wuie_hdr *wuie); int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); @@ -194,11 +190,8 @@ void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, struct whc_qtd *qtd); enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); void qset_remove_complete(struct whc *whc, struct whc_qset *qset); +void dump_qset(struct whc_qset *qset, struct device *dev); void pzl_update(struct whc *whc, uint32_t wusbcmd); void asl_update(struct whc *whc, uint32_t wusbcmd); -/* debug.c */ -void whc_dbg_init(struct whc *whc); -void whc_dbg_clean_up(struct whc *whc); - #endif /* #ifndef __WHCD_H */ diff --git a/trunk/drivers/usb/host/whci/whci-hc.h b/trunk/drivers/usb/host/whci/whci-hc.h index 51df7e313b38..bff1eb7a35cf 100644 --- a/trunk/drivers/usb/host/whci/whci-hc.h +++ b/trunk/drivers/usb/host/whci/whci-hc.h @@ -410,8 +410,6 @@ struct dn_buf_entry { # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) #define WUSBTIME 0x68 -# define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff - #define WUSBBPST 0x6c #define WUSBDIBUPDATED 0x70 diff --git a/trunk/drivers/usb/host/whci/wusb.c b/trunk/drivers/usb/host/whci/wusb.c index f24efdebad17..66e4ddcd961d 100644 --- a/trunk/drivers/usb/host/whci/wusb.c +++ b/trunk/drivers/usb/host/whci/wusb.c @@ -15,19 +15,47 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include #include +#define D_LOCAL 1 +#include #include "../../wusbcore/wusbhc.h" #include "whcd.h" +#if D_LOCAL >= 1 +static void dump_di(struct whc *whc, int idx) +{ + struct di_buf_entry *di = &whc->di_buf[idx]; + struct device *dev = &whc->umc->dev; + char buf[128]; + + bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS); + + d_printf(1, dev, "DI[%d]\n", idx); + d_printf(1, dev, " availability: %s\n", buf); + d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n", + (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', + (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', + (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, + (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); +} +#else +static inline void dump_di(struct whc *whc, int idx) +{ +} +#endif + static int whc_update_di(struct whc *whc, int idx) { int offset = idx / 32; u32 bit = 1 << (idx % 32); + dump_di(whc, idx); + le_writel(bit, whc->base + WUSBDIBUPDATED + offset); return whci_wait_for(&whc->umc->dev, @@ -36,9 +64,8 @@ static int whc_update_di(struct whc *whc, int idx) } /* - * WHCI starts MMCs based on there being a valid GTK so these need - * only start/stop the asynchronous and periodic schedules and send a - * channel stop command. + * WHCI starts and stops MMCs based on there being a valid GTK so + * these need only start/stop the asynchronous and periodic schedules. */ int whc_wusbhc_start(struct wusbhc *wusbhc) @@ -51,20 +78,12 @@ int whc_wusbhc_start(struct wusbhc *wusbhc) return 0; } -void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay) +void whc_wusbhc_stop(struct wusbhc *wusbhc) { struct whc *whc = wusbhc_to_whc(wusbhc); - u32 stop_time, now_time; - int ret; pzl_stop(whc); asl_stop(whc); - - now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK; - stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff; - ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0); - if (ret == 0) - msleep(delay); } int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, diff --git a/trunk/drivers/usb/serial/console.c b/trunk/drivers/usb/serial/console.c index 19e24045b137..5b95009d2fbb 100644 --- a/trunk/drivers/usb/serial/console.c +++ b/trunk/drivers/usb/serial/console.c @@ -241,25 +241,12 @@ static void usb_console_write(struct console *co, } } -static struct tty_driver *usb_console_device(struct console *co, int *index) -{ - struct tty_driver **p = (struct tty_driver **)co->data; - - if (!*p) - return NULL; - - *index = co->index; - return *p; -} - static struct console usbcons = { .name = "ttyUSB", .write = usb_console_write, - .device = usb_console_device, .setup = usb_console_setup, .flags = CON_PRINTBUFFER, .index = -1, - .data = &usb_serial_tty_driver, }; void usb_serial_console_disconnect(struct usb_serial *serial) diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index ef6cfa5a447f..fb6f2933b01b 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -1054,8 +1054,6 @@ static int set_serial_info(struct tty_struct *tty, if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) return -EFAULT; - - lock_kernel(); old_priv = *priv; /* Do error checking and permission checking */ @@ -1071,10 +1069,8 @@ static int set_serial_info(struct tty_struct *tty, } if ((new_serial.baud_base != priv->baud_base) && - (new_serial.baud_base < 9600)) { - unlock_kernel(); + (new_serial.baud_base < 9600)) return -EINVAL; - } /* Make the changes - these are privileged changes! */ @@ -1102,11 +1098,8 @@ static int set_serial_info(struct tty_struct *tty, (priv->flags & ASYNC_SPD_MASK)) || (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && (old_priv.custom_divisor != priv->custom_divisor))) { - unlock_kernel(); change_speed(tty, port); } - else - unlock_kernel(); return 0; } /* set_serial_info */ diff --git a/trunk/drivers/usb/serial/kl5kusb105.c b/trunk/drivers/usb/serial/kl5kusb105.c index fcd9082f3e7f..dc36a052766f 100644 --- a/trunk/drivers/usb/serial/kl5kusb105.c +++ b/trunk/drivers/usb/serial/kl5kusb105.c @@ -878,7 +878,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) dbg("%sstate=%d", __func__, break_state); - /* LOCKING */ if (break_state) lcr |= MCT_U232_SET_BREAK; diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index 82930a7d5093..07710cf31d0d 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -721,10 +721,10 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) spin_lock_irqsave(&priv->lock, flags); lcr = priv->last_lcr; + spin_unlock_irqrestore(&priv->lock, flags); if (break_state) lcr |= MCT_U232_SET_BREAK; - spin_unlock_irqrestore(&priv->lock, flags); mct_u232_set_line_ctrl(serial, lcr); } /* mct_u232_break_ctl */ diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index 96a8c7713212..fda4a6421c44 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -1343,7 +1343,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state) else data = mos7840_port->shadowLCR & ~LCR_SET_BREAK; - /* FIXME: no locking on shadowLCR anywhere in driver */ mos7840_port->shadowLCR = data; dbg("mcs7840_break mos7840_port->shadowLCR is %x\n", mos7840_port->shadowLCR); @@ -2215,12 +2214,10 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port, break; } - lock_kernel(); mos7840_port->shadowMCR = mcr; Data = mos7840_port->shadowMCR; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - unlock_kernel(); if (status < 0) { dbg("setting MODEM_CONTROL_REGISTER Failed\n"); return -1; diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index d9bf9a5c20ec..0f2b67244af6 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -442,7 +442,7 @@ static void sierra_indat_callback(struct urb *urb) " endpoint %02x.", __func__, status, endpoint); } else { if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); + tty = tty_port_tty_get(&port->port); tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index 080ade223d53..794b5ffe4397 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -269,19 +269,15 @@ static void serial_close(struct tty_struct *tty, struct file *filp) return; } - if (port->port.count == 1) + --port->port.count; + if (port->port.count == 0) /* only call the device specific close if this - * port is being closed by the last owner. Ensure we do - * this before we drop the port count. The call is protected - * by the port mutex - */ + * port is being closed by the last owner */ port->serial->type->close(tty, port, filp); - if (port->port.count == (port->console ? 2 : 1)) { + if (port->port.count == (port->console? 1 : 0)) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) { - /* We must do this before we drop the port count to - zero. */ if (tty->driver_data) tty->driver_data = NULL; tty_port_tty_set(&port->port, NULL); @@ -289,14 +285,13 @@ static void serial_close(struct tty_struct *tty, struct file *filp) } } - if (port->port.count == 1) { + if (port->port.count == 0) { mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) usb_autopm_put_interface(port->serial->interface); mutex_unlock(&port->serial->disc_mutex); module_put(port->serial->type->driver.owner); } - --port->port.count; mutex_unlock(&port->mutex); usb_serial_put(port->serial); @@ -339,10 +334,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty) dbg("%s = port %d", __func__, port->number); WARN_ON(!port->port.count); - /* if the device was unplugged then any remaining characters - fell out of the connector ;) */ - if (port->serial->disconnected) - return 0; /* pass on to the driver specific version of this function */ return port->serial->type->chars_in_buffer(tty); } @@ -382,7 +373,9 @@ static int serial_ioctl(struct tty_struct *tty, struct file *file, /* pass on to the driver specific version of this function if it is available */ if (port->serial->type->ioctl) { + lock_kernel(); retval = port->serial->type->ioctl(tty, file, cmd, arg); + unlock_kernel(); } else retval = -ENOIOCTLCMD; return retval; @@ -411,8 +404,11 @@ static int serial_break(struct tty_struct *tty, int break_state) WARN_ON(!port->port.count); /* pass on to the driver specific version of this function if it is available */ - if (port->serial->type->break_ctl) + if (port->serial->type->break_ctl) { + lock_kernel(); port->serial->type->break_ctl(tty, break_state); + unlock_kernel(); + } return 0; } diff --git a/trunk/drivers/usb/wusbcore/cbaf.c b/trunk/drivers/usb/wusbcore/cbaf.c index 1335cbe1191d..ab4788d1785a 100644 --- a/trunk/drivers/usb/wusbcore/cbaf.c +++ b/trunk/drivers/usb/wusbcore/cbaf.c @@ -88,6 +88,7 @@ */ #include #include +#include #include #include #include diff --git a/trunk/drivers/usb/wusbcore/crypto.c b/trunk/drivers/usb/wusbcore/crypto.c index 9ec7fd5da489..c36c4389baae 100644 --- a/trunk/drivers/usb/wusbcore/crypto.c +++ b/trunk/drivers/usb/wusbcore/crypto.c @@ -51,17 +51,9 @@ #include #include #include +#define D_LOCAL 0 +#include -static int debug_crypto_verify = 0; - -module_param(debug_crypto_verify, int, 0); -MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms"); - -static void wusb_key_dump(const void *buf, size_t len) -{ - print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_OFFSET, 16, 1, - buf, len, 0); -} /* * Block of data, as understood by AES-CCM @@ -211,6 +203,9 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, const u8 bzero[16] = { 0 }; size_t zero_padding; + d_fnstart(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, " + "n %p, a %p, b %p, blen %zu)\n", + tfm_cbc, tfm_aes, mic, n, a, b, blen); /* * These checks should be compile time optimized out * ensure @a fills b1's mac_header and following fields @@ -252,6 +247,16 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, b1.la = cpu_to_be16(blen + 14); memcpy(&b1.mac_header, a, sizeof(*a)); + d_printf(4, NULL, "I: B0 (%zu bytes)\n", sizeof(b0)); + d_dump(4, NULL, &b0, sizeof(b0)); + d_printf(4, NULL, "I: B1 (%zu bytes)\n", sizeof(b1)); + d_dump(4, NULL, &b1, sizeof(b1)); + d_printf(4, NULL, "I: B (%zu bytes)\n", blen); + d_dump(4, NULL, b, blen); + d_printf(4, NULL, "I: B 0-padding (%zu bytes)\n", zero_padding); + d_printf(4, NULL, "D: IV before crypto (%zu)\n", ivsize); + d_dump(4, NULL, iv, ivsize); + sg_init_table(sg, ARRAY_SIZE(sg)); sg_set_buf(&sg[0], &b0, sizeof(b0)); sg_set_buf(&sg[1], &b1, sizeof(b1)); @@ -268,6 +273,8 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, result); goto error_cbc_crypt; } + d_printf(4, NULL, "D: MIC tag\n"); + d_dump(4, NULL, iv, ivsize); /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] * The procedure is to AES crypt the A0 block and XOR the MIC @@ -282,10 +289,17 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, ax.counter = 0; crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); bytewise_xor(mic, &ax, iv, 8); + d_printf(4, NULL, "D: CTR[MIC]\n"); + d_dump(4, NULL, &ax, 8); + d_printf(4, NULL, "D: CCM-MIC tag\n"); + d_dump(4, NULL, mic, 8); result = 8; error_cbc_crypt: kfree(dst_buf); error_dst_buf: + d_fnend(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, " + "n %p, a %p, b %p, blen %zu)\n", + tfm_cbc, tfm_aes, mic, n, a, b, blen); return result; } @@ -307,6 +321,10 @@ ssize_t wusb_prf(void *out, size_t out_size, u64 sfn = 0; __le64 sfn_le; + d_fnstart(3, NULL, "(out %p, out_size %zu, key %p, _n %p, " + "a %p, b %p, blen %zu, len %zu)\n", out, out_size, + key, _n, a, b, blen, len); + tfm_cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm_cbc)) { result = PTR_ERR(tfm_cbc); @@ -348,6 +366,9 @@ ssize_t wusb_prf(void *out, size_t out_size, error_setkey_cbc: crypto_free_blkcipher(tfm_cbc); error_alloc_cbc: + d_fnend(3, NULL, "(out %p, out_size %zu, key %p, _n %p, " + "a %p, b %p, blen %zu, len %zu) = %d\n", out, out_size, + key, _n, a, b, blen, len, (int)bytes); return result; } @@ -401,14 +422,14 @@ static int wusb_oob_mic_verify(void) "mismatch between MIC result and WUSB1.0[A2]\n"); hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC); printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size); - wusb_key_dump(&stv_hsmic_hs, hs_size); + dump_bytes(NULL, &stv_hsmic_hs, hs_size); printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n", sizeof(stv_hsmic_n)); - wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n)); + dump_bytes(NULL, &stv_hsmic_n, sizeof(stv_hsmic_n)); printk(KERN_ERR "E: MIC out:\n"); - wusb_key_dump(mic, sizeof(mic)); + dump_bytes(NULL, mic, sizeof(mic)); printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n"); - wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC)); + dump_bytes(NULL, stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC)); result = -EINVAL; } else result = 0; @@ -476,16 +497,19 @@ static int wusb_key_derive_verify(void) printk(KERN_ERR "E: WUSB key derivation test: " "mismatch between key derivation result " "and WUSB1.0[A1] Errata 2006/12\n"); - printk(KERN_ERR "E: keydvt in: key\n"); - wusb_key_dump(stv_key_a1, sizeof(stv_key_a1)); - printk(KERN_ERR "E: keydvt in: nonce\n"); - wusb_key_dump( &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); - printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n"); - wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); + printk(KERN_ERR "E: keydvt in: key (%zu bytes)\n", + sizeof(stv_key_a1)); + dump_bytes(NULL, stv_key_a1, sizeof(stv_key_a1)); + printk(KERN_ERR "E: keydvt in: nonce (%zu bytes)\n", + sizeof(stv_keydvt_n_a1)); + dump_bytes(NULL, &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); + printk(KERN_ERR "E: keydvt in: hnonce & dnonce (%zu bytes)\n", + sizeof(stv_keydvt_in_a1)); + dump_bytes(NULL, &stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); printk(KERN_ERR "E: keydvt out: KCK\n"); - wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck)); + dump_bytes(NULL, &keydvt_out.kck, sizeof(keydvt_out.kck)); printk(KERN_ERR "E: keydvt out: PTK\n"); - wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk)); + dump_bytes(NULL, &keydvt_out.ptk, sizeof(keydvt_out.ptk)); result = -EINVAL; } else result = 0; @@ -502,13 +526,10 @@ int wusb_crypto_init(void) { int result; - if (debug_crypto_verify) { - result = wusb_key_derive_verify(); - if (result < 0) - return result; - return wusb_oob_mic_verify(); - } - return 0; + result = wusb_key_derive_verify(); + if (result < 0) + return result; + return wusb_oob_mic_verify(); } void wusb_crypto_exit(void) diff --git a/trunk/drivers/usb/wusbcore/dev-sysfs.c b/trunk/drivers/usb/wusbcore/dev-sysfs.c index 101834576236..7897a19652e5 100644 --- a/trunk/drivers/usb/wusbcore/dev-sysfs.c +++ b/trunk/drivers/usb/wusbcore/dev-sysfs.c @@ -28,6 +28,10 @@ #include #include "wusbhc.h" +#undef D_LOCAL +#define D_LOCAL 4 +#include + static ssize_t wusb_disconnect_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) diff --git a/trunk/drivers/usb/wusbcore/devconnect.c b/trunk/drivers/usb/wusbcore/devconnect.c index e2e7e4bc8463..f45d777bef34 100644 --- a/trunk/drivers/usb/wusbcore/devconnect.c +++ b/trunk/drivers/usb/wusbcore/devconnect.c @@ -57,6 +57,9 @@ * Called by notif.c:wusb_handle_dn_connect() * when a DN_Connect is received. * + * wusbhc_devconnect_auth() Called by rh.c:wusbhc_rh_port_reset() when + * doing the device connect sequence. + * * wusb_devconnect_acked() Ack done, release resources. * * wusb_handle_dn_alive() Called by notif.c:wusb_handle_dn() @@ -66,6 +69,9 @@ * process a disconenct request from a * device. * + * wusb_dev_reset() Called by rh.c:wusbhc_rh_port_reset() when + * resetting a device. + * * __wusb_dev_disable() Called by rh.c:wusbhc_rh_clear_port_feat() when * disabling a port. * @@ -91,6 +97,10 @@ #include #include "wusbhc.h" +#undef D_LOCAL +#define D_LOCAL 1 +#include + static void wusbhc_devconnect_acked_work(struct work_struct *work); static void wusb_dev_free(struct wusb_dev *wusb_dev) @@ -230,7 +240,6 @@ static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc, list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list); wusbhc->cack_count++; wusbhc_fill_cack_ie(wusbhc); - return wusb_dev; } @@ -241,9 +250,12 @@ static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc, */ static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) { + struct device *dev = wusbhc->dev; + d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev); list_del_init(&wusb_dev->cack_node); wusbhc->cack_count--; wusbhc_fill_cack_ie(wusbhc); + d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev); } /* @@ -251,11 +263,14 @@ static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) static void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) { + struct device *dev = wusbhc->dev; + d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev); wusbhc_cack_rm(wusbhc, wusb_dev); if (wusbhc->cack_count) wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); else wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr); + d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev); } static void wusbhc_devconnect_acked_work(struct work_struct *work) @@ -305,6 +320,7 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc, struct wusb_port *port; unsigned idx, devnum; + d_fnstart(3, dev, "(%p, %p, %s)\n", wusbhc, dnc, pr_cdid); mutex_lock(&wusbhc->mutex); /* Check we are not handling it already */ @@ -350,13 +366,16 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc, port->wusb_dev = wusb_dev; port->status |= USB_PORT_STAT_CONNECTION; port->change |= USB_PORT_STAT_C_CONNECTION; + port->reset_count = 0; /* Now the port status changed to connected; khubd will * pick the change up and try to reset the port to bring it to * the enabled state--so this process returns up to the stack - * and it calls back into wusbhc_rh_port_reset(). + * and it calls back into wusbhc_rh_port_reset() who will call + * devconnect_auth(). */ error_unlock: mutex_unlock(&wusbhc->mutex); + d_fnend(3, dev, "(%p, %p, %s) = void\n", wusbhc, dnc, pr_cdid); return; } @@ -379,8 +398,10 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc, static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, struct wusb_port *port) { + struct device *dev = wusbhc->dev; struct wusb_dev *wusb_dev = port->wusb_dev; + d_fnstart(3, dev, "(wusbhc %p, port %p)\n", wusbhc, port); port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); @@ -392,17 +413,54 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, wusb_dev_put(wusb_dev); } port->wusb_dev = NULL; + /* don't reset the reset_count to zero or wusbhc_rh_port_reset will get + * confused! We only reset to zero when we connect a new device. + */ /* After a device disconnects, change the GTK (see [WUSB] * section 6.2.11.2). */ wusbhc_gtk_rekey(wusbhc); + d_fnend(3, dev, "(wusbhc %p, port %p) = void\n", wusbhc, port); /* The Wireless USB part has forgotten about the device already; now * khubd's timer will pick up the disconnection and remove the USB * device from the system */ } +/* + * Authenticate a device into the WUSB Cluster + * + * Called from the Root Hub code (rh.c:wusbhc_rh_port_reset()) when + * asking for a reset on a port that is not enabled (ie: first connect + * on the port). + * + * Performs the 4way handshake to allow the device to comunicate w/ the + * WUSB Cluster securely; once done, issue a request to the device for + * it to change to address 0. + * + * This mimics the reset step of Wired USB that once resetting a + * device, leaves the port in enabled state and the dev with the + * default address (0). + * + * WUSB1.0[7.1.2] + * + * @port_idx: port where the change happened--This is the index into + * the wusbhc port array, not the USB port number. + */ +int wusbhc_devconnect_auth(struct wusbhc *wusbhc, u8 port_idx) +{ + struct device *dev = wusbhc->dev; + struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); + + d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); + port->status &= ~USB_PORT_STAT_RESET; + port->status |= USB_PORT_STAT_ENABLE; + port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; + d_fnend(3, dev, "(%p, %u) = 0\n", wusbhc, port_idx); + return 0; +} + /* * Refresh the list of keep alives to emit in the MMC * @@ -470,15 +528,21 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc) */ static void wusbhc_keep_alive_run(struct work_struct *ws) { - struct delayed_work *dw = container_of(ws, struct delayed_work, work); - struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer); - - mutex_lock(&wusbhc->mutex); - __wusbhc_keep_alive(wusbhc); - mutex_unlock(&wusbhc->mutex); - - queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, - msecs_to_jiffies(wusbhc->trust_timeout / 2)); + struct delayed_work *dw = + container_of(ws, struct delayed_work, work); + struct wusbhc *wusbhc = + container_of(dw, struct wusbhc, keep_alive_timer); + + d_fnstart(5, wusbhc->dev, "(wusbhc %p)\n", wusbhc); + if (wusbhc->active) { + mutex_lock(&wusbhc->mutex); + __wusbhc_keep_alive(wusbhc); + mutex_unlock(&wusbhc->mutex); + queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, + (wusbhc->trust_timeout * CONFIG_HZ)/1000/2); + } + d_fnend(5, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); + return; } /* @@ -521,6 +585,10 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr) */ static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) { + struct device *dev = wusbhc->dev; + + d_printf(2, dev, "DN ALIVE: device 0x%02x pong\n", wusb_dev->addr); + mutex_lock(&wusbhc->mutex); wusb_dev->entry_ts = jiffies; __wusbhc_keep_alive(wusbhc); @@ -553,10 +621,11 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, "no-beacon" }; + d_fnstart(3, dev, "(%p, %p, %zu)\n", wusbhc, dn_hdr, size); if (size < sizeof(*dnc)) { dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n", size, sizeof(*dnc)); - return; + goto out; } dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); @@ -568,6 +637,10 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect"); /* ACK the connect */ wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid); +out: + d_fnend(3, dev, "(%p, %p, %zu) = void\n", + wusbhc, dn_hdr, size); + return; } /* @@ -588,6 +661,60 @@ static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev * mutex_unlock(&wusbhc->mutex); } +/* + * Reset a WUSB device on a HWA + * + * @wusbhc + * @port_idx Index of the port where the device is + * + * In Wireless USB, a reset is more or less equivalent to a full + * disconnect; so we just do a full disconnect and send the device a + * Device Reset IE (WUSB1.0[7.5.11]) giving it a few millisecs (6 MMCs). + * + * @wusbhc should be refcounted and unlocked + */ +int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port_idx) +{ + int result; + struct device *dev = wusbhc->dev; + struct wusb_dev *wusb_dev; + struct wuie_reset *ie; + + d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); + mutex_lock(&wusbhc->mutex); + result = 0; + wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; + if (wusb_dev == NULL) { + /* reset no device? ignore */ + dev_dbg(dev, "RESET: no device at port %u, ignoring\n", + port_idx); + goto error_unlock; + } + result = -ENOMEM; + ie = kzalloc(sizeof(*ie), GFP_KERNEL); + if (ie == NULL) + goto error_unlock; + ie->hdr.bLength = sizeof(ie->hdr) + sizeof(ie->CDID); + ie->hdr.bIEIdentifier = WUIE_ID_RESET_DEVICE; + ie->CDID = wusb_dev->cdid; + result = wusbhc_mmcie_set(wusbhc, 0xff, 6, &ie->hdr); + if (result < 0) { + dev_err(dev, "RESET: cant's set MMC: %d\n", result); + goto error_kfree; + } + __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); + + /* 120ms, hopefully 6 MMCs (FIXME) */ + msleep(120); + wusbhc_mmcie_rm(wusbhc, &ie->hdr); +error_kfree: + kfree(ie); +error_unlock: + mutex_unlock(&wusbhc->mutex); + d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result); + return result; +} + /* * Handle a Device Notification coming a host * @@ -608,17 +735,19 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr, struct device *dev = wusbhc->dev; struct wusb_dev *wusb_dev; + d_fnstart(3, dev, "(%p, %p)\n", wusbhc, dn_hdr); + if (size < sizeof(struct wusb_dn_hdr)) { dev_err(dev, "DN data shorter than DN header (%d < %d)\n", (int)size, (int)sizeof(struct wusb_dn_hdr)); - return; + goto out; } wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) { dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n", dn_hdr->bType, srcaddr); - return; + goto out; } switch (dn_hdr->bType) { @@ -643,6 +772,9 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr, dev_warn(dev, "unknown DN %u (%d octets) from %u\n", dn_hdr->bType, (int)size, srcaddr); } +out: + d_fnend(3, dev, "(%p, %p) = void\n", wusbhc, dn_hdr); + return; } EXPORT_SYMBOL_GPL(wusbhc_handle_dn); @@ -672,30 +804,59 @@ void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx) struct wusb_dev *wusb_dev; struct wuie_disconnect *ie; + d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); + result = 0; wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; if (wusb_dev == NULL) { /* reset no device? ignore */ dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n", port_idx); - return; + goto error; } __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); + result = -ENOMEM; ie = kzalloc(sizeof(*ie), GFP_KERNEL); if (ie == NULL) - return; + goto error; ie->hdr.bLength = sizeof(*ie); ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT; ie->bDeviceAddress = wusb_dev->addr; result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr); - if (result < 0) + if (result < 0) { dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result); - else { - /* At least 6 MMCs, assuming at least 1 MMC per zone. */ - msleep(7*4); - wusbhc_mmcie_rm(wusbhc, &ie->hdr); + goto error_kfree; } + + /* 120ms, hopefully 6 MMCs */ + msleep(100); + wusbhc_mmcie_rm(wusbhc, &ie->hdr); +error_kfree: kfree(ie); +error: + d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result); + return; +} + +static void wusb_cap_descr_printf(const unsigned level, struct device *dev, + const struct usb_wireless_cap_descriptor *wcd) +{ + d_printf(level, dev, + "WUSB Capability Descriptor\n" + " bDevCapabilityType 0x%02x\n" + " bmAttributes 0x%02x\n" + " wPhyRates 0x%04x\n" + " bmTFITXPowerInfo 0x%02x\n" + " bmFFITXPowerInfo 0x%02x\n" + " bmBandGroup 0x%04x\n" + " bReserved 0x%02x\n", + wcd->bDevCapabilityType, + wcd->bmAttributes, + le16_to_cpu(wcd->wPHYRates), + wcd->bmTFITXPowerInfo, + wcd->bmFFITXPowerInfo, + wcd->bmBandGroup, + wcd->bReserved); } /* @@ -738,6 +899,8 @@ static int wusb_dev_bos_grok(struct usb_device *usb_dev, } cap_size = cap_hdr->bLength; cap_type = cap_hdr->bDevCapabilityType; + d_printf(4, dev, "BOS Capability: 0x%02x (%zu bytes)\n", + cap_type, cap_size); if (cap_size == 0) break; if (cap_size > top - itr) { @@ -749,6 +912,7 @@ static int wusb_dev_bos_grok(struct usb_device *usb_dev, result = -EBADF; goto error_bad_cap; } + d_dump(3, dev, itr, cap_size); switch (cap_type) { case USB_CAP_TYPE_WIRELESS_USB: if (cap_size != sizeof(*wusb_dev->wusb_cap_descr)) @@ -756,8 +920,10 @@ static int wusb_dev_bos_grok(struct usb_device *usb_dev, "descriptor is %zu bytes vs %zu " "needed\n", cap_size, sizeof(*wusb_dev->wusb_cap_descr)); - else + else { wusb_dev->wusb_cap_descr = itr; + wusb_cap_descr_printf(3, dev, itr); + } break; default: dev_err(dev, "BUG? Unknown BOS capability 0x%02x " @@ -822,7 +988,9 @@ static int wusb_dev_bos_add(struct usb_device *usb_dev, "%zu bytes): %zd\n", desc_size, result); goto error_get_descriptor; } - + d_printf(2, dev, "Got BOS descriptor %zd bytes, %u capabilities\n", + result, bos->bNumDeviceCaps); + d_dump(2, dev, bos, result); result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result); if (result < 0) goto error_bad_bos; @@ -888,6 +1056,8 @@ static void wusb_dev_add_ncb(struct usb_device *usb_dev) if (usb_dev->wusb == 0 || usb_dev->devnum == 1) return; /* skip non wusb and wusb RHs */ + d_fnstart(3, dev, "(usb_dev %p)\n", usb_dev); + wusbhc = wusbhc_get_by_usb_dev(usb_dev); if (wusbhc == NULL) goto error_nodev; @@ -917,6 +1087,7 @@ static void wusb_dev_add_ncb(struct usb_device *usb_dev) wusb_dev_put(wusb_dev); wusbhc_put(wusbhc); error_nodev: + d_fnend(3, dev, "(usb_dev %p) = void\n", usb_dev); return; wusb_dev_sysfs_rm(wusb_dev); @@ -1003,10 +1174,11 @@ EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev); void wusb_dev_destroy(struct kref *_wusb_dev) { - struct wusb_dev *wusb_dev = container_of(_wusb_dev, struct wusb_dev, refcnt); - + struct wusb_dev *wusb_dev + = container_of(_wusb_dev, struct wusb_dev, refcnt); list_del_init(&wusb_dev->cack_node); wusb_dev_free(wusb_dev); + d_fnend(1, NULL, "%s (wusb_dev %p) = void\n", __func__, wusb_dev); } EXPORT_SYMBOL_GPL(wusb_dev_destroy); @@ -1018,6 +1190,8 @@ EXPORT_SYMBOL_GPL(wusb_dev_destroy); */ int wusbhc_devconnect_create(struct wusbhc *wusbhc) { + d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc); + wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE; wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr); INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run); @@ -1026,6 +1200,7 @@ int wusbhc_devconnect_create(struct wusbhc *wusbhc) wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr); INIT_LIST_HEAD(&wusbhc->cack_list); + d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); return 0; } @@ -1034,7 +1209,8 @@ int wusbhc_devconnect_create(struct wusbhc *wusbhc) */ void wusbhc_devconnect_destroy(struct wusbhc *wusbhc) { - /* no op */ + d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc); + d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); } /* @@ -1046,7 +1222,8 @@ void wusbhc_devconnect_destroy(struct wusbhc *wusbhc) * FIXME: This also enables the keep alives but this is not necessary * until there are connected and authenticated devices. */ -int wusbhc_devconnect_start(struct wusbhc *wusbhc) +int wusbhc_devconnect_start(struct wusbhc *wusbhc, + const struct wusb_ckhdid *chid) { struct device *dev = wusbhc->dev; struct wuie_host_info *hi; @@ -1059,7 +1236,7 @@ int wusbhc_devconnect_start(struct wusbhc *wusbhc) hi->hdr.bLength = sizeof(*hi); hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO; hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL); - hi->CHID = wusbhc->chid; + hi->CHID = *chid; result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr); if (result < 0) { dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result); diff --git a/trunk/drivers/usb/wusbcore/mmc.c b/trunk/drivers/usb/wusbcore/mmc.c index 3b52161e6e9c..cfa77a01cebd 100644 --- a/trunk/drivers/usb/wusbcore/mmc.c +++ b/trunk/drivers/usb/wusbcore/mmc.c @@ -159,35 +159,15 @@ void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie) } EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm); -static int wusbhc_mmc_start(struct wusbhc *wusbhc) -{ - int ret; - - mutex_lock(&wusbhc->mutex); - ret = wusbhc->start(wusbhc); - if (ret >= 0) - wusbhc->active = 1; - mutex_unlock(&wusbhc->mutex); - - return ret; -} - -static void wusbhc_mmc_stop(struct wusbhc *wusbhc) -{ - mutex_lock(&wusbhc->mutex); - wusbhc->active = 0; - wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS); - mutex_unlock(&wusbhc->mutex); -} - /* * wusbhc_start - start transmitting MMCs and accepting connections * @wusbhc: the HC to start + * @chid: the CHID to use for this host * * Establishes a cluster reservation, enables device connections, and * starts MMCs with appropriate DNTS parameters. */ -int wusbhc_start(struct wusbhc *wusbhc) +int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) { int result; struct device *dev = wusbhc->dev; @@ -201,7 +181,7 @@ int wusbhc_start(struct wusbhc *wusbhc) goto error_rsv_establish; } - result = wusbhc_devconnect_start(wusbhc); + result = wusbhc_devconnect_start(wusbhc, chid); if (result < 0) { dev_err(dev, "error enabling device connections: %d\n", result); goto error_devconnect_start; @@ -219,12 +199,12 @@ int wusbhc_start(struct wusbhc *wusbhc) dev_err(dev, "Cannot set DNTS parameters: %d\n", result); goto error_set_num_dnts; } - result = wusbhc_mmc_start(wusbhc); + result = wusbhc->start(wusbhc); if (result < 0) { dev_err(dev, "error starting wusbch: %d\n", result); goto error_wusbhc_start; } - + wusbhc->active = 1; return 0; error_wusbhc_start: @@ -238,18 +218,77 @@ int wusbhc_start(struct wusbhc *wusbhc) return result; } +/* + * Disconnect all from the WUSB Channel + * + * Send a Host Disconnect IE in the MMC, wait, don't send it any more + */ +static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc) +{ + int result = -ENOMEM; + struct wuie_host_disconnect *host_disconnect_ie; + might_sleep(); + host_disconnect_ie = kmalloc(sizeof(*host_disconnect_ie), GFP_KERNEL); + if (host_disconnect_ie == NULL) + goto error_alloc; + host_disconnect_ie->hdr.bLength = sizeof(*host_disconnect_ie); + host_disconnect_ie->hdr.bIEIdentifier = WUIE_ID_HOST_DISCONNECT; + result = wusbhc_mmcie_set(wusbhc, 0, 0, &host_disconnect_ie->hdr); + if (result < 0) + goto error_mmcie_set; + + /* WUSB1.0[8.5.3.1 & 7.5.2] */ + msleep(100); + wusbhc_mmcie_rm(wusbhc, &host_disconnect_ie->hdr); +error_mmcie_set: + kfree(host_disconnect_ie); +error_alloc: + return result; +} + /* * wusbhc_stop - stop transmitting MMCs * @wusbhc: the HC to stop * - * Stops the WUSB channel and removes the cluster reservation. + * Send a Host Disconnect IE, wait, remove all the MMCs (stop sending MMCs). + * + * If we can't allocate a Host Stop IE, screw it, we don't notify the + * devices we are disconnecting... */ void wusbhc_stop(struct wusbhc *wusbhc) { - wusbhc_mmc_stop(wusbhc); - wusbhc_sec_stop(wusbhc); - wusbhc_devconnect_stop(wusbhc); - wusbhc_rsv_terminate(wusbhc); + if (wusbhc->active) { + wusbhc->active = 0; + wusbhc->stop(wusbhc); + wusbhc_sec_stop(wusbhc); + __wusbhc_host_disconnect_ie(wusbhc); + wusbhc_devconnect_stop(wusbhc); + wusbhc_rsv_terminate(wusbhc); + } +} +EXPORT_SYMBOL_GPL(wusbhc_stop); + +/* + * Change the CHID in a WUSB Channel + * + * If it is just a new CHID, send a Host Disconnect IE and then change + * the CHID IE. + */ +static int __wusbhc_chid_change(struct wusbhc *wusbhc, + const struct wusb_ckhdid *chid) +{ + int result = -ENOSYS; + struct device *dev = wusbhc->dev; + dev_err(dev, "%s() not implemented yet\n", __func__); + return result; + + BUG_ON(wusbhc->wuie_host_info == NULL); + __wusbhc_host_disconnect_ie(wusbhc); + wusbhc->wuie_host_info->CHID = *chid; + result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->wuie_host_info->hdr); + if (result < 0) + dev_err(dev, "Can't update Host Info WUSB IE: %d\n", result); + return result; } /* @@ -267,19 +306,16 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) chid = NULL; mutex_lock(&wusbhc->mutex); - if (chid) { - if (wusbhc->active) { - mutex_unlock(&wusbhc->mutex); - return -EBUSY; - } - wusbhc->chid = *chid; + if (wusbhc->active) { + if (chid) + result = __wusbhc_chid_change(wusbhc, chid); + else + wusbhc_stop(wusbhc); + } else { + if (chid) + wusbhc_start(wusbhc, chid); } mutex_unlock(&wusbhc->mutex); - - if (chid) - result = uwb_radio_start(&wusbhc->pal); - else - uwb_radio_stop(&wusbhc->pal); return result; } EXPORT_SYMBOL_GPL(wusbhc_chid_set); diff --git a/trunk/drivers/usb/wusbcore/pal.c b/trunk/drivers/usb/wusbcore/pal.c index d0b172c5ecc7..7cc51e9905cf 100644 --- a/trunk/drivers/usb/wusbcore/pal.c +++ b/trunk/drivers/usb/wusbcore/pal.c @@ -18,16 +18,6 @@ */ #include "wusbhc.h" -static void wusbhc_channel_changed(struct uwb_pal *pal, int channel) -{ - struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal); - - if (channel < 0) - wusbhc_stop(wusbhc); - else - wusbhc_start(wusbhc); -} - /** * wusbhc_pal_register - register the WUSB HC as a UWB PAL * @wusbhc: the WUSB HC @@ -38,10 +28,8 @@ int wusbhc_pal_register(struct wusbhc *wusbhc) wusbhc->pal.name = "wusbhc"; wusbhc->pal.device = wusbhc->usb_hcd.self.controller; - wusbhc->pal.rc = wusbhc->uwb_rc; - wusbhc->pal.channel_changed = wusbhc_channel_changed; - return uwb_pal_register(&wusbhc->pal); + return uwb_pal_register(wusbhc->uwb_rc, &wusbhc->pal); } /** @@ -50,5 +38,5 @@ int wusbhc_pal_register(struct wusbhc *wusbhc) */ void wusbhc_pal_unregister(struct wusbhc *wusbhc) { - uwb_pal_unregister(&wusbhc->pal); + uwb_pal_unregister(wusbhc->uwb_rc, &wusbhc->pal); } diff --git a/trunk/drivers/usb/wusbcore/reservation.c b/trunk/drivers/usb/wusbcore/reservation.c index 4ed97360c046..fc63e77ded2d 100644 --- a/trunk/drivers/usb/wusbcore/reservation.c +++ b/trunk/drivers/usb/wusbcore/reservation.c @@ -48,19 +48,18 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv) { struct wusbhc *wusbhc = rsv->pal_priv; struct device *dev = wusbhc->dev; - struct uwb_mas_bm mas; char buf[72]; switch (rsv->state) { case UWB_RSV_STATE_O_ESTABLISHED: - uwb_rsv_get_usable_mas(rsv, &mas); - bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS); + bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS); dev_dbg(dev, "established reservation: %s\n", buf); - wusbhc_bwa_set(wusbhc, rsv->stream, &mas); + wusbhc_bwa_set(wusbhc, rsv->stream, &rsv->mas); break; case UWB_RSV_STATE_NONE: dev_dbg(dev, "removed reservation\n"); wusbhc_bwa_set(wusbhc, 0, NULL); + wusbhc->rsv = NULL; break; default: dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state); @@ -87,12 +86,13 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc) bcid.data[0] = wusbhc->cluster_id; bcid.data[1] = 0; + rsv->owner = &rc->uwb_dev; rsv->target.type = UWB_RSV_TARGET_DEVADDR; rsv->target.devaddr = bcid; rsv->type = UWB_DRP_TYPE_PRIVATE; - rsv->max_mas = 256; /* try to get as much as possible */ - rsv->min_mas = 15; /* one MAS per zone */ - rsv->max_interval = 1; /* max latency is one zone */ + rsv->max_mas = 256; + rsv->min_mas = 16; /* one MAS per zone? */ + rsv->sparsity = 16; /* at least one MAS in each zone? */ rsv->is_multicast = true; ret = uwb_rsv_establish(rsv); @@ -105,14 +105,11 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc) /** - * wusbhc_rsv_terminate - terminate the cluster reservation + * wusbhc_rsv_terminate - terminate any cluster reservation * @wusbhc: the WUSB host whose reservation is to be terminated */ void wusbhc_rsv_terminate(struct wusbhc *wusbhc) { - if (wusbhc->rsv) { + if (wusbhc->rsv) uwb_rsv_terminate(wusbhc->rsv); - uwb_rsv_destroy(wusbhc->rsv); - wusbhc->rsv = NULL; - } } diff --git a/trunk/drivers/usb/wusbcore/rh.c b/trunk/drivers/usb/wusbcore/rh.c index 95c6fa3bf6b2..267a64325106 100644 --- a/trunk/drivers/usb/wusbcore/rh.c +++ b/trunk/drivers/usb/wusbcore/rh.c @@ -71,20 +71,19 @@ */ #include "wusbhc.h" +#define D_LOCAL 0 +#include + /* * Reset a fake port * - * Using a Reset Device IE is too heavyweight as it causes the device - * to enter the UnConnected state and leave the cluster, this can mean - * that when the device reconnects it is connected to a different fake - * port. - * - * Instead, reset authenticated devices with a SetAddress(0), followed - * by a SetAddresss(AuthAddr). + * This can be called to reset a port from any other state or to reset + * it when connecting. In Wireless USB they are different; when doing + * a new connect that involves going over the authentication. When + * just reseting, its a different story. * - * For unauthenticated devices just pretend to reset but do nothing. - * If the device initialization continues to fail it will eventually - * time out after TrustTimeout and enter the UnConnected state. + * The Linux USB stack resets a port twice before it considers it + * enabled, so we have to detect and ignore that. * * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. * @@ -98,20 +97,20 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) { int result = 0; struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); - struct wusb_dev *wusb_dev = port->wusb_dev; - port->status |= USB_PORT_STAT_RESET; - port->change |= USB_PORT_STAT_C_RESET; - - if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH) - result = 0; + d_fnstart(3, wusbhc->dev, "(wusbhc %p port_idx %u)\n", + wusbhc, port_idx); + if (port->reset_count == 0) { + wusbhc_devconnect_auth(wusbhc, port_idx); + port->reset_count++; + } else if (port->reset_count == 1) + /* see header */ + d_printf(2, wusbhc->dev, "Ignoring second reset on port_idx " + "%u\n", port_idx); else - result = wusb_dev_update_address(wusbhc, wusb_dev); - - port->status &= ~USB_PORT_STAT_RESET; - port->status |= USB_PORT_STAT_ENABLE; - port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; - + result = wusbhc_dev_reset(wusbhc, port_idx); + d_fnend(3, wusbhc->dev, "(wusbhc %p port_idx %u) = %d\n", + wusbhc, port_idx, result); return result; } @@ -139,6 +138,7 @@ int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf) size_t cnt, size; unsigned long *buf = (unsigned long *) _buf; + d_fnstart(1, wusbhc->dev, "(wusbhc %p)\n", wusbhc); /* WE DON'T LOCK, see comment */ size = wusbhc->ports_max + 1 /* hub bit */; size = (size + 8 - 1) / 8; /* round to bytes */ @@ -147,6 +147,8 @@ int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf) set_bit(cnt + 1, buf); else clear_bit(cnt + 1, buf); + d_fnend(1, wusbhc->dev, "(wusbhc %p) %u, buffer:\n", wusbhc, (int)size); + d_dump(1, wusbhc->dev, _buf, size); return size; } EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); @@ -195,7 +197,9 @@ static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue, static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) { int result; + struct device *dev = wusbhc->dev; + d_fnstart(4, dev, "(%p, feature 0x%04u)\n", wusbhc, feature); switch (feature) { case C_HUB_LOCAL_POWER: /* FIXME: maybe plug bit 0 to the power input status, @@ -207,6 +211,7 @@ static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) default: result = -EPIPE; } + d_fnend(4, dev, "(%p, feature 0x%04u), %d\n", wusbhc, feature, result); return result; } @@ -233,10 +238,14 @@ static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf, static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, u8 selector, u8 port_idx) { + int result = -EINVAL; struct device *dev = wusbhc->dev; + d_fnstart(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d)\n", + feature, selector, port_idx); + if (port_idx > wusbhc->ports_max) - return -EINVAL; + goto error; switch (feature) { /* According to USB2.0[11.24.2.13]p2, these features @@ -246,27 +255,35 @@ static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, case USB_PORT_FEAT_C_SUSPEND: case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_RESET: - return 0; + result = 0; + break; + case USB_PORT_FEAT_POWER: /* No such thing, but we fake it works */ mutex_lock(&wusbhc->mutex); wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER; mutex_unlock(&wusbhc->mutex); - return 0; + result = 0; + break; case USB_PORT_FEAT_RESET: - return wusbhc_rh_port_reset(wusbhc, port_idx); + result = wusbhc_rh_port_reset(wusbhc, port_idx); + break; case USB_PORT_FEAT_ENABLE: case USB_PORT_FEAT_SUSPEND: dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n", port_idx, feature, selector); - return -ENOSYS; + result = -ENOSYS; + break; default: dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n", port_idx, feature, selector); - return -EPIPE; + result = -EPIPE; + break; } - - return 0; +error: + d_fnend(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d) = %d\n", + feature, selector, port_idx, result); + return result; } /* @@ -277,13 +294,17 @@ static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, u8 selector, u8 port_idx) { - int result = 0; + int result = -EINVAL; struct device *dev = wusbhc->dev; + d_fnstart(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d)\n", + wusbhc, feature, selector, port_idx); + if (port_idx > wusbhc->ports_max) - return -EINVAL; + goto error; mutex_lock(&wusbhc->mutex); + result = 0; switch (feature) { case USB_PORT_FEAT_POWER: /* fake port always on */ /* According to USB2.0[11.24.2.7.1.4], no need to implement? */ @@ -303,8 +324,10 @@ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, break; case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_C_SUSPEND: + case 0xffff: /* ??? FIXME */ dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n", port_idx, feature, selector); + /* dump_stack(); */ result = -ENOSYS; break; default: @@ -314,7 +337,9 @@ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, break; } mutex_unlock(&wusbhc->mutex); - +error: + d_fnend(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d) = " + "%d\n", wusbhc, feature, selector, port_idx, result); return result; } @@ -326,17 +351,22 @@ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx, u32 *_buf, u16 wLength) { + int result = -EINVAL; u16 *buf = (u16 *) _buf; + d_fnstart(1, wusbhc->dev, "(wusbhc %p port_idx %u wLength %u)\n", + wusbhc, port_idx, wLength); if (port_idx > wusbhc->ports_max) - return -EINVAL; - + goto error; mutex_lock(&wusbhc->mutex); buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status); buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change); + result = 0; mutex_unlock(&wusbhc->mutex); - - return 0; +error: + d_fnend(1, wusbhc->dev, "(wusbhc %p) = %d, buffer:\n", wusbhc, result); + d_dump(1, wusbhc->dev, _buf, wLength); + return result; } /* diff --git a/trunk/drivers/usb/wusbcore/security.c b/trunk/drivers/usb/wusbcore/security.c index f4aa28eca70d..a101cad6a8d4 100644 --- a/trunk/drivers/usb/wusbcore/security.c +++ b/trunk/drivers/usb/wusbcore/security.c @@ -27,6 +27,19 @@ #include #include "wusbhc.h" +/* + * DEBUG & SECURITY WARNING!!!! + * + * If you enable this past 1, the debug code will weaken the + * cryptographic safety of the system (on purpose, for debugging). + * + * Weaken means: + * we print secret keys and intermediate values all the way, + */ +#undef D_LOCAL +#define D_LOCAL 2 +#include + static void wusbhc_set_gtk_callback(struct urb *urb); static void wusbhc_gtk_rekey_done_work(struct work_struct *work); @@ -206,6 +219,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, const void *itr, *top; char buf[64]; + d_fnstart(3, dev, "(usb_dev %p, wusb_dev %p)\n", usb_dev, wusb_dev); result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, 0, &secd, sizeof(secd)); if (result < sizeof(secd)) { @@ -214,6 +228,8 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, goto error_secd; } secd_size = le16_to_cpu(secd.wTotalLength); + d_printf(5, dev, "got %d bytes of sec descriptor, total is %d\n", + result, secd_size); secd_buf = kmalloc(secd_size, GFP_KERNEL); if (secd_buf == NULL) { dev_err(dev, "Can't allocate space for security descriptors\n"); @@ -226,6 +242,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, "not enough data: %d\n", result); goto error_secd_all; } + d_printf(5, dev, "got %d bytes of sec descriptors\n", result); bytes = 0; itr = secd_buf + sizeof(secd); top = secd_buf + result; @@ -262,12 +279,14 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, goto error_no_ccm1; } wusb_dev->ccm1_etd = *ccm1_etd; - dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", - buf, wusb_et_name(ccm1_etd->bEncryptionType), - ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); + dev_info(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", + buf, wusb_et_name(ccm1_etd->bEncryptionType), + ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); result = 0; kfree(secd_buf); out: + d_fnend(3, dev, "(usb_dev %p, wusb_dev %p) = %d\n", + usb_dev, wusb_dev, result); return result; @@ -284,6 +303,32 @@ void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) /* Nothing so far */ } +static void hs_printk(unsigned level, struct device *dev, + struct usb_handshake *hs) +{ + d_printf(level, dev, + " bMessageNumber: %u\n" + " bStatus: %u\n" + " tTKID: %02x %02x %02x\n" + " CDID: %02x %02x %02x %02x %02x %02x %02x %02x\n" + " %02x %02x %02x %02x %02x %02x %02x %02x\n" + " nonce: %02x %02x %02x %02x %02x %02x %02x %02x\n" + " %02x %02x %02x %02x %02x %02x %02x %02x\n" + " MIC: %02x %02x %02x %02x %02x %02x %02x %02x\n", + hs->bMessageNumber, hs->bStatus, + hs->tTKID[2], hs->tTKID[1], hs->tTKID[0], + hs->CDID[0], hs->CDID[1], hs->CDID[2], hs->CDID[3], + hs->CDID[4], hs->CDID[5], hs->CDID[6], hs->CDID[7], + hs->CDID[8], hs->CDID[9], hs->CDID[10], hs->CDID[11], + hs->CDID[12], hs->CDID[13], hs->CDID[14], hs->CDID[15], + hs->nonce[0], hs->nonce[1], hs->nonce[2], hs->nonce[3], + hs->nonce[4], hs->nonce[5], hs->nonce[6], hs->nonce[7], + hs->nonce[8], hs->nonce[9], hs->nonce[10], hs->nonce[11], + hs->nonce[12], hs->nonce[13], hs->nonce[14], hs->nonce[15], + hs->MIC[0], hs->MIC[1], hs->MIC[2], hs->MIC[3], + hs->MIC[4], hs->MIC[5], hs->MIC[6], hs->MIC[7]); +} + /** * Update the address of an unauthenticated WUSB device * @@ -293,7 +338,8 @@ void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) * Before the device's address (as known by it) was usb_dev->devnum | * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum. */ -int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) +static int wusb_dev_update_address(struct wusbhc *wusbhc, + struct wusb_dev *wusb_dev) { int result = -ENOMEM; struct usb_device *usb_dev = wusb_dev->usb_dev; @@ -376,6 +422,9 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce)); memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */ + d_printf(1, dev, "I: sending hs1:\n"); + hs_printk(2, dev, &hs[0]); + result = usb_control_msg( usb_dev, usb_sndctrlpipe(usb_dev, 0), USB_REQ_SET_HANDSHAKE, @@ -396,6 +445,8 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, dev_err(dev, "Handshake2: request failed: %d\n", result); goto error_hs2; } + d_printf(1, dev, "got HS2:\n"); + hs_printk(2, dev, &hs[1]); result = -EINVAL; if (hs[1].bMessageNumber != 2) { @@ -436,6 +487,10 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, result); goto error_hs2; } + d_printf(2, dev, "KCK:\n"); + d_dump(2, dev, keydvt_out.kck, sizeof(keydvt_out.kck)); + d_printf(2, dev, "PTK:\n"); + d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk)); /* Compute MIC and verify it */ result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]); @@ -445,6 +500,8 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, goto error_hs2; } + d_printf(2, dev, "MIC:\n"); + d_dump(2, dev, mic, sizeof(mic)); if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) { dev_err(dev, "Handshake2 failed: MIC mismatch\n"); goto error_hs2; @@ -464,6 +521,9 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, goto error_hs2; } + d_printf(1, dev, "I: sending hs3:\n"); + hs_printk(2, dev, &hs[2]); + result = usb_control_msg( usb_dev, usb_sndctrlpipe(usb_dev, 0), USB_REQ_SET_HANDSHAKE, @@ -474,11 +534,14 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, goto error_hs3; } + d_printf(1, dev, "I: turning on encryption on host for device\n"); + d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk)); result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid, keydvt_out.ptk, sizeof(keydvt_out.ptk)); if (result < 0) goto error_wusbhc_set_ptk; + d_printf(1, dev, "I: setting a GTK\n"); result = wusb_dev_set_gtk(wusbhc, wusb_dev); if (result < 0) { dev_err(dev, "Set GTK for device: request failed: %d\n", @@ -488,12 +551,13 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, /* Update the device's address from unauth to auth */ if (usb_dev->authenticated == 0) { + d_printf(1, dev, "I: updating addres to auth from non-auth\n"); result = wusb_dev_update_address(wusbhc, wusb_dev); if (result < 0) goto error_dev_update_address; } result = 0; - dev_info(dev, "device authenticated\n"); + d_printf(1, dev, "I: 4way handshke done, device authenticated\n"); error_dev_update_address: error_wusbhc_set_gtk: @@ -506,8 +570,10 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, memset(&keydvt_in, 0, sizeof(keydvt_in)); memset(&ccm_n, 0, sizeof(ccm_n)); memset(mic, 0, sizeof(mic)); - if (result < 0) + if (result < 0) { + /* error path */ wusb_dev_set_encryption(usb_dev, 0); + } error_dev_set_encryption: kfree(hs); error_kzalloc: diff --git a/trunk/drivers/usb/wusbcore/wa-nep.c b/trunk/drivers/usb/wusbcore/wa-nep.c index 17d2626038be..3f542990c73f 100644 --- a/trunk/drivers/usb/wusbcore/wa-nep.c +++ b/trunk/drivers/usb/wusbcore/wa-nep.c @@ -51,7 +51,7 @@ */ #include #include - +#include #include "wa-hc.h" #include "wusbhc.h" @@ -139,10 +139,13 @@ static void wa_notif_dispatch(struct work_struct *ws) /* FIXME: unimplemented WA NOTIFs */ /* fallthru */ default: - dev_err(dev, "HWA: unknown notification 0x%x, " - "%zu bytes; discarding\n", - notif_hdr->bNotifyType, - (size_t)notif_hdr->bLength); + if (printk_ratelimit()) { + dev_err(dev, "HWA: unknown notification 0x%x, " + "%zu bytes; discarding\n", + notif_hdr->bNotifyType, + (size_t)notif_hdr->bLength); + dump_bytes(dev, notif_hdr, 16); + } break; } } @@ -157,9 +160,12 @@ static void wa_notif_dispatch(struct work_struct *ws) * discard the data, as this should not happen. */ exhausted_buffer: + if (!printk_ratelimit()) + goto out; dev_warn(dev, "HWA: device sent short notification, " "%d bytes missing; discarding %d bytes.\n", missing, (int)size); + dump_bytes(dev, itr, size); goto out; } diff --git a/trunk/drivers/usb/wusbcore/wa-rpipe.c b/trunk/drivers/usb/wusbcore/wa-rpipe.c index 7369655f69cd..f18e4aae66e9 100644 --- a/trunk/drivers/usb/wusbcore/wa-rpipe.c +++ b/trunk/drivers/usb/wusbcore/wa-rpipe.c @@ -60,10 +60,13 @@ #include #include #include - #include "wusbhc.h" #include "wa-hc.h" +#define D_LOCAL 0 +#include + + static int __rpipe_get_descr(struct wahc *wa, struct usb_rpipe_descriptor *descr, u16 index) { @@ -73,6 +76,7 @@ static int __rpipe_get_descr(struct wahc *wa, /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor() * function because the arguments are different. */ + d_printf(1, dev, "rpipe %u: get descr\n", index); result = usb_control_msg( wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), USB_REQ_GET_DESCRIPTOR, @@ -111,6 +115,7 @@ static int __rpipe_set_descr(struct wahc *wa, /* we cannot use the usb_get_descriptor() function because the * arguments are different. */ + d_printf(1, dev, "rpipe %u: set descr\n", index); result = usb_control_msg( wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), USB_REQ_SET_DESCRIPTOR, @@ -169,12 +174,13 @@ void rpipe_destroy(struct kref *_rpipe) { struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt); u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex); - + d_fnstart(1, NULL, "(rpipe %p %u)\n", rpipe, index); if (rpipe->ep) rpipe->ep->hcpriv = NULL; rpipe_put_idx(rpipe->wa, index); wa_put(rpipe->wa); kfree(rpipe); + d_fnend(1, NULL, "(rpipe %p %u)\n", rpipe, index); } EXPORT_SYMBOL_GPL(rpipe_destroy); @@ -196,6 +202,7 @@ static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, struct wa_rpipe *rpipe; struct device *dev = &wa->usb_iface->dev; + d_fnstart(3, dev, "(wa %p crs 0x%02x)\n", wa, crs); rpipe = kzalloc(sizeof(*rpipe), gfp); if (rpipe == NULL) return -ENOMEM; @@ -216,12 +223,14 @@ static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, } *prpipe = NULL; kfree(rpipe); + d_fnend(3, dev, "(wa %p crs 0x%02x) = -ENXIO\n", wa, crs); return -ENXIO; found: set_bit(rpipe_idx, wa->rpipe_bm); rpipe->wa = wa_get(wa); *prpipe = rpipe; + d_fnstart(3, dev, "(wa %p crs 0x%02x) = 0\n", wa, crs); return 0; } @@ -230,6 +239,7 @@ static int __rpipe_reset(struct wahc *wa, unsigned index) int result; struct device *dev = &wa->usb_iface->dev; + d_printf(1, dev, "rpipe %u: reset\n", index); result = usb_control_msg( wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), USB_REQ_RPIPE_RESET, @@ -266,6 +276,7 @@ static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( struct usb_descriptor_header *hdr; struct usb_wireless_ep_comp_descriptor *epcd; + d_fnstart(3, dev, "(ep %p)\n", ep); if (ep->desc.bEndpointAddress == 0) { epcd = &epc0; goto out; @@ -299,6 +310,7 @@ static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( itr_size -= hdr->bDescriptorType; } out: + d_fnend(3, dev, "(ep %p) = %p\n", ep, epcd); return epcd; } @@ -317,6 +329,8 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, struct usb_wireless_ep_comp_descriptor *epcd; u8 unauth; + d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", + rpipe, wa, ep, urb); epcd = rpipe_epc_find(dev, ep); if (epcd == NULL) { dev_err(dev, "ep 0x%02x: can't find companion descriptor\n", @@ -336,12 +350,10 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, /* FIXME: use maximum speed as supported or recommended by device */ rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ? UWB_PHY_RATE_53 : UWB_PHY_RATE_200; - - dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", - urb->dev->devnum, urb->dev->devnum | unauth, - le16_to_cpu(rpipe->descr.wRPipeIndex), - usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); - + d_printf(2, dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", + urb->dev->devnum, urb->dev->devnum | unauth, + le16_to_cpu(rpipe->descr.wRPipeIndex), + usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); /* see security.c:wusb_update_address() */ if (unlikely(urb->dev->devnum == 0x80)) rpipe->descr.bDeviceAddress = 0; @@ -372,6 +384,8 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, } result = 0; error: + d_fnend(3, dev, "(rpipe %p wa %p ep %p urb %p) = %d\n", + rpipe, wa, ep, urb, result); return result; } @@ -391,6 +405,8 @@ static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0; u8 portnum = wusb_port_no_to_idx(urb->dev->portnum); + d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", + rpipe, wa, ep, urb); #define AIM_CHECK(rdf, val, text) \ do { \ if (rpipe->descr.rdf != (val)) { \ @@ -435,6 +451,8 @@ int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, struct wa_rpipe *rpipe; u8 eptype; + d_fnstart(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, + gfp); mutex_lock(&wa->rpipe_mutex); rpipe = ep->hcpriv; if (rpipe != NULL) { @@ -444,9 +462,9 @@ int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, goto error; } __rpipe_get(rpipe); - dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n", - ep->desc.bEndpointAddress, - le16_to_cpu(rpipe->descr.wRPipeIndex)); + d_printf(2, dev, "ep 0x%02x: reusing rpipe %u\n", + ep->desc.bEndpointAddress, + le16_to_cpu(rpipe->descr.wRPipeIndex)); } else { /* hmm, assign idle rpipe, aim it */ result = -ENOBUFS; @@ -462,12 +480,14 @@ int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, ep->hcpriv = rpipe; rpipe->ep = ep; __rpipe_get(rpipe); /* for caching into ep->hcpriv */ - dev_dbg(dev, "ep 0x%02x: using rpipe %u\n", - ep->desc.bEndpointAddress, - le16_to_cpu(rpipe->descr.wRPipeIndex)); + d_printf(2, dev, "ep 0x%02x: using rpipe %u\n", + ep->desc.bEndpointAddress, + le16_to_cpu(rpipe->descr.wRPipeIndex)); } + d_dump(4, dev, &rpipe->descr, sizeof(rpipe->descr)); error: mutex_unlock(&wa->rpipe_mutex); + d_fnend(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, gfp); return result; } @@ -487,7 +507,7 @@ int wa_rpipes_create(struct wahc *wa) void wa_rpipes_destroy(struct wahc *wa) { struct device *dev = &wa->usb_iface->dev; - + d_fnstart(3, dev, "(wa %p)\n", wa); if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) { char buf[256]; WARN_ON(1); @@ -495,6 +515,7 @@ void wa_rpipes_destroy(struct wahc *wa) dev_err(dev, "BUG: pipes not released on exit: %s\n", buf); } kfree(wa->rpipe_bm); + d_fnend(3, dev, "(wa %p)\n", wa); } /* @@ -509,20 +530,33 @@ void wa_rpipes_destroy(struct wahc *wa) */ void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) { + struct device *dev = &wa->usb_iface->dev; struct wa_rpipe *rpipe; - + d_fnstart(2, dev, "(wa %p ep %p)\n", wa, ep); mutex_lock(&wa->rpipe_mutex); rpipe = ep->hcpriv; if (rpipe != NULL) { + unsigned rc = atomic_read(&rpipe->refcnt.refcount); + int result; u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); - usb_control_msg( + if (rc != 1) + d_printf(1, dev, "(wa %p ep %p) rpipe %p refcnt %u\n", + wa, ep, rpipe, rc); + + d_printf(1, dev, "rpipe %u: abort\n", index); + result = usb_control_msg( wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), USB_REQ_RPIPE_ABORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); + if (result < 0 && result != -ENODEV /* dev is gone */) + d_printf(1, dev, "(wa %p rpipe %u): abort failed: %d\n", + wa, index, result); rpipe_put(rpipe); } mutex_unlock(&wa->rpipe_mutex); + d_fnend(2, dev, "(wa %p ep %p)\n", wa, ep); + return; } EXPORT_SYMBOL_GPL(rpipe_ep_disable); diff --git a/trunk/drivers/usb/wusbcore/wa-xfer.c b/trunk/drivers/usb/wusbcore/wa-xfer.c index 238a96aee3a1..c038635d1c64 100644 --- a/trunk/drivers/usb/wusbcore/wa-xfer.c +++ b/trunk/drivers/usb/wusbcore/wa-xfer.c @@ -82,10 +82,13 @@ #include #include #include - #include "wa-hc.h" #include "wusbhc.h" +#undef D_LOCAL +#define D_LOCAL 0 /* 0 disabled, > 0 different levels... */ +#include + enum { WA_SEGS_MAX = 255, }; @@ -177,6 +180,7 @@ static void wa_xfer_destroy(struct kref *_xfer) } } kfree(xfer); + d_printf(2, NULL, "xfer %p destroyed\n", xfer); } static void wa_xfer_get(struct wa_xfer *xfer) @@ -186,7 +190,10 @@ static void wa_xfer_get(struct wa_xfer *xfer) static void wa_xfer_put(struct wa_xfer *xfer) { + d_fnstart(3, NULL, "(xfer %p) -- ref count bef put %d\n", + xfer, atomic_read(&xfer->refcnt.refcount)); kref_put(&xfer->refcnt, wa_xfer_destroy); + d_fnend(3, NULL, "(xfer %p) = void\n", xfer); } /* @@ -202,7 +209,7 @@ static void wa_xfer_put(struct wa_xfer *xfer) static void wa_xfer_giveback(struct wa_xfer *xfer) { unsigned long flags; - + d_fnstart(3, NULL, "(xfer %p)\n", xfer); spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags); list_del_init(&xfer->list_node); spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags); @@ -210,6 +217,7 @@ static void wa_xfer_giveback(struct wa_xfer *xfer) wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result); wa_put(xfer->wa); wa_xfer_put(xfer); + d_fnend(3, NULL, "(xfer %p) = void\n", xfer); } /* @@ -219,10 +227,13 @@ static void wa_xfer_giveback(struct wa_xfer *xfer) */ static void wa_xfer_completion(struct wa_xfer *xfer) { + d_fnstart(3, NULL, "(xfer %p)\n", xfer); if (xfer->wusb_dev) wusb_dev_put(xfer->wusb_dev); rpipe_put(xfer->ep->hcpriv); wa_xfer_giveback(xfer); + d_fnend(3, NULL, "(xfer %p) = void\n", xfer); + return; } /* @@ -232,12 +243,12 @@ static void wa_xfer_completion(struct wa_xfer *xfer) */ static unsigned __wa_xfer_is_done(struct wa_xfer *xfer) { - struct device *dev = &xfer->wa->usb_iface->dev; unsigned result, cnt; struct wa_seg *seg; struct urb *urb = xfer->urb; unsigned found_short = 0; + d_fnstart(3, NULL, "(xfer %p)\n", xfer); result = xfer->segs_done == xfer->segs_submitted; if (result == 0) goto out; @@ -247,8 +258,10 @@ static unsigned __wa_xfer_is_done(struct wa_xfer *xfer) switch (seg->status) { case WA_SEG_DONE: if (found_short && seg->result > 0) { - dev_dbg(dev, "xfer %p#%u: bad short segments (%zu)\n", - xfer, cnt, seg->result); + if (printk_ratelimit()) + printk(KERN_ERR "xfer %p#%u: bad short " + "segments (%zu)\n", xfer, cnt, + seg->result); urb->status = -EINVAL; goto out; } @@ -256,30 +269,36 @@ static unsigned __wa_xfer_is_done(struct wa_xfer *xfer) if (seg->result < xfer->seg_size && cnt != xfer->segs-1) found_short = 1; - dev_dbg(dev, "xfer %p#%u: DONE short %d " - "result %zu urb->actual_length %d\n", - xfer, seg->index, found_short, seg->result, - urb->actual_length); + d_printf(2, NULL, "xfer %p#%u: DONE short %d " + "result %zu urb->actual_length %d\n", + xfer, seg->index, found_short, seg->result, + urb->actual_length); break; case WA_SEG_ERROR: xfer->result = seg->result; - dev_dbg(dev, "xfer %p#%u: ERROR result %zu\n", - xfer, seg->index, seg->result); + d_printf(2, NULL, "xfer %p#%u: ERROR result %zu\n", + xfer, seg->index, seg->result); goto out; case WA_SEG_ABORTED: - dev_dbg(dev, "xfer %p#%u ABORTED: result %d\n", - xfer, seg->index, urb->status); + WARN_ON(urb->status != -ECONNRESET + && urb->status != -ENOENT); + d_printf(2, NULL, "xfer %p#%u ABORTED: result %d\n", + xfer, seg->index, urb->status); xfer->result = urb->status; goto out; default: - dev_warn(dev, "xfer %p#%u: is_done bad state %d\n", - xfer, cnt, seg->status); + /* if (printk_ratelimit()) */ + printk(KERN_ERR "xfer %p#%u: " + "is_done bad state %d\n", + xfer, cnt, seg->status); xfer->result = -EINVAL; + WARN_ON(1); goto out; } } xfer->result = 0; out: + d_fnend(3, NULL, "(xfer %p) = void\n", xfer); return result; } @@ -405,6 +424,8 @@ static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer, struct urb *urb = xfer->urb; struct wa_rpipe *rpipe = xfer->ep->hcpriv; + d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n", + xfer, rpipe, urb); switch (rpipe->descr.bmAttribute & 0x3) { case USB_ENDPOINT_XFER_CONTROL: *pxfer_type = WA_XFER_TYPE_CTL; @@ -451,10 +472,12 @@ static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer, if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL) xfer->segs = 1; error: + d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n", + xfer, rpipe, urb, (int)result); return result; } -/* Fill in the common request header and xfer-type specific data. */ +/** Fill in the common request header and xfer-type specific data. */ static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer, struct wa_xfer_hdr *xfer_hdr0, enum wa_xfer_type xfer_type, @@ -511,13 +534,14 @@ static void wa_seg_dto_cb(struct urb *urb) unsigned rpipe_ready = 0; u8 done = 0; + d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); switch (urb->status) { case 0: spin_lock_irqsave(&xfer->lock, flags); wa = xfer->wa; dev = &wa->usb_iface->dev; - dev_dbg(dev, "xfer %p#%u: data out done (%d bytes)\n", - xfer, seg->index, urb->actual_length); + d_printf(2, dev, "xfer %p#%u: data out done (%d bytes)\n", + xfer, seg->index, urb->actual_length); if (seg->status < WA_SEG_PENDING) seg->status = WA_SEG_PENDING; seg->result = urb->actual_length; @@ -531,8 +555,9 @@ static void wa_seg_dto_cb(struct urb *urb) wa = xfer->wa; dev = &wa->usb_iface->dev; rpipe = xfer->ep->hcpriv; - dev_dbg(dev, "xfer %p#%u: data out error %d\n", - xfer, seg->index, urb->status); + if (printk_ratelimit()) + dev_err(dev, "xfer %p#%u: data out error %d\n", + xfer, seg->index, urb->status); if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)){ dev_err(dev, "DTO: URB max acceptable errors " @@ -553,6 +578,7 @@ static void wa_seg_dto_cb(struct urb *urb) if (rpipe_ready) wa_xfer_delayed_run(rpipe); } + d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); } /* @@ -584,12 +610,14 @@ static void wa_seg_cb(struct urb *urb) unsigned rpipe_ready; u8 done = 0; + d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); switch (urb->status) { case 0: spin_lock_irqsave(&xfer->lock, flags); wa = xfer->wa; dev = &wa->usb_iface->dev; - dev_dbg(dev, "xfer %p#%u: request done\n", xfer, seg->index); + d_printf(2, dev, "xfer %p#%u: request done\n", + xfer, seg->index); if (xfer->is_inbound && seg->status < WA_SEG_PENDING) seg->status = WA_SEG_PENDING; spin_unlock_irqrestore(&xfer->lock, flags); @@ -624,6 +652,7 @@ static void wa_seg_cb(struct urb *urb) if (rpipe_ready) wa_xfer_delayed_run(rpipe); } + d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); } /* @@ -721,6 +750,9 @@ static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb) size_t xfer_hdr_size, cnt, transfer_size; struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr; + d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n", + xfer, xfer->ep->hcpriv, urb); + result = __wa_xfer_setup_sizes(xfer, &xfer_type); if (result < 0) goto error_setup_sizes; @@ -756,6 +788,8 @@ static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb) result = 0; error_setup_segs: error_setup_sizes: + d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n", + xfer, xfer->ep->hcpriv, urb, result); return result; } @@ -809,6 +843,9 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) struct wa_xfer *xfer; unsigned long flags; + d_fnstart(1, dev, "(rpipe #%d) %d segments available\n", + le16_to_cpu(rpipe->descr.wRPipeIndex), + atomic_read(&rpipe->segs_available)); spin_lock_irqsave(&rpipe->seg_lock, flags); while (atomic_read(&rpipe->segs_available) > 0 && !list_empty(&rpipe->seg_list)) { @@ -817,8 +854,10 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) list_del(&seg->list_node); xfer = seg->xfer; result = __wa_seg_submit(rpipe, xfer, seg); - dev_dbg(dev, "xfer %p#%u submitted from delayed [%d segments available] %d\n", - xfer, seg->index, atomic_read(&rpipe->segs_available), result); + d_printf(1, dev, "xfer %p#%u submitted from delayed " + "[%d segments available] %d\n", + xfer, seg->index, + atomic_read(&rpipe->segs_available), result); if (unlikely(result < 0)) { spin_unlock_irqrestore(&rpipe->seg_lock, flags); spin_lock_irqsave(&xfer->lock, flags); @@ -829,6 +868,10 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) } } spin_unlock_irqrestore(&rpipe->seg_lock, flags); + d_fnend(1, dev, "(rpipe #%d) = void, %d segments available\n", + le16_to_cpu(rpipe->descr.wRPipeIndex), + atomic_read(&rpipe->segs_available)); + } /* @@ -851,6 +894,9 @@ static int __wa_xfer_submit(struct wa_xfer *xfer) u8 available; u8 empty; + d_fnstart(3, dev, "(xfer %p [rpipe %p])\n", + xfer, xfer->ep->hcpriv); + spin_lock_irqsave(&wa->xfer_list_lock, flags); list_add_tail(&xfer->list_node, &wa->xfer_list); spin_unlock_irqrestore(&wa->xfer_list_lock, flags); @@ -862,24 +908,30 @@ static int __wa_xfer_submit(struct wa_xfer *xfer) available = atomic_read(&rpipe->segs_available); empty = list_empty(&rpipe->seg_list); seg = xfer->seg[cnt]; - dev_dbg(dev, "xfer %p#%u: available %u empty %u (%s)\n", - xfer, cnt, available, empty, - available == 0 || !empty ? "delayed" : "submitted"); + d_printf(2, dev, "xfer %p#%u: available %u empty %u (%s)\n", + xfer, cnt, available, empty, + available == 0 || !empty ? "delayed" : "submitted"); if (available == 0 || !empty) { - dev_dbg(dev, "xfer %p#%u: delayed\n", xfer, cnt); + d_printf(1, dev, "xfer %p#%u: delayed\n", xfer, cnt); seg->status = WA_SEG_DELAYED; list_add_tail(&seg->list_node, &rpipe->seg_list); } else { result = __wa_seg_submit(rpipe, xfer, seg); - if (result < 0) { - __wa_xfer_abort(xfer); + if (result < 0) goto error_seg_submit; - } } xfer->segs_submitted++; } + spin_unlock_irqrestore(&rpipe->seg_lock, flags); + d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer, + xfer->ep->hcpriv); + return result; + error_seg_submit: + __wa_xfer_abort(xfer); spin_unlock_irqrestore(&rpipe->seg_lock, flags); + d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer, + xfer->ep->hcpriv); return result; } @@ -912,9 +964,11 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer) struct urb *urb = xfer->urb; struct wahc *wa = xfer->wa; struct wusbhc *wusbhc = wa->wusb; + struct device *dev = &wa->usb_iface->dev; struct wusb_dev *wusb_dev; unsigned done; + d_fnstart(3, dev, "(wa %p urb %p)\n", wa, urb); result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp); if (result < 0) goto error_rpipe_get; @@ -943,6 +997,7 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer) if (result < 0) goto error_xfer_submit; spin_unlock_irqrestore(&xfer->lock, flags); + d_fnend(3, dev, "(wa %p urb %p) = void\n", wa, urb); return; /* this is basically wa_xfer_completion() broken up wa_xfer_giveback() @@ -960,6 +1015,7 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer) error_rpipe_get: xfer->result = result; wa_xfer_giveback(xfer); + d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result); return; error_xfer_submit: @@ -968,6 +1024,8 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer) spin_unlock_irqrestore(&xfer->lock, flags); if (done) wa_xfer_completion(xfer); + d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result); + return; } /* @@ -983,9 +1041,11 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer) void wa_urb_enqueue_run(struct work_struct *ws) { struct wahc *wa = container_of(ws, struct wahc, xfer_work); + struct device *dev = &wa->usb_iface->dev; struct wa_xfer *xfer, *next; struct urb *urb; + d_fnstart(3, dev, "(wa %p)\n", wa); spin_lock_irq(&wa->xfer_list_lock); list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list, list_node) { @@ -999,6 +1059,7 @@ void wa_urb_enqueue_run(struct work_struct *ws) spin_lock_irq(&wa->xfer_list_lock); } spin_unlock_irq(&wa->xfer_list_lock); + d_fnend(3, dev, "(wa %p) = void\n", wa); } EXPORT_SYMBOL_GPL(wa_urb_enqueue_run); @@ -1023,6 +1084,9 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, unsigned long my_flags; unsigned cant_sleep = irqs_disabled() | in_atomic(); + d_fnstart(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x)\n", + wa, ep, urb, urb->transfer_buffer_length, gfp); + if (urb->transfer_buffer == NULL && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) && urb->transfer_buffer_length != 0) { @@ -1044,13 +1108,11 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, xfer->gfp = gfp; xfer->ep = ep; urb->hcpriv = xfer; - - dev_dbg(dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n", - xfer, urb, urb->pipe, urb->transfer_buffer_length, - urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma", - urb->pipe & USB_DIR_IN ? "inbound" : "outbound", - cant_sleep ? "deferred" : "inline"); - + d_printf(2, dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n", + xfer, urb, urb->pipe, urb->transfer_buffer_length, + urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma", + urb->pipe & USB_DIR_IN ? "inbound" : "outbound", + cant_sleep ? "deferred" : "inline"); if (cant_sleep) { usb_get_urb(urb); spin_lock_irqsave(&wa->xfer_list_lock, my_flags); @@ -1060,11 +1122,15 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, } else { wa_urb_enqueue_b(xfer); } + d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = 0\n", + wa, ep, urb, urb->transfer_buffer_length, gfp); return 0; error_dequeued: kfree(xfer); error_kmalloc: + d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = %d\n", + wa, ep, urb, urb->transfer_buffer_length, gfp, result); return result; } EXPORT_SYMBOL_GPL(wa_urb_enqueue); @@ -1089,6 +1155,7 @@ EXPORT_SYMBOL_GPL(wa_urb_enqueue); */ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) { + struct device *dev = &wa->usb_iface->dev; unsigned long flags, flags2; struct wa_xfer *xfer; struct wa_seg *seg; @@ -1096,6 +1163,9 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) unsigned cnt; unsigned rpipe_ready = 0; + d_fnstart(3, dev, "(wa %p, urb %p)\n", wa, urb); + + d_printf(1, dev, "xfer %p urb %p: aborting\n", urb->hcpriv, urb); xfer = urb->hcpriv; if (xfer == NULL) { /* NOthing setup yet enqueue will see urb->status != @@ -1164,11 +1234,13 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) wa_xfer_completion(xfer); if (rpipe_ready) wa_xfer_delayed_run(rpipe); + d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); return 0; out_unlock: spin_unlock_irqrestore(&xfer->lock, flags); out: + d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); return 0; dequeue_delayed: @@ -1178,6 +1250,7 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) spin_unlock_irqrestore(&xfer->lock, flags); wa_xfer_giveback(xfer); usb_put_urb(urb); /* we got a ref in enqueue() */ + d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); return 0; } EXPORT_SYMBOL_GPL(wa_urb_dequeue); @@ -1253,6 +1326,7 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) u8 usb_status; unsigned rpipe_ready = 0; + d_fnstart(3, dev, "(wa %p xfer %p)\n", wa, xfer); spin_lock_irqsave(&xfer->lock, flags); seg_idx = xfer_result->bTransferSegment & 0x7f; if (unlikely(seg_idx >= xfer->segs)) @@ -1260,8 +1334,8 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) seg = xfer->seg[seg_idx]; rpipe = xfer->ep->hcpriv; usb_status = xfer_result->bTransferStatus; - dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n", - xfer, seg_idx, usb_status, seg->status); + d_printf(2, dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n", + xfer, seg_idx, usb_status, seg->status); if (seg->status == WA_SEG_ABORTED || seg->status == WA_SEG_ERROR) /* already handled */ goto segment_aborted; @@ -1317,8 +1391,10 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) wa_xfer_completion(xfer); if (rpipe_ready) wa_xfer_delayed_run(rpipe); + d_fnend(3, dev, "(wa %p xfer %p) = void\n", wa, xfer); return; + error_submit_buf_in: if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { dev_err(dev, "DTI: URB max acceptable errors " @@ -1340,8 +1416,11 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) wa_xfer_completion(xfer); if (rpipe_ready) wa_xfer_delayed_run(rpipe); + d_fnend(3, dev, "(wa %p xfer %p) = void [segment/DTI-submit error]\n", + wa, xfer); return; + error_bad_seg: spin_unlock_irqrestore(&xfer->lock, flags); wa_urb_dequeue(wa, xfer->urb); @@ -1352,11 +1431,17 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) "exceeded, resetting device\n"); wa_reset_all(wa); } + d_fnend(3, dev, "(wa %p xfer %p) = void [bad seg]\n", wa, xfer); return; + segment_aborted: /* nothing to do, as the aborter did the completion */ spin_unlock_irqrestore(&xfer->lock, flags); + d_fnend(3, dev, "(wa %p xfer %p) = void [segment aborted]\n", + wa, xfer); + return; + } /* @@ -1380,14 +1465,15 @@ static void wa_buf_in_cb(struct urb *urb) unsigned long flags; u8 done = 0; + d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); switch (urb->status) { case 0: spin_lock_irqsave(&xfer->lock, flags); wa = xfer->wa; dev = &wa->usb_iface->dev; rpipe = xfer->ep->hcpriv; - dev_dbg(dev, "xfer %p#%u: data in done (%zu bytes)\n", - xfer, seg->index, (size_t)urb->actual_length); + d_printf(2, dev, "xfer %p#%u: data in done (%zu bytes)\n", + xfer, seg->index, (size_t)urb->actual_length); seg->status = WA_SEG_DONE; seg->result = urb->actual_length; xfer->segs_done++; @@ -1428,6 +1514,7 @@ static void wa_buf_in_cb(struct urb *urb) if (rpipe_ready) wa_xfer_delayed_run(rpipe); } + d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); } /* @@ -1466,12 +1553,14 @@ static void wa_xfer_result_cb(struct urb *urb) struct wa_xfer *xfer; u8 usb_status; + d_fnstart(3, dev, "(%p)\n", wa); BUG_ON(wa->dti_urb != urb); switch (wa->dti_urb->status) { case 0: /* We have a xfer result buffer; check it */ - dev_dbg(dev, "DTI: xfer result %d bytes at %p\n", - urb->actual_length, urb->transfer_buffer); + d_printf(2, dev, "DTI: xfer result %d bytes at %p\n", + urb->actual_length, urb->transfer_buffer); + d_dump(3, dev, urb->transfer_buffer, urb->actual_length); if (wa->dti_urb->actual_length != sizeof(*xfer_result)) { dev_err(dev, "DTI Error: xfer result--bad size " "xfer result (%d bytes vs %zu needed)\n", @@ -1533,6 +1622,7 @@ static void wa_xfer_result_cb(struct urb *urb) wa_reset_all(wa); } out: + d_fnend(3, dev, "(%p) = void\n", wa); return; } @@ -1563,6 +1653,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) struct wa_notif_xfer *notif_xfer; const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; + d_fnstart(4, dev, "(%p, %p)\n", wa, notif_hdr); notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr); BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER); @@ -1602,6 +1693,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) goto error_dti_urb_submit; } out: + d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr); return; error_dti_urb_submit: @@ -1612,4 +1704,6 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) error_dti_urb_alloc: error: wa_reset_all(wa); + d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr); + return; } diff --git a/trunk/drivers/usb/wusbcore/wusbhc.h b/trunk/drivers/usb/wusbcore/wusbhc.h index 797c2453a35b..d0c132434f1b 100644 --- a/trunk/drivers/usb/wusbcore/wusbhc.h +++ b/trunk/drivers/usb/wusbcore/wusbhc.h @@ -64,13 +64,6 @@ #include #include -/* - * Time from a WUSB channel stop request to the last transmitted MMC. - * - * This needs to be > 4.096 ms in case no MMCs can be transmitted in - * zone 0. - */ -#define WUSB_CHANNEL_STOP_DELAY_MS 8 /** * Wireless USB device @@ -154,6 +147,7 @@ struct wusb_port { u16 status; u16 change; struct wusb_dev *wusb_dev; /* connected device's info */ + unsigned reset_count; u32 ptk_tkid; }; @@ -204,18 +198,21 @@ struct wusb_port { * @mmcies_max Max number of Information Elements this HC can send * in its MMC. Read-only. * - * @start Start the WUSB channel. - * - * @stop Stop the WUSB channel after the specified number of - * milliseconds. Channel Stop IEs should be transmitted - * as required by [WUSB] 4.16.2.1. - * * @mmcie_add HC specific operation (WHCI or HWA) for adding an * MMCIE. * * @mmcie_rm HC specific operation (WHCI or HWA) for removing an * MMCIE. * + * @enc_types Array which describes the encryptions methods + * supported by the host as described in WUSB1.0 -- + * one entry per supported method. As of WUSB1.0 there + * is only four methods, we make space for eight just in + * case they decide to add some more (and pray they do + * it in sequential order). if 'enc_types[enc_method] + * != 0', then it is supported by the host. enc_method + * is USB_ENC_TYPE*. + * * @set_ptk: Set the PTK and enable encryption for a device. Or, if * the supplied key is NULL, disable encryption for that * device. @@ -252,8 +249,7 @@ struct wusbhc { struct uwb_pal pal; unsigned trust_timeout; /* in jiffies */ - struct wusb_ckhdid chid; - struct wuie_host_info *wuie_host_info; + struct wuie_host_info *wuie_host_info; /* Includes CHID */ struct mutex mutex; /* locks everything else */ u16 cluster_id; /* Wireless USB Cluster ID */ @@ -273,7 +269,7 @@ struct wusbhc { u8 mmcies_max; /* FIXME: make wusbhc_ops? */ int (*start)(struct wusbhc *wusbhc); - void (*stop)(struct wusbhc *wusbhc, int delay); + void (*stop)(struct wusbhc *wusbhc); int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, u8 handle, struct wuie_hdr *wuie); int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle); @@ -377,17 +373,20 @@ static inline void wusbhc_put(struct wusbhc *wusbhc) usb_put_hcd(&wusbhc->usb_hcd); } -int wusbhc_start(struct wusbhc *wusbhc); +int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid); void wusbhc_stop(struct wusbhc *wusbhc); extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *); /* Device connect handling */ extern int wusbhc_devconnect_create(struct wusbhc *); extern void wusbhc_devconnect_destroy(struct wusbhc *); -extern int wusbhc_devconnect_start(struct wusbhc *wusbhc); +extern int wusbhc_devconnect_start(struct wusbhc *wusbhc, + const struct wusb_ckhdid *chid); extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc); +extern int wusbhc_devconnect_auth(struct wusbhc *, u8); extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr, struct wusb_dn_hdr *dn_hdr, size_t size); +extern int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port); extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port); extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, void *priv); @@ -433,7 +432,6 @@ extern void wusb_dev_sec_rm(struct wusb_dev *) ; extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *, struct wusb_ckhdid *ck); void wusbhc_gtk_rekey(struct wusbhc *wusbhc); -int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev); /* WUSB Cluster ID handling */ diff --git a/trunk/drivers/uwb/Makefile b/trunk/drivers/uwb/Makefile index 2f98d080fe78..257e6908304c 100644 --- a/trunk/drivers/uwb/Makefile +++ b/trunk/drivers/uwb/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_UWB_I1480U) += i1480/ uwb-objs := \ address.o \ - allocator.o \ beacon.o \ driver.o \ drp.o \ @@ -14,12 +13,10 @@ uwb-objs := \ drp-ie.o \ est.o \ ie.o \ - ie-rcv.o \ lc-dev.o \ lc-rc.o \ neh.o \ pal.o \ - radio.o \ reset.o \ rsv.o \ scan.o \ diff --git a/trunk/drivers/uwb/address.c b/trunk/drivers/uwb/address.c index ad21b1d7218c..1664ae5f1706 100644 --- a/trunk/drivers/uwb/address.c +++ b/trunk/drivers/uwb/address.c @@ -28,7 +28,7 @@ #include #include #include - +#include #include "uwb-internal.h" diff --git a/trunk/drivers/uwb/allocator.c b/trunk/drivers/uwb/allocator.c deleted file mode 100644 index c8185e6b0cd5..000000000000 --- a/trunk/drivers/uwb/allocator.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * UWB reservation management. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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, see . - */ -#include -#include -#include - -#include "uwb-internal.h" - -static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info *ai) -{ - int col, mas, safe_mas, unsafe_mas; - unsigned char *bm = ai->bm; - struct uwb_rsv_col_info *ci = ai->ci; - unsigned char c; - - for (col = ci->csi.start_col; col < UWB_NUM_ZONES; col += ci->csi.interval) { - - safe_mas = ci->csi.safe_mas_per_col; - unsafe_mas = ci->csi.unsafe_mas_per_col; - - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++ ) { - if (bm[col * UWB_MAS_PER_ZONE + mas] == 0) { - - if (safe_mas > 0) { - safe_mas--; - c = UWB_RSV_MAS_SAFE; - } else if (unsafe_mas > 0) { - unsafe_mas--; - c = UWB_RSV_MAS_UNSAFE; - } else { - break; - } - bm[col * UWB_MAS_PER_ZONE + mas] = c; - } - } - } -} - -static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info *ai) -{ - int mas, col, rows; - unsigned char *bm = ai->bm; - struct uwb_rsv_row_info *ri = &ai->ri; - unsigned char c; - - rows = 1; - c = UWB_RSV_MAS_SAFE; - for (mas = UWB_MAS_PER_ZONE - 1; mas >= 0; mas--) { - if (ri->avail[mas] == 1) { - - if (rows > ri->used_rows) { - break; - } else if (rows > 7) { - c = UWB_RSV_MAS_UNSAFE; - } - - for (col = 0; col < UWB_NUM_ZONES; col++) { - if (bm[col * UWB_NUM_ZONES + mas] != UWB_RSV_MAS_NOT_AVAIL) { - bm[col * UWB_NUM_ZONES + mas] = c; - if(c == UWB_RSV_MAS_SAFE) - ai->safe_allocated_mases++; - else - ai->unsafe_allocated_mases++; - } - } - rows++; - } - } - ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases; -} - -/* - * Find the best column set for a given availability, interval, num safe mas and - * num unsafe mas. - * - * The different sets are tried in order as shown below, depending on the interval. - * - * interval = 16 - * deep = 0 - * set 1 -> { 8 } - * deep = 1 - * set 1 -> { 4 } - * set 2 -> { 12 } - * deep = 2 - * set 1 -> { 2 } - * set 2 -> { 6 } - * set 3 -> { 10 } - * set 4 -> { 14 } - * deep = 3 - * set 1 -> { 1 } - * set 2 -> { 3 } - * set 3 -> { 5 } - * set 4 -> { 7 } - * set 5 -> { 9 } - * set 6 -> { 11 } - * set 7 -> { 13 } - * set 8 -> { 15 } - * - * interval = 8 - * deep = 0 - * set 1 -> { 4 12 } - * deep = 1 - * set 1 -> { 2 10 } - * set 2 -> { 6 14 } - * deep = 2 - * set 1 -> { 1 9 } - * set 2 -> { 3 11 } - * set 3 -> { 5 13 } - * set 4 -> { 7 15 } - * - * interval = 4 - * deep = 0 - * set 1 -> { 2 6 10 14 } - * deep = 1 - * set 1 -> { 1 5 9 13 } - * set 2 -> { 3 7 11 15 } - * - * interval = 2 - * deep = 0 - * set 1 -> { 1 3 5 7 9 11 13 15 } - */ -static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info *ai, int interval, - int num_safe_mas, int num_unsafe_mas) -{ - struct uwb_rsv_col_info *ci = ai->ci; - struct uwb_rsv_col_set_info *csi = &ci->csi; - struct uwb_rsv_col_set_info tmp_csi; - int deep, set, col, start_col_deep, col_start_set; - int start_col, max_mas_in_set, lowest_max_mas_in_deep; - int n_mas; - int found = UWB_RSV_ALLOC_NOT_FOUND; - - tmp_csi.start_col = 0; - start_col_deep = interval; - n_mas = num_unsafe_mas + num_safe_mas; - - for (deep = 0; ((interval >> deep) & 0x1) == 0; deep++) { - start_col_deep /= 2; - col_start_set = 0; - lowest_max_mas_in_deep = UWB_MAS_PER_ZONE; - - for (set = 1; set <= (1 << deep); set++) { - max_mas_in_set = 0; - start_col = start_col_deep + col_start_set; - for (col = start_col; col < UWB_NUM_ZONES; col += interval) { - - if (ci[col].max_avail_safe >= num_safe_mas && - ci[col].max_avail_unsafe >= n_mas) { - if (ci[col].highest_mas[n_mas] > max_mas_in_set) - max_mas_in_set = ci[col].highest_mas[n_mas]; - } else { - max_mas_in_set = 0; - break; - } - } - if ((lowest_max_mas_in_deep > max_mas_in_set) && max_mas_in_set) { - lowest_max_mas_in_deep = max_mas_in_set; - - tmp_csi.start_col = start_col; - } - col_start_set += (interval >> deep); - } - - if (lowest_max_mas_in_deep < 8) { - csi->start_col = tmp_csi.start_col; - found = UWB_RSV_ALLOC_FOUND; - break; - } else if ((lowest_max_mas_in_deep > 8) && - (lowest_max_mas_in_deep != UWB_MAS_PER_ZONE) && - (found == UWB_RSV_ALLOC_NOT_FOUND)) { - csi->start_col = tmp_csi.start_col; - found = UWB_RSV_ALLOC_FOUND; - } - } - - if (found == UWB_RSV_ALLOC_FOUND) { - csi->interval = interval; - csi->safe_mas_per_col = num_safe_mas; - csi->unsafe_mas_per_col = num_unsafe_mas; - - ai->safe_allocated_mases = (UWB_NUM_ZONES / interval) * num_safe_mas; - ai->unsafe_allocated_mases = (UWB_NUM_ZONES / interval) * num_unsafe_mas; - ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases; - ai->interval = interval; - } - return found; -} - -static void get_row_descriptors(struct uwb_rsv_alloc_info *ai) -{ - unsigned char *bm = ai->bm; - struct uwb_rsv_row_info *ri = &ai->ri; - int col, mas; - - ri->free_rows = 16; - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) { - ri->avail[mas] = 1; - for (col = 1; col < UWB_NUM_ZONES; col++) { - if (bm[col * UWB_NUM_ZONES + mas] == UWB_RSV_MAS_NOT_AVAIL) { - ri->free_rows--; - ri->avail[mas]=0; - break; - } - } - } -} - -static void uwb_rsv_fill_column_info(unsigned char *bm, int column, struct uwb_rsv_col_info *rci) -{ - int mas; - int block_count = 0, start_block = 0; - int previous_avail = 0; - int available = 0; - int safe_mas_in_row[UWB_MAS_PER_ZONE] = { - 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, - }; - - rci->max_avail_safe = 0; - - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) { - if (!bm[column * UWB_NUM_ZONES + mas]) { - available++; - rci->max_avail_unsafe = available; - - rci->highest_mas[available] = mas; - - if (previous_avail) { - block_count++; - if ((block_count > safe_mas_in_row[start_block]) && - (!rci->max_avail_safe)) - rci->max_avail_safe = available - 1; - } else { - previous_avail = 1; - start_block = mas; - block_count = 1; - } - } else { - previous_avail = 0; - } - } - if (!rci->max_avail_safe) - rci->max_avail_safe = rci->max_avail_unsafe; -} - -static void get_column_descriptors(struct uwb_rsv_alloc_info *ai) -{ - unsigned char *bm = ai->bm; - struct uwb_rsv_col_info *ci = ai->ci; - int col; - - for (col = 1; col < UWB_NUM_ZONES; col++) { - uwb_rsv_fill_column_info(bm, col, &ci[col]); - } -} - -static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info *ai) -{ - int n_rows; - int max_rows = ai->max_mas / UWB_USABLE_MAS_PER_ROW; - int min_rows = ai->min_mas / UWB_USABLE_MAS_PER_ROW; - if (ai->min_mas % UWB_USABLE_MAS_PER_ROW) - min_rows++; - for (n_rows = max_rows; n_rows >= min_rows; n_rows--) { - if (n_rows <= ai->ri.free_rows) { - ai->ri.used_rows = n_rows; - ai->interval = 1; /* row reservation */ - uwb_rsv_fill_row_alloc(ai); - return UWB_RSV_ALLOC_FOUND; - } - } - return UWB_RSV_ALLOC_NOT_FOUND; -} - -static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info *ai, int interval) -{ - int n_safe, n_unsafe, n_mas; - int n_column = UWB_NUM_ZONES / interval; - int max_per_zone = ai->max_mas / n_column; - int min_per_zone = ai->min_mas / n_column; - - if (ai->min_mas % n_column) - min_per_zone++; - - if (min_per_zone > UWB_MAS_PER_ZONE) { - return UWB_RSV_ALLOC_NOT_FOUND; - } - - if (max_per_zone > UWB_MAS_PER_ZONE) { - max_per_zone = UWB_MAS_PER_ZONE; - } - - for (n_mas = max_per_zone; n_mas >= min_per_zone; n_mas--) { - if (uwb_rsv_find_best_column_set(ai, interval, 0, n_mas) == UWB_RSV_ALLOC_NOT_FOUND) - continue; - for (n_safe = n_mas; n_safe >= 0; n_safe--) { - n_unsafe = n_mas - n_safe; - if (uwb_rsv_find_best_column_set(ai, interval, n_safe, n_unsafe) == UWB_RSV_ALLOC_FOUND) { - uwb_rsv_fill_column_alloc(ai); - return UWB_RSV_ALLOC_FOUND; - } - } - } - return UWB_RSV_ALLOC_NOT_FOUND; -} - -int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available, - struct uwb_mas_bm *result) -{ - struct uwb_rsv_alloc_info *ai; - int interval; - int bit_index; - - ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL); - - ai->min_mas = rsv->min_mas; - ai->max_mas = rsv->max_mas; - ai->max_interval = rsv->max_interval; - - - /* fill the not available vector from the available bm */ - for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) { - if (!test_bit(bit_index, available->bm)) - ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL; - } - - if (ai->max_interval == 1) { - get_row_descriptors(ai); - if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND) - goto alloc_found; - else - goto alloc_not_found; - } - - get_column_descriptors(ai); - - for (interval = 16; interval >= 2; interval>>=1) { - if (interval > ai->max_interval) - continue; - if (uwb_rsv_find_best_col_alloc(ai, interval) == UWB_RSV_ALLOC_FOUND) - goto alloc_found; - } - - /* try row reservation if no column is found */ - get_row_descriptors(ai); - if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND) - goto alloc_found; - else - goto alloc_not_found; - - alloc_found: - bitmap_zero(result->bm, UWB_NUM_MAS); - bitmap_zero(result->unsafe_bm, UWB_NUM_MAS); - /* fill the safe and unsafe bitmaps */ - for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) { - if (ai->bm[bit_index] == UWB_RSV_MAS_SAFE) - set_bit(bit_index, result->bm); - else if (ai->bm[bit_index] == UWB_RSV_MAS_UNSAFE) - set_bit(bit_index, result->unsafe_bm); - } - bitmap_or(result->bm, result->bm, result->unsafe_bm, UWB_NUM_MAS); - - result->safe = ai->safe_allocated_mases; - result->unsafe = ai->unsafe_allocated_mases; - - kfree(ai); - return UWB_RSV_ALLOC_FOUND; - - alloc_not_found: - kfree(ai); - return UWB_RSV_ALLOC_NOT_FOUND; -} diff --git a/trunk/drivers/uwb/beacon.c b/trunk/drivers/uwb/beacon.c index 36bc3158006f..46b18eec5026 100644 --- a/trunk/drivers/uwb/beacon.c +++ b/trunk/drivers/uwb/beacon.c @@ -22,16 +22,19 @@ * * FIXME: docs */ + #include #include #include #include #include #include - #include "uwb-internal.h" -/* Start Beaconing command structure */ +#define D_LOCAL 0 +#include + +/** Start Beaconing command structure */ struct uwb_rc_cmd_start_beacon { struct uwb_rccb rccb; __le16 wBPSTOffset; @@ -116,6 +119,7 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset) int result; struct device *dev = &rc->uwb_dev.dev; + mutex_lock(&rc->uwb_dev.mutex); if (channel < 0) channel = -1; if (channel == -1) @@ -124,7 +128,7 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset) /* channel >= 0...dah */ result = uwb_rc_start_beacon(rc, bpst_offset, channel); if (result < 0) - return result; + goto out_up; if (le16_to_cpu(rc->ies->wIELength) > 0) { result = uwb_rc_set_ie(rc, rc->ies); if (result < 0) { @@ -133,12 +137,19 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset) result = uwb_rc_stop_beacon(rc); channel = -1; bpst_offset = 0; - } + } else + result = 0; } } - if (result >= 0) - rc->beaconing = channel; + if (result < 0) + goto out_up; + rc->beaconing = channel; + + uwb_notify(rc, NULL, uwb_bg_joined(rc) ? UWB_NOTIF_BG_JOIN : UWB_NOTIF_BG_LEAVE); + +out_up: + mutex_unlock(&rc->uwb_dev.mutex); return result; } @@ -157,6 +168,12 @@ int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset) * FIXME: use something faster for search than a list */ +struct uwb_beca uwb_beca = { + .list = LIST_HEAD_INIT(uwb_beca.list), + .mutex = __MUTEX_INITIALIZER(uwb_beca.mutex) +}; + + void uwb_bce_kfree(struct kref *_bce) { struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt); @@ -168,11 +185,13 @@ void uwb_bce_kfree(struct kref *_bce) /* Find a beacon by dev addr in the cache */ static -struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc, - const struct uwb_dev_addr *dev_addr) +struct uwb_beca_e *__uwb_beca_find_bydev(const struct uwb_dev_addr *dev_addr) { struct uwb_beca_e *bce, *next; - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { + list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { + d_printf(6, NULL, "looking for addr %02x:%02x in %02x:%02x\n", + dev_addr->data[0], dev_addr->data[1], + bce->dev_addr.data[0], bce->dev_addr.data[1]); if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr))) goto out; } @@ -183,11 +202,10 @@ struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc, /* Find a beacon by dev addr in the cache */ static -struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc, - const struct uwb_mac_addr *mac_addr) +struct uwb_beca_e *__uwb_beca_find_bymac(const struct uwb_mac_addr *mac_addr) { struct uwb_beca_e *bce, *next; - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { + list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { if (!memcmp(bce->mac_addr, mac_addr->data, sizeof(struct uwb_mac_addr))) goto out; @@ -211,11 +229,11 @@ struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, struct uwb_dev *found = NULL; struct uwb_beca_e *bce; - mutex_lock(&rc->uwb_beca.mutex); - bce = __uwb_beca_find_bydev(rc, devaddr); + mutex_lock(&uwb_beca.mutex); + bce = __uwb_beca_find_bydev(devaddr); if (bce) found = uwb_dev_try_get(rc, bce->uwb_dev); - mutex_unlock(&rc->uwb_beca.mutex); + mutex_unlock(&uwb_beca.mutex); return found; } @@ -231,11 +249,11 @@ struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, struct uwb_dev *found = NULL; struct uwb_beca_e *bce; - mutex_lock(&rc->uwb_beca.mutex); - bce = __uwb_beca_find_bymac(rc, macaddr); + mutex_lock(&uwb_beca.mutex); + bce = __uwb_beca_find_bymac(macaddr); if (bce) found = uwb_dev_try_get(rc, bce->uwb_dev); - mutex_unlock(&rc->uwb_beca.mutex); + mutex_unlock(&uwb_beca.mutex); return found; } @@ -256,9 +274,7 @@ static void uwb_beca_e_init(struct uwb_beca_e *bce) * @bf: Beacon frame (part of b, really) * @ts_jiffies: Timestamp (in jiffies) when the beacon was received */ -static -struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc, - struct uwb_rc_evt_beacon *be, +struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *be, struct uwb_beacon_frame *bf, unsigned long ts_jiffies) { @@ -270,7 +286,7 @@ struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc, uwb_beca_e_init(bce); bce->ts_jiffies = ts_jiffies; bce->uwb_dev = NULL; - list_add(&bce->node, &rc->uwb_beca.list); + list_add(&bce->node, &uwb_beca.list); return bce; } @@ -279,32 +295,33 @@ struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc, * * Remove associated devicest too. */ -void uwb_beca_purge(struct uwb_rc *rc) +void uwb_beca_purge(void) { struct uwb_beca_e *bce, *next; unsigned long expires; - mutex_lock(&rc->uwb_beca.mutex); - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { + mutex_lock(&uwb_beca.mutex); + list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms); if (time_after(jiffies, expires)) { uwbd_dev_offair(bce); + list_del(&bce->node); + uwb_bce_put(bce); } } - mutex_unlock(&rc->uwb_beca.mutex); + mutex_unlock(&uwb_beca.mutex); } /* Clean up the whole beacon cache. Called on shutdown */ -void uwb_beca_release(struct uwb_rc *rc) +void uwb_beca_release(void) { struct uwb_beca_e *bce, *next; - - mutex_lock(&rc->uwb_beca.mutex); - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { + mutex_lock(&uwb_beca.mutex); + list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { list_del(&bce->node); uwb_bce_put(bce); } - mutex_unlock(&rc->uwb_beca.mutex); + mutex_unlock(&uwb_beca.mutex); } static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be, @@ -332,22 +349,22 @@ ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce, ssize_t result = 0; struct uwb_rc_evt_beacon *be; struct uwb_beacon_frame *bf; - int ies_len; - struct uwb_ie_hdr *ies; + struct uwb_buf_ctx ctx = { + .buf = buf, + .bytes = 0, + .size = size + }; mutex_lock(&bce->mutex); - be = bce->be; - if (be) { - bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo; - ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame); - ies = (struct uwb_ie_hdr *)bf->IEData; - - result = uwb_ie_dump_hex(ies, ies_len, buf, size); - } - + if (be == NULL) + goto out; + bf = (void *) be->BeaconInfo; + uwb_ie_for_each(uwb_dev, uwb_ie_dump_hex, &ctx, + bf->IEData, be->wBeaconInfoLength - sizeof(*bf)); + result = ctx.bytes; +out: mutex_unlock(&bce->mutex); - return result; } @@ -420,18 +437,18 @@ int uwbd_evt_handle_rc_beacon(struct uwb_event *evt) if (uwb_mac_addr_bcast(&bf->Device_Identifier)) return 0; - mutex_lock(&rc->uwb_beca.mutex); - bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier); + mutex_lock(&uwb_beca.mutex); + bce = __uwb_beca_find_bymac(&bf->Device_Identifier); if (bce == NULL) { /* Not in there, a new device is pinging */ uwb_beacon_print(evt->rc, be, bf); - bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies); + bce = __uwb_beca_add(be, bf, evt->ts_jiffies); if (bce == NULL) { - mutex_unlock(&rc->uwb_beca.mutex); + mutex_unlock(&uwb_beca.mutex); return -ENOMEM; } } - mutex_unlock(&rc->uwb_beca.mutex); + mutex_unlock(&uwb_beca.mutex); mutex_lock(&bce->mutex); /* purge old beacon data */ @@ -571,6 +588,19 @@ int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt) return result; } +/** + * uwb_bg_joined - is the RC in a beacon group? + * @rc: the radio controller + * + * Returns true if the radio controller is in a beacon group (even if + * it's the sole member). + */ +int uwb_bg_joined(struct uwb_rc *rc) +{ + return rc->beaconing != -1; +} +EXPORT_SYMBOL_GPL(uwb_bg_joined); + /* * Print beaconing state. */ @@ -589,6 +619,9 @@ static ssize_t uwb_rc_beacon_show(struct device *dev, /* * Start beaconing on the specified channel, or stop beaconing. + * + * The BPST offset of when to start searching for a beacon group to + * join may be specified. */ static ssize_t uwb_rc_beacon_store(struct device *dev, struct device_attribute *attr, @@ -597,11 +630,12 @@ static ssize_t uwb_rc_beacon_store(struct device *dev, struct uwb_dev *uwb_dev = to_uwb_dev(dev); struct uwb_rc *rc = uwb_dev->rc; int channel; + unsigned bpst_offset = 0; ssize_t result = -EINVAL; - result = sscanf(buf, "%d", &channel); + result = sscanf(buf, "%d %u\n", &channel, &bpst_offset); if (result >= 1) - result = uwb_radio_force_channel(rc, channel); + result = uwb_rc_beacon(rc, channel, bpst_offset); return result < 0 ? result : size; } diff --git a/trunk/drivers/uwb/driver.c b/trunk/drivers/uwb/driver.c index da77e41de990..521cdeb84971 100644 --- a/trunk/drivers/uwb/driver.c +++ b/trunk/drivers/uwb/driver.c @@ -53,7 +53,7 @@ #include #include #include - +#include #include "uwb-internal.h" @@ -118,6 +118,7 @@ static int __init uwb_subsys_init(void) result = class_register(&uwb_rc_class); if (result < 0) goto error_uwb_rc_class_register; + uwbd_start(); uwb_dbg_init(); return 0; @@ -131,6 +132,7 @@ module_init(uwb_subsys_init); static void __exit uwb_subsys_exit(void) { uwb_dbg_exit(); + uwbd_stop(); class_unregister(&uwb_rc_class); uwb_est_destroy(); return; diff --git a/trunk/drivers/uwb/drp-avail.c b/trunk/drivers/uwb/drp-avail.c index 40a540a5a72e..3febd8552808 100644 --- a/trunk/drivers/uwb/drp-avail.c +++ b/trunk/drivers/uwb/drp-avail.c @@ -58,7 +58,7 @@ void uwb_drp_avail_init(struct uwb_rc *rc) * * avail = global & local & pending */ -void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail) +static void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail) { bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS); @@ -105,7 +105,6 @@ void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas) bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); rc->drp_avail.ie_valid = false; - uwb_rsv_handle_drp_avail_change(rc); } /** @@ -281,7 +280,6 @@ int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt) mutex_lock(&rc->rsvs_mutex); bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS); rc->drp_avail.ie_valid = false; - uwb_rsv_handle_drp_avail_change(rc); mutex_unlock(&rc->rsvs_mutex); uwb_rsv_sched_update(rc); diff --git a/trunk/drivers/uwb/drp-ie.c b/trunk/drivers/uwb/drp-ie.c index 2840d7bf9e67..882724c5f126 100644 --- a/trunk/drivers/uwb/drp-ie.c +++ b/trunk/drivers/uwb/drp-ie.c @@ -16,102 +16,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include #include #include "uwb-internal.h" - -/* - * Return the reason code for a reservations's DRP IE. - */ -int uwb_rsv_reason_code(struct uwb_rsv *rsv) -{ - static const int reason_codes[] = { - [UWB_RSV_STATE_O_INITIATED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_PENDING] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_MODIFIED] = UWB_DRP_REASON_MODIFIED, - [UWB_RSV_STATE_O_ESTABLISHED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_TO_BE_MOVED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_MOVE_COMBINING] = UWB_DRP_REASON_MODIFIED, - [UWB_RSV_STATE_O_MOVE_REDUCING] = UWB_DRP_REASON_MODIFIED, - [UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_ACCEPTED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_CONFLICT] = UWB_DRP_REASON_CONFLICT, - [UWB_RSV_STATE_T_PENDING] = UWB_DRP_REASON_PENDING, - [UWB_RSV_STATE_T_DENIED] = UWB_DRP_REASON_DENIED, - [UWB_RSV_STATE_T_RESIZED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED, - }; - - return reason_codes[rsv->state]; -} - -/* - * Return the reason code for a reservations's companion DRP IE . - */ -int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv) -{ - static const int companion_reason_codes[] = { - [UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED, - }; - - return companion_reason_codes[rsv->state]; -} - -/* - * Return the status bit for a reservations's DRP IE. - */ -int uwb_rsv_status(struct uwb_rsv *rsv) -{ - static const int statuses[] = { - [UWB_RSV_STATE_O_INITIATED] = 0, - [UWB_RSV_STATE_O_PENDING] = 0, - [UWB_RSV_STATE_O_MODIFIED] = 1, - [UWB_RSV_STATE_O_ESTABLISHED] = 1, - [UWB_RSV_STATE_O_TO_BE_MOVED] = 0, - [UWB_RSV_STATE_O_MOVE_COMBINING] = 1, - [UWB_RSV_STATE_O_MOVE_REDUCING] = 1, - [UWB_RSV_STATE_O_MOVE_EXPANDING] = 1, - [UWB_RSV_STATE_T_ACCEPTED] = 1, - [UWB_RSV_STATE_T_CONFLICT] = 0, - [UWB_RSV_STATE_T_PENDING] = 0, - [UWB_RSV_STATE_T_DENIED] = 0, - [UWB_RSV_STATE_T_RESIZED] = 1, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 1, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = 1, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = 1, - - }; - - return statuses[rsv->state]; -} - -/* - * Return the status bit for a reservations's companion DRP IE . - */ -int uwb_rsv_companion_status(struct uwb_rsv *rsv) -{ - static const int companion_statuses[] = { - [UWB_RSV_STATE_O_MOVE_EXPANDING] = 0, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 0, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = 0, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = 0, - }; - - return companion_statuses[rsv->state]; -} - /* * Allocate a DRP IE. * @@ -123,12 +34,16 @@ int uwb_rsv_companion_status(struct uwb_rsv *rsv) static struct uwb_ie_drp *uwb_drp_ie_alloc(void) { struct uwb_ie_drp *drp_ie; + unsigned tiebreaker; drp_ie = kzalloc(sizeof(struct uwb_ie_drp) + UWB_NUM_ZONES * sizeof(struct uwb_drp_alloc), GFP_KERNEL); if (drp_ie) { drp_ie->hdr.element_id = UWB_IE_DRP; + + get_random_bytes(&tiebreaker, sizeof(unsigned)); + uwb_ie_drp_set_tiebreaker(drp_ie, tiebreaker & 1); } return drp_ie; } @@ -189,17 +104,43 @@ static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie, */ int uwb_drp_ie_update(struct uwb_rsv *rsv) { + struct device *dev = &rsv->rc->uwb_dev.dev; struct uwb_ie_drp *drp_ie; - struct uwb_rsv_move *mv; - int unsafe; + int reason_code, status; - if (rsv->state == UWB_RSV_STATE_NONE) { + switch (rsv->state) { + case UWB_RSV_STATE_NONE: kfree(rsv->drp_ie); rsv->drp_ie = NULL; return 0; + case UWB_RSV_STATE_O_INITIATED: + reason_code = UWB_DRP_REASON_ACCEPTED; + status = 0; + break; + case UWB_RSV_STATE_O_PENDING: + reason_code = UWB_DRP_REASON_ACCEPTED; + status = 0; + break; + case UWB_RSV_STATE_O_MODIFIED: + reason_code = UWB_DRP_REASON_MODIFIED; + status = 1; + break; + case UWB_RSV_STATE_O_ESTABLISHED: + reason_code = UWB_DRP_REASON_ACCEPTED; + status = 1; + break; + case UWB_RSV_STATE_T_ACCEPTED: + reason_code = UWB_DRP_REASON_ACCEPTED; + status = 1; + break; + case UWB_RSV_STATE_T_DENIED: + reason_code = UWB_DRP_REASON_DENIED; + status = 0; + break; + default: + dev_dbg(dev, "rsv with unhandled state (%d)\n", rsv->state); + return -EINVAL; } - - unsafe = rsv->mas.unsafe ? 1 : 0; if (rsv->drp_ie == NULL) { rsv->drp_ie = uwb_drp_ie_alloc(); @@ -208,11 +149,9 @@ int uwb_drp_ie_update(struct uwb_rsv *rsv) } drp_ie = rsv->drp_ie; - uwb_ie_drp_set_unsafe(drp_ie, unsafe); - uwb_ie_drp_set_tiebreaker(drp_ie, rsv->tiebreaker); uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv)); - uwb_ie_drp_set_status(drp_ie, uwb_rsv_status(rsv)); - uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_reason_code(rsv)); + uwb_ie_drp_set_status(drp_ie, status); + uwb_ie_drp_set_reason_code(drp_ie, reason_code); uwb_ie_drp_set_stream_index(drp_ie, rsv->stream); uwb_ie_drp_set_type(drp_ie, rsv->type); @@ -230,27 +169,6 @@ int uwb_drp_ie_update(struct uwb_rsv *rsv) uwb_drp_ie_from_bm(drp_ie, &rsv->mas); - if (uwb_rsv_has_two_drp_ies(rsv)) { - mv = &rsv->mv; - if (mv->companion_drp_ie == NULL) { - mv->companion_drp_ie = uwb_drp_ie_alloc(); - if (mv->companion_drp_ie == NULL) - return -ENOMEM; - } - drp_ie = mv->companion_drp_ie; - - /* keep all the same configuration of the main drp_ie */ - memcpy(drp_ie, rsv->drp_ie, sizeof(struct uwb_ie_drp)); - - - /* FIXME: handle properly the unsafe bit */ - uwb_ie_drp_set_unsafe(drp_ie, 1); - uwb_ie_drp_set_status(drp_ie, uwb_rsv_companion_status(rsv)); - uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_companion_reason_code(rsv)); - - uwb_drp_ie_from_bm(drp_ie, &mv->companion_mas); - } - rsv->ie_valid = true; return 0; } @@ -301,8 +219,6 @@ void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie) u8 zone; u16 zone_mask; - bitmap_zero(bm->bm, UWB_NUM_MAS); - for (cnt = 0; cnt < numallocs; cnt++) { alloc = &drp_ie->allocs[cnt]; zone_bm = le16_to_cpu(alloc->zone_bm); @@ -314,4 +230,3 @@ void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie) } } } - diff --git a/trunk/drivers/uwb/drp.c b/trunk/drivers/uwb/drp.c index 2b4f9406789d..c0b1e5e2bd08 100644 --- a/trunk/drivers/uwb/drp.c +++ b/trunk/drivers/uwb/drp.c @@ -23,59 +23,6 @@ #include #include "uwb-internal.h" - -/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */ -enum uwb_drp_conflict_action { - /* Reservation is mantained, no action needed */ - UWB_DRP_CONFLICT_MANTAIN = 0, - - /* the device shall not transmit frames in conflicting MASs in - * the following superframe. If the device is the reservation - * target, it shall also set the Reason Code in its DRP IE to - * Conflict in its beacon in the following superframe. - */ - UWB_DRP_CONFLICT_ACT1, - - /* the device shall not set the Reservation Status bit to ONE - * and shall not transmit frames in conflicting MASs. If the - * device is the reservation target, it shall also set the - * Reason Code in its DRP IE to Conflict. - */ - UWB_DRP_CONFLICT_ACT2, - - /* the device shall not transmit frames in conflicting MASs in - * the following superframe. It shall remove the conflicting - * MASs from the reservation or set the Reservation Status to - * ZERO in its beacon in the following superframe. If the - * device is the reservation target, it shall also set the - * Reason Code in its DRP IE to Conflict. - */ - UWB_DRP_CONFLICT_ACT3, -}; - - -static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg, - struct uwb_rceb *reply, ssize_t reply_size) -{ - struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply; - - if (r != NULL) { - if (r->bResultCode != UWB_RC_RES_SUCCESS) - dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n", - uwb_rc_strerror(r->bResultCode), r->bResultCode); - } else - dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n"); - - spin_lock(&rc->rsvs_lock); - if (rc->set_drp_ie_pending > 1) { - rc->set_drp_ie_pending = 0; - uwb_rsv_queue_update(rc); - } else { - rc->set_drp_ie_pending = 0; - } - spin_unlock(&rc->rsvs_lock); -} - /** * Construct and send the SET DRP IE * @@ -90,32 +37,28 @@ static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg, * * A DRP Availability IE is appended. * - * rc->rsvs_mutex is held + * rc->uwb_dev.mutex is held * * FIXME We currently ignore the returned value indicating the remaining space * in beacon. This could be used to deny reservation requests earlier if * determined that they would cause the beacon space to be exceeded. */ -int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) +static +int uwb_rc_gen_send_drp_ie(struct uwb_rc *rc) { int result; + struct device *dev = &rc->uwb_dev.dev; struct uwb_rc_cmd_set_drp_ie *cmd; + struct uwb_rc_evt_set_drp_ie reply; struct uwb_rsv *rsv; - struct uwb_rsv_move *mv; int num_bytes = 0; u8 *IEDataptr; result = -ENOMEM; /* First traverse all reservations to determine memory needed. */ list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->drp_ie != NULL) { + if (rsv->drp_ie != NULL) num_bytes += rsv->drp_ie->hdr.length + 2; - if (uwb_rsv_has_two_drp_ies(rsv) && - (rsv->mv.companion_drp_ie != NULL)) { - mv = &rsv->mv; - num_bytes += mv->companion_drp_ie->hdr.length + 2; - } - } } num_bytes += sizeof(rc->drp_avail.ie); cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL); @@ -126,322 +69,128 @@ int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) cmd->wIELength = num_bytes; IEDataptr = (u8 *)&cmd->IEData[0]; - /* FIXME: DRV avail IE is not always needed */ - /* put DRP avail IE first */ - memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie)); - IEDataptr += sizeof(struct uwb_ie_drp_avail); - /* Next traverse all reservations to place IEs in allocated memory. */ list_for_each_entry(rsv, &rc->reservations, rc_node) { if (rsv->drp_ie != NULL) { memcpy(IEDataptr, rsv->drp_ie, rsv->drp_ie->hdr.length + 2); IEDataptr += rsv->drp_ie->hdr.length + 2; - - if (uwb_rsv_has_two_drp_ies(rsv) && - (rsv->mv.companion_drp_ie != NULL)) { - mv = &rsv->mv; - memcpy(IEDataptr, mv->companion_drp_ie, - mv->companion_drp_ie->hdr.length + 2); - IEDataptr += mv->companion_drp_ie->hdr.length + 2; - } } } + memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie)); - result = uwb_rc_cmd_async(rc, "SET-DRP-IE", &cmd->rccb, sizeof(*cmd) + num_bytes, - UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE, - uwb_rc_set_drp_cmd_done, NULL); - - rc->set_drp_ie_pending = 1; - + reply.rceb.bEventType = UWB_RC_CET_GENERAL; + reply.rceb.wEvent = UWB_RC_CMD_SET_DRP_IE; + result = uwb_rc_cmd(rc, "SET-DRP-IE", &cmd->rccb, + sizeof(*cmd) + num_bytes, &reply.rceb, + sizeof(reply)); + if (result < 0) + goto error_cmd; + result = le16_to_cpu(reply.wRemainingSpace); + if (reply.bResultCode != UWB_RC_RES_SUCCESS) { + dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: command execution " + "failed: %s (%d). RemainingSpace in beacon " + "= %d\n", uwb_rc_strerror(reply.bResultCode), + reply.bResultCode, result); + result = -EIO; + } else { + dev_dbg(dev, "SET-DRP-IE sent. RemainingSpace in beacon " + "= %d.\n", result); + result = 0; + } +error_cmd: kfree(cmd); error: return result; -} -/* - * Evaluate the action to perform using conflict resolution rules +} +/** + * Send all DRP IEs associated with this host * - * Return a uwb_drp_conflict_action. + * @returns: >= 0 number of bytes still available in the beacon + * < 0 errno code on error. + * + * As per the protocol we obtain the host controller device lock to access + * bandwidth structures. */ -static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot, - struct uwb_rsv *rsv, int our_status) +int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) { - int our_tie_breaker = rsv->tiebreaker; - int our_type = rsv->type; - int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot; - - int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie); - int ext_status = uwb_ie_drp_status(ext_drp_ie); - int ext_type = uwb_ie_drp_type(ext_drp_ie); - - - /* [ECMA-368 2nd Edition] 17.4.6 */ - if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-1 */ - if (our_type == UWB_DRP_TYPE_ALIEN_BP) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-2 */ - if (ext_type == UWB_DRP_TYPE_ALIEN_BP) { - /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */ - return UWB_DRP_CONFLICT_ACT1; - } - - /* [ECMA-368 2nd Edition] 17.4.6-3 */ - if (our_status == 0 && ext_status == 1) { - return UWB_DRP_CONFLICT_ACT2; - } - - /* [ECMA-368 2nd Edition] 17.4.6-4 */ - if (our_status == 1 && ext_status == 0) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-5a */ - if (our_tie_breaker == ext_tie_breaker && - our_beacon_slot < ext_beacon_slot) { - return UWB_DRP_CONFLICT_MANTAIN; - } + int result; - /* [ECMA-368 2nd Edition] 17.4.6-5b */ - if (our_tie_breaker != ext_tie_breaker && - our_beacon_slot > ext_beacon_slot) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - if (our_status == 0) { - if (our_tie_breaker == ext_tie_breaker) { - /* [ECMA-368 2nd Edition] 17.4.6-6a */ - if (our_beacon_slot > ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT2; - } - } else { - /* [ECMA-368 2nd Edition] 17.4.6-6b */ - if (our_beacon_slot < ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT2; - } - } - } else { - if (our_tie_breaker == ext_tie_breaker) { - /* [ECMA-368 2nd Edition] 17.4.6-7a */ - if (our_beacon_slot > ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT3; - } - } else { - /* [ECMA-368 2nd Edition] 17.4.6-7b */ - if (our_beacon_slot < ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT3; - } - } - } - return UWB_DRP_CONFLICT_MANTAIN; + mutex_lock(&rc->uwb_dev.mutex); + result = uwb_rc_gen_send_drp_ie(rc); + mutex_unlock(&rc->uwb_dev.mutex); + return result; } -static void handle_conflict_normal(struct uwb_ie_drp *drp_ie, - int ext_beacon_slot, - struct uwb_rsv *rsv, - struct uwb_mas_bm *conflicting_mas) +void uwb_drp_handle_timeout(struct uwb_rsv *rsv) { - struct uwb_rc *rc = rsv->rc; - struct uwb_rsv_move *mv = &rsv->mv; - struct uwb_drp_backoff_win *bow = &rc->bow; - int action; - - action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv)); - - if (uwb_rsv_is_owner(rsv)) { - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - /* try move */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED); - if (bow->can_reserve_extra_mases == false) - uwb_rsv_backoff_win_increment(rc); - - break; - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_backoff_win_increment(rc); - /* drop some mases with reason modified */ - /* put in the companion the mases to be dropped */ - bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED); - default: - break; - } - } else { - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); - default: - break; - } + struct device *dev = &rsv->rc->uwb_dev.dev; - } - -} + dev_dbg(dev, "reservation timeout in state %s (%d)\n", + uwb_rsv_state_str(rsv->state), rsv->state); -static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot, - struct uwb_rsv *rsv, bool companion_only, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rc *rc = rsv->rc; - struct uwb_drp_backoff_win *bow = &rc->bow; - struct uwb_rsv_move *mv = &rsv->mv; - int action; - - if (companion_only) { - /* status of companion is 0 at this point */ - action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0); - if (uwb_rsv_is_owner(rsv)) { - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - rsv->needs_release_companion_mas = false; - if (bow->can_reserve_extra_mases == false) - uwb_rsv_backoff_win_increment(rc); - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - } - } else { /* rsv is target */ - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_EXPANDING_CONFLICT); - /* send_drp_avail_ie = true; */ - } - } - } else { /* also base part of the reservation is conflicting */ - if (uwb_rsv_is_owner(rsv)) { - uwb_rsv_backoff_win_increment(rc); - /* remove companion part */ - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - - /* drop some mases with reason modified */ - - /* put in the companion the mases to be dropped */ - bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED); - } else { /* it is a target rsv */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); - /* send_drp_avail_ie = true; */ - } - } -} - -static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rsv_move *mv; - - /* check if the conflicting reservation has two drp_ies */ - if (uwb_rsv_has_two_drp_ies(rsv)) { - mv = &rsv->mv; - if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS)) { - handle_conflict_expanding(drp_ie, drp_evt->beacon_slot_number, - rsv, false, conflicting_mas); - } else { - if (bitmap_intersects(mv->companion_mas.bm, conflicting_mas->bm, UWB_NUM_MAS)) { - handle_conflict_expanding(drp_ie, drp_evt->beacon_slot_number, - rsv, true, conflicting_mas); - } + switch (rsv->state) { + case UWB_RSV_STATE_O_INITIATED: + if (rsv->is_multicast) { + uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); + return; } - } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS)) { - handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number, rsv, conflicting_mas); + break; + case UWB_RSV_STATE_O_ESTABLISHED: + if (rsv->is_multicast) + return; + break; + default: + break; } + uwb_rsv_remove(rsv); } -static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rsv *rsv; - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, conflicting_mas); - } -} - /* * Based on the DRP IE, transition a target reservation to a new * state. */ static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv, - struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt) + struct uwb_ie_drp *drp_ie) { struct device *dev = &rc->uwb_dev.dev; - struct uwb_rsv_move *mv = &rsv->mv; int status; enum uwb_drp_reason reason_code; - struct uwb_mas_bm mas; - + status = uwb_ie_drp_status(drp_ie); reason_code = uwb_ie_drp_reason_code(drp_ie); - uwb_drp_ie_to_bm(&mas, drp_ie); - switch (reason_code) { - case UWB_DRP_REASON_ACCEPTED: - - if (rsv->state == UWB_RSV_STATE_T_CONFLICT) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); - break; - } - - if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) { - /* drp_ie is companion */ - if (!bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) - /* stroke companion */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED); - } else { - if (!bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) { - if (uwb_drp_avail_reserve_pending(rc, &mas) == -EBUSY) { - /* FIXME: there is a conflict, find - * the conflicting reservations and - * take a sensible action. Consider - * that in drp_ie there is the - * "neighbour" */ - uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas); - } else { - /* accept the extra reservation */ - bitmap_copy(mv->companion_mas.bm, mas.bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED); - } - } else { - if (status) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); - } - } - - } - break; - - case UWB_DRP_REASON_MODIFIED: - /* check to see if we have already modified the reservation */ - if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) { + if (status) { + switch (reason_code) { + case UWB_DRP_REASON_ACCEPTED: uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); break; + case UWB_DRP_REASON_MODIFIED: + dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", + reason_code, status); + break; + default: + dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", + reason_code, status); } - - /* find if the owner wants to expand or reduce */ - if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) { - /* owner is reducing */ - bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm, UWB_NUM_MAS); - uwb_drp_avail_release(rsv->rc, &mv->companion_mas); + } else { + switch (reason_code) { + case UWB_DRP_REASON_ACCEPTED: + /* New reservations are handled in uwb_rsv_find(). */ + break; + case UWB_DRP_REASON_DENIED: + uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); + break; + case UWB_DRP_REASON_CONFLICT: + case UWB_DRP_REASON_MODIFIED: + dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", + reason_code, status); + break; + default: + dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", + reason_code, status); } - - bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED); - break; - default: - dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", - reason_code, status); } } @@ -450,60 +199,23 @@ static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv, * state. */ static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv, - struct uwb_dev *src, struct uwb_ie_drp *drp_ie, - struct uwb_rc_evt_drp *drp_evt) + struct uwb_ie_drp *drp_ie) { struct device *dev = &rc->uwb_dev.dev; - struct uwb_rsv_move *mv = &rsv->mv; int status; enum uwb_drp_reason reason_code; - struct uwb_mas_bm mas; status = uwb_ie_drp_status(drp_ie); reason_code = uwb_ie_drp_reason_code(drp_ie); - uwb_drp_ie_to_bm(&mas, drp_ie); if (status) { switch (reason_code) { case UWB_DRP_REASON_ACCEPTED: - switch (rsv->state) { - case UWB_RSV_STATE_O_PENDING: - case UWB_RSV_STATE_O_INITIATED: - case UWB_RSV_STATE_O_ESTABLISHED: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - break; - case UWB_RSV_STATE_O_MODIFIED: - if (bitmap_equal(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - } else { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED); - } - break; - - case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */ - if (bitmap_equal(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - } else { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - } - break; - case UWB_RSV_STATE_O_MOVE_EXPANDING: - if (bitmap_equal(mas.bm, mv->companion_mas.bm, UWB_NUM_MAS)) { - /* Companion reservation accepted */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - } else { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING); - } - break; - case UWB_RSV_STATE_O_MOVE_COMBINING: - if (bitmap_equal(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - else - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - break; - default: - break; - } + uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); + break; + case UWB_DRP_REASON_MODIFIED: + dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", + reason_code, status); break; default: dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", @@ -518,10 +230,9 @@ static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv, uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); break; case UWB_DRP_REASON_CONFLICT: - /* resolve the conflict */ - bitmap_complement(mas.bm, src->last_availability_bm, - UWB_NUM_MAS); - uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas); + case UWB_DRP_REASON_MODIFIED: + dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", + reason_code, status); break; default: dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", @@ -530,110 +241,12 @@ static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv, } } -static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt) -{ - unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US; - mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us)); -} - -static void uwb_cnflt_update_work(struct work_struct *work) -{ - struct uwb_cnflt_alien *cnflt = container_of(work, - struct uwb_cnflt_alien, - cnflt_update_work); - struct uwb_cnflt_alien *c; - struct uwb_rc *rc = cnflt->rc; - - unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; - - mutex_lock(&rc->rsvs_mutex); - - list_del(&cnflt->rc_node); - - /* update rc global conflicting alien bitmap */ - bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS); - - list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) { - bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, c->mas.bm, UWB_NUM_MAS); - } - - queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us)); - - kfree(cnflt); - mutex_unlock(&rc->rsvs_mutex); -} - -static void uwb_cnflt_timer(unsigned long arg) -{ - struct uwb_cnflt_alien *cnflt = (struct uwb_cnflt_alien *)arg; - - queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work); -} - /* - * We have received an DRP_IE of type Alien BP and we need to make - * sure we do not transmit in conflicting MASs. + * Process a received DRP IE, it's either for a reservation owned by + * the RC or targeted at it (or it's for a WUSB cluster reservation). */ -static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_mas_bm mas; - struct uwb_cnflt_alien *cnflt; - char buf[72]; - unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; - - uwb_drp_ie_to_bm(&mas, drp_ie); - bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS); - - list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) { - if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) { - /* Existing alien BP reservation conflicting - * bitmap, just reset the timer */ - uwb_cnflt_alien_stroke_timer(cnflt); - return; - } - } - - /* New alien BP reservation conflicting bitmap */ - - /* alloc and initialize new uwb_cnflt_alien */ - cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL); - if (!cnflt) - dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n"); - INIT_LIST_HEAD(&cnflt->rc_node); - init_timer(&cnflt->timer); - cnflt->timer.function = uwb_cnflt_timer; - cnflt->timer.data = (unsigned long)cnflt; - - cnflt->rc = rc; - INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work); - - bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS); - - list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list); - - /* update rc global conflicting alien bitmap */ - bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS); - - queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us)); - - /* start the timer */ - uwb_cnflt_alien_stroke_timer(cnflt); -} - -static void uwb_drp_process_not_involved(struct uwb_rc *rc, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie) -{ - struct uwb_mas_bm mas; - - uwb_drp_ie_to_bm(&mas, drp_ie); - uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas); -} - -static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie) +static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src, + struct uwb_ie_drp *drp_ie) { struct uwb_rsv *rsv; @@ -646,7 +259,7 @@ static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src, */ return; } - + /* * Do nothing with DRP IEs for reservations that have been * terminated. @@ -655,43 +268,13 @@ static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src, uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); return; } - - if (uwb_ie_drp_owner(drp_ie)) - uwb_drp_process_target(rc, rsv, drp_ie, drp_evt); - else - uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt); - -} - - -static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie) -{ - return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0; -} -/* - * Process a received DRP IE. - */ -static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, - struct uwb_dev *src, struct uwb_ie_drp *drp_ie) -{ - if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP) - uwb_drp_handle_alien_drp(rc, drp_ie); - else if (uwb_drp_involves_us(rc, drp_ie)) - uwb_drp_process_involved(rc, src, drp_evt, drp_ie); + if (uwb_ie_drp_owner(drp_ie)) + uwb_drp_process_target(rc, rsv, drp_ie); else - uwb_drp_process_not_involved(rc, drp_evt, drp_ie); + uwb_drp_process_owner(rc, rsv, drp_ie); } -/* - * Process a received DRP Availability IE - */ -static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src, - struct uwb_ie_drp_avail *drp_availability_ie) -{ - bitmap_copy(src->last_availability_bm, - drp_availability_ie->bmp, UWB_NUM_MAS); -} /* * Process all the DRP IEs (both DRP IEs and the DRP Availability IE) @@ -713,10 +296,10 @@ void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, switch (ie_hdr->element_id) { case UWB_IE_DRP_AVAILABILITY: - uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr); + /* FIXME: does something need to be done with this? */ break; case UWB_IE_DRP: - uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr); + uwb_drp_process(rc, src_dev, (struct uwb_ie_drp *)ie_hdr); break; default: dev_warn(dev, "unexpected IE in DRP notification\n"); @@ -729,6 +312,55 @@ void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, (int)ielen); } + +/* + * Go through all the DRP IEs and find the ones that conflict with our + * reservations. + * + * FIXME: must resolve the conflict according the the rules in + * [ECMA-368]. + */ +static +void uwb_drp_process_conflict_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, + size_t ielen, struct uwb_dev *src_dev) +{ + struct device *dev = &rc->uwb_dev.dev; + struct uwb_ie_hdr *ie_hdr; + struct uwb_ie_drp *drp_ie; + void *ptr; + + ptr = drp_evt->ie_data; + for (;;) { + ie_hdr = uwb_ie_next(&ptr, &ielen); + if (!ie_hdr) + break; + + drp_ie = container_of(ie_hdr, struct uwb_ie_drp, hdr); + + /* FIXME: check if this DRP IE conflicts. */ + } + + if (ielen > 0) + dev_warn(dev, "%d octets remaining in DRP notification\n", + (int)ielen); +} + + +/* + * Terminate all reservations owned by, or targeted at, 'uwb_dev'. + */ +static void uwb_drp_terminate_all(struct uwb_rc *rc, struct uwb_dev *uwb_dev) +{ + struct uwb_rsv *rsv; + + list_for_each_entry(rsv, &rc->reservations, rc_node) { + if (rsv->owner == uwb_dev + || (rsv->target.type == UWB_RSV_TARGET_DEV && rsv->target.dev == uwb_dev)) + uwb_rsv_remove(rsv); + } +} + + /** * uwbd_evt_handle_rc_drp - handle a DRP_IE event * @evt: the DRP_IE event from the radio controller @@ -769,6 +401,7 @@ int uwbd_evt_handle_rc_drp(struct uwb_event *evt) size_t ielength, bytes_left; struct uwb_dev_addr src_addr; struct uwb_dev *src_dev; + int reason; /* Is there enough data to decode the event (and any IEs in its payload)? */ @@ -804,8 +437,22 @@ int uwbd_evt_handle_rc_drp(struct uwb_event *evt) mutex_lock(&rc->rsvs_mutex); - /* We do not distinguish from the reason */ - uwb_drp_process_all(rc, drp_evt, ielength, src_dev); + reason = uwb_rc_evt_drp_reason(drp_evt); + + switch (reason) { + case UWB_DRP_NOTIF_DRP_IE_RCVD: + uwb_drp_process_all(rc, drp_evt, ielength, src_dev); + break; + case UWB_DRP_NOTIF_CONFLICT: + uwb_drp_process_conflict_all(rc, drp_evt, ielength, src_dev); + break; + case UWB_DRP_NOTIF_TERMINATE: + uwb_drp_terminate_all(rc, src_dev); + break; + default: + dev_warn(dev, "ignored DRP event with reason code: %d\n", reason); + break; + } mutex_unlock(&rc->rsvs_mutex); diff --git a/trunk/drivers/uwb/est.c b/trunk/drivers/uwb/est.c index 328fcc2b6099..5fe566b7c845 100644 --- a/trunk/drivers/uwb/est.c +++ b/trunk/drivers/uwb/est.c @@ -40,9 +40,11 @@ * uwb_est_get_size() */ #include - +#define D_LOCAL 0 +#include #include "uwb-internal.h" + struct uwb_est { u16 type_event_high; u16 vendor, product; @@ -50,6 +52,7 @@ struct uwb_est { const struct uwb_est_entry *entry; }; + static struct uwb_est *uwb_est; static u8 uwb_est_size; static u8 uwb_est_used; @@ -437,12 +440,21 @@ ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb, u8 *ptr = (u8 *) rceb; read_lock_irqsave(&uwb_est_lock, flags); + d_printf(2, dev, "Size query for event 0x%02x/%04x/%02x," + " buffer size %ld\n", + (unsigned) rceb->bEventType, + (unsigned) le16_to_cpu(rceb->wEvent), + (unsigned) rceb->bEventContext, + (long) rceb_size); size = -ENOSPC; if (rceb_size < sizeof(*rceb)) goto out; event = le16_to_cpu(rceb->wEvent); type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8; for (itr = 0; itr < uwb_est_used; itr++) { + d_printf(3, dev, "Checking EST 0x%04x/%04x/%04x\n", + uwb_est[itr].type_event_high, uwb_est[itr].vendor, + uwb_est[itr].product); if (uwb_est[itr].type_event_high != type_event_high) continue; size = uwb_est_get_size(rc, &uwb_est[itr], diff --git a/trunk/drivers/uwb/hwa-rc.c b/trunk/drivers/uwb/hwa-rc.c index 559f8784acf3..3d26fa0f8ae1 100644 --- a/trunk/drivers/uwb/hwa-rc.c +++ b/trunk/drivers/uwb/hwa-rc.c @@ -51,14 +51,16 @@ * * */ +#include #include #include #include #include #include #include - #include "uwb-internal.h" +#define D_LOCAL 1 +#include /* The device uses commands and events from the WHCI specification, although * reporting itself as WUSB compliant. */ @@ -629,13 +631,17 @@ void hwarc_neep_cb(struct urb *urb) switch (result = urb->status) { case 0: + d_printf(3, dev, "NEEP: receive stat %d, %zu bytes\n", + urb->status, (size_t)urb->actual_length); uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer, urb->actual_length); break; case -ECONNRESET: /* Not an error, but a controlled situation; */ case -ENOENT: /* (we killed the URB)...so, no broadcast */ + d_printf(2, dev, "NEEP: URB reset/noent %d\n", urb->status); goto out; case -ESHUTDOWN: /* going away! */ + d_printf(2, dev, "NEEP: URB down %d\n", urb->status); goto out; default: /* On general errors, retry unless it gets ugly */ if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS, @@ -644,6 +650,7 @@ void hwarc_neep_cb(struct urb *urb) dev_err(dev, "NEEP: URB error %d\n", urb->status); } result = usb_submit_urb(urb, GFP_ATOMIC); + d_printf(3, dev, "NEEP: submit %d\n", result); if (result < 0) { dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n", result); @@ -752,11 +759,11 @@ static int hwarc_get_version(struct uwb_rc *rc) itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); while (itr_size >= sizeof(*hdr)) { hdr = (struct usb_descriptor_header *) itr; - dev_dbg(dev, "Extra device descriptor: " - "type %02x/%u bytes @ %zu (%zu left)\n", - hdr->bDescriptorType, hdr->bLength, - (itr - usb_dev->rawdescriptors[actconfig_idx]), - itr_size); + d_printf(3, dev, "Extra device descriptor: " + "type %02x/%u bytes @ %zu (%zu left)\n", + hdr->bDescriptorType, hdr->bLength, + (itr - usb_dev->rawdescriptors[actconfig_idx]), + itr_size); if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL) goto found; itr += hdr->bLength; @@ -788,7 +795,8 @@ static int hwarc_get_version(struct uwb_rc *rc) goto error; } rc->version = version; - dev_dbg(dev, "Device supports WUSB protocol version 0x%04x \n", rc->version); + d_printf(3, dev, "Device supports WUSB protocol version 0x%04x \n", + rc->version); result = 0; error: return result; @@ -869,28 +877,11 @@ static void hwarc_disconnect(struct usb_interface *iface) uwb_rc_rm(uwb_rc); usb_put_intf(hwarc->usb_iface); usb_put_dev(hwarc->usb_dev); + d_printf(1, &hwarc->usb_iface->dev, "freed hwarc %p\n", hwarc); kfree(hwarc); uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */ } -static int hwarc_pre_reset(struct usb_interface *iface) -{ - struct hwarc *hwarc = usb_get_intfdata(iface); - struct uwb_rc *uwb_rc = hwarc->uwb_rc; - - uwb_rc_pre_reset(uwb_rc); - return 0; -} - -static int hwarc_post_reset(struct usb_interface *iface) -{ - struct hwarc *hwarc = usb_get_intfdata(iface); - struct uwb_rc *uwb_rc = hwarc->uwb_rc; - - uwb_rc_post_reset(uwb_rc); - return 0; -} - /** USB device ID's that we handle */ static struct usb_device_id hwarc_id_table[] = { /* D-Link DUB-1210 */ @@ -907,16 +898,20 @@ MODULE_DEVICE_TABLE(usb, hwarc_id_table); static struct usb_driver hwarc_driver = { .name = "hwa-rc", - .id_table = hwarc_id_table, .probe = hwarc_probe, .disconnect = hwarc_disconnect, - .pre_reset = hwarc_pre_reset, - .post_reset = hwarc_post_reset, + .id_table = hwarc_id_table, }; static int __init hwarc_driver_init(void) { - return usb_register(&hwarc_driver); + int result; + result = usb_register(&hwarc_driver); + if (result < 0) + printk(KERN_ERR "HWA-RC: Cannot register USB driver: %d\n", + result); + return result; + } module_init(hwarc_driver_init); diff --git a/trunk/drivers/uwb/i1480/dfu/dfu.c b/trunk/drivers/uwb/i1480/dfu/dfu.c index da7b1d08003c..9097b3b30385 100644 --- a/trunk/drivers/uwb/i1480/dfu/dfu.c +++ b/trunk/drivers/uwb/i1480/dfu/dfu.c @@ -34,7 +34,10 @@ #include #include -/* +#define D_LOCAL 0 +#include + +/** * i1480_rceb_check - Check RCEB for expected field values * @i1480: pointer to device for which RCEB is being checked * @rceb: RCEB being checked @@ -80,7 +83,7 @@ int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb, EXPORT_SYMBOL_GPL(i1480_rceb_check); -/* +/** * Execute a Radio Control Command * * Command data has to be in i1480->cmd_buf. @@ -98,6 +101,7 @@ ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size, u8 expected_type = reply->bEventType; u8 context; + d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); init_completion(&i1480->evt_complete); i1480->evt_result = -EINPROGRESS; do { @@ -146,6 +150,8 @@ ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size, result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context, expected_type, expected_event); error: + d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n", + i1480, cmd_name, cmd_size, result); return result; } EXPORT_SYMBOL_GPL(i1480_cmd); diff --git a/trunk/drivers/uwb/i1480/dfu/mac.c b/trunk/drivers/uwb/i1480/dfu/mac.c index 694d0daf88ab..2e4d8f07c165 100644 --- a/trunk/drivers/uwb/i1480/dfu/mac.c +++ b/trunk/drivers/uwb/i1480/dfu/mac.c @@ -31,6 +31,9 @@ #include #include "i1480-dfu.h" +#define D_LOCAL 0 +#include + /* * Descriptor for a continuous segment of MAC fw data */ @@ -181,6 +184,10 @@ ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr) } if (memcmp(i1480->cmd_buf, bin + src_itr, result)) { u8 *buf = i1480->cmd_buf; + d_printf(2, i1480->dev, + "original data @ %p + %u, %zu bytes\n", + bin, src_itr, result); + d_dump(4, i1480->dev, bin + src_itr, result); for (cnt = 0; cnt < result; cnt++) if (bin[src_itr + cnt] != buf[cnt]) { dev_err(i1480->dev, "byte failed at " @@ -217,6 +224,7 @@ int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr, struct fw_hdr *hdr_itr; int verif_retry_count; + d_fnstart(3, dev, "(%p, %p)\n", i1480, hdr); /* Now, header by header, push them to the hw */ for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) { verif_retry_count = 0; @@ -256,6 +264,7 @@ int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr, break; } } + d_fnend(3, dev, "(%zd)\n", result); return result; } @@ -328,9 +337,11 @@ int __mac_fw_upload(struct i1480 *i1480, const char *fw_name, const struct firmware *fw; struct fw_hdr *fw_hdrs; + d_fnstart(3, i1480->dev, "(%p, %s, %s)\n", i1480, fw_name, fw_tag); result = request_firmware(&fw, fw_name, i1480->dev); if (result < 0) /* Up to caller to complain on -ENOENT */ goto out; + d_printf(3, i1480->dev, "%s fw '%s': uploading\n", fw_tag, fw_name); result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size); if (result < 0) { dev_err(i1480->dev, "%s fw '%s': failed to parse firmware " @@ -352,6 +363,8 @@ int __mac_fw_upload(struct i1480 *i1480, const char *fw_name, out_release: release_firmware(fw); out: + d_fnend(3, i1480->dev, "(%p, %s, %s) = %d\n", i1480, fw_name, fw_tag, + result); return result; } @@ -420,6 +433,7 @@ int i1480_fw_is_running_q(struct i1480 *i1480) int result; u32 *val = (u32 *) i1480->cmd_buf; + d_fnstart(3, i1480->dev, "(i1480 %p)\n", i1480); for (cnt = 0; cnt < 10; cnt++) { msleep(100); result = i1480->read(i1480, 0x80080000, 4); @@ -433,6 +447,7 @@ int i1480_fw_is_running_q(struct i1480 *i1480) dev_err(i1480->dev, "Timed out waiting for fw to start\n"); result = -ETIMEDOUT; out: + d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result); return result; } @@ -452,6 +467,7 @@ int i1480_mac_fw_upload(struct i1480 *i1480) int result = 0, deprecated_name = 0; struct i1480_rceb *rcebe = (void *) i1480->evt_buf; + d_fnstart(3, i1480->dev, "(%p)\n", i1480); result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC"); if (result == -ENOENT) { result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate, @@ -485,6 +501,7 @@ int i1480_mac_fw_upload(struct i1480 *i1480) dev_err(i1480->dev, "MAC fw '%s': initialization event returns " "wrong size (%zu bytes vs %zu needed)\n", i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe)); + dump_bytes(i1480->dev, rcebe, min(i1480->evt_result, (ssize_t)32)); goto error_size; } result = -EIO; @@ -505,5 +522,6 @@ int i1480_mac_fw_upload(struct i1480 *i1480) error_init_timeout: error_size: error_setup: + d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result); return result; } diff --git a/trunk/drivers/uwb/i1480/dfu/usb.c b/trunk/drivers/uwb/i1480/dfu/usb.c index 686795e97195..98eeeff051aa 100644 --- a/trunk/drivers/uwb/i1480/dfu/usb.c +++ b/trunk/drivers/uwb/i1480/dfu/usb.c @@ -35,6 +35,7 @@ * the functions are i1480_usb_NAME(). */ #include +#include #include #include #include @@ -43,6 +44,10 @@ #include #include "i1480-dfu.h" +#define D_LOCAL 0 +#include + + struct i1480_usb { struct i1480 i1480; struct usb_device *usb_dev; @@ -113,6 +118,8 @@ int i1480_usb_write(struct i1480 *i1480, u32 memory_address, struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); size_t buffer_size, itr = 0; + d_fnstart(3, i1480->dev, "(%p, 0x%08x, %p, %zu)\n", + i1480, memory_address, buffer, size); BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ while (size > 0) { buffer_size = size < i1480->buf_size ? size : i1480->buf_size; @@ -125,10 +132,16 @@ int i1480_usb_write(struct i1480 *i1480, u32 memory_address, i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */); if (result < 0) break; + d_printf(3, i1480->dev, + "wrote @ 0x%08x %u bytes (of %zu bytes requested)\n", + memory_address, result, buffer_size); + d_dump(4, i1480->dev, i1480->cmd_buf, result); itr += result; memory_address += result; size -= result; } + d_fnend(3, i1480->dev, "(%p, 0x%08x, %p, %zu) = %d\n", + i1480, memory_address, buffer, size, result); return result; } @@ -153,6 +166,8 @@ int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size) size_t itr, read_size = i1480->buf_size; struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); + d_fnstart(3, i1480->dev, "(%p, 0x%08x, %zu)\n", + i1480, addr, size); BUG_ON(size > i1480->buf_size); BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ BUG_ON(read_size > 512); @@ -186,6 +201,10 @@ int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size) } result = bytes; out: + d_fnend(3, i1480->dev, "(%p, 0x%08x, %zu) = %zd\n", + i1480, addr, size, result); + if (result > 0) + d_dump(4, i1480->dev, i1480->cmd_buf, result); return result; } @@ -241,6 +260,7 @@ int i1480_usb_wait_init_done(struct i1480 *i1480) struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); struct usb_endpoint_descriptor *epd; + d_fnstart(3, dev, "(%p)\n", i1480); init_completion(&i1480->evt_complete); i1480->evt_result = -EINPROGRESS; epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; @@ -262,12 +282,14 @@ int i1480_usb_wait_init_done(struct i1480 *i1480) goto error_wait; } usb_kill_urb(i1480_usb->neep_urb); + d_fnend(3, dev, "(%p) = 0\n", i1480); return 0; error_wait: usb_kill_urb(i1480_usb->neep_urb); error_submit: i1480->evt_result = result; + d_fnend(3, dev, "(%p) = %d\n", i1480, result); return result; } @@ -298,6 +320,7 @@ int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size) struct uwb_rccb *cmd = i1480->cmd_buf; u8 iface_no; + d_fnstart(3, dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); /* Post a read on the notification & event endpoint */ iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber; epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; @@ -325,11 +348,15 @@ int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size) cmd_name, result); goto error_submit_ep0; } + d_fnend(3, dev, "(%p, %s, %zu) = %d\n", + i1480, cmd_name, cmd_size, result); return result; error_submit_ep0: usb_kill_urb(i1480_usb->neep_urb); error_submit_ep1: + d_fnend(3, dev, "(%p, %s, %zu) = %d\n", + i1480, cmd_name, cmd_size, result); return result; } diff --git a/trunk/drivers/uwb/i1480/i1480u-wlp/lc.c b/trunk/drivers/uwb/i1480/i1480u-wlp/lc.c index 049c05d4cc6a..737d60cd5b73 100644 --- a/trunk/drivers/uwb/i1480/i1480u-wlp/lc.c +++ b/trunk/drivers/uwb/i1480/i1480u-wlp/lc.c @@ -55,9 +55,10 @@ * is being removed. * i1480u_rm() */ +#include #include #include - +#include #include "i1480u-wlp.h" @@ -206,7 +207,7 @@ int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) wlp->fill_device_info = i1480u_fill_device_info; wlp->stop_queue = i1480u_stop_queue; wlp->start_queue = i1480u_start_queue; - result = wlp_setup(wlp, rc, net_dev); + result = wlp_setup(wlp, rc); if (result < 0) { dev_err(&iface->dev, "Cannot setup WLP\n"); goto error_wlp_setup; diff --git a/trunk/drivers/uwb/i1480/i1480u-wlp/netdev.c b/trunk/drivers/uwb/i1480/i1480u-wlp/netdev.c index e3873ffb942c..8802ac43d872 100644 --- a/trunk/drivers/uwb/i1480/i1480u-wlp/netdev.c +++ b/trunk/drivers/uwb/i1480/i1480u-wlp/netdev.c @@ -41,7 +41,7 @@ #include #include - +#include #include "i1480u-wlp.h" struct i1480u_cmd_set_ip_mas { @@ -207,11 +207,6 @@ int i1480u_open(struct net_device *net_dev) result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */ if (result < 0) goto error_rx_setup; - - result = uwb_radio_start(&wlp->pal); - if (result < 0) - goto error_radio_start; - netif_wake_queue(net_dev); #ifdef i1480u_FLOW_CONTROL result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);; @@ -220,20 +215,25 @@ int i1480u_open(struct net_device *net_dev) goto error_notif_urb_submit; } #endif + i1480u->uwb_notifs_handler.cb = i1480u_uwb_notifs_cb; + i1480u->uwb_notifs_handler.data = i1480u; + if (uwb_bg_joined(rc)) + netif_carrier_on(net_dev); + else + netif_carrier_off(net_dev); + uwb_notifs_register(rc, &i1480u->uwb_notifs_handler); /* Interface is up with an address, now we can create WSS */ result = wlp_wss_setup(net_dev, &wlp->wss); if (result < 0) { dev_err(dev, "Can't create WSS: %d. \n", result); - goto error_wss_setup; + goto error_notif_deregister; } return 0; -error_wss_setup: +error_notif_deregister: + uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler); #ifdef i1480u_FLOW_CONTROL - usb_kill_urb(i1480u->notif_urb); error_notif_urb_submit: #endif - uwb_radio_stop(&wlp->pal); -error_radio_start: netif_stop_queue(net_dev); i1480u_rx_release(i1480u); error_rx_setup: @@ -248,15 +248,16 @@ int i1480u_stop(struct net_device *net_dev) { struct i1480u *i1480u = netdev_priv(net_dev); struct wlp *wlp = &i1480u->wlp; + struct uwb_rc *rc = wlp->rc; BUG_ON(wlp->rc == NULL); wlp_wss_remove(&wlp->wss); + uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler); netif_carrier_off(net_dev); #ifdef i1480u_FLOW_CONTROL usb_kill_urb(i1480u->notif_urb); #endif netif_stop_queue(net_dev); - uwb_radio_stop(&wlp->pal); i1480u_rx_release(i1480u); i1480u_tx_release(i1480u); return 0; @@ -302,6 +303,34 @@ int i1480u_change_mtu(struct net_device *net_dev, int mtu) return 0; } + +/** + * Callback function to handle events from UWB + * When we see other devices we know the carrier is ok, + * if we are the only device in the beacon group we set the carrier + * state to off. + * */ +void i1480u_uwb_notifs_cb(void *data, struct uwb_dev *uwb_dev, + enum uwb_notifs event) +{ + struct i1480u *i1480u = data; + struct net_device *net_dev = i1480u->net_dev; + struct device *dev = &i1480u->usb_iface->dev; + switch (event) { + case UWB_NOTIF_BG_JOIN: + netif_carrier_on(net_dev); + dev_info(dev, "Link is up\n"); + break; + case UWB_NOTIF_BG_LEAVE: + netif_carrier_off(net_dev); + dev_info(dev, "Link is down\n"); + break; + default: + dev_err(dev, "don't know how to handle event %d from uwb\n", + event); + } +} + /** * Stop the network queue * diff --git a/trunk/drivers/uwb/i1480/i1480u-wlp/rx.c b/trunk/drivers/uwb/i1480/i1480u-wlp/rx.c index 34f4cf9a7d34..9fc035354a76 100644 --- a/trunk/drivers/uwb/i1480/i1480u-wlp/rx.c +++ b/trunk/drivers/uwb/i1480/i1480u-wlp/rx.c @@ -68,7 +68,11 @@ #include #include "i1480u-wlp.h" -/* +#define D_LOCAL 0 +#include + + +/** * Setup the RX context * * Each URB is provided with a transfer_buffer that is the data field @@ -125,7 +129,7 @@ int i1480u_rx_setup(struct i1480u *i1480u) } -/* Release resources associated to the rx context */ +/** Release resources associated to the rx context */ void i1480u_rx_release(struct i1480u *i1480u) { int cnt; @@ -151,7 +155,7 @@ void i1480u_rx_unlink_urbs(struct i1480u *i1480u) } } -/* Fix an out-of-sequence packet */ +/** Fix an out-of-sequence packet */ #define i1480u_fix(i1480u, msg...) \ do { \ if (printk_ratelimit()) \ @@ -162,7 +166,7 @@ do { \ } while (0) -/* Drop an out-of-sequence packet */ +/** Drop an out-of-sequence packet */ #define i1480u_drop(i1480u, msg...) \ do { \ if (printk_ratelimit()) \ @@ -173,7 +177,7 @@ do { \ -/* Finalizes setting up the SKB and delivers it +/** Finalizes setting up the SKB and delivers it * * We first pass the incoming frame to WLP substack for verification. It * may also be a WLP association frame in which case WLP will take over the @@ -188,11 +192,18 @@ void i1480u_skb_deliver(struct i1480u *i1480u) struct net_device *net_dev = i1480u->net_dev; struct device *dev = &i1480u->usb_iface->dev; + d_printf(6, dev, "RX delivered pre skb(%p), %u bytes\n", + i1480u->rx_skb, i1480u->rx_skb->len); + d_dump(7, dev, i1480u->rx_skb->data, i1480u->rx_skb->len); should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb, &i1480u->rx_srcaddr); if (!should_parse) goto out; i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev); + d_printf(5, dev, "RX delivered skb(%p), %u bytes\n", + i1480u->rx_skb, i1480u->rx_skb->len); + d_dump(7, dev, i1480u->rx_skb->data, + i1480u->rx_skb->len > 72 ? 72 : i1480u->rx_skb->len); i1480u->stats.rx_packets++; i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size; net_dev->last_rx = jiffies; @@ -205,7 +216,7 @@ void i1480u_skb_deliver(struct i1480u *i1480u) } -/* +/** * Process a buffer of data received from the USB RX endpoint * * First fragment arrives with next or last fragment. All other fragments @@ -393,7 +404,7 @@ void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf) } -/* +/** * Called when an RX URB has finished receiving or has found some kind * of error condition. * diff --git a/trunk/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/trunk/drivers/uwb/i1480/i1480u-wlp/sysfs.c index 4ffaf546cc6c..a1d8ca6ac935 100644 --- a/trunk/drivers/uwb/i1480/i1480u-wlp/sysfs.c +++ b/trunk/drivers/uwb/i1480/i1480u-wlp/sysfs.c @@ -25,8 +25,8 @@ #include #include +#include #include - #include "i1480u-wlp.h" @@ -226,6 +226,7 @@ ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight, * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a * class_device_attr_NAME or device_attr_NAME (for group registration). */ +#include #define i1480u_SHOW(name, fn, param) \ static ssize_t i1480u_show_##name(struct device *dev, \ diff --git a/trunk/drivers/uwb/i1480/i1480u-wlp/tx.c b/trunk/drivers/uwb/i1480/i1480u-wlp/tx.c index 39032cc3503e..3426bfb68240 100644 --- a/trunk/drivers/uwb/i1480/i1480u-wlp/tx.c +++ b/trunk/drivers/uwb/i1480/i1480u-wlp/tx.c @@ -55,6 +55,8 @@ */ #include "i1480u-wlp.h" +#define D_LOCAL 5 +#include enum { /* This is only for Next and Last TX packets */ @@ -62,7 +64,7 @@ enum { - sizeof(struct untd_hdr_rst), }; -/* Free resources allocated to a i1480u tx context. */ +/** Free resources allocated to a i1480u tx context. */ static void i1480u_tx_free(struct i1480u_tx *wtx) { @@ -97,7 +99,7 @@ void i1480u_tx_unlink_urbs(struct i1480u *i1480u) } -/* +/** * Callback for a completed tx USB URB. * * TODO: @@ -147,6 +149,8 @@ void i1480u_tx_cb(struct urb *urb) <= i1480u->tx_inflight.threshold && netif_queue_stopped(net_dev) && i1480u->tx_inflight.threshold != 0) { + if (d_test(2) && printk_ratelimit()) + d_printf(2, dev, "Restart queue. \n"); netif_start_queue(net_dev); atomic_inc(&i1480u->tx_inflight.restart_count); } @@ -154,7 +158,7 @@ void i1480u_tx_cb(struct urb *urb) } -/* +/** * Given a buffer that doesn't fit in a single fragment, create an * scatter/gather structure for delivery to the USB pipe. * @@ -249,11 +253,15 @@ int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, /* Now do each remaining fragment */ result = -EINVAL; while (pl_size_left > 0) { + d_printf(5, NULL, "ITR HDR: pl_size_left %zu buf_itr %zu\n", + pl_size_left, buf_itr - wtx->buf); if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf > wtx->buf_size) { printk(KERN_ERR "BUG: no space for header\n"); goto error_bug; } + d_printf(5, NULL, "ITR HDR 2: pl_size_left %zu buf_itr %zu\n", + pl_size_left, buf_itr - wtx->buf); untd_hdr_rst = buf_itr; buf_itr += sizeof(*untd_hdr_rst); if (pl_size_left > i1480u_MAX_PL_SIZE) { @@ -263,6 +271,9 @@ int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, frg_pl_size = pl_size_left; untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST); } + d_printf(5, NULL, + "ITR PL: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n", + pl_size_left, buf_itr - wtx->buf, frg_pl_size); untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0); untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size); untd_hdr_rst->padding = 0; @@ -275,6 +286,9 @@ int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, buf_itr += frg_pl_size; pl_itr += frg_pl_size; pl_size_left -= frg_pl_size; + d_printf(5, NULL, + "ITR PL 2: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n", + pl_size_left, buf_itr - wtx->buf, frg_pl_size); } dev_kfree_skb_irq(skb); return 0; @@ -294,7 +308,7 @@ int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, } -/* +/** * Given a buffer that fits in a single fragment, fill out a @wtx * struct for transmitting it down the USB pipe. * @@ -332,7 +346,7 @@ int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb, } -/* +/** * Given a skb to transmit, massage it to become palatable for the TX pipe * * This will break the buffer in chunks smaller than @@ -411,7 +425,7 @@ struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u, return NULL; } -/* +/** * Actual fragmentation and transmission of frame * * @wlp: WLP substack data structure @@ -433,12 +447,20 @@ int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, struct i1480u_tx *wtx; struct wlp_tx_hdr *wlp_tx_hdr; static unsigned char dev_bcast[2] = { 0xff, 0xff }; +#if 0 + int lockup = 50; +#endif + d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len, + net_dev); BUG_ON(i1480u->wlp.rc == NULL); if ((net_dev->flags & IFF_UP) == 0) goto out; result = -EBUSY; if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) { + if (d_test(2) && printk_ratelimit()) + d_printf(2, dev, "Max frames in flight " + "stopping queue.\n"); netif_stop_queue(net_dev); goto error_max_inflight; } @@ -467,6 +489,21 @@ int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority); } +#if 0 + dev_info(dev, "TX delivering skb -> USB, %zu bytes\n", skb->len); + dump_bytes(dev, skb->data, skb->len > 72 ? 72 : skb->len); +#endif +#if 0 + /* simulates a device lockup after every lockup# packets */ + if (lockup && ((i1480u->stats.tx_packets + 1) % lockup) == 0) { + /* Simulate a dropped transmit interrupt */ + net_dev->trans_start = jiffies; + netif_stop_queue(net_dev); + dev_err(dev, "Simulate lockup at %ld\n", jiffies); + return result; + } +#endif + result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */ if (result < 0) { dev_err(dev, "TX: cannot submit URB: %d\n", result); @@ -476,6 +513,8 @@ int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, } atomic_inc(&i1480u->tx_inflight.count); net_dev->trans_start = jiffies; + d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, + net_dev, result); return result; error_tx_urb_submit: @@ -483,11 +522,13 @@ int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, error_wtx_alloc: error_max_inflight: out: + d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, + net_dev, result); return result; } -/* +/** * Transmit an skb Called when an skbuf has to be transmitted * * The skb is first passed to WLP substack to ensure this is a valid @@ -510,6 +551,9 @@ int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) struct device *dev = &i1480u->usb_iface->dev; struct uwb_dev_addr dst; + d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len, + net_dev); + BUG_ON(i1480u->wlp.rc == NULL); if ((net_dev->flags & IFF_UP) == 0) goto error; result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst); @@ -518,25 +562,31 @@ int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) "Dropping packet.\n", result); goto error; } else if (result == 1) { + d_printf(6, dev, "WLP will transmit frame. \n"); /* trans_start time will be set when WLP actually transmits * the frame */ goto out; } + d_printf(6, dev, "Transmitting frame. \n"); result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst); if (result < 0) { dev_err(dev, "Frame TX failed (%d).\n", result); goto error; } + d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, + net_dev, result); return NETDEV_TX_OK; error: dev_kfree_skb_any(skb); i1480u->stats.tx_dropped++; out: + d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, + net_dev, result); return NETDEV_TX_OK; } -/* +/** * Called when a pkt transmission doesn't complete in a reasonable period * Device reset may sleep - do it outside of interrupt context (delayed) */ diff --git a/trunk/drivers/uwb/ie-rcv.c b/trunk/drivers/uwb/ie-rcv.c deleted file mode 100644 index 917e6d78a798..000000000000 --- a/trunk/drivers/uwb/ie-rcv.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Ultra Wide Band - * IE Received notification handling. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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, see . - */ - -#include -#include -#include -#include -#include "uwb-internal.h" - -/* - * Process an incoming IE Received notification. - */ -int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *evt) -{ - int result = -EINVAL; - struct device *dev = &evt->rc->uwb_dev.dev; - struct uwb_rc_evt_ie_rcv *iercv; - size_t iesize; - - /* Is there enough data to decode it? */ - if (evt->notif.size < sizeof(*iercv)) { - dev_err(dev, "IE Received notification: Not enough data to " - "decode (%zu vs %zu bytes needed)\n", - evt->notif.size, sizeof(*iercv)); - goto error; - } - iercv = container_of(evt->notif.rceb, struct uwb_rc_evt_ie_rcv, rceb); - iesize = le16_to_cpu(iercv->wIELength); - - dev_dbg(dev, "IE received, element ID=%d\n", iercv->IEData[0]); - - if (iercv->IEData[0] == UWB_RELINQUISH_REQUEST_IE) { - dev_warn(dev, "unhandled Relinquish Request IE\n"); - } - - return 0; -error: - return result; -} diff --git a/trunk/drivers/uwb/ie.c b/trunk/drivers/uwb/ie.c index ab976686175b..cf6f3d152b9d 100644 --- a/trunk/drivers/uwb/ie.c +++ b/trunk/drivers/uwb/ie.c @@ -25,6 +25,8 @@ */ #include "uwb-internal.h" +#define D_LOCAL 0 +#include /** * uwb_ie_next - get the next IE in a buffer @@ -58,42 +60,6 @@ struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len) } EXPORT_SYMBOL_GPL(uwb_ie_next); -/** - * uwb_ie_dump_hex - print IEs to a character buffer - * @ies: the IEs to print. - * @len: length of all the IEs. - * @buf: the destination buffer. - * @size: size of @buf. - * - * Returns the number of characters written. - */ -int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len, - char *buf, size_t size) -{ - void *ptr; - const struct uwb_ie_hdr *ie; - int r = 0; - u8 *d; - - ptr = (void *)ies; - for (;;) { - ie = uwb_ie_next(&ptr, &len); - if (!ie) - break; - - r += scnprintf(buf + r, size - r, "%02x %02x", - (unsigned)ie->element_id, - (unsigned)ie->length); - d = (uint8_t *)ie + sizeof(struct uwb_ie_hdr); - while (d != ptr && r < size) - r += scnprintf(buf + r, size - r, " %02x", (unsigned)*d++); - if (r < size) - buf[r++] = '\n'; - }; - - return r; -} - /** * Get the IEs that a radio controller is sending in its beacon * @@ -104,7 +70,6 @@ int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len, * anything. Once done with the iedata buffer, call * uwb_rc_ie_release(iedata). Don't call kfree on it. */ -static ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie) { ssize_t result; @@ -113,35 +78,148 @@ ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie) struct uwb_rceb *reply = NULL; struct uwb_rc_evt_get_ie *get_ie; + d_fnstart(3, dev, "(%p, %p)\n", uwb_rc, pget_ie); + result = -ENOMEM; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) - return -ENOMEM; - + goto error_kzalloc; cmd->bCommandType = UWB_RC_CET_GENERAL; cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE); result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd), UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE, &reply); - kfree(cmd); if (result < 0) - return result; - + goto error_cmd; get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb); if (result < sizeof(*get_ie)) { dev_err(dev, "not enough data returned for decoding GET IE " "(%zu bytes received vs %zu needed)\n", result, sizeof(*get_ie)); - return -EINVAL; + result = -EINVAL; } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) { dev_err(dev, "not enough data returned for decoding GET IE " "payload (%zu bytes received vs %zu needed)\n", result, sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)); + result = -EINVAL; + } else + *pget_ie = get_ie; +error_cmd: + kfree(cmd); +error_kzalloc: + d_fnend(3, dev, "(%p, %p) = %d\n", uwb_rc, pget_ie, (int)result); + return result; +} +EXPORT_SYMBOL_GPL(uwb_rc_get_ie); + + +/* + * Given a pointer to an IE, print it in ASCII/hex followed by a new line + * + * @ie_hdr: pointer to the IE header. Length is in there, and it is + * guaranteed that the ie_hdr->length bytes following it are + * safely accesible. + * + * @_data: context data passed from uwb_ie_for_each(), an struct output_ctx + */ +int uwb_ie_dump_hex(struct uwb_dev *uwb_dev, const struct uwb_ie_hdr *ie_hdr, + size_t offset, void *_ctx) +{ + struct uwb_buf_ctx *ctx = _ctx; + const u8 *pl = (void *)(ie_hdr + 1); + u8 pl_itr; + + ctx->bytes += scnprintf(ctx->buf + ctx->bytes, ctx->size - ctx->bytes, + "%02x %02x ", (unsigned) ie_hdr->element_id, + (unsigned) ie_hdr->length); + pl_itr = 0; + while (pl_itr < ie_hdr->length && ctx->bytes < ctx->size) + ctx->bytes += scnprintf(ctx->buf + ctx->bytes, + ctx->size - ctx->bytes, + "%02x ", (unsigned) pl[pl_itr++]); + if (ctx->bytes < ctx->size) + ctx->buf[ctx->bytes++] = '\n'; + return 0; +} +EXPORT_SYMBOL_GPL(uwb_ie_dump_hex); + + +/** + * Verify that a pointer in a buffer points to valid IE + * + * @start: pointer to start of buffer in which IE appears + * @itr: pointer to IE inside buffer that will be verified + * @top: pointer to end of buffer + * + * @returns: 0 if IE is valid, <0 otherwise + * + * Verification involves checking that the buffer can contain a + * header and the amount of data reported in the IE header can be found in + * the buffer. + */ +static +int uwb_rc_ie_verify(struct uwb_dev *uwb_dev, const void *start, + const void *itr, const void *top) +{ + struct device *dev = &uwb_dev->dev; + const struct uwb_ie_hdr *ie_hdr; + + if (top - itr < sizeof(*ie_hdr)) { + dev_err(dev, "Bad IE: no data to decode header " + "(%zu bytes left vs %zu needed) at offset %zu\n", + top - itr, sizeof(*ie_hdr), itr - start); + return -EINVAL; + } + ie_hdr = itr; + itr += sizeof(*ie_hdr); + if (top - itr < ie_hdr->length) { + dev_err(dev, "Bad IE: not enough data for payload " + "(%zu bytes left vs %zu needed) at offset %zu\n", + top - itr, (size_t)ie_hdr->length, + (void *)ie_hdr - start); return -EINVAL; } + return 0; +} - *pget_ie = get_ie; + +/** + * Walk a buffer filled with consecutive IE's a buffer + * + * @uwb_dev: UWB device this IEs belong to (for err messages mainly) + * + * @fn: function to call with each IE; if it returns 0, we keep + * traversing the buffer. If it returns !0, we'll stop and return + * that value. + * + * @data: pointer passed to @fn + * + * @buf: buffer where the consecutive IEs are located + * + * @size: size of @buf + * + * Each IE is checked for basic correctness (there is space left for + * the header and the payload). If that test is failed, we stop + * processing. For every good IE, @fn is called. + */ +ssize_t uwb_ie_for_each(struct uwb_dev *uwb_dev, uwb_ie_f fn, void *data, + const void *buf, size_t size) +{ + ssize_t result = 0; + const struct uwb_ie_hdr *ie_hdr; + const void *itr = buf, *top = itr + size; + + while (itr < top) { + if (uwb_rc_ie_verify(uwb_dev, buf, itr, top) != 0) + break; + ie_hdr = itr; + itr += sizeof(*ie_hdr) + ie_hdr->length; + result = fn(uwb_dev, ie_hdr, itr - buf, data); + if (result != 0) + break; + } return result; } +EXPORT_SYMBOL_GPL(uwb_ie_for_each); /** @@ -178,6 +256,70 @@ int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd) return result; } +/** + * Determine by IE id if IE is host settable + * WUSB 1.0 [8.6.2.8 Table 8.85] + * + * EXCEPTION: + * All but UWB_IE_WLP appears in Table 8.85 from WUSB 1.0. Setting this IE + * is required for the WLP substack to perform association with its WSS so + * we hope that the WUSB spec will be changed to reflect this. + */ +static +int uwb_rc_ie_is_host_settable(enum uwb_ie element_id) +{ + if (element_id == UWB_PCA_AVAILABILITY || + element_id == UWB_BP_SWITCH_IE || + element_id == UWB_MAC_CAPABILITIES_IE || + element_id == UWB_PHY_CAPABILITIES_IE || + element_id == UWB_APP_SPEC_PROBE_IE || + element_id == UWB_IDENTIFICATION_IE || + element_id == UWB_MASTER_KEY_ID_IE || + element_id == UWB_IE_WLP || + element_id == UWB_APP_SPEC_IE) + return 1; + return 0; +} + + +/** + * Extract Host Settable IEs from IE + * + * @ie_data: pointer to buffer containing all IEs + * @size: size of buffer + * + * @returns: length of buffer that only includes host settable IEs + * + * Given a buffer of IEs we move all Host Settable IEs to front of buffer + * by overwriting the IEs that are not Host Settable. + * Buffer length is adjusted accordingly. + */ +static +ssize_t uwb_rc_parse_host_settable_ie(struct uwb_dev *uwb_dev, + void *ie_data, size_t size) +{ + size_t new_len = size; + struct uwb_ie_hdr *ie_hdr; + size_t ie_length; + void *itr = ie_data, *top = itr + size; + + while (itr < top) { + if (uwb_rc_ie_verify(uwb_dev, ie_data, itr, top) != 0) + break; + ie_hdr = itr; + ie_length = sizeof(*ie_hdr) + ie_hdr->length; + if (uwb_rc_ie_is_host_settable(ie_hdr->element_id)) { + itr += ie_length; + } else { + memmove(itr, itr + ie_length, top - (itr + ie_length)); + new_len -= ie_length; + top -= ie_length; + } + } + return new_len; +} + + /* Cleanup the whole IE management subsystem */ void uwb_rc_ie_init(struct uwb_rc *uwb_rc) { @@ -186,34 +328,49 @@ void uwb_rc_ie_init(struct uwb_rc *uwb_rc) /** - * uwb_rc_ie_setup - setup a radio controller's IE manager - * @uwb_rc: the radio controller. + * Set up cache for host settable IEs currently being transmitted * - * The current set of IEs are obtained from the hardware with a GET-IE - * command (since the radio controller is not yet beaconing this will - * be just the hardware's MAC and PHY Capability IEs). + * First we just call GET-IE to get the current IEs being transmitted + * (or we workaround and pretend we did) and (because the format is + * the same) reuse that as the IE cache (with the command prefix, as + * explained in 'struct uwb_rc'). * - * Returns 0 on success; -ve on an error. + * @returns: size of cache created */ -int uwb_rc_ie_setup(struct uwb_rc *uwb_rc) +ssize_t uwb_rc_ie_setup(struct uwb_rc *uwb_rc) { - struct uwb_rc_evt_get_ie *ie_info = NULL; - int capacity; - - capacity = uwb_rc_get_ie(uwb_rc, &ie_info); - if (capacity < 0) - return capacity; + struct device *dev = &uwb_rc->uwb_dev.dev; + ssize_t result; + size_t capacity; + struct uwb_rc_evt_get_ie *ie_info; + d_fnstart(3, dev, "(%p)\n", uwb_rc); mutex_lock(&uwb_rc->ies_mutex); - - uwb_rc->ies = (struct uwb_rc_cmd_set_ie *)ie_info; + result = uwb_rc_get_ie(uwb_rc, &ie_info); + if (result < 0) + goto error_get_ie; + capacity = result; + d_printf(5, dev, "Got IEs %zu bytes (%zu long at %p)\n", result, + (size_t)le16_to_cpu(ie_info->wIELength), ie_info); + + /* Remove IEs that host should not set. */ + result = uwb_rc_parse_host_settable_ie(&uwb_rc->uwb_dev, + ie_info->IEData, le16_to_cpu(ie_info->wIELength)); + if (result < 0) + goto error_parse; + d_printf(5, dev, "purged non-settable IEs to %zu bytes\n", result); + uwb_rc->ies = (void *) ie_info; uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL; uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE); uwb_rc->ies_capacity = capacity; - + d_printf(5, dev, "IE cache at %p %zu bytes, %zu capacity\n", + ie_info, result, capacity); + result = 0; +error_parse: +error_get_ie: mutex_unlock(&uwb_rc->ies_mutex); - - return 0; + d_fnend(3, dev, "(%p) = %zu\n", uwb_rc, result); + return result; } @@ -226,47 +383,26 @@ void uwb_rc_ie_release(struct uwb_rc *uwb_rc) } -static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie) +static +int __acc_size(struct uwb_dev *uwb_dev, const struct uwb_ie_hdr *ie_hdr, + size_t offset, void *_ctx) { - struct uwb_rc_cmd_set_ie *new_ies; - void *ptr, *prev_ie; - struct uwb_ie_hdr *ie; - size_t length, new_ie_len, new_capacity, size, prev_size; - - length = le16_to_cpu(rc->ies->wIELength); - new_ie_len = sizeof(struct uwb_ie_hdr) + new_ie->length; - new_capacity = sizeof(struct uwb_rc_cmd_set_ie) + length + new_ie_len; - - if (new_capacity > rc->ies_capacity) { - new_ies = krealloc(rc->ies, new_capacity, GFP_KERNEL); - if (!new_ies) - return -ENOMEM; - rc->ies = new_ies; - } - - ptr = rc->ies->IEData; - size = length; - for (;;) { - prev_ie = ptr; - prev_size = size; - ie = uwb_ie_next(&ptr, &size); - if (!ie || ie->element_id > new_ie->element_id) - break; - } - - memmove(prev_ie + new_ie_len, prev_ie, prev_size); - memcpy(prev_ie, new_ie, new_ie_len); - rc->ies->wIELength = cpu_to_le16(length + new_ie_len); - + size_t *acc_size = _ctx; + *acc_size += sizeof(*ie_hdr) + ie_hdr->length; + d_printf(6, &uwb_dev->dev, "new acc size %zu\n", *acc_size); return 0; } + /** - * uwb_rc_ie_add - add new IEs to the radio controller's beacon - * @uwb_rc: the radio controller. + * Add a new IE to IEs currently being transmitted by device + * * @ies: the buffer containing the new IE or IEs to be added to - * the device's beacon. - * @size: length of all the IEs. + * the device's beacon. The buffer will be verified for + * consistence (meaning the headers should be right) and + * consistent with the buffer size. + * @size: size of @ies (in bytes, total buffer size) + * @returns: 0 if ok, <0 errno code on error * * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB * after the device sent the first beacon that includes the IEs specified @@ -275,40 +411,66 @@ static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie) * we start beaconing. * * Setting an IE on the device will overwrite all current IEs in device. So - * we take the current IEs being transmitted by the device, insert the + * we take the current IEs being transmitted by the device, append the * new one, and call SET IE with all the IEs needed. * - * Returns 0 on success; or -ENOMEM. + * The local IE cache will only be updated with the new IE if SET IE + * completed successfully. */ int uwb_rc_ie_add(struct uwb_rc *uwb_rc, const struct uwb_ie_hdr *ies, size_t size) { int result = 0; - void *ptr; - const struct uwb_ie_hdr *ie; - + struct device *dev = &uwb_rc->uwb_dev.dev; + struct uwb_rc_cmd_set_ie *new_ies; + size_t ies_size, total_size, acc_size = 0; + + if (uwb_rc->ies == NULL) + return -ESHUTDOWN; + uwb_ie_for_each(&uwb_rc->uwb_dev, __acc_size, &acc_size, ies, size); + if (acc_size != size) { + dev_err(dev, "BUG: bad IEs, misconstructed headers " + "[%zu bytes reported vs %zu calculated]\n", + size, acc_size); + WARN_ON(1); + return -EINVAL; + } mutex_lock(&uwb_rc->ies_mutex); - - ptr = (void *)ies; - for (;;) { - ie = uwb_ie_next(&ptr, &size); - if (!ie) - break; - - result = uwb_rc_ie_add_one(uwb_rc, ie); - if (result < 0) - break; + ies_size = le16_to_cpu(uwb_rc->ies->wIELength); + total_size = sizeof(*uwb_rc->ies) + ies_size; + if (total_size + size > uwb_rc->ies_capacity) { + d_printf(4, dev, "Reallocating IE cache from %p capacity %zu " + "to capacity %zu\n", uwb_rc->ies, uwb_rc->ies_capacity, + total_size + size); + new_ies = kzalloc(total_size + size, GFP_KERNEL); + if (new_ies == NULL) { + dev_err(dev, "No memory for adding new IE\n"); + result = -ENOMEM; + goto error_alloc; + } + memcpy(new_ies, uwb_rc->ies, total_size); + uwb_rc->ies_capacity = total_size + size; + kfree(uwb_rc->ies); + uwb_rc->ies = new_ies; + d_printf(4, dev, "New IE cache at %p capacity %zu\n", + uwb_rc->ies, uwb_rc->ies_capacity); } - if (result >= 0) { - if (size == 0) { - if (uwb_rc->beaconing != -1) - result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); + memcpy((void *)uwb_rc->ies + total_size, ies, size); + uwb_rc->ies->wIELength = cpu_to_le16(ies_size + size); + if (uwb_rc->beaconing != -1) { + result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); + if (result < 0) { + dev_err(dev, "Cannot set new IE on device: %d\n", + result); + uwb_rc->ies->wIELength = cpu_to_le16(ies_size); } else - result = -EINVAL; + result = 0; } - + d_printf(4, dev, "IEs now occupy %hu bytes of %zu capacity at %p\n", + le16_to_cpu(uwb_rc->ies->wIELength), uwb_rc->ies_capacity, + uwb_rc->ies); +error_alloc: mutex_unlock(&uwb_rc->ies_mutex); - return result; } EXPORT_SYMBOL_GPL(uwb_rc_ie_add); @@ -327,52 +489,53 @@ EXPORT_SYMBOL_GPL(uwb_rc_ie_add); * beacon. We don't reallocate, we just mark the size smaller. */ static -void uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove) +int uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove) { - struct uwb_ie_hdr *ie; - size_t len = le16_to_cpu(uwb_rc->ies->wIELength); - void *ptr; - size_t size; - - ptr = uwb_rc->ies->IEData; - size = len; - for (;;) { - ie = uwb_ie_next(&ptr, &size); - if (!ie) - break; - if (ie->element_id == to_remove) { - len -= sizeof(struct uwb_ie_hdr) + ie->length; - memmove(ie, ptr, size); - ptr = ie; + struct uwb_ie_hdr *ie_hdr; + size_t new_len = le16_to_cpu(uwb_rc->ies->wIELength); + void *itr = uwb_rc->ies->IEData; + void *top = itr + new_len; + + while (itr < top) { + ie_hdr = itr; + if (ie_hdr->element_id != to_remove) { + itr += sizeof(*ie_hdr) + ie_hdr->length; + } else { + int ie_length; + ie_length = sizeof(*ie_hdr) + ie_hdr->length; + if (top - itr != ie_length) + memmove(itr, itr + ie_length, top - itr + ie_length); + top -= ie_length; + new_len -= ie_length; } } - uwb_rc->ies->wIELength = cpu_to_le16(len); + uwb_rc->ies->wIELength = cpu_to_le16(new_len); + return 0; } /** - * uwb_rc_ie_rm - remove an IE from the radio controller's beacon - * @uwb_rc: the radio controller. - * @element_id: the element ID of the IE to remove. + * Remove an IE currently being transmitted by device * - * Only IEs previously added with uwb_rc_ie_add() may be removed. - * - * Returns 0 on success; or -ve the SET-IE command to the radio - * controller failed. + * @element_id: id of IE to be removed from device's beacon */ int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id) { - int result = 0; + struct device *dev = &uwb_rc->uwb_dev.dev; + int result; + if (uwb_rc->ies == NULL) + return -ESHUTDOWN; mutex_lock(&uwb_rc->ies_mutex); - - uwb_rc_ie_cache_rm(uwb_rc, element_id); - - if (uwb_rc->beaconing != -1) + result = uwb_rc_ie_cache_rm(uwb_rc, element_id); + if (result < 0) + dev_err(dev, "Cannot remove IE from cache.\n"); + if (uwb_rc->beaconing != -1) { result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); - + if (result < 0) + dev_err(dev, "Cannot set new IE on device.\n"); + } mutex_unlock(&uwb_rc->ies_mutex); - return result; } EXPORT_SYMBOL_GPL(uwb_rc_ie_rm); diff --git a/trunk/drivers/uwb/lc-dev.c b/trunk/drivers/uwb/lc-dev.c index e9fe1bb7eb23..15f856c9689a 100644 --- a/trunk/drivers/uwb/lc-dev.c +++ b/trunk/drivers/uwb/lc-dev.c @@ -22,6 +22,7 @@ * * FIXME: docs */ + #include #include #include @@ -29,6 +30,10 @@ #include #include "uwb-internal.h" +#define D_LOCAL 1 +#include + + /* We initialize addresses to 0xff (invalid, as it is bcast) */ static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr) { @@ -99,9 +104,12 @@ static void uwb_dev_sys_release(struct device *dev) { struct uwb_dev *uwb_dev = to_uwb_dev(dev); + d_fnstart(4, NULL, "(dev %p uwb_dev %p)\n", dev, uwb_dev); uwb_bce_put(uwb_dev->bce); + d_printf(0, &uwb_dev->dev, "uwb_dev %p freed\n", uwb_dev); memset(uwb_dev, 0x69, sizeof(*uwb_dev)); kfree(uwb_dev); + d_fnend(4, NULL, "(dev %p uwb_dev %p) = void\n", dev, uwb_dev); } /* @@ -267,8 +275,12 @@ static struct attribute_group *groups[] = { */ static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev) { + int result; struct device *dev; + d_fnstart(4, NULL, "(uwb_dev %p parent_dev %p)\n", uwb_dev, parent_dev); + BUG_ON(parent_dev == NULL); + dev = &uwb_dev->dev; /* Device sysfs files are only useful for neighbor devices not local radio controllers. */ @@ -277,14 +289,18 @@ static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev) dev->parent = parent_dev; dev_set_drvdata(dev, uwb_dev); - return device_add(dev); + result = device_add(dev); + d_fnend(4, NULL, "(uwb_dev %p parent_dev %p) = %d\n", uwb_dev, parent_dev, result); + return result; } static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev) { + d_fnstart(4, NULL, "(uwb_dev %p)\n", uwb_dev); dev_set_drvdata(&uwb_dev->dev, NULL); device_del(&uwb_dev->dev); + d_fnend(4, NULL, "(uwb_dev %p) = void\n", uwb_dev); } @@ -368,6 +384,7 @@ int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc) struct device *dev = &uwb_dev->dev; char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; + d_fnstart(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p)\n", dev, uwb_dev, rc); uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr); uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr); dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n", @@ -375,10 +392,8 @@ int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc) rc ? rc->uwb_dev.dev.parent->bus->name : "n/a", rc ? dev_name(rc->uwb_dev.dev.parent) : ""); uwb_dev_rm(uwb_dev); - list_del(&uwb_dev->bce->node); - uwb_bce_put(uwb_dev->bce); uwb_dev_put(uwb_dev); /* for the creation in _onair() */ - + d_fnend(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p) = 0\n", dev, uwb_dev, rc); return 0; } diff --git a/trunk/drivers/uwb/lc-rc.c b/trunk/drivers/uwb/lc-rc.c index 9cf21e6bb624..ee5772f00d42 100644 --- a/trunk/drivers/uwb/lc-rc.c +++ b/trunk/drivers/uwb/lc-rc.c @@ -36,6 +36,8 @@ #include #include +#define D_LOCAL 1 +#include #include "uwb-internal.h" static int uwb_rc_index_match(struct device *dev, void *data) @@ -79,7 +81,9 @@ static void uwb_rc_sys_release(struct device *dev) struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev); struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev); + uwb_rc_neh_destroy(rc); uwb_rc_ie_release(rc); + d_printf(1, dev, "freed uwb_rc %p\n", rc); kfree(rc); } @@ -96,8 +100,6 @@ void uwb_rc_init(struct uwb_rc *rc) rc->scan_type = UWB_SCAN_DISABLED; INIT_LIST_HEAD(&rc->notifs_chain.list); mutex_init(&rc->notifs_chain.mutex); - INIT_LIST_HEAD(&rc->uwb_beca.list); - mutex_init(&rc->uwb_beca.mutex); uwb_drp_avail_init(rc); uwb_rc_ie_init(rc); uwb_rsv_init(rc); @@ -189,9 +191,9 @@ static int uwb_rc_setup(struct uwb_rc *rc) int result; struct device *dev = &rc->uwb_dev.dev; - result = uwb_radio_setup(rc); + result = uwb_rc_reset(rc); if (result < 0) { - dev_err(dev, "cannot setup UWB radio: %d\n", result); + dev_err(dev, "cannot reset UWB radio: %d\n", result); goto error; } result = uwb_rc_mac_addr_setup(rc); @@ -248,12 +250,6 @@ int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv) rc->priv = priv; - init_waitqueue_head(&rc->uwbd.wq); - INIT_LIST_HEAD(&rc->uwbd.event_list); - spin_lock_init(&rc->uwbd.event_list_lock); - - uwbd_start(rc); - result = rc->start(rc); if (result < 0) goto error_rc_start; @@ -288,7 +284,7 @@ int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv) error_dev_add: error_rc_setup: rc->stop(rc); - uwbd_stop(rc); + uwbd_flush(rc); error_rc_start: return result; } @@ -310,24 +306,25 @@ void uwb_rc_rm(struct uwb_rc *rc) rc->ready = 0; uwb_dbg_del_rc(rc); - uwb_rsv_remove_all(rc); - uwb_radio_shutdown(rc); + uwb_rsv_cleanup(rc); + uwb_rc_ie_rm(rc, UWB_IDENTIFICATION_IE); + if (rc->beaconing >= 0) + uwb_rc_beacon(rc, -1, 0); + if (rc->scan_type != UWB_SCAN_DISABLED) + uwb_rc_scan(rc, rc->scanning, UWB_SCAN_DISABLED, 0); + uwb_rc_reset(rc); rc->stop(rc); - - uwbd_stop(rc); - uwb_rc_neh_destroy(rc); + uwbd_flush(rc); uwb_dev_lock(&rc->uwb_dev); rc->priv = NULL; rc->cmd = NULL; uwb_dev_unlock(&rc->uwb_dev); - mutex_lock(&rc->uwb_beca.mutex); + mutex_lock(&uwb_beca.mutex); uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL); __uwb_rc_sys_rm(rc); - mutex_unlock(&rc->uwb_beca.mutex); - uwb_rsv_cleanup(rc); - uwb_beca_release(rc); + mutex_unlock(&uwb_beca.mutex); uwb_dev_rm(&rc->uwb_dev); } EXPORT_SYMBOL_GPL(uwb_rc_rm); @@ -471,3 +468,28 @@ void uwb_rc_put(struct uwb_rc *rc) __uwb_rc_put(rc); } EXPORT_SYMBOL_GPL(uwb_rc_put); + +/* + * + * + */ +ssize_t uwb_rc_print_IEs(struct uwb_rc *uwb_rc, char *buf, size_t size) +{ + ssize_t result; + struct uwb_rc_evt_get_ie *ie_info; + struct uwb_buf_ctx ctx; + + result = uwb_rc_get_ie(uwb_rc, &ie_info); + if (result < 0) + goto error_get_ie; + ctx.buf = buf; + ctx.size = size; + ctx.bytes = 0; + uwb_ie_for_each(&uwb_rc->uwb_dev, uwb_ie_dump_hex, &ctx, + ie_info->IEData, result - sizeof(*ie_info)); + result = ctx.bytes; + kfree(ie_info); +error_get_ie: + return result; +} + diff --git a/trunk/drivers/uwb/neh.c b/trunk/drivers/uwb/neh.c index 0af8916d9bef..9b4eb64327ac 100644 --- a/trunk/drivers/uwb/neh.c +++ b/trunk/drivers/uwb/neh.c @@ -86,6 +86,8 @@ #include #include "uwb-internal.h" +#define D_LOCAL 0 +#include /* * UWB Radio Controller Notification/Event Handle @@ -252,6 +254,7 @@ struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd, static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) { + del_timer(&neh->timer); __uwb_rc_ctx_put(rc, neh); list_del(&neh->list_node); } @@ -272,7 +275,6 @@ void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) __uwb_rc_neh_rm(rc, neh); spin_unlock_irqrestore(&rc->neh_lock, flags); - del_timer_sync(&neh->timer); uwb_rc_neh_put(neh); } @@ -347,7 +349,7 @@ struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc, } -/* +/** * Process notifications coming from the radio control interface * * @rc: UWB Radio Control Interface descriptor @@ -399,6 +401,23 @@ void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size) uwb_evt->notif.size = size; uwb_evt->notif.rceb = rceb; + switch (le16_to_cpu(rceb->wEvent)) { + /* Trap some vendor specific events + * + * FIXME: move this to handling in ptc-est, where we + * register a NULL event handler for these two guys + * using the Intel IDs. + */ + case 0x0103: + dev_info(dev, "FIXME: DEVICE ADD\n"); + return; + case 0x0104: + dev_info(dev, "FIXME: DEVICE RM\n"); + return; + default: + break; + } + uwbd_event_queue(uwb_evt); } @@ -419,10 +438,9 @@ static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size rceb->bEventContext, size); } else { neh = uwb_rc_neh_lookup(rc, rceb); - if (neh) { - del_timer_sync(&neh->timer); + if (neh) uwb_rc_neh_cb(neh, rceb, size); - } else + else dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n", rceb->bEventType, le16_to_cpu(rceb->wEvent), rceb->bEventContext, size); @@ -477,6 +495,8 @@ void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size) size_t size, real_size, event_size; int needtofree; + d_fnstart(3, dev, "(rc %p buf %p %zu buf_size)\n", rc, buf, buf_size); + d_printf(2, dev, "groking event block: %zu bytes\n", buf_size); itr = buf; size = buf_size; while (size > 0) { @@ -524,7 +544,10 @@ void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size) itr += real_size; size -= real_size; + d_printf(2, dev, "consumed %zd bytes, %zu left\n", + event_size, size); } + d_fnend(3, dev, "(rc %p buf %p %zu buf_size) = void\n", rc, buf, buf_size); } EXPORT_SYMBOL_GPL(uwb_rc_neh_grok); @@ -539,22 +562,16 @@ EXPORT_SYMBOL_GPL(uwb_rc_neh_grok); */ void uwb_rc_neh_error(struct uwb_rc *rc, int error) { - struct uwb_rc_neh *neh; + struct uwb_rc_neh *neh, *next; unsigned long flags; - for (;;) { - spin_lock_irqsave(&rc->neh_lock, flags); - if (list_empty(&rc->neh_list)) { - spin_unlock_irqrestore(&rc->neh_lock, flags); - break; - } - neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node); + BUG_ON(error >= 0); + spin_lock_irqsave(&rc->neh_lock, flags); + list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) { __uwb_rc_neh_rm(rc, neh); - spin_unlock_irqrestore(&rc->neh_lock, flags); - - del_timer_sync(&neh->timer); uwb_rc_neh_cb(neh, NULL, error); } + spin_unlock_irqrestore(&rc->neh_lock, flags); } EXPORT_SYMBOL_GPL(uwb_rc_neh_error); @@ -566,14 +583,10 @@ static void uwb_rc_neh_timer(unsigned long arg) unsigned long flags; spin_lock_irqsave(&rc->neh_lock, flags); - if (neh->context) - __uwb_rc_neh_rm(rc, neh); - else - neh = NULL; + __uwb_rc_neh_rm(rc, neh); spin_unlock_irqrestore(&rc->neh_lock, flags); - if (neh) - uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT); + uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT); } /** Initializes the @rc's neh subsystem @@ -592,19 +605,12 @@ void uwb_rc_neh_create(struct uwb_rc *rc) void uwb_rc_neh_destroy(struct uwb_rc *rc) { unsigned long flags; - struct uwb_rc_neh *neh; + struct uwb_rc_neh *neh, *next; - for (;;) { - spin_lock_irqsave(&rc->neh_lock, flags); - if (list_empty(&rc->neh_list)) { - spin_unlock_irqrestore(&rc->neh_lock, flags); - break; - } - neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node); + spin_lock_irqsave(&rc->neh_lock, flags); + list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) { __uwb_rc_neh_rm(rc, neh); - spin_unlock_irqrestore(&rc->neh_lock, flags); - - del_timer_sync(&neh->timer); uwb_rc_neh_put(neh); } + spin_unlock_irqrestore(&rc->neh_lock, flags); } diff --git a/trunk/drivers/uwb/pal.c b/trunk/drivers/uwb/pal.c index 99a19c199095..1afb38eacb9a 100644 --- a/trunk/drivers/uwb/pal.c +++ b/trunk/drivers/uwb/pal.c @@ -16,7 +16,6 @@ * along with this program. If not, see . */ #include -#include #include #include "uwb-internal.h" @@ -33,13 +32,13 @@ EXPORT_SYMBOL_GPL(uwb_pal_init); /** * uwb_pal_register - register a UWB PAL + * @rc: the radio controller the PAL will be using * @pal: the PAL * * The PAL must be initialized with uwb_pal_init(). */ -int uwb_pal_register(struct uwb_pal *pal) +int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal) { - struct uwb_rc *rc = pal->rc; int ret; if (pal->device) { @@ -55,11 +54,9 @@ int uwb_pal_register(struct uwb_pal *pal) } } - pal->debugfs_dir = uwb_dbg_create_pal_dir(pal); - - mutex_lock(&rc->uwb_dev.mutex); + spin_lock(&rc->pal_lock); list_add(&pal->node, &rc->pals); - mutex_unlock(&rc->uwb_dev.mutex); + spin_unlock(&rc->pal_lock); return 0; } @@ -67,19 +64,14 @@ EXPORT_SYMBOL_GPL(uwb_pal_register); /** * uwb_pal_register - unregister a UWB PAL + * @rc: the radio controller the PAL was using * @pal: the PAL */ -void uwb_pal_unregister(struct uwb_pal *pal) +void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal) { - struct uwb_rc *rc = pal->rc; - - uwb_radio_stop(pal); - - mutex_lock(&rc->uwb_dev.mutex); + spin_lock(&rc->pal_lock); list_del(&pal->node); - mutex_unlock(&rc->uwb_dev.mutex); - - debugfs_remove(pal->debugfs_dir); + spin_unlock(&rc->pal_lock); if (pal->device) { sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name); @@ -94,5 +86,6 @@ EXPORT_SYMBOL_GPL(uwb_pal_unregister); */ void uwb_rc_pal_init(struct uwb_rc *rc) { + spin_lock_init(&rc->pal_lock); INIT_LIST_HEAD(&rc->pals); } diff --git a/trunk/drivers/uwb/radio.c b/trunk/drivers/uwb/radio.c deleted file mode 100644 index f0d55495f5e9..000000000000 --- a/trunk/drivers/uwb/radio.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * UWB radio (channel) management. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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, see . - */ -#include -#include - -#include "uwb-internal.h" - - -static int uwb_radio_select_channel(struct uwb_rc *rc) -{ - /* - * Default to channel 9 (BG1, TFC1) unless the user has - * selected a specific channel or there are no active PALs. - */ - if (rc->active_pals == 0) - return -1; - if (rc->beaconing_forced) - return rc->beaconing_forced; - return 9; -} - - -/* - * Notify all active PALs that the channel has changed. - */ -static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel) -{ - struct uwb_pal *pal; - - list_for_each_entry(pal, &rc->pals, node) { - if (pal->channel && channel != pal->channel) { - pal->channel = channel; - if (pal->channel_changed) - pal->channel_changed(pal, pal->channel); - } - } -} - -/* - * Change to a new channel and notify any active PALs of the new - * channel. - * - * When stopping the radio, PALs need to be notified first so they can - * terminate any active reservations. - */ -static int uwb_radio_change_channel(struct uwb_rc *rc, int channel) -{ - int ret = 0; - - if (channel == -1) - uwb_radio_channel_changed(rc, channel); - - if (channel != rc->beaconing) { - if (rc->beaconing != -1 && channel != -1) { - /* - * FIXME: should signal the channel change - * with a Channel Change IE. - */ - ret = uwb_radio_change_channel(rc, -1); - if (ret < 0) - return ret; - } - ret = uwb_rc_beacon(rc, channel, 0); - } - - if (channel != -1) - uwb_radio_channel_changed(rc, rc->beaconing); - - return ret; -} - -/** - * uwb_radio_start - request that the radio be started - * @pal: the PAL making the request. - * - * If the radio is not already active, aa suitable channel is selected - * and beacons are started. - */ -int uwb_radio_start(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - int ret = 0; - - mutex_lock(&rc->uwb_dev.mutex); - - if (!pal->channel) { - pal->channel = -1; - rc->active_pals++; - ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc)); - } - - mutex_unlock(&rc->uwb_dev.mutex); - return ret; -} -EXPORT_SYMBOL_GPL(uwb_radio_start); - -/** - * uwb_radio_stop - request tha the radio be stopped. - * @pal: the PAL making the request. - * - * Stops the radio if no other PAL is making use of it. - */ -void uwb_radio_stop(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - - mutex_lock(&rc->uwb_dev.mutex); - - if (pal->channel) { - rc->active_pals--; - uwb_radio_change_channel(rc, uwb_radio_select_channel(rc)); - pal->channel = 0; - } - - mutex_unlock(&rc->uwb_dev.mutex); -} -EXPORT_SYMBOL_GPL(uwb_radio_stop); - -/* - * uwb_radio_force_channel - force a specific channel to be used - * @rc: the radio controller. - * @channel: the channel to use; -1 to force the radio to stop; 0 to - * use the default channel selection algorithm. - */ -int uwb_radio_force_channel(struct uwb_rc *rc, int channel) -{ - int ret = 0; - - mutex_lock(&rc->uwb_dev.mutex); - - rc->beaconing_forced = channel; - ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc)); - - mutex_unlock(&rc->uwb_dev.mutex); - return ret; -} - -/* - * uwb_radio_setup - setup the radio manager - * @rc: the radio controller. - * - * The radio controller is reset to ensure it's in a known state - * before it's used. - */ -int uwb_radio_setup(struct uwb_rc *rc) -{ - return uwb_rc_reset(rc); -} - -/* - * uwb_radio_reset_state - reset any radio manager state - * @rc: the radio controller. - * - * All internal radio manager state is reset to values corresponding - * to a reset radio controller. - */ -void uwb_radio_reset_state(struct uwb_rc *rc) -{ - struct uwb_pal *pal; - - mutex_lock(&rc->uwb_dev.mutex); - - list_for_each_entry(pal, &rc->pals, node) { - if (pal->channel) { - pal->channel = -1; - if (pal->channel_changed) - pal->channel_changed(pal, -1); - } - } - - rc->beaconing = -1; - rc->scanning = -1; - - mutex_unlock(&rc->uwb_dev.mutex); -} - -/* - * uwb_radio_shutdown - shutdown the radio manager - * @rc: the radio controller. - * - * The radio controller is reset. - */ -void uwb_radio_shutdown(struct uwb_rc *rc) -{ - uwb_radio_reset_state(rc); - uwb_rc_reset(rc); -} diff --git a/trunk/drivers/uwb/reset.c b/trunk/drivers/uwb/reset.c index 70f8050221ff..8de856fa7958 100644 --- a/trunk/drivers/uwb/reset.c +++ b/trunk/drivers/uwb/reset.c @@ -32,6 +32,8 @@ #include #include "uwb-internal.h" +#define D_LOCAL 0 +#include /** * Command result codes (WUSB1.0[T8-69]) @@ -321,16 +323,17 @@ int uwbd_msg_handle_reset(struct uwb_event *evt) struct uwb_rc *rc = evt->rc; int ret; + /* Need to prevent the RC hardware module going away while in + the rc->reset() call. */ + if (!try_module_get(rc->owner)) + return 0; + dev_info(&rc->uwb_dev.dev, "resetting radio controller\n"); ret = rc->reset(rc); - if (ret) { + if (ret) dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret); - goto error; - } - return 0; -error: - /* Nothing can be done except try the reset again. */ - uwb_rc_reset_all(rc); + + module_put(rc->owner); return ret; } @@ -357,33 +360,3 @@ void uwb_rc_reset_all(struct uwb_rc *rc) uwbd_event_queue(evt); } EXPORT_SYMBOL_GPL(uwb_rc_reset_all); - -void uwb_rc_pre_reset(struct uwb_rc *rc) -{ - rc->stop(rc); - uwbd_flush(rc); - - uwb_radio_reset_state(rc); - uwb_rsv_remove_all(rc); -} -EXPORT_SYMBOL_GPL(uwb_rc_pre_reset); - -void uwb_rc_post_reset(struct uwb_rc *rc) -{ - int ret; - - ret = rc->start(rc); - if (ret) - goto error; - ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr); - if (ret) - goto error; - ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr); - if (ret) - goto error; - return; -error: - /* Nothing can be done except try the reset again. */ - uwb_rc_reset_all(rc); -} -EXPORT_SYMBOL_GPL(uwb_rc_post_reset); diff --git a/trunk/drivers/uwb/rsv.c b/trunk/drivers/uwb/rsv.c index ec6eecb32f30..bae16204576d 100644 --- a/trunk/drivers/uwb/rsv.c +++ b/trunk/drivers/uwb/rsv.c @@ -15,33 +15,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include -#include #include "uwb-internal.h" static void uwb_rsv_timer(unsigned long arg); static const char *rsv_states[] = { - [UWB_RSV_STATE_NONE] = "none ", - [UWB_RSV_STATE_O_INITIATED] = "o initiated ", - [UWB_RSV_STATE_O_PENDING] = "o pending ", - [UWB_RSV_STATE_O_MODIFIED] = "o modified ", - [UWB_RSV_STATE_O_ESTABLISHED] = "o established ", - [UWB_RSV_STATE_O_TO_BE_MOVED] = "o to be moved ", - [UWB_RSV_STATE_O_MOVE_EXPANDING] = "o move expanding", - [UWB_RSV_STATE_O_MOVE_COMBINING] = "o move combining", - [UWB_RSV_STATE_O_MOVE_REDUCING] = "o move reducing ", - [UWB_RSV_STATE_T_ACCEPTED] = "t accepted ", - [UWB_RSV_STATE_T_CONFLICT] = "t conflict ", - [UWB_RSV_STATE_T_PENDING] = "t pending ", - [UWB_RSV_STATE_T_DENIED] = "t denied ", - [UWB_RSV_STATE_T_RESIZED] = "t resized ", - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = "t expanding acc ", - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = "t expanding conf", - [UWB_RSV_STATE_T_EXPANDING_PENDING] = "t expanding pend", - [UWB_RSV_STATE_T_EXPANDING_DENIED] = "t expanding den ", + [UWB_RSV_STATE_NONE] = "none", + [UWB_RSV_STATE_O_INITIATED] = "initiated", + [UWB_RSV_STATE_O_PENDING] = "pending", + [UWB_RSV_STATE_O_MODIFIED] = "modified", + [UWB_RSV_STATE_O_ESTABLISHED] = "established", + [UWB_RSV_STATE_T_ACCEPTED] = "accepted", + [UWB_RSV_STATE_T_DENIED] = "denied", + [UWB_RSV_STATE_T_PENDING] = "pending", }; static const char *rsv_types[] = { @@ -52,31 +42,6 @@ static const char *rsv_types[] = { [UWB_DRP_TYPE_PCA] = "pca", }; -bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv) -{ - static const bool has_two_drp_ies[] = { - [UWB_RSV_STATE_O_INITIATED] = false, - [UWB_RSV_STATE_O_PENDING] = false, - [UWB_RSV_STATE_O_MODIFIED] = false, - [UWB_RSV_STATE_O_ESTABLISHED] = false, - [UWB_RSV_STATE_O_TO_BE_MOVED] = false, - [UWB_RSV_STATE_O_MOVE_COMBINING] = false, - [UWB_RSV_STATE_O_MOVE_REDUCING] = false, - [UWB_RSV_STATE_O_MOVE_EXPANDING] = true, - [UWB_RSV_STATE_T_ACCEPTED] = false, - [UWB_RSV_STATE_T_CONFLICT] = false, - [UWB_RSV_STATE_T_PENDING] = false, - [UWB_RSV_STATE_T_DENIED] = false, - [UWB_RSV_STATE_T_RESIZED] = false, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = true, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = true, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = true, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = true, - }; - - return has_two_drp_ies[rsv->state]; -} - /** * uwb_rsv_state_str - return a string for a reservation state * @state: the reservation state. @@ -101,7 +66,7 @@ const char *uwb_rsv_type_str(enum uwb_drp_type type) } EXPORT_SYMBOL_GPL(uwb_rsv_type_str); -void uwb_rsv_dump(char *text, struct uwb_rsv *rsv) +static void uwb_rsv_dump(struct uwb_rsv *rsv) { struct device *dev = &rsv->rc->uwb_dev.dev; struct uwb_dev_addr devaddr; @@ -117,23 +82,6 @@ void uwb_rsv_dump(char *text, struct uwb_rsv *rsv) dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state)); } -static void uwb_rsv_release(struct kref *kref) -{ - struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref); - - kfree(rsv); -} - -void uwb_rsv_get(struct uwb_rsv *rsv) -{ - kref_get(&rsv->kref); -} - -void uwb_rsv_put(struct uwb_rsv *rsv) -{ - kref_put(&rsv->kref, uwb_rsv_release); -} - /* * Get a free stream index for a reservation. * @@ -144,7 +92,6 @@ void uwb_rsv_put(struct uwb_rsv *rsv) static int uwb_rsv_get_stream(struct uwb_rsv *rsv) { struct uwb_rc *rc = rsv->rc; - struct device *dev = &rc->uwb_dev.dev; unsigned long *streams_bm; int stream; @@ -166,15 +113,12 @@ static int uwb_rsv_get_stream(struct uwb_rsv *rsv) rsv->stream = stream; set_bit(stream, streams_bm); - dev_dbg(dev, "get stream %d\n", rsv->stream); - return 0; } static void uwb_rsv_put_stream(struct uwb_rsv *rsv) { struct uwb_rc *rc = rsv->rc; - struct device *dev = &rc->uwb_dev.dev; unsigned long *streams_bm; switch (rsv->target.type) { @@ -189,52 +133,86 @@ static void uwb_rsv_put_stream(struct uwb_rsv *rsv) } clear_bit(rsv->stream, streams_bm); - - dev_dbg(dev, "put stream %d\n", rsv->stream); } -void uwb_rsv_backoff_win_timer(unsigned long arg) +/* + * Generate a MAS allocation with a single row component. + */ +static void uwb_rsv_gen_alloc_row(struct uwb_mas_bm *mas, + int first_mas, int mas_per_zone, + int zs, int ze) { - struct uwb_drp_backoff_win *bow = (struct uwb_drp_backoff_win *)arg; - struct uwb_rc *rc = container_of(bow, struct uwb_rc, bow); - struct device *dev = &rc->uwb_dev.dev; - - bow->can_reserve_extra_mases = true; - if (bow->total_expired <= 4) { - bow->total_expired++; - } else { - /* after 4 backoff window has expired we can exit from - * the backoff procedure */ - bow->total_expired = 0; - bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1; - } - dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n: ", bow->total_expired, bow->n); + struct uwb_mas_bm col; + int z; - /* try to relocate all the "to be moved" relocations */ - uwb_rsv_handle_drp_avail_change(rc); + bitmap_zero(mas->bm, UWB_NUM_MAS); + bitmap_zero(col.bm, UWB_NUM_MAS); + bitmap_fill(col.bm, mas_per_zone); + bitmap_shift_left(col.bm, col.bm, first_mas + zs * UWB_MAS_PER_ZONE, UWB_NUM_MAS); + + for (z = zs; z <= ze; z++) { + bitmap_or(mas->bm, mas->bm, col.bm, UWB_NUM_MAS); + bitmap_shift_left(col.bm, col.bm, UWB_MAS_PER_ZONE, UWB_NUM_MAS); + } } -void uwb_rsv_backoff_win_increment(struct uwb_rc *rc) +/* + * Allocate some MAS for this reservation based on current local + * availability, the reservation parameters (max_mas, min_mas, + * sparsity), and the WiMedia rules for MAS allocations. + * + * Returns -EBUSY is insufficient free MAS are available. + * + * FIXME: to simplify this, only safe reservations with a single row + * component in zones 1 to 15 are tried (zone 0 is skipped to avoid + * problems with the MAS reserved for the BP). + * + * [ECMA-368] section B.2. + */ +static int uwb_rsv_alloc_mas(struct uwb_rsv *rsv) { - struct uwb_drp_backoff_win *bow = &rc->bow; - struct device *dev = &rc->uwb_dev.dev; - unsigned timeout_us; + static const int safe_mas_in_row[UWB_NUM_ZONES] = { + 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, + }; + int n, r; + struct uwb_mas_bm mas; + bool found = false; - dev_dbg(dev, "backoff_win_increment: window=%d\n", bow->window); + /* + * Search all valid safe allocations until either: too few MAS + * are available; or the smallest allocation with sufficient + * MAS is found. + * + * The top of the zones are preferred, so space for larger + * allocations is available in the bottom of the zone (e.g., a + * 15 MAS allocation should start in row 14 leaving space for + * a 120 MAS allocation at row 0). + */ + for (n = safe_mas_in_row[0]; n >= 1; n--) { + int num_mas; - bow->can_reserve_extra_mases = false; + num_mas = n * (UWB_NUM_ZONES - 1); + if (num_mas < rsv->min_mas) + break; + if (found && num_mas < rsv->max_mas) + break; - if((bow->window << 1) == UWB_DRP_BACKOFF_WIN_MAX) - return; + for (r = UWB_MAS_PER_ZONE-1; r >= 0; r--) { + if (safe_mas_in_row[r] < n) + continue; + uwb_rsv_gen_alloc_row(&mas, r, n, 1, UWB_NUM_ZONES); + if (uwb_drp_avail_reserve_pending(rsv->rc, &mas) == 0) { + found = true; + break; + } + } + } - bow->window <<= 1; - bow->n = random32() & (bow->window - 1); - dev_dbg(dev, "new_window=%d, n=%d\n: ", bow->window, bow->n); + if (!found) + return -EBUSY; - /* reset the timer associated variables */ - timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US; - bow->total_expired = 0; - mod_timer(&bow->timer, jiffies + usecs_to_jiffies(timeout_us)); + bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS); + return 0; } static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv) @@ -247,16 +225,13 @@ static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv) * received. */ if (rsv->is_multicast) { - if (rsv->state == UWB_RSV_STATE_O_INITIATED - || rsv->state == UWB_RSV_STATE_O_MOVE_EXPANDING - || rsv->state == UWB_RSV_STATE_O_MOVE_COMBINING - || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) + if (rsv->state == UWB_RSV_STATE_O_INITIATED) sframes = 1; if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED) sframes = 0; - } + rsv->expired = false; if (sframes > 0) { /* * Add an additional 2 superframes to account for the @@ -278,7 +253,7 @@ static void uwb_rsv_state_update(struct uwb_rsv *rsv, rsv->state = new_state; rsv->ie_valid = false; - uwb_rsv_dump("SU", rsv); + uwb_rsv_dump(rsv); uwb_rsv_stroke_timer(rsv); uwb_rsv_sched_update(rsv->rc); @@ -292,17 +267,10 @@ static void uwb_rsv_callback(struct uwb_rsv *rsv) void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) { - struct uwb_rsv_move *mv = &rsv->mv; - if (rsv->state == new_state) { switch (rsv->state) { case UWB_RSV_STATE_O_ESTABLISHED: - case UWB_RSV_STATE_O_MOVE_EXPANDING: - case UWB_RSV_STATE_O_MOVE_COMBINING: - case UWB_RSV_STATE_O_MOVE_REDUCING: case UWB_RSV_STATE_T_ACCEPTED: - case UWB_RSV_STATE_T_EXPANDING_ACCEPTED: - case UWB_RSV_STATE_T_RESIZED: case UWB_RSV_STATE_NONE: uwb_rsv_stroke_timer(rsv); break; @@ -314,10 +282,10 @@ void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) return; } - uwb_rsv_dump("SC", rsv); - switch (new_state) { case UWB_RSV_STATE_NONE: + uwb_drp_avail_release(rsv->rc, &rsv->mas); + uwb_rsv_put_stream(rsv); uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE); uwb_rsv_callback(rsv); break; @@ -327,45 +295,12 @@ void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) case UWB_RSV_STATE_O_PENDING: uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING); break; - case UWB_RSV_STATE_O_MODIFIED: - /* in the companion there are the MASes to drop */ - bitmap_andnot(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MODIFIED); - break; case UWB_RSV_STATE_O_ESTABLISHED: - if (rsv->state == UWB_RSV_STATE_O_MODIFIED - || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) { - uwb_drp_avail_release(rsv->rc, &mv->companion_mas); - rsv->needs_release_companion_mas = false; - } uwb_drp_avail_reserve(rsv->rc, &rsv->mas); uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED); uwb_rsv_callback(rsv); break; - case UWB_RSV_STATE_O_MOVE_EXPANDING: - rsv->needs_release_companion_mas = true; - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING); - break; - case UWB_RSV_STATE_O_MOVE_COMBINING: - rsv->needs_release_companion_mas = false; - uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas); - bitmap_or(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS); - rsv->mas.safe += mv->companion_mas.safe; - rsv->mas.unsafe += mv->companion_mas.unsafe; - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - break; - case UWB_RSV_STATE_O_MOVE_REDUCING: - bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS); - rsv->needs_release_companion_mas = true; - rsv->mas.safe = mv->final_mas.safe; - rsv->mas.unsafe = mv->final_mas.unsafe; - bitmap_copy(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS); - bitmap_copy(rsv->mas.unsafe_bm, mv->final_mas.unsafe_bm, UWB_NUM_MAS); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - break; case UWB_RSV_STATE_T_ACCEPTED: - case UWB_RSV_STATE_T_RESIZED: - rsv->needs_release_companion_mas = false; uwb_drp_avail_reserve(rsv->rc, &rsv->mas); uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED); uwb_rsv_callback(rsv); @@ -373,82 +308,12 @@ void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) case UWB_RSV_STATE_T_DENIED: uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED); break; - case UWB_RSV_STATE_T_CONFLICT: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_CONFLICT); - break; - case UWB_RSV_STATE_T_PENDING: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_PENDING); - break; - case UWB_RSV_STATE_T_EXPANDING_ACCEPTED: - rsv->needs_release_companion_mas = true; - uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED); - break; default: dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n", uwb_rsv_state_str(new_state), new_state); } } -static void uwb_rsv_handle_timeout_work(struct work_struct *work) -{ - struct uwb_rsv *rsv = container_of(work, struct uwb_rsv, - handle_timeout_work); - struct uwb_rc *rc = rsv->rc; - - mutex_lock(&rc->rsvs_mutex); - - uwb_rsv_dump("TO", rsv); - - switch (rsv->state) { - case UWB_RSV_STATE_O_INITIATED: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - goto unlock; - } - break; - case UWB_RSV_STATE_O_MOVE_EXPANDING: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - goto unlock; - } - break; - case UWB_RSV_STATE_O_MOVE_COMBINING: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - goto unlock; - } - break; - case UWB_RSV_STATE_O_MOVE_REDUCING: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - goto unlock; - } - break; - case UWB_RSV_STATE_O_ESTABLISHED: - if (rsv->is_multicast) - goto unlock; - break; - case UWB_RSV_STATE_T_EXPANDING_ACCEPTED: - /* - * The time out could be for the main or of the - * companion DRP, assume it's for the companion and - * drop that first. A further time out is required to - * drop the main. - */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - goto unlock; - default: - break; - } - - uwb_rsv_remove(rsv); - -unlock: - mutex_unlock(&rc->rsvs_mutex); -} - static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) { struct uwb_rsv *rsv; @@ -459,17 +324,23 @@ static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) INIT_LIST_HEAD(&rsv->rc_node); INIT_LIST_HEAD(&rsv->pal_node); - kref_init(&rsv->kref); init_timer(&rsv->timer); rsv->timer.function = uwb_rsv_timer; rsv->timer.data = (unsigned long)rsv; rsv->rc = rc; - INIT_WORK(&rsv->handle_timeout_work, uwb_rsv_handle_timeout_work); return rsv; } +static void uwb_rsv_free(struct uwb_rsv *rsv) +{ + uwb_dev_put(rsv->owner); + if (rsv->target.type == UWB_RSV_TARGET_DEV) + uwb_dev_put(rsv->target.dev); + kfree(rsv); +} + /** * uwb_rsv_create - allocate and initialize a UWB reservation structure * @rc: the radio controller @@ -500,36 +371,26 @@ EXPORT_SYMBOL_GPL(uwb_rsv_create); void uwb_rsv_remove(struct uwb_rsv *rsv) { - uwb_rsv_dump("RM", rsv); - if (rsv->state != UWB_RSV_STATE_NONE) uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); - - if (rsv->needs_release_companion_mas) - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - uwb_drp_avail_release(rsv->rc, &rsv->mas); - - if (uwb_rsv_is_owner(rsv)) - uwb_rsv_put_stream(rsv); - del_timer_sync(&rsv->timer); - uwb_dev_put(rsv->owner); - if (rsv->target.type == UWB_RSV_TARGET_DEV) - uwb_dev_put(rsv->target.dev); - - list_del_init(&rsv->rc_node); - uwb_rsv_put(rsv); + list_del(&rsv->rc_node); + uwb_rsv_free(rsv); } /** * uwb_rsv_destroy - free a UWB reservation structure * @rsv: the reservation to free * - * The reservation must already be terminated. + * The reservation will be terminated if it is pending or established. */ void uwb_rsv_destroy(struct uwb_rsv *rsv) { - uwb_rsv_put(rsv); + struct uwb_rc *rc = rsv->rc; + + mutex_lock(&rc->rsvs_mutex); + uwb_rsv_remove(rsv); + mutex_unlock(&rc->rsvs_mutex); } EXPORT_SYMBOL_GPL(uwb_rsv_destroy); @@ -538,7 +399,7 @@ EXPORT_SYMBOL_GPL(uwb_rsv_destroy); * @rsv: the reservation * * The PAL should fill in @rsv's owner, target, type, max_mas, - * min_mas, max_interval and is_multicast fields. If the target is a + * min_mas, sparsity and is_multicast fields. If the target is a * uwb_dev it must be referenced. * * The reservation's callback will be called when the reservation is @@ -547,32 +408,20 @@ EXPORT_SYMBOL_GPL(uwb_rsv_destroy); int uwb_rsv_establish(struct uwb_rsv *rsv) { struct uwb_rc *rc = rsv->rc; - struct uwb_mas_bm available; int ret; mutex_lock(&rc->rsvs_mutex); + ret = uwb_rsv_get_stream(rsv); if (ret) goto out; - rsv->tiebreaker = random32() & 1; - /* get available mas bitmap */ - uwb_drp_available(rc, &available); - - ret = uwb_rsv_find_best_allocation(rsv, &available, &rsv->mas); - if (ret == UWB_RSV_ALLOC_NOT_FOUND) { - ret = -EBUSY; - uwb_rsv_put_stream(rsv); - goto out; - } - - ret = uwb_drp_avail_reserve_pending(rc, &rsv->mas); - if (ret != 0) { + ret = uwb_rsv_alloc_mas(rsv); + if (ret) { uwb_rsv_put_stream(rsv); goto out; } - uwb_rsv_get(rsv); list_add_tail(&rsv->rc_node, &rc->reservations); rsv->owner = &rc->uwb_dev; uwb_dev_get(rsv->owner); @@ -588,71 +437,16 @@ EXPORT_SYMBOL_GPL(uwb_rsv_establish); * @rsv: the reservation to modify * @max_mas: new maximum MAS to reserve * @min_mas: new minimum MAS to reserve - * @max_interval: new max_interval to use + * @sparsity: new sparsity to use * * FIXME: implement this once there are PALs that use it. */ -int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int max_interval) +int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int sparsity) { return -ENOSYS; } EXPORT_SYMBOL_GPL(uwb_rsv_modify); -/* - * move an already established reservation (rc->rsvs_mutex must to be - * taken when tis function is called) - */ -int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available) -{ - struct uwb_rc *rc = rsv->rc; - struct uwb_drp_backoff_win *bow = &rc->bow; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rsv_move *mv; - int ret = 0; - - if (bow->can_reserve_extra_mases == false) - return -EBUSY; - - mv = &rsv->mv; - - if (uwb_rsv_find_best_allocation(rsv, available, &mv->final_mas) == UWB_RSV_ALLOC_FOUND) { - - if (!bitmap_equal(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS)) { - /* We want to move the reservation */ - bitmap_andnot(mv->companion_mas.bm, mv->final_mas.bm, rsv->mas.bm, UWB_NUM_MAS); - uwb_drp_avail_reserve_pending(rc, &mv->companion_mas); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING); - } - } else { - dev_dbg(dev, "new allocation not found\n"); - } - - return ret; -} - -/* It will try to move every reservation in state O_ESTABLISHED giving - * to the MAS allocator algorithm an availability that is the real one - * plus the allocation already established from the reservation. */ -void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc) -{ - struct uwb_drp_backoff_win *bow = &rc->bow; - struct uwb_rsv *rsv; - struct uwb_mas_bm mas; - - if (bow->can_reserve_extra_mases == false) - return; - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED || - rsv->state == UWB_RSV_STATE_O_TO_BE_MOVED) { - uwb_drp_available(rc, &mas); - bitmap_or(mas.bm, mas.bm, rsv->mas.bm, UWB_NUM_MAS); - uwb_rsv_try_move(rsv, &mas); - } - } - -} - /** * uwb_rsv_terminate - terminate an established reservation * @rsv: the reservation to terminate @@ -669,8 +463,7 @@ void uwb_rsv_terminate(struct uwb_rsv *rsv) mutex_lock(&rc->rsvs_mutex); - if (rsv->state != UWB_RSV_STATE_NONE) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); + uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); mutex_unlock(&rc->rsvs_mutex); } @@ -684,14 +477,9 @@ EXPORT_SYMBOL_GPL(uwb_rsv_terminate); * * Reservation requests from peers are denied unless a PAL accepts it * by calling this function. - * - * The PAL call uwb_rsv_destroy() for all accepted reservations before - * calling uwb_pal_unregister(). */ void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv) { - uwb_rsv_get(rsv); - rsv->callback = cb; rsv->pal_priv = pal_priv; rsv->state = UWB_RSV_STATE_T_ACCEPTED; @@ -742,9 +530,9 @@ static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, uwb_dev_get(rsv->owner); rsv->target.type = UWB_RSV_TARGET_DEV; rsv->target.dev = &rc->uwb_dev; - uwb_dev_get(&rc->uwb_dev); rsv->type = uwb_ie_drp_type(drp_ie); rsv->stream = uwb_ie_drp_stream_index(drp_ie); + set_bit(rsv->stream, rsv->owner->streams); uwb_drp_ie_to_bm(&rsv->mas, drp_ie); /* @@ -752,45 +540,23 @@ static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, * deny the request. */ rsv->state = UWB_RSV_STATE_T_DENIED; - mutex_lock(&rc->uwb_dev.mutex); + spin_lock(&rc->pal_lock); list_for_each_entry(pal, &rc->pals, node) { if (pal->new_rsv) - pal->new_rsv(pal, rsv); + pal->new_rsv(rsv); if (rsv->state == UWB_RSV_STATE_T_ACCEPTED) break; } - mutex_unlock(&rc->uwb_dev.mutex); + spin_unlock(&rc->pal_lock); list_add_tail(&rsv->rc_node, &rc->reservations); state = rsv->state; rsv->state = UWB_RSV_STATE_NONE; - - /* FIXME: do something sensible here */ - if (state == UWB_RSV_STATE_T_ACCEPTED - && uwb_drp_avail_reserve_pending(rc, &rsv->mas) == -EBUSY) { - /* FIXME: do something sensible here */ - } else { - uwb_rsv_set_state(rsv, state); - } + uwb_rsv_set_state(rsv, state); return rsv; } -/** - * uwb_rsv_get_usable_mas - get the bitmap of the usable MAS of a reservations - * @rsv: the reservation. - * @mas: returns the available MAS. - * - * The usable MAS of a reservation may be less than the negotiated MAS - * if alien BPs are present. - */ -void uwb_rsv_get_usable_mas(struct uwb_rsv *rsv, struct uwb_mas_bm *mas) -{ - bitmap_zero(mas->bm, UWB_NUM_MAS); - bitmap_andnot(mas->bm, rsv->mas.bm, rsv->rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS); -} -EXPORT_SYMBOL_GPL(uwb_rsv_get_usable_mas); - /** * uwb_rsv_find - find a reservation for a received DRP IE. * @rc: the radio controller @@ -830,6 +596,8 @@ static bool uwb_rsv_update_all(struct uwb_rc *rc) bool ie_updated = false; list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { + if (rsv->expired) + uwb_drp_handle_timeout(rsv); if (!rsv->ie_valid) { uwb_drp_ie_update(rsv); ie_updated = true; @@ -839,47 +607,9 @@ static bool uwb_rsv_update_all(struct uwb_rc *rc) return ie_updated; } -void uwb_rsv_queue_update(struct uwb_rc *rc) -{ - unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; - - queue_delayed_work(rc->rsv_workq, &rc->rsv_update_work, usecs_to_jiffies(delay_us)); -} - -/** - * uwb_rsv_sched_update - schedule an update of the DRP IEs - * @rc: the radio controller. - * - * To improve performance and ensure correctness with [ECMA-368] the - * number of SET-DRP-IE commands that are done are limited. - * - * DRP IEs update come from two sources: DRP events from the hardware - * which all occur at the beginning of the superframe ('syncronous' - * events) and reservation establishment/termination requests from - * PALs or timers ('asynchronous' events). - * - * A delayed work ensures that all the synchronous events result in - * one SET-DRP-IE command. - * - * Additional logic (the set_drp_ie_pending and rsv_updated_postponed - * flags) will prevent an asynchrous event starting a SET-DRP-IE - * command if one is currently awaiting a response. - * - * FIXME: this does leave a window where an asynchrous event can delay - * the SET-DRP-IE for a synchronous event by one superframe. - */ void uwb_rsv_sched_update(struct uwb_rc *rc) { - spin_lock(&rc->rsvs_lock); - if (!delayed_work_pending(&rc->rsv_update_work)) { - if (rc->set_drp_ie_pending > 0) { - rc->set_drp_ie_pending++; - goto unlock; - } - uwb_rsv_queue_update(rc); - } -unlock: - spin_unlock(&rc->rsvs_lock); + queue_work(rc->rsv_workq, &rc->rsv_update_work); } /* @@ -888,8 +618,7 @@ void uwb_rsv_sched_update(struct uwb_rc *rc) */ static void uwb_rsv_update_work(struct work_struct *work) { - struct uwb_rc *rc = container_of(work, struct uwb_rc, - rsv_update_work.work); + struct uwb_rc *rc = container_of(work, struct uwb_rc, rsv_update_work); bool ie_updated; mutex_lock(&rc->rsvs_mutex); @@ -901,71 +630,25 @@ static void uwb_rsv_update_work(struct work_struct *work) ie_updated = true; } - if (ie_updated && (rc->set_drp_ie_pending == 0)) + if (ie_updated) uwb_rc_send_all_drp_ie(rc); mutex_unlock(&rc->rsvs_mutex); } -static void uwb_rsv_alien_bp_work(struct work_struct *work) -{ - struct uwb_rc *rc = container_of(work, struct uwb_rc, - rsv_alien_bp_work.work); - struct uwb_rsv *rsv; - - mutex_lock(&rc->rsvs_mutex); - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->type != UWB_DRP_TYPE_ALIEN_BP) { - rsv->callback(rsv); - } - } - - mutex_unlock(&rc->rsvs_mutex); -} - static void uwb_rsv_timer(unsigned long arg) { struct uwb_rsv *rsv = (struct uwb_rsv *)arg; - queue_work(rsv->rc->rsv_workq, &rsv->handle_timeout_work); -} - -/** - * uwb_rsv_remove_all - remove all reservations - * @rc: the radio controller - * - * A DRP IE update is not done. - */ -void uwb_rsv_remove_all(struct uwb_rc *rc) -{ - struct uwb_rsv *rsv, *t; - - mutex_lock(&rc->rsvs_mutex); - list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { - uwb_rsv_remove(rsv); - } - /* Cancel any postponed update. */ - rc->set_drp_ie_pending = 0; - mutex_unlock(&rc->rsvs_mutex); - - cancel_delayed_work_sync(&rc->rsv_update_work); + rsv->expired = true; + uwb_rsv_sched_update(rsv->rc); } void uwb_rsv_init(struct uwb_rc *rc) { INIT_LIST_HEAD(&rc->reservations); - INIT_LIST_HEAD(&rc->cnflt_alien_list); mutex_init(&rc->rsvs_mutex); - spin_lock_init(&rc->rsvs_lock); - INIT_DELAYED_WORK(&rc->rsv_update_work, uwb_rsv_update_work); - INIT_DELAYED_WORK(&rc->rsv_alien_bp_work, uwb_rsv_alien_bp_work); - rc->bow.can_reserve_extra_mases = true; - rc->bow.total_expired = 0; - rc->bow.window = UWB_DRP_BACKOFF_WIN_MIN >> 1; - init_timer(&rc->bow.timer); - rc->bow.timer.function = uwb_rsv_backoff_win_timer; - rc->bow.timer.data = (unsigned long)&rc->bow; + INIT_WORK(&rc->rsv_update_work, uwb_rsv_update_work); bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS); } @@ -984,6 +667,14 @@ int uwb_rsv_setup(struct uwb_rc *rc) void uwb_rsv_cleanup(struct uwb_rc *rc) { - uwb_rsv_remove_all(rc); + struct uwb_rsv *rsv, *t; + + mutex_lock(&rc->rsvs_mutex); + list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { + uwb_rsv_remove(rsv); + } + mutex_unlock(&rc->rsvs_mutex); + + cancel_work_sync(&rc->rsv_update_work); destroy_workqueue(rc->rsv_workq); } diff --git a/trunk/drivers/uwb/umc-bus.c b/trunk/drivers/uwb/umc-bus.c index 5ad36164c13b..2d8d62d9f53e 100644 --- a/trunk/drivers/uwb/umc-bus.c +++ b/trunk/drivers/uwb/umc-bus.c @@ -11,48 +11,23 @@ #include #include -static int umc_bus_pre_reset_helper(struct device *dev, void *data) +static int umc_bus_unbind_helper(struct device *dev, void *data) { - int ret = 0; - - if (dev->driver) { - struct umc_dev *umc = to_umc_dev(dev); - struct umc_driver *umc_drv = to_umc_driver(dev->driver); - - if (umc_drv->pre_reset) - ret = umc_drv->pre_reset(umc); - else - device_release_driver(dev); - } - return ret; -} - -static int umc_bus_post_reset_helper(struct device *dev, void *data) -{ - int ret = 0; - - if (dev->driver) { - struct umc_dev *umc = to_umc_dev(dev); - struct umc_driver *umc_drv = to_umc_driver(dev->driver); - - if (umc_drv->post_reset) - ret = umc_drv->post_reset(umc); - } else - ret = device_attach(dev); + struct device *parent = data; - return ret; + if (dev->parent == parent && dev->driver) + device_release_driver(dev); + return 0; } /** * umc_controller_reset - reset the whole UMC controller * @umc: the UMC device for the radio controller. * - * Drivers or all capabilities of the controller will have their - * pre_reset methods called or be unbound from their device. Then all - * post_reset methods will be called or the drivers will be rebound. - * - * Radio controllers must provide pre_reset and post_reset methods and - * reset the hardware in their start method. + * Drivers will be unbound from all UMC devices belonging to the + * controller and then the radio controller will be rebound. The + * radio controller is expected to do a full hardware reset when it is + * probed. * * If this is called while a probe() or remove() is in progress it * will return -EAGAIN and not perform the reset. @@ -60,13 +35,14 @@ static int umc_bus_post_reset_helper(struct device *dev, void *data) int umc_controller_reset(struct umc_dev *umc) { struct device *parent = umc->dev.parent; - int ret = 0; + int ret; - if(down_trylock(&parent->sem)) + if (down_trylock(&parent->sem)) return -EAGAIN; - ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper); - if (ret >= 0) - device_for_each_child(parent, parent, umc_bus_post_reset_helper); + bus_for_each_dev(&umc_bus_type, NULL, parent, umc_bus_unbind_helper); + ret = device_attach(&umc->dev); + if (ret == 1) + ret = 0; up(&parent->sem); return ret; @@ -99,10 +75,10 @@ static int umc_bus_rescan_helper(struct device *dev, void *data) if (!dev->driver) ret = device_attach(dev); - return ret; + return ret < 0 ? ret : 0; } -static void umc_bus_rescan(struct device *parent) +static void umc_bus_rescan(void) { int err; @@ -110,7 +86,7 @@ static void umc_bus_rescan(struct device *parent) * We can't use bus_rescan_devices() here as it deadlocks when * it tries to retake the dev->parent semaphore. */ - err = device_for_each_child(parent, NULL, umc_bus_rescan_helper); + err = bus_for_each_dev(&umc_bus_type, NULL, NULL, umc_bus_rescan_helper); if (err < 0) printk(KERN_WARNING "%s: rescan of bus failed: %d\n", KBUILD_MODNAME, err); @@ -144,7 +120,7 @@ static int umc_device_probe(struct device *dev) if (err) put_device(dev); else - umc_bus_rescan(dev->parent); + umc_bus_rescan(); return err; } diff --git a/trunk/drivers/uwb/umc-dev.c b/trunk/drivers/uwb/umc-dev.c index 1fc7d8270bb8..aa44e1c1a102 100644 --- a/trunk/drivers/uwb/umc-dev.c +++ b/trunk/drivers/uwb/umc-dev.c @@ -7,6 +7,8 @@ */ #include #include +#define D_LOCAL 0 +#include static void umc_device_release(struct device *dev) { @@ -29,7 +31,8 @@ struct umc_dev *umc_device_create(struct device *parent, int n) umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL); if (umc) { - dev_set_name(&umc->dev, "%s-%d", dev_name(parent), n); + snprintf(umc->dev.bus_id, sizeof(umc->dev.bus_id), "%s-%d", + parent->bus_id, n); umc->dev.parent = parent; umc->dev.bus = &umc_bus_type; umc->dev.release = umc_device_release; @@ -51,6 +54,8 @@ int umc_device_register(struct umc_dev *umc) { int err; + d_fnstart(3, &umc->dev, "(umc_dev %p)\n", umc); + err = request_resource(umc->resource.parent, &umc->resource); if (err < 0) { dev_err(&umc->dev, "can't allocate resource range " @@ -64,11 +69,13 @@ int umc_device_register(struct umc_dev *umc) err = device_register(&umc->dev); if (err < 0) goto error_device_register; + d_fnend(3, &umc->dev, "(umc_dev %p) = 0\n", umc); return 0; error_device_register: release_resource(&umc->resource); error_request_resource: + d_fnend(3, &umc->dev, "(umc_dev %p) = %d\n", umc, err); return err; } EXPORT_SYMBOL_GPL(umc_device_register); @@ -88,8 +95,10 @@ void umc_device_unregister(struct umc_dev *umc) if (!umc) return; dev = get_device(&umc->dev); + d_fnstart(3, dev, "(umc_dev %p)\n", umc); device_unregister(&umc->dev); release_resource(&umc->resource); + d_fnend(3, dev, "(umc_dev %p) = void\n", umc); put_device(dev); } EXPORT_SYMBOL_GPL(umc_device_unregister); diff --git a/trunk/drivers/uwb/uwb-debug.c b/trunk/drivers/uwb/uwb-debug.c index 4a42993700c1..6d232c35d07d 100644 --- a/trunk/drivers/uwb/uwb-debug.c +++ b/trunk/drivers/uwb/uwb-debug.c @@ -4,7 +4,6 @@ * * Copyright (C) 2005-2006 Intel Corporation * Inaky Perez-Gonzalez - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version @@ -34,9 +33,31 @@ #include #include +#define D_LOCAL 0 +#include #include "uwb-internal.h" +void dump_bytes(struct device *dev, const void *_buf, size_t rsize) +{ + const char *buf = _buf; + char line[32]; + size_t offset = 0; + int cnt, cnt2; + for (cnt = 0; cnt < rsize; cnt += 8) { + size_t rtop = rsize - cnt < 8 ? rsize - cnt : 8; + for (offset = cnt2 = 0; cnt2 < rtop; cnt2++) { + offset += scnprintf(line + offset, sizeof(line) - offset, + "%02x ", buf[cnt + cnt2] & 0xff); + } + if (dev) + dev_info(dev, "%s\n", line); + else + printk(KERN_INFO "%s\n", line); + } +} +EXPORT_SYMBOL_GPL(dump_bytes); + /* * Debug interface * @@ -63,23 +84,26 @@ struct uwb_dbg { struct dentry *reservations_f; struct dentry *accept_f; struct dentry *drp_avail_f; - spinlock_t list_lock; }; static struct dentry *root_dir; static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv) { - struct uwb_dbg *dbg = rsv->pal_priv; - - uwb_rsv_dump("debug", rsv); + struct uwb_rc *rc = rsv->rc; + struct device *dev = &rc->uwb_dev.dev; + struct uwb_dev_addr devaddr; + char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; + + uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); + if (rsv->target.type == UWB_RSV_TARGET_DEV) + devaddr = rsv->target.dev->dev_addr; + else + devaddr = rsv->target.devaddr; + uwb_dev_addr_print(target, sizeof(target), &devaddr); - if (rsv->state == UWB_RSV_STATE_NONE) { - spin_lock(&dbg->list_lock); - list_del(&rsv->pal_node); - spin_unlock(&dbg->list_lock); - uwb_rsv_destroy(rsv); - } + dev_dbg(dev, "debug: rsv %s -> %s: %s\n", + owner, target, uwb_rsv_state_str(rsv->state)); } static int cmd_rsv_establish(struct uwb_rc *rc, @@ -95,27 +119,26 @@ static int cmd_rsv_establish(struct uwb_rc *rc, if (target == NULL) return -ENODEV; - rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg); + rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, NULL); if (rsv == NULL) { uwb_dev_put(target); return -ENOMEM; } - rsv->target.type = UWB_RSV_TARGET_DEV; - rsv->target.dev = target; - rsv->type = cmd->type; - rsv->max_mas = cmd->max_mas; - rsv->min_mas = cmd->min_mas; - rsv->max_interval = cmd->max_interval; + rsv->owner = &rc->uwb_dev; + rsv->target.type = UWB_RSV_TARGET_DEV; + rsv->target.dev = target; + rsv->type = cmd->type; + rsv->max_mas = cmd->max_mas; + rsv->min_mas = cmd->min_mas; + rsv->sparsity = cmd->sparsity; ret = uwb_rsv_establish(rsv); if (ret) uwb_rsv_destroy(rsv); - else { - spin_lock(&(rc->dbg)->list_lock); + else list_add_tail(&rsv->pal_node, &rc->dbg->rsvs); - spin_unlock(&(rc->dbg)->list_lock); - } + return ret; } @@ -125,40 +148,21 @@ static int cmd_rsv_terminate(struct uwb_rc *rc, struct uwb_rsv *rsv, *found = NULL; int i = 0; - spin_lock(&(rc->dbg)->list_lock); - list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) { if (i == cmd->index) { found = rsv; - uwb_rsv_get(found); break; } - i++; } - - spin_unlock(&(rc->dbg)->list_lock); - if (!found) return -EINVAL; + list_del(&found->pal_node); uwb_rsv_terminate(found); - uwb_rsv_put(found); return 0; } -static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add) -{ - return uwb_rc_ie_add(rc, - (const struct uwb_ie_hdr *) ie_to_add->data, - ie_to_add->len); -} - -static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm) -{ - return uwb_rc_ie_rm(rc, ie_to_rm->data[0]); -} - static int command_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -171,8 +175,8 @@ static ssize_t command_write(struct file *file, const char __user *buf, { struct uwb_rc *rc = file->private_data; struct uwb_dbg_cmd cmd; - int ret = 0; - + int ret; + if (len != sizeof(struct uwb_dbg_cmd)) return -EINVAL; @@ -186,18 +190,6 @@ static ssize_t command_write(struct file *file, const char __user *buf, case UWB_DBG_CMD_RSV_TERMINATE: ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate); break; - case UWB_DBG_CMD_IE_ADD: - ret = cmd_ie_add(rc, &cmd.ie_add); - break; - case UWB_DBG_CMD_IE_RM: - ret = cmd_ie_rm(rc, &cmd.ie_rm); - break; - case UWB_DBG_CMD_RADIO_START: - ret = uwb_radio_start(&rc->dbg->pal); - break; - case UWB_DBG_CMD_RADIO_STOP: - uwb_radio_stop(&rc->dbg->pal); - break; default: return -EINVAL; } @@ -291,26 +283,12 @@ static struct file_operations drp_avail_fops = { .owner = THIS_MODULE, }; -static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel) -{ - struct device *dev = &pal->rc->uwb_dev.dev; - - if (channel > 0) - dev_info(dev, "debug: channel %d started\n", channel); - else - dev_info(dev, "debug: channel stopped\n"); -} - -static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv) +static void uwb_dbg_new_rsv(struct uwb_rsv *rsv) { - struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal); + struct uwb_rc *rc = rsv->rc; - if (dbg->accept) { - spin_lock(&dbg->list_lock); - list_add_tail(&rsv->pal_node, &dbg->rsvs); - spin_unlock(&dbg->list_lock); - uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg); - } + if (rc->dbg->accept) + uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL); } /** @@ -324,14 +302,10 @@ void uwb_dbg_add_rc(struct uwb_rc *rc) return; INIT_LIST_HEAD(&rc->dbg->rsvs); - spin_lock_init(&(rc->dbg)->list_lock); uwb_pal_init(&rc->dbg->pal); - rc->dbg->pal.rc = rc; - rc->dbg->pal.channel_changed = uwb_dbg_channel_changed; rc->dbg->pal.new_rsv = uwb_dbg_new_rsv; - uwb_pal_register(&rc->dbg->pal); - + uwb_pal_register(rc, &rc->dbg->pal); if (root_dir) { rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev), root_dir); @@ -351,7 +325,7 @@ void uwb_dbg_add_rc(struct uwb_rc *rc) } /** - * uwb_dbg_del_rc - remove a radio controller's debug interface + * uwb_dbg_add_rc - remove a radio controller's debug interface * @rc: the radio controller */ void uwb_dbg_del_rc(struct uwb_rc *rc) @@ -362,10 +336,10 @@ void uwb_dbg_del_rc(struct uwb_rc *rc) return; list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) { - uwb_rsv_terminate(rsv); + uwb_rsv_destroy(rsv); } - uwb_pal_unregister(&rc->dbg->pal); + uwb_pal_unregister(rc, &rc->dbg->pal); if (root_dir) { debugfs_remove(rc->dbg->drp_avail_f); @@ -391,16 +365,3 @@ void uwb_dbg_exit(void) { debugfs_remove(root_dir); } - -/** - * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL - * @pal: The PAL. - */ -struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - - if (root_dir && rc->dbg && rc->dbg->root_d && pal->name) - return debugfs_create_dir(pal->name, rc->dbg->root_d); - return NULL; -} diff --git a/trunk/drivers/uwb/uwb-internal.h b/trunk/drivers/uwb/uwb-internal.h index d5bcfc1c227a..2ad307d12961 100644 --- a/trunk/drivers/uwb/uwb-internal.h +++ b/trunk/drivers/uwb/uwb-internal.h @@ -66,14 +66,14 @@ extern int uwb_rc_scan(struct uwb_rc *rc, unsigned channel, enum uwb_scan_type type, unsigned bpst_offset); extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc); - -void uwb_rc_ie_init(struct uwb_rc *); -int uwb_rc_ie_setup(struct uwb_rc *); -void uwb_rc_ie_release(struct uwb_rc *); -int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len, - char *buf, size_t size); -int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *); - +extern ssize_t uwb_rc_print_IEs(struct uwb_rc *rc, char *, size_t); +extern void uwb_rc_ie_init(struct uwb_rc *); +extern void uwb_rc_ie_init(struct uwb_rc *); +extern ssize_t uwb_rc_ie_setup(struct uwb_rc *); +extern void uwb_rc_ie_release(struct uwb_rc *); +extern int uwb_rc_ie_add(struct uwb_rc *, + const struct uwb_ie_hdr *, size_t); +extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie); extern const char *uwb_rc_strerror(unsigned code); @@ -92,12 +92,6 @@ extern const char *uwb_rc_strerror(unsigned code); struct uwb_rc_neh; -extern int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name, - struct uwb_rccb *cmd, size_t cmd_size, - u8 expected_type, u16 expected_event, - uwb_rc_cmd_cb_f cb, void *arg); - - void uwb_rc_neh_create(struct uwb_rc *rc); void uwb_rc_neh_destroy(struct uwb_rc *rc); @@ -112,69 +106,7 @@ void uwb_rc_neh_put(struct uwb_rc_neh *neh); extern int uwb_est_create(void); extern void uwb_est_destroy(void); -/* - * UWB conflicting alien reservations - */ -struct uwb_cnflt_alien { - struct uwb_rc *rc; - struct list_head rc_node; - struct uwb_mas_bm mas; - struct timer_list timer; - struct work_struct cnflt_update_work; -}; - -enum uwb_uwb_rsv_alloc_result { - UWB_RSV_ALLOC_FOUND = 0, - UWB_RSV_ALLOC_NOT_FOUND, -}; - -enum uwb_rsv_mas_status { - UWB_RSV_MAS_NOT_AVAIL = 1, - UWB_RSV_MAS_SAFE, - UWB_RSV_MAS_UNSAFE, -}; - -struct uwb_rsv_col_set_info { - unsigned char start_col; - unsigned char interval; - unsigned char safe_mas_per_col; - unsigned char unsafe_mas_per_col; -}; - -struct uwb_rsv_col_info { - unsigned char max_avail_safe; - unsigned char max_avail_unsafe; - unsigned char highest_mas[UWB_MAS_PER_ZONE]; - struct uwb_rsv_col_set_info csi; -}; - -struct uwb_rsv_row_info { - unsigned char avail[UWB_MAS_PER_ZONE]; - unsigned char free_rows; - unsigned char used_rows; -}; - -/* - * UWB find allocation - */ -struct uwb_rsv_alloc_info { - unsigned char bm[UWB_MAS_PER_ZONE * UWB_NUM_ZONES]; - struct uwb_rsv_col_info ci[UWB_NUM_ZONES]; - struct uwb_rsv_row_info ri; - struct uwb_mas_bm *not_available; - struct uwb_mas_bm *result; - int min_mas; - int max_mas; - int max_interval; - int total_allocated_mases; - int safe_allocated_mases; - int unsafe_allocated_mases; - int interval; -}; -int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available, - struct uwb_mas_bm *result); -void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc); /* * UWB Events & management daemon */ @@ -228,14 +160,13 @@ struct uwb_event { }; }; -extern void uwbd_start(struct uwb_rc *rc); -extern void uwbd_stop(struct uwb_rc *rc); +extern void uwbd_start(void); +extern void uwbd_stop(void); extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask); extern void uwbd_event_queue(struct uwb_event *); void uwbd_flush(struct uwb_rc *rc); /* UWB event handlers */ -extern int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *); extern int uwbd_evt_handle_rc_beacon(struct uwb_event *); extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *); extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *); @@ -262,6 +193,15 @@ int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt); extern unsigned long beacon_timeout_ms; +/** Beacon cache list */ +struct uwb_beca { + struct list_head list; + size_t entries; + struct mutex mutex; +}; + +extern struct uwb_beca uwb_beca; + /** * Beacon cache entry * @@ -288,6 +228,9 @@ struct uwb_beca_e { struct uwb_beacon_frame; extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *, char *, size_t); +extern struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *, + struct uwb_beacon_frame *, + unsigned long); extern void uwb_bce_kfree(struct kref *_bce); static inline void uwb_bce_get(struct uwb_beca_e *bce) @@ -298,19 +241,14 @@ static inline void uwb_bce_put(struct uwb_beca_e *bce) { kref_put(&bce->refcnt, uwb_bce_kfree); } -extern void uwb_beca_purge(struct uwb_rc *rc); -extern void uwb_beca_release(struct uwb_rc *rc); +extern void uwb_beca_purge(void); +extern void uwb_beca_release(void); struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, const struct uwb_dev_addr *devaddr); struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, const struct uwb_mac_addr *macaddr); -int uwb_radio_setup(struct uwb_rc *rc); -void uwb_radio_reset_state(struct uwb_rc *rc); -void uwb_radio_shutdown(struct uwb_rc *rc); -int uwb_radio_force_channel(struct uwb_rc *rc, int channel); - /* -- UWB Sysfs representation */ extern struct class uwb_rc_class; extern struct device_attribute dev_attr_mac_address; @@ -321,29 +259,18 @@ extern struct device_attribute dev_attr_scan; void uwb_rsv_init(struct uwb_rc *rc); int uwb_rsv_setup(struct uwb_rc *rc); void uwb_rsv_cleanup(struct uwb_rc *rc); -void uwb_rsv_remove_all(struct uwb_rc *rc); -void uwb_rsv_get(struct uwb_rsv *rsv); -void uwb_rsv_put(struct uwb_rsv *rsv); -bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv); -void uwb_rsv_dump(char *text, struct uwb_rsv *rsv); -int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available); -void uwb_rsv_backoff_win_timer(unsigned long arg); -void uwb_rsv_backoff_win_increment(struct uwb_rc *rc); -int uwb_rsv_status(struct uwb_rsv *rsv); -int uwb_rsv_companion_status(struct uwb_rsv *rsv); void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state); void uwb_rsv_remove(struct uwb_rsv *rsv); struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src, struct uwb_ie_drp *drp_ie); void uwb_rsv_sched_update(struct uwb_rc *rc); -void uwb_rsv_queue_update(struct uwb_rc *rc); +void uwb_drp_handle_timeout(struct uwb_rsv *rsv); int uwb_drp_ie_update(struct uwb_rsv *rsv); void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie); void uwb_drp_avail_init(struct uwb_rc *rc); -void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail); int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas); void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas); void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas); @@ -362,7 +289,8 @@ void uwb_dbg_init(void); void uwb_dbg_exit(void); void uwb_dbg_add_rc(struct uwb_rc *rc); void uwb_dbg_del_rc(struct uwb_rc *rc); -struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal); + +/* Workarounds for version specific stuff */ static inline void uwb_dev_lock(struct uwb_dev *uwb_dev) { diff --git a/trunk/drivers/uwb/uwbd.c b/trunk/drivers/uwb/uwbd.c index 57bd6bfef37e..78908416e42c 100644 --- a/trunk/drivers/uwb/uwbd.c +++ b/trunk/drivers/uwb/uwbd.c @@ -68,13 +68,17 @@ * * Handler functions are called normally uwbd_evt_handle_*(). */ + #include #include #include - #include "uwb-internal.h" -/* +#define D_LOCAL 1 +#include + + +/** * UWBD Event handler function signature * * Return !0 if the event needs not to be freed (ie the handler @@ -97,12 +101,9 @@ struct uwbd_event { const char *name; }; -/* Table of handlers for and properties of the UWBD Radio Control Events */ -static struct uwbd_event uwbd_urc_events[] = { - [UWB_RC_EVT_IE_RCV] = { - .handler = uwbd_evt_handle_rc_ie_rcv, - .name = "IE_RECEIVED" - }, +/** Table of handlers for and properties of the UWBD Radio Control Events */ +static +struct uwbd_event uwbd_events[] = { [UWB_RC_EVT_BEACON] = { .handler = uwbd_evt_handle_rc_beacon, .name = "BEACON_RECEIVED" @@ -141,15 +142,23 @@ struct uwbd_evt_type_handler { size_t size; }; -/* Table of handlers for each UWBD Event type. */ -static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = { - [UWB_RC_CET_GENERAL] = { - .name = "URC", - .uwbd_events = uwbd_urc_events, - .size = ARRAY_SIZE(uwbd_urc_events), - }, +#define UWBD_EVT_TYPE_HANDLER(n,a) { \ + .name = (n), \ + .uwbd_events = (a), \ + .size = sizeof(a)/sizeof((a)[0]) \ +} + + +/** Table of handlers for each UWBD Event type. */ +static +struct uwbd_evt_type_handler uwbd_evt_type_handlers[] = { + [UWB_RC_CET_GENERAL] = UWBD_EVT_TYPE_HANDLER("RC", uwbd_events) }; +static const +size_t uwbd_evt_type_handlers_len = + sizeof(uwbd_evt_type_handlers) / sizeof(uwbd_evt_type_handlers[0]); + static const struct uwbd_event uwbd_message_handlers[] = { [UWB_EVT_MSG_RESET] = { .handler = uwbd_msg_handle_reset, @@ -157,7 +166,9 @@ static const struct uwbd_event uwbd_message_handlers[] = { }, }; -/* +static DEFINE_MUTEX(uwbd_event_mutex); + +/** * Handle an URC event passed to the UWB Daemon * * @evt: the event to handle @@ -177,7 +188,6 @@ static const struct uwbd_event uwbd_message_handlers[] = { static int uwbd_event_handle_urc(struct uwb_event *evt) { - int result = -EINVAL; struct uwbd_evt_type_handler *type_table; uwbd_evt_handler_f handler; u8 type, context; @@ -187,24 +197,26 @@ int uwbd_event_handle_urc(struct uwb_event *evt) event = le16_to_cpu(evt->notif.rceb->wEvent); context = evt->notif.rceb->bEventContext; - if (type > ARRAY_SIZE(uwbd_urc_evt_type_handlers)) - goto out; - type_table = &uwbd_urc_evt_type_handlers[type]; - if (type_table->uwbd_events == NULL) - goto out; - if (event > type_table->size) - goto out; + if (type > uwbd_evt_type_handlers_len) { + printk(KERN_ERR "UWBD: event type %u: unknown (too high)\n", type); + return -EINVAL; + } + type_table = &uwbd_evt_type_handlers[type]; + if (type_table->uwbd_events == NULL) { + printk(KERN_ERR "UWBD: event type %u: unknown\n", type); + return -EINVAL; + } + if (event > type_table->size) { + printk(KERN_ERR "UWBD: event %s[%u]: unknown (too high)\n", + type_table->name, event); + return -EINVAL; + } handler = type_table->uwbd_events[event].handler; - if (handler == NULL) - goto out; - - result = (*handler)(evt); -out: - if (result < 0) - dev_err(&evt->rc->uwb_dev.dev, - "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n", - type, event, context, result); - return result; + if (handler == NULL) { + printk(KERN_ERR "UWBD: event %s[%u]: unknown\n", type_table->name, event); + return -EINVAL; + } + return (*handler)(evt); } static void uwbd_event_handle_message(struct uwb_event *evt) @@ -219,10 +231,19 @@ static void uwbd_event_handle_message(struct uwb_event *evt) return; } + /* If this is a reset event we need to drop the + * uwbd_event_mutex or it deadlocks when the reset handler + * attempts to flush the uwbd events. */ + if (evt->message == UWB_EVT_MSG_RESET) + mutex_unlock(&uwbd_event_mutex); + result = uwbd_message_handlers[evt->message].handler(evt); if (result < 0) dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n", uwbd_message_handlers[evt->message].name, result); + + if (evt->message == UWB_EVT_MSG_RESET) + mutex_lock(&uwbd_event_mutex); } static void uwbd_event_handle(struct uwb_event *evt) @@ -250,6 +271,20 @@ static void uwbd_event_handle(struct uwb_event *evt) __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */ } +/* The UWB Daemon */ + + +/** Daemon's PID: used to decide if we can queue or not */ +static int uwbd_pid; +/** Daemon's task struct for managing the kthread */ +static struct task_struct *uwbd_task; +/** Daemon's waitqueue for waiting for new events */ +static DECLARE_WAIT_QUEUE_HEAD(uwbd_wq); +/** Daemon's list of events; we queue/dequeue here */ +static struct list_head uwbd_event_list = LIST_HEAD_INIT(uwbd_event_list); +/** Daemon's list lock to protect concurent access */ +static DEFINE_SPINLOCK(uwbd_event_list_lock); + /** * UWB Daemon @@ -263,58 +298,65 @@ static void uwbd_event_handle(struct uwb_event *evt) * FIXME: should change so we don't have a 1HZ timer all the time, but * only if there are devices. */ -static int uwbd(void *param) +static int uwbd(void *unused) { - struct uwb_rc *rc = param; unsigned long flags; - struct uwb_event *evt; + struct list_head list = LIST_HEAD_INIT(list); + struct uwb_event *evt, *nxt; int should_stop = 0; - while (1) { wait_event_interruptible_timeout( - rc->uwbd.wq, - !list_empty(&rc->uwbd.event_list) + uwbd_wq, + !list_empty(&uwbd_event_list) || (should_stop = kthread_should_stop()), HZ); if (should_stop) break; try_to_freeze(); - spin_lock_irqsave(&rc->uwbd.event_list_lock, flags); - if (!list_empty(&rc->uwbd.event_list)) { - evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node); + mutex_lock(&uwbd_event_mutex); + spin_lock_irqsave(&uwbd_event_list_lock, flags); + list_splice_init(&uwbd_event_list, &list); + spin_unlock_irqrestore(&uwbd_event_list_lock, flags); + list_for_each_entry_safe(evt, nxt, &list, list_node) { list_del(&evt->list_node); - } else - evt = NULL; - spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags); - - if (evt) { uwbd_event_handle(evt); kfree(evt); } + mutex_unlock(&uwbd_event_mutex); - uwb_beca_purge(rc); /* Purge devices that left */ + uwb_beca_purge(); /* Purge devices that left */ } return 0; } /** Start the UWB daemon */ -void uwbd_start(struct uwb_rc *rc) +void uwbd_start(void) { - rc->uwbd.task = kthread_run(uwbd, rc, "uwbd"); - if (rc->uwbd.task == NULL) + uwbd_task = kthread_run(uwbd, NULL, "uwbd"); + if (uwbd_task == NULL) printk(KERN_ERR "UWB: Cannot start management daemon; " "UWB won't work\n"); else - rc->uwbd.pid = rc->uwbd.task->pid; + uwbd_pid = uwbd_task->pid; } /* Stop the UWB daemon and free any unprocessed events */ -void uwbd_stop(struct uwb_rc *rc) +void uwbd_stop(void) { - kthread_stop(rc->uwbd.task); - uwbd_flush(rc); + unsigned long flags; + struct uwb_event *evt, *nxt; + kthread_stop(uwbd_task); + spin_lock_irqsave(&uwbd_event_list_lock, flags); + uwbd_pid = 0; + list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) { + if (evt->type == UWB_EVT_TYPE_NOTIF) + kfree(evt->notif.rceb); + kfree(evt); + } + spin_unlock_irqrestore(&uwbd_event_list_lock, flags); + uwb_beca_release(); } /* @@ -331,20 +373,18 @@ void uwbd_stop(struct uwb_rc *rc) */ void uwbd_event_queue(struct uwb_event *evt) { - struct uwb_rc *rc = evt->rc; unsigned long flags; - - spin_lock_irqsave(&rc->uwbd.event_list_lock, flags); - if (rc->uwbd.pid != 0) { - list_add(&evt->list_node, &rc->uwbd.event_list); - wake_up_all(&rc->uwbd.wq); + spin_lock_irqsave(&uwbd_event_list_lock, flags); + if (uwbd_pid != 0) { + list_add(&evt->list_node, &uwbd_event_list); + wake_up_all(&uwbd_wq); } else { __uwb_rc_put(evt->rc); if (evt->type == UWB_EVT_TYPE_NOTIF) kfree(evt->notif.rceb); kfree(evt); } - spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags); + spin_unlock_irqrestore(&uwbd_event_list_lock, flags); return; } @@ -352,8 +392,10 @@ void uwbd_flush(struct uwb_rc *rc) { struct uwb_event *evt, *nxt; - spin_lock_irq(&rc->uwbd.event_list_lock); - list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) { + mutex_lock(&uwbd_event_mutex); + + spin_lock_irq(&uwbd_event_list_lock); + list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) { if (evt->rc == rc) { __uwb_rc_put(rc); list_del(&evt->list_node); @@ -362,5 +404,7 @@ void uwbd_flush(struct uwb_rc *rc) kfree(evt); } } - spin_unlock_irq(&rc->uwbd.event_list_lock); + spin_unlock_irq(&uwbd_event_list_lock); + + mutex_unlock(&uwbd_event_mutex); } diff --git a/trunk/drivers/uwb/whc-rc.c b/trunk/drivers/uwb/whc-rc.c index 19a1dd129212..1711deadb114 100644 --- a/trunk/drivers/uwb/whc-rc.c +++ b/trunk/drivers/uwb/whc-rc.c @@ -39,6 +39,7 @@ * them to the hw and transfer the replies/notifications back to the * UWB stack through the UWB daemon (UWBD). */ +#include #include #include #include @@ -48,9 +49,11 @@ #include #include #include - #include "uwb-internal.h" +#define D_LOCAL 0 +#include + /** * Descriptor for an instance of the UWB Radio Control Driver that * attaches to the URC interface of the WHCI PCI card. @@ -95,8 +98,13 @@ static int whcrc_cmd(struct uwb_rc *uwb_rc, struct device *dev = &whcrc->umc_dev->dev; u32 urccmd; - if (cmd_size >= 4096) - return -EINVAL; + d_fnstart(3, dev, "(%p, %p, %zu)\n", uwb_rc, cmd, cmd_size); + might_sleep(); + + if (cmd_size >= 4096) { + result = -E2BIG; + goto error; + } /* * If the URC is halted, then the hardware has reset itself. @@ -107,14 +115,16 @@ static int whcrc_cmd(struct uwb_rc *uwb_rc, if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) { dev_err(dev, "requesting reset of halted radio controller\n"); uwb_rc_reset_all(uwb_rc); - return -EIO; + result = -EIO; + goto error; } result = wait_event_timeout(whcrc->cmd_wq, !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2); if (result == 0) { dev_err(dev, "device is not ready to execute commands\n"); - return -ETIMEDOUT; + result = -ETIMEDOUT; + goto error; } memmove(whcrc->cmd_buf, cmd, cmd_size); @@ -127,7 +137,10 @@ static int whcrc_cmd(struct uwb_rc *uwb_rc, whcrc->rc_base + URCCMD); spin_unlock(&whcrc->irq_lock); - return 0; +error: + d_fnend(3, dev, "(%p, %p, %zu) = %d\n", + uwb_rc, cmd, cmd_size, result); + return result; } static int whcrc_reset(struct uwb_rc *rc) @@ -154,25 +167,34 @@ static int whcrc_reset(struct uwb_rc *rc) static void whcrc_enable_events(struct whcrc *whcrc) { + struct device *dev = &whcrc->umc_dev->dev; u32 urccmd; + d_fnstart(4, dev, "(whcrc %p)\n", whcrc); + le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR); spin_lock(&whcrc->irq_lock); urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE; le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD); spin_unlock(&whcrc->irq_lock); + + d_fnend(4, dev, "(whcrc %p) = void\n", whcrc); } static void whcrc_event_work(struct work_struct *work) { struct whcrc *whcrc = container_of(work, struct whcrc, event_work); + struct device *dev = &whcrc->umc_dev->dev; size_t size; u64 urcevtaddr; urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR); size = urcevtaddr & URCEVTADDR_OFFSET_MASK; + d_printf(3, dev, "received %zu octet event\n", size); + d_dump(4, dev, whcrc->evt_buf, size > 32 ? 32 : size); + uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size); whcrc_enable_events(whcrc); } @@ -195,15 +217,22 @@ irqreturn_t whcrc_irq_cb(int irq, void *_whcrc) return IRQ_NONE; le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS); + d_printf(4, dev, "acked 0x%08x, urcsts 0x%08x\n", + le_readl(whcrc->rc_base + URCSTS), urcsts); + if (urcsts & URCSTS_HSE) { dev_err(dev, "host system error -- hardware halted\n"); /* FIXME: do something sensible here */ goto out; } - if (urcsts & URCSTS_ER) + if (urcsts & URCSTS_ER) { + d_printf(3, dev, "ER: event ready\n"); schedule_work(&whcrc->event_work); - if (urcsts & URCSTS_RCI) + } + if (urcsts & URCSTS_RCI) { + d_printf(3, dev, "RCI: ready to execute another command\n"); wake_up_all(&whcrc->cmd_wq); + } out: return IRQ_HANDLED; } @@ -222,7 +251,8 @@ int whcrc_setup_rc_umc(struct whcrc *whcrc) whcrc->area = umc_dev->resource.start; whcrc->rc_len = umc_dev->resource.end - umc_dev->resource.start + 1; result = -EBUSY; - if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) { + if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) + == NULL) { dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n", whcrc->rc_len, whcrc->area, result); goto error_request_region; @@ -257,6 +287,8 @@ int whcrc_setup_rc_umc(struct whcrc *whcrc) dev_err(dev, "Can't allocate evt transfer buffer\n"); goto error_evt_buffer; } + d_printf(3, dev, "UWB RC Interface: %zu bytes at 0x%p, irq %u\n", + whcrc->rc_len, whcrc->rc_base, umc_dev->irq); return 0; error_evt_buffer: @@ -301,23 +333,47 @@ void whcrc_release_rc_umc(struct whcrc *whcrc) static int whcrc_start_rc(struct uwb_rc *rc) { struct whcrc *whcrc = rc->priv; + int result = 0; struct device *dev = &whcrc->umc_dev->dev; + unsigned long start, duration; /* Reset the thing */ le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD); + if (d_test(3)) + start = jiffies; if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0, - 5000, "hardware reset") < 0) - return -EBUSY; + 5000, "device to reset at init") < 0) { + result = -EBUSY; + goto error; + } else if (d_test(3)) { + duration = jiffies - start; + if (duration > msecs_to_jiffies(40)) + dev_err(dev, "Device took %ums to " + "reset. MAX expected: 40ms\n", + jiffies_to_msecs(duration)); + } /* Set the event buffer, start the controller (enable IRQs later) */ le_writel(0, whcrc->rc_base + URCINTR); le_writel(URCCMD_RS, whcrc->rc_base + URCCMD); + result = -ETIMEDOUT; + if (d_test(3)) + start = jiffies; if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0, - 5000, "radio controller start") < 0) - return -ETIMEDOUT; + 5000, "device to start") < 0) + goto error; + if (d_test(3)) { + duration = jiffies - start; + if (duration > msecs_to_jiffies(40)) + dev_err(dev, "Device took %ums to start. " + "MAX expected: 40ms\n", + jiffies_to_msecs(duration)); + } whcrc_enable_events(whcrc); + result = 0; le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR); - return 0; +error: + return result; } @@ -339,7 +395,7 @@ void whcrc_stop_rc(struct uwb_rc *rc) le_writel(0, whcrc->rc_base + URCCMD); whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS, - URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop"); + URCSTS_HALTED, 0, 40, "URCSTS.HALTED"); } static void whcrc_init(struct whcrc *whcrc) @@ -365,6 +421,7 @@ int whcrc_probe(struct umc_dev *umc_dev) struct whcrc *whcrc; struct device *dev = &umc_dev->dev; + d_fnstart(3, dev, "(umc_dev %p)\n", umc_dev); result = -ENOMEM; uwb_rc = uwb_rc_alloc(); if (uwb_rc == NULL) { @@ -396,6 +453,7 @@ int whcrc_probe(struct umc_dev *umc_dev) if (result < 0) goto error_rc_add; umc_set_drvdata(umc_dev, whcrc); + d_fnend(3, dev, "(umc_dev %p) = 0\n", umc_dev); return 0; error_rc_add: @@ -405,6 +463,7 @@ int whcrc_probe(struct umc_dev *umc_dev) error_alloc: uwb_rc_put(uwb_rc); error_rc_alloc: + d_fnend(3, dev, "(umc_dev %p) = %d\n", umc_dev, result); return result; } @@ -427,24 +486,7 @@ static void whcrc_remove(struct umc_dev *umc_dev) whcrc_release_rc_umc(whcrc); kfree(whcrc); uwb_rc_put(uwb_rc); -} - -static int whcrc_pre_reset(struct umc_dev *umc) -{ - struct whcrc *whcrc = umc_get_drvdata(umc); - struct uwb_rc *uwb_rc = whcrc->uwb_rc; - - uwb_rc_pre_reset(uwb_rc); - return 0; -} - -static int whcrc_post_reset(struct umc_dev *umc) -{ - struct whcrc *whcrc = umc_get_drvdata(umc); - struct uwb_rc *uwb_rc = whcrc->uwb_rc; - - uwb_rc_post_reset(uwb_rc); - return 0; + d_printf(1, &umc_dev->dev, "freed whcrc %p\n", whcrc); } /* PCI device ID's that we handle [so it gets loaded] */ @@ -455,12 +497,10 @@ static struct pci_device_id whcrc_id_table[] = { MODULE_DEVICE_TABLE(pci, whcrc_id_table); static struct umc_driver whcrc_driver = { - .name = "whc-rc", - .cap_id = UMC_CAP_ID_WHCI_RC, - .probe = whcrc_probe, - .remove = whcrc_remove, - .pre_reset = whcrc_pre_reset, - .post_reset = whcrc_post_reset, + .name = "whc-rc", + .cap_id = UMC_CAP_ID_WHCI_RC, + .probe = whcrc_probe, + .remove = whcrc_remove, }; static int __init whcrc_driver_init(void) diff --git a/trunk/drivers/uwb/whci.c b/trunk/drivers/uwb/whci.c index 1f8964ed9882..3df2388f908f 100644 --- a/trunk/drivers/uwb/whci.c +++ b/trunk/drivers/uwb/whci.c @@ -67,11 +67,11 @@ int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result, val = le_readl(reg); if ((val & mask) == result) break; + msleep(10); if (t >= max_ms) { - dev_err(dev, "%s timed out\n", tag); + dev_err(dev, "timed out waiting for %s ", tag); return -ETIMEDOUT; } - msleep(10); t += 10; } return 0; @@ -111,7 +111,7 @@ static int whci_add_cap(struct whci_card *card, int n) + UWBCAPDATA_TO_OFFSET(capdata); umc->resource.end = umc->resource.start + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1; - umc->resource.name = dev_name(&umc->dev); + umc->resource.name = umc->dev.bus_id; umc->resource.flags = card->pci->resource[bar].flags; umc->resource.parent = &card->pci->resource[bar]; umc->irq = card->pci->irq; diff --git a/trunk/drivers/uwb/wlp/eda.c b/trunk/drivers/uwb/wlp/eda.c index 69e020039718..10985fa233cc 100644 --- a/trunk/drivers/uwb/wlp/eda.c +++ b/trunk/drivers/uwb/wlp/eda.c @@ -51,7 +51,9 @@ * the tag and address of the transmitting neighbor. */ +#define D_LOCAL 5 #include +#include #include #include #include "wlp-internal.h" @@ -302,6 +304,7 @@ int wlp_eda_for_virtual(struct wlp_eda *eda, { int result = 0; struct wlp *wlp = container_of(eda, struct wlp, eda); + struct device *dev = &wlp->rc->uwb_dev.dev; struct wlp_eda_node *itr; unsigned long flags; int found = 0; @@ -310,14 +313,26 @@ int wlp_eda_for_virtual(struct wlp_eda *eda, list_for_each_entry(itr, &eda->cache, list_node) { if (!memcmp(itr->virt_addr, virt_addr, sizeof(itr->virt_addr))) { + d_printf(6, dev, "EDA: looking for %pM hit %02x:%02x " + "wss %p tag 0x%02x state %u\n", + virt_addr, + itr->dev_addr.data[1], + itr->dev_addr.data[0], itr->wss, + itr->tag, itr->state); result = (*function)(wlp, itr, priv); *dev_addr = itr->dev_addr; found = 1; break; - } + } else + d_printf(6, dev, "EDA: looking for %pM against %pM miss\n", + virt_addr, itr->virt_addr); } - if (!found) + if (!found) { + if (printk_ratelimit()) + dev_err(dev, "EDA: Eth addr %pM not found.\n", + virt_addr); result = -ENODEV; + } spin_unlock_irqrestore(&eda->lock, flags); return result; } diff --git a/trunk/drivers/uwb/wlp/messages.c b/trunk/drivers/uwb/wlp/messages.c index aa42fcee4c4f..a64cb8241713 100644 --- a/trunk/drivers/uwb/wlp/messages.c +++ b/trunk/drivers/uwb/wlp/messages.c @@ -24,7 +24,8 @@ */ #include - +#define D_LOCAL 6 +#include #include "wlp-internal.h" static @@ -104,18 +105,24 @@ static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type, #define wlp_set(type, type_code, name) \ static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ { \ + d_fnstart(6, NULL, "(attribute %p)\n", attr); \ wlp_set_attr_hdr(&attr->hdr, type_code, \ sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \ attr->name = value; \ + d_dump(6, NULL, attr, sizeof(*attr)); \ + d_fnend(6, NULL, "(attribute %p)\n", attr); \ return sizeof(*attr); \ } #define wlp_pset(type, type_code, name) \ static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ { \ + d_fnstart(6, NULL, "(attribute %p)\n", attr); \ wlp_set_attr_hdr(&attr->hdr, type_code, \ sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \ attr->name = *value; \ + d_dump(6, NULL, attr, sizeof(*attr)); \ + d_fnend(6, NULL, "(attribute %p)\n", attr); \ return sizeof(*attr); \ } @@ -132,8 +139,11 @@ static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \ size_t len) \ { \ + d_fnstart(6, NULL, "(attribute %p)\n", attr); \ wlp_set_attr_hdr(&attr->hdr, type_code, len); \ memcpy(attr->name, value, len); \ + d_dump(6, NULL, attr, sizeof(*attr) + len); \ + d_fnend(6, NULL, "(attribute %p)\n", attr); \ return sizeof(*attr) + len; \ } @@ -172,7 +182,7 @@ static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr, size_t datalen; void *ptr = attr->wss_info; size_t used = sizeof(*attr); - + d_fnstart(6, NULL, "(attribute %p)\n", attr); datalen = sizeof(struct wlp_wss_info) + strlen(wss->name); wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen); used = wlp_set_wssid(ptr, &wss->wssid); @@ -180,6 +190,9 @@ static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr, used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll); used += wlp_set_wss_sec_status(ptr + used, wss->secure_status); used += wlp_set_wss_bcast(ptr + used, &wss->bcast); + d_dump(6, NULL, attr, sizeof(*attr) + datalen); + d_fnend(6, NULL, "(attribute %p, used %d)\n", + attr, (int)(sizeof(*attr) + used)); return sizeof(*attr) + used; } @@ -401,6 +414,7 @@ static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp, size_t used = 0; ssize_t result = -EINVAL; + d_printf(6, dev, "WLP: WSS info: Retrieving WSS name\n"); result = wlp_get_wss_name(wlp, ptr, info->name, buflen); if (result < 0) { dev_err(dev, "WLP: unable to obtain WSS name from " @@ -408,7 +422,7 @@ static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp, goto error_parse; } used += result; - + d_printf(6, dev, "WLP: WSS info: Retrieving accept enroll\n"); result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll, buflen - used); if (result < 0) { @@ -423,7 +437,7 @@ static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp, goto error_parse; } used += result; - + d_printf(6, dev, "WLP: WSS info: Retrieving secure status\n"); result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status, buflen - used); if (result < 0) { @@ -438,7 +452,7 @@ static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp, goto error_parse; } used += result; - + d_printf(6, dev, "WLP: WSS info: Retrieving broadcast\n"); result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast, buflen - used); if (result < 0) { @@ -516,7 +530,7 @@ static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr, len = result; used = sizeof(*attr); ptr = attr; - + d_printf(6, dev, "WLP: WSS info: Retrieving WSSID\n"); result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used); if (result < 0) { dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n"); @@ -539,6 +553,8 @@ static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr, goto out; } result = used; + d_printf(6, dev, "WLP: Successfully parsed WLP information " + "attribute. used %zu bytes\n", used); out: return result; } @@ -582,6 +598,8 @@ static ssize_t wlp_get_all_wss_info(struct wlp *wlp, struct wlp_wssid_e *wssid_e; char buf[WLP_WSS_UUID_STRSIZE]; + d_fnstart(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d \n", + wlp, attr, neighbor, wss, (int)buflen); if (buflen < 0) goto out; @@ -620,7 +638,8 @@ static ssize_t wlp_get_all_wss_info(struct wlp *wlp, wss->accept_enroll = wss_info.accept_enroll; wss->state = WLP_WSS_STATE_PART_ENROLLED; wlp_wss_uuid_print(buf, sizeof(buf), &wssid); - dev_dbg(dev, "WLP: Found WSS %s. Enrolling.\n", buf); + d_printf(2, dev, "WLP: Found WSS %s. Enrolling.\n", + buf); } else { wssid_e = wlp_create_wssid_e(wlp, neighbor); if (wssid_e == NULL) { @@ -641,6 +660,9 @@ static ssize_t wlp_get_all_wss_info(struct wlp *wlp, if (result < 0 && !enroll) /* this was a discovery */ wlp_remove_neighbor_tmp_info(neighbor); out: + d_fnend(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d, " + "result %d \n", wlp, attr, neighbor, wss, (int)buflen, + (int)result); return result; } @@ -696,6 +718,7 @@ static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss, struct sk_buff *_skb; void *d1_itr; + d_fnstart(6, dev, "wlp %p\n", wlp); if (wlp->dev_info == NULL) { result = __wlp_setup_device_info(wlp); if (result < 0) { @@ -705,6 +728,24 @@ static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss, } } info = wlp->dev_info; + d_printf(6, dev, "Local properties:\n" + "Device name (%d bytes): %s\n" + "Model name (%d bytes): %s\n" + "Manufacturer (%d bytes): %s\n" + "Model number (%d bytes): %s\n" + "Serial number (%d bytes): %s\n" + "Primary device type: \n" + " Category: %d \n" + " OUI: %02x:%02x:%02x \n" + " OUI Subdivision: %u \n", + (int)strlen(info->name), info->name, + (int)strlen(info->model_name), info->model_name, + (int)strlen(info->manufacturer), info->manufacturer, + (int)strlen(info->model_nr), info->model_nr, + (int)strlen(info->serial), info->serial, + info->prim_dev_type.category, + info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1], + info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv); _skb = dev_alloc_skb(sizeof(*_d1) + sizeof(struct wlp_attr_uuid_e) + sizeof(struct wlp_attr_wss_sel_mthd) @@ -727,6 +768,7 @@ static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss, goto error; } _d1 = (void *) _skb->data; + d_printf(6, dev, "D1 starts at %p \n", _d1); _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); _d1->hdr.type = WLP_FRAME_ASSOCIATION; _d1->type = WLP_ASSOC_D1; @@ -749,8 +791,25 @@ static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss, used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type); used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE); skb_put(_skb, sizeof(*_d1) + used); + d_printf(6, dev, "D1 message:\n"); + d_dump(6, dev, _d1, sizeof(*_d1) + + sizeof(struct wlp_attr_uuid_e) + + sizeof(struct wlp_attr_wss_sel_mthd) + + sizeof(struct wlp_attr_dev_name) + + strlen(info->name) + + sizeof(struct wlp_attr_manufacturer) + + strlen(info->manufacturer) + + sizeof(struct wlp_attr_model_name) + + strlen(info->model_name) + + sizeof(struct wlp_attr_model_nr) + + strlen(info->model_nr) + + sizeof(struct wlp_attr_serial) + + strlen(info->serial) + + sizeof(struct wlp_attr_prim_dev_type) + + sizeof(struct wlp_attr_wlp_assc_err)); *skb = _skb; error: + d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result); return result; } @@ -778,6 +837,7 @@ int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss, void *d2_itr; size_t mem_needed; + d_fnstart(6, dev, "wlp %p\n", wlp); if (wlp->dev_info == NULL) { result = __wlp_setup_device_info(wlp); if (result < 0) { @@ -787,6 +847,24 @@ int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss, } } info = wlp->dev_info; + d_printf(6, dev, "Local properties:\n" + "Device name (%d bytes): %s\n" + "Model name (%d bytes): %s\n" + "Manufacturer (%d bytes): %s\n" + "Model number (%d bytes): %s\n" + "Serial number (%d bytes): %s\n" + "Primary device type: \n" + " Category: %d \n" + " OUI: %02x:%02x:%02x \n" + " OUI Subdivision: %u \n", + (int)strlen(info->name), info->name, + (int)strlen(info->model_name), info->model_name, + (int)strlen(info->manufacturer), info->manufacturer, + (int)strlen(info->model_nr), info->model_nr, + (int)strlen(info->serial), info->serial, + info->prim_dev_type.category, + info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1], + info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv); mem_needed = sizeof(*_d2) + sizeof(struct wlp_attr_uuid_e) + sizeof(struct wlp_attr_uuid_r) @@ -814,6 +892,7 @@ int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss, goto error; } _d2 = (void *) _skb->data; + d_printf(6, dev, "D2 starts at %p \n", _d2); _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); _d2->hdr.type = WLP_FRAME_ASSOCIATION; _d2->type = WLP_ASSOC_D2; @@ -838,8 +917,11 @@ int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss, used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type); used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE); skb_put(_skb, sizeof(*_d2) + used); + d_printf(6, dev, "D2 message:\n"); + d_dump(6, dev, _d2, mem_needed); *skb = _skb; error: + d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result); return result; } @@ -865,6 +947,7 @@ int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb, struct sk_buff *_skb; struct wlp_nonce tmp; + d_fnstart(6, dev, "wlp %p\n", wlp); _skb = dev_alloc_skb(sizeof(*f0)); if (_skb == NULL) { dev_err(dev, "WLP: Unable to allocate memory for F0 " @@ -872,6 +955,7 @@ int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb, goto error_alloc; } f0 = (void *) _skb->data; + d_printf(6, dev, "F0 starts at %p \n", f0); f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION; f0->f0_hdr.type = WLP_ASSOC_F0; @@ -885,6 +969,7 @@ int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb, *skb = _skb; result = 0; error_alloc: + d_fnend(6, dev, "wlp %p, result %d \n", wlp, result); return result; } @@ -1157,9 +1242,12 @@ void wlp_handle_d1_frame(struct work_struct *ws) enum wlp_wss_sel_mthd sel_mthd = 0; struct wlp_device_info dev_info; enum wlp_assc_error assc_err; + char uuid[WLP_WSS_UUID_STRSIZE]; struct sk_buff *resp = NULL; /* Parse D1 frame */ + d_fnstart(6, dev, "WLP: handle D1 frame. wlp = %p, skb = %p\n", + wlp, skb); mutex_lock(&wss->mutex); mutex_lock(&wlp->mutex); /* to access wlp->uuid */ memset(&dev_info, 0, sizeof(dev_info)); @@ -1170,6 +1258,30 @@ void wlp_handle_d1_frame(struct work_struct *ws) kfree_skb(skb); goto out; } + wlp_wss_uuid_print(uuid, sizeof(uuid), &uuid_e); + d_printf(6, dev, "From D1 frame:\n" + "UUID-E: %s\n" + "Selection method: %d\n" + "Device name (%d bytes): %s\n" + "Model name (%d bytes): %s\n" + "Manufacturer (%d bytes): %s\n" + "Model number (%d bytes): %s\n" + "Serial number (%d bytes): %s\n" + "Primary device type: \n" + " Category: %d \n" + " OUI: %02x:%02x:%02x \n" + " OUI Subdivision: %u \n", + uuid, sel_mthd, + (int)strlen(dev_info.name), dev_info.name, + (int)strlen(dev_info.model_name), dev_info.model_name, + (int)strlen(dev_info.manufacturer), dev_info.manufacturer, + (int)strlen(dev_info.model_nr), dev_info.model_nr, + (int)strlen(dev_info.serial), dev_info.serial, + dev_info.prim_dev_type.category, + dev_info.prim_dev_type.OUI[0], + dev_info.prim_dev_type.OUI[1], + dev_info.prim_dev_type.OUI[2], + dev_info.prim_dev_type.OUIsubdiv); kfree_skb(skb); if (!wlp_uuid_is_set(&wlp->uuid)) { @@ -1204,6 +1316,7 @@ void wlp_handle_d1_frame(struct work_struct *ws) kfree(frame_ctx); mutex_unlock(&wlp->mutex); mutex_unlock(&wss->mutex); + d_fnend(6, dev, "WLP: handle D1 frame. wlp = %p\n", wlp); } /** @@ -1433,8 +1546,10 @@ int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb, void *ptr = skb->data; size_t len = skb->len; size_t used; + char buf[WLP_WSS_UUID_STRSIZE]; struct wlp_frame_assoc *assoc = ptr; + d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb); used = sizeof(*assoc); result = wlp_get_wssid(wlp, ptr + used, wssid, len - used); if (result < 0) { @@ -1457,7 +1572,14 @@ int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb, wlp_assoc_frame_str(assoc->type)); goto error_parse; } + wlp_wss_uuid_print(buf, sizeof(buf), wssid); + d_printf(6, dev, "WLP: parsed: WSSID %s, tag 0x%02x, virt " + "%02x:%02x:%02x:%02x:%02x:%02x \n", buf, *tag, + virt_addr->data[0], virt_addr->data[1], virt_addr->data[2], + virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]); + error_parse: + d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result); return result; } @@ -1478,6 +1600,7 @@ int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss, } *c; struct sk_buff *_skb; + d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss); _skb = dev_alloc_skb(sizeof(*c)); if (_skb == NULL) { dev_err(dev, "WLP: Unable to allocate memory for C1/C2 " @@ -1485,6 +1608,7 @@ int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss, goto error_alloc; } c = (void *) _skb->data; + d_printf(6, dev, "C1/C2 starts at %p \n", c); c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION; c->c_hdr.type = type; @@ -1492,9 +1616,12 @@ int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss, wlp_set_msg_type(&c->c_hdr.msg_type, type); wlp_set_wssid(&c->wssid, &wss->wssid); skb_put(_skb, sizeof(*c)); + d_printf(6, dev, "C1/C2 message:\n"); + d_dump(6, dev, c, sizeof(*c)); *skb = _skb; result = 0; error_alloc: + d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result); return result; } @@ -1533,6 +1660,7 @@ int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss, } *c; struct sk_buff *_skb; + d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss); _skb = dev_alloc_skb(sizeof(*c)); if (_skb == NULL) { dev_err(dev, "WLP: Unable to allocate memory for C3/C4 " @@ -1540,6 +1668,7 @@ int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss, goto error_alloc; } c = (void *) _skb->data; + d_printf(6, dev, "C3/C4 starts at %p \n", c); c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION; c->c_hdr.type = type; @@ -1549,9 +1678,12 @@ int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss, wlp_set_wss_tag(&c->wss_tag, wss->tag); wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr); skb_put(_skb, sizeof(*c)); + d_printf(6, dev, "C3/C4 message:\n"); + d_dump(6, dev, c, sizeof(*c)); *skb = _skb; result = 0; error_alloc: + d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result); return result; } @@ -1577,7 +1709,10 @@ static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \ struct device *dev = &wlp->rc->uwb_dev.dev; \ int result; \ struct sk_buff *skb = NULL; \ - \ + d_fnstart(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \ + wlp, wss, dev_addr->data[1], dev_addr->data[0]); \ + d_printf(6, dev, "WLP: Constructing %s frame. \n", \ + wlp_assoc_frame_str(id)); \ /* Build the frame */ \ result = wlp_build_assoc_##type(wlp, wss, &skb); \ if (result < 0) { \ @@ -1586,6 +1721,9 @@ static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \ goto error_build_assoc; \ } \ /* Send the frame */ \ + d_printf(6, dev, "Transmitting %s frame to %02x:%02x \n", \ + wlp_assoc_frame_str(id), \ + dev_addr->data[1], dev_addr->data[0]); \ BUG_ON(wlp->xmit_frame == NULL); \ result = wlp->xmit_frame(wlp, skb, dev_addr); \ if (result < 0) { \ @@ -1602,6 +1740,8 @@ error_xmit: \ /* We could try again ... */ \ dev_kfree_skb_any(skb);/*we need to free if tx fails*/ \ error_build_assoc: \ + d_fnend(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \ + wlp, wss, dev_addr->data[1], dev_addr->data[0]); \ return result; \ } @@ -1654,9 +1794,12 @@ void wlp_handle_c1_frame(struct work_struct *ws) struct uwb_dev_addr *src = &frame_ctx->src; int result; struct wlp_uuid wssid; + char buf[WLP_WSS_UUID_STRSIZE]; struct sk_buff *resp = NULL; /* Parse C1 frame */ + d_fnstart(6, dev, "WLP: handle C1 frame. wlp = %p, c1 = %p\n", + wlp, c1); mutex_lock(&wss->mutex); result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid, len - sizeof(*c1)); @@ -1664,8 +1807,12 @@ void wlp_handle_c1_frame(struct work_struct *ws) dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n"); goto out; } + wlp_wss_uuid_print(buf, sizeof(buf), &wssid); + d_printf(6, dev, "Received C1 frame with WSSID %s \n", buf); if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)) && wss->state == WLP_WSS_STATE_ACTIVE) { + d_printf(6, dev, "WSSID from C1 frame is known locally " + "and is active\n"); /* Construct C2 frame */ result = wlp_build_assoc_c2(wlp, wss, &resp); if (result < 0) { @@ -1673,6 +1820,8 @@ void wlp_handle_c1_frame(struct work_struct *ws) goto out; } } else { + d_printf(6, dev, "WSSID from C1 frame is not known locally " + "or is not active\n"); /* Construct F0 frame */ result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV); if (result < 0) { @@ -1681,6 +1830,8 @@ void wlp_handle_c1_frame(struct work_struct *ws) } } /* Send C2 frame */ + d_printf(6, dev, "Transmitting response (C2/F0) frame to %02x:%02x \n", + src->data[1], src->data[0]); BUG_ON(wlp->xmit_frame == NULL); result = wlp->xmit_frame(wlp, resp, src); if (result < 0) { @@ -1695,6 +1846,7 @@ void wlp_handle_c1_frame(struct work_struct *ws) kfree_skb(frame_ctx->skb); kfree(frame_ctx); mutex_unlock(&wss->mutex); + d_fnend(6, dev, "WLP: handle C1 frame. wlp = %p\n", wlp); } /** @@ -1716,20 +1868,27 @@ void wlp_handle_c3_frame(struct work_struct *ws) struct sk_buff *skb = frame_ctx->skb; struct uwb_dev_addr *src = &frame_ctx->src; int result; + char buf[WLP_WSS_UUID_STRSIZE]; struct sk_buff *resp = NULL; struct wlp_uuid wssid; u8 tag; struct uwb_mac_addr virt_addr; /* Parse C3 frame */ + d_fnstart(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n", + wlp, skb); mutex_lock(&wss->mutex); result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr); if (result < 0) { dev_err(dev, "WLP: unable to obtain values from C3 frame.\n"); goto out; } + wlp_wss_uuid_print(buf, sizeof(buf), &wssid); + d_printf(6, dev, "Received C3 frame with WSSID %s \n", buf); if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)) && wss->state >= WLP_WSS_STATE_ACTIVE) { + d_printf(6, dev, "WSSID from C3 frame is known locally " + "and is active\n"); result = wlp_eda_update_node(&wlp->eda, src, wss, (void *) virt_addr.data, tag, WLP_WSS_CONNECTED); @@ -1754,6 +1913,8 @@ void wlp_handle_c3_frame(struct work_struct *ws) } } } else { + d_printf(6, dev, "WSSID from C3 frame is not known locally " + "or is not active\n"); /* Construct F0 frame */ result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV); if (result < 0) { @@ -1762,6 +1923,8 @@ void wlp_handle_c3_frame(struct work_struct *ws) } } /* Send C4 frame */ + d_printf(6, dev, "Transmitting response (C4/F0) frame to %02x:%02x \n", + src->data[1], src->data[0]); BUG_ON(wlp->xmit_frame == NULL); result = wlp->xmit_frame(wlp, resp, src); if (result < 0) { @@ -1776,6 +1939,8 @@ void wlp_handle_c3_frame(struct work_struct *ws) kfree_skb(frame_ctx->skb); kfree(frame_ctx); mutex_unlock(&wss->mutex); + d_fnend(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n", + wlp, skb); } diff --git a/trunk/drivers/uwb/wlp/sysfs.c b/trunk/drivers/uwb/wlp/sysfs.c index 0370399ff4bb..1bb9b1f97d47 100644 --- a/trunk/drivers/uwb/wlp/sysfs.c +++ b/trunk/drivers/uwb/wlp/sysfs.c @@ -23,8 +23,8 @@ * FIXME: Docs * */ -#include +#include #include "wlp-internal.h" static diff --git a/trunk/drivers/uwb/wlp/txrx.c b/trunk/drivers/uwb/wlp/txrx.c index cd2035768b47..c701bd1a2887 100644 --- a/trunk/drivers/uwb/wlp/txrx.c +++ b/trunk/drivers/uwb/wlp/txrx.c @@ -26,10 +26,12 @@ #include #include - +#define D_LOCAL 5 +#include #include "wlp-internal.h" -/* + +/** * Direct incoming association msg to correct parsing routine * * We only expect D1, E1, C1, C3 messages as new. All other incoming @@ -46,31 +48,35 @@ void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb, struct device *dev = &wlp->rc->uwb_dev.dev; struct wlp_frame_assoc *assoc = (void *) skb->data; struct wlp_assoc_frame_ctx *frame_ctx; - + d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb); frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC); if (frame_ctx == NULL) { dev_err(dev, "WLP: Unable to allocate memory for association " "frame handling.\n"); kfree_skb(skb); - return; + goto out; } frame_ctx->wlp = wlp; frame_ctx->skb = skb; frame_ctx->src = *src; switch (assoc->type) { case WLP_ASSOC_D1: + d_printf(5, dev, "Received a D1 frame.\n"); INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame); schedule_work(&frame_ctx->ws); break; case WLP_ASSOC_E1: + d_printf(5, dev, "Received a E1 frame. FIXME?\n"); kfree_skb(skb); /* Temporary until we handle it */ kfree(frame_ctx); /* Temporary until we handle it */ break; case WLP_ASSOC_C1: + d_printf(5, dev, "Received a C1 frame.\n"); INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame); schedule_work(&frame_ctx->ws); break; case WLP_ASSOC_C3: + d_printf(5, dev, "Received a C3 frame.\n"); INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame); schedule_work(&frame_ctx->ws); break; @@ -81,9 +87,11 @@ void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb, kfree(frame_ctx); break; } +out: + d_fnend(5, dev, "wlp %p\n", wlp); } -/* +/** * Process incoming association frame * * Although it could be possible to deal with some incoming association @@ -104,6 +112,7 @@ void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb, struct wlp_frame_assoc *assoc = (void *) skb->data; struct wlp_session *session = wlp->session; u8 version; + d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb); if (wlp_get_version(wlp, &assoc->version, &version, sizeof(assoc->version)) < 0) @@ -141,12 +150,14 @@ void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb, } else { wlp_direct_assoc_frame(wlp, skb, src); } + d_fnend(5, dev, "wlp %p\n", wlp); return; error: kfree_skb(skb); + d_fnend(5, dev, "wlp %p\n", wlp); } -/* +/** * Verify incoming frame is from connected neighbor, prep to pass to WLP client * * Verification proceeds according to WLP 0.99 [7.3.1]. The source address @@ -165,6 +176,7 @@ int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb, struct wlp_eda_node eda_entry; struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data; + d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb); /*verify*/ result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry); if (result < 0) { @@ -195,10 +207,11 @@ int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb, /*prep*/ skb_pull(skb, sizeof(*hdr)); out: + d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result); return result; } -/* +/** * Receive a WLP frame from device * * @returns: 1 if calling function should free the skb @@ -213,12 +226,14 @@ int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb, struct wlp_frame_hdr *hdr; int result = 0; + d_fnstart(6, dev, "skb (%p), len (%u)\n", skb, len); if (len < sizeof(*hdr)) { dev_err(dev, "Not enough data to parse WLP header.\n"); result = -EINVAL; goto out; } hdr = ptr; + d_dump(6, dev, hdr, sizeof(*hdr)); if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) { dev_err(dev, "Not a WLP frame type.\n"); result = -EINVAL; @@ -255,6 +270,7 @@ int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb, "WLP header.\n"); goto out; } + d_printf(5, dev, "Association frame received.\n"); wlp_receive_assoc_frame(wlp, skb, src); break; default: @@ -267,12 +283,13 @@ int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb, kfree_skb(skb); result = 0; } + d_fnend(6, dev, "skb (%p)\n", skb); return result; } EXPORT_SYMBOL_GPL(wlp_receive_frame); -/* +/** * Verify frame from network stack, prepare for further transmission * * @skb: the socket buffer that needs to be prepared for transmission (it @@ -326,7 +343,9 @@ int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp, int result = -EINVAL; struct ethhdr *eth_hdr = (void *) skb->data; + d_fnstart(6, dev, "wlp (%p), skb (%p) \n", wlp, skb); if (is_broadcast_ether_addr(eth_hdr->h_dest)) { + d_printf(6, dev, "WLP: handling broadcast frame. \n"); result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb); if (result < 0) { if (printk_ratelimit()) @@ -338,6 +357,7 @@ int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp, result = 1; /* Frame will be transmitted by WLP. */ } else { + d_printf(6, dev, "WLP: handling unicast frame. \n"); result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst, wlp_wss_prep_hdr, skb); if (unlikely(result < 0)) { @@ -348,6 +368,7 @@ int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp, } } out: + d_fnend(6, dev, "wlp (%p), skb (%p). result = %d \n", wlp, skb, result); return result; } EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame); diff --git a/trunk/drivers/uwb/wlp/wlp-internal.h b/trunk/drivers/uwb/wlp/wlp-internal.h index 3e8d5de7c5b9..1c94fabfb1a7 100644 --- a/trunk/drivers/uwb/wlp/wlp-internal.h +++ b/trunk/drivers/uwb/wlp/wlp-internal.h @@ -42,6 +42,10 @@ enum wlp_wss_connect { extern struct kobj_type wss_ktype; extern struct attribute_group wss_attr_group; +extern int uwb_rc_ie_add(struct uwb_rc *, const struct uwb_ie_hdr *, size_t); +extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie); + + /* This should be changed to a dynamic array where entries are sorted * by eth_addr and search is done in a binary form * diff --git a/trunk/drivers/uwb/wlp/wlp-lc.c b/trunk/drivers/uwb/wlp/wlp-lc.c index 13db739c4e39..0799402e73fb 100644 --- a/trunk/drivers/uwb/wlp/wlp-lc.c +++ b/trunk/drivers/uwb/wlp/wlp-lc.c @@ -21,10 +21,13 @@ * * FIXME: docs */ -#include +#include +#define D_LOCAL 6 +#include #include "wlp-internal.h" + static void wlp_neighbor_init(struct wlp_neighbor_e *neighbor) { @@ -58,6 +61,11 @@ int __wlp_alloc_device_info(struct wlp *wlp) static void __wlp_fill_device_info(struct wlp *wlp) { + struct device *dev = &wlp->rc->uwb_dev.dev; + + BUG_ON(wlp->fill_device_info == NULL); + d_printf(6, dev, "Retrieving device information " + "from device driver.\n"); wlp->fill_device_info(wlp, wlp->dev_info); } @@ -119,7 +127,7 @@ void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor) } } -/* +/** * Populate WLP neighborhood cache with neighbor information * * A new neighbor is found. If it is discoverable then we add it to the @@ -133,7 +141,10 @@ int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev) int discoverable; struct wlp_neighbor_e *neighbor; - /* + d_fnstart(6, &dev->dev, "uwb %p \n", dev); + d_printf(6, &dev->dev, "Found neighbor device %02x:%02x \n", + dev->dev_addr.data[1], dev->dev_addr.data[0]); + /** * FIXME: * Use contents of WLP IE found in beacon cache to determine if * neighbor is discoverable. @@ -156,6 +167,7 @@ int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev) list_add(&neighbor->node, &wlp->neighbors); } error_no_mem: + d_fnend(6, &dev->dev, "uwb %p, result = %d \n", dev, result); return result; } @@ -243,6 +255,8 @@ int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor, dev_err(dev, "Unable to send D1 frame to neighbor " "%02x:%02x (%d)\n", dev_addr->data[1], dev_addr->data[0], result); + d_printf(6, dev, "Add placeholders into buffer next to " + "neighbor information we have (dev address).\n"); goto out; } /* Create session, wait for response */ @@ -270,6 +284,8 @@ int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor, /* Parse message in session->data: it will be either D2 or F0 */ skb = session.data; resp = (void *) skb->data; + d_printf(6, dev, "Received response to D1 frame. \n"); + d_dump(6, dev, skb->data, skb->len > 72 ? 72 : skb->len); if (resp->type == WLP_ASSOC_F0) { result = wlp_parse_f0(wlp, skb); @@ -321,9 +337,10 @@ int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor, struct device *dev = &wlp->rc->uwb_dev.dev; char buf[WLP_WSS_UUID_STRSIZE]; struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; - wlp_wss_uuid_print(buf, sizeof(buf), wssid); - + d_fnstart(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n", + wlp, neighbor, wss, wssid, buf); + d_printf(6, dev, "Complete me.\n"); result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid); if (result < 0) { dev_err(dev, "WLP: D1/D2 message exchange for enrollment " @@ -343,10 +360,13 @@ int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor, goto error; } else { wss->state = WLP_WSS_STATE_ENROLLED; - dev_dbg(dev, "WLP: Success Enrollment into unsecure WSS " - "%s using neighbor %02x:%02x. \n", - buf, dev_addr->data[1], dev_addr->data[0]); + d_printf(2, dev, "WLP: Success Enrollment into unsecure WSS " + "%s using neighbor %02x:%02x. \n", buf, + dev_addr->data[1], dev_addr->data[0]); } + + d_fnend(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n", + wlp, neighbor, wss, wssid, buf); out: return result; error: @@ -429,6 +449,7 @@ ssize_t wlp_discover(struct wlp *wlp) int result = 0; struct device *dev = &wlp->rc->uwb_dev.dev; + d_fnstart(6, dev, "wlp %p \n", wlp); mutex_lock(&wlp->nbmutex); /* Clear current neighborhood cache. */ __wlp_neighbors_release(wlp); @@ -448,6 +469,7 @@ ssize_t wlp_discover(struct wlp *wlp) } error_dev_for_each: mutex_unlock(&wlp->nbmutex); + d_fnend(6, dev, "wlp %p \n", wlp); return result; } @@ -470,6 +492,9 @@ void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev, int result; switch (event) { case UWB_NOTIF_ONAIR: + d_printf(6, dev, "UWB device %02x:%02x is onair\n", + uwb_dev->dev_addr.data[1], + uwb_dev->dev_addr.data[0]); result = wlp_eda_create_node(&wlp->eda, uwb_dev->mac_addr.data, &uwb_dev->dev_addr); @@ -480,11 +505,18 @@ void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev, uwb_dev->dev_addr.data[0]); break; case UWB_NOTIF_OFFAIR: + d_printf(6, dev, "UWB device %02x:%02x is offair\n", + uwb_dev->dev_addr.data[1], + uwb_dev->dev_addr.data[0]); wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr); mutex_lock(&wlp->nbmutex); - list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { - if (neighbor->uwb_dev == uwb_dev) + list_for_each_entry_safe(neighbor, next, &wlp->neighbors, + node) { + if (neighbor->uwb_dev == uwb_dev) { + d_printf(6, dev, "Removing device from " + "neighborhood.\n"); __wlp_neighbor_release(neighbor); + } } mutex_unlock(&wlp->nbmutex); break; @@ -494,47 +526,38 @@ void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev, } } -static void wlp_channel_changed(struct uwb_pal *pal, int channel) -{ - struct wlp *wlp = container_of(pal, struct wlp, pal); - - if (channel < 0) - netif_carrier_off(wlp->ndev); - else - netif_carrier_on(wlp->ndev); -} - -int wlp_setup(struct wlp *wlp, struct uwb_rc *rc, struct net_device *ndev) +int wlp_setup(struct wlp *wlp, struct uwb_rc *rc) { + struct device *dev = &rc->uwb_dev.dev; int result; + d_fnstart(6, dev, "wlp %p\n", wlp); BUG_ON(wlp->fill_device_info == NULL); BUG_ON(wlp->xmit_frame == NULL); BUG_ON(wlp->stop_queue == NULL); BUG_ON(wlp->start_queue == NULL); - wlp->rc = rc; - wlp->ndev = ndev; wlp_eda_init(&wlp->eda);/* Set up address cache */ wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb; wlp->uwb_notifs_handler.data = wlp; uwb_notifs_register(rc, &wlp->uwb_notifs_handler); uwb_pal_init(&wlp->pal); - wlp->pal.rc = rc; - wlp->pal.channel_changed = wlp_channel_changed; - result = uwb_pal_register(&wlp->pal); + result = uwb_pal_register(rc, &wlp->pal); if (result < 0) uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); + d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result); return result; } EXPORT_SYMBOL_GPL(wlp_setup); void wlp_remove(struct wlp *wlp) { + struct device *dev = &wlp->rc->uwb_dev.dev; + d_fnstart(6, dev, "wlp %p\n", wlp); wlp_neighbors_release(wlp); - uwb_pal_unregister(&wlp->pal); + uwb_pal_unregister(wlp->rc, &wlp->pal); uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); wlp_eda_release(&wlp->eda); mutex_lock(&wlp->mutex); @@ -542,6 +565,9 @@ void wlp_remove(struct wlp *wlp) kfree(wlp->dev_info); mutex_unlock(&wlp->mutex); wlp->rc = NULL; + /* We have to use NULL here because this function can be called + * when the device disappeared. */ + d_fnend(6, NULL, "wlp %p\n", wlp); } EXPORT_SYMBOL_GPL(wlp_remove); diff --git a/trunk/drivers/uwb/wlp/wss-lc.c b/trunk/drivers/uwb/wlp/wss-lc.c index 5913c7a5d922..96b18c9bd6e9 100644 --- a/trunk/drivers/uwb/wlp/wss-lc.c +++ b/trunk/drivers/uwb/wlp/wss-lc.c @@ -43,12 +43,15 @@ * wlp_wss_release() * wlp_wss_reset() */ + #include /* for is_valid_ether_addr */ #include #include - +#define D_LOCAL 5 +#include #include "wlp-internal.h" + size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key) { size_t result; @@ -113,6 +116,9 @@ struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss) */ void wlp_wss_reset(struct wlp_wss *wss) { + struct wlp *wlp = container_of(wss, struct wlp, wss); + struct device *dev = &wlp->rc->uwb_dev.dev; + d_fnstart(5, dev, "wss (%p) \n", wss); memset(&wss->wssid, 0, sizeof(wss->wssid)); wss->hash = 0; memset(&wss->name[0], 0, sizeof(wss->name)); @@ -121,6 +127,7 @@ void wlp_wss_reset(struct wlp_wss *wss) memset(&wss->master_key[0], 0, sizeof(wss->master_key)); wss->tag = 0; wss->state = WLP_WSS_STATE_NONE; + d_fnend(5, dev, "wss (%p) \n", wss); } /** @@ -138,6 +145,7 @@ int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str) struct device *dev = &wlp->rc->uwb_dev.dev; int result; + d_fnstart(5, dev, "wss (%p), wssid: %s\n", wss, wssid_str); result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str); if (result < 0) return result; @@ -154,6 +162,7 @@ int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str) result); goto error_sysfs_create_group; } + d_fnend(5, dev, "Completed. result = %d \n", result); return 0; error_sysfs_create_group: @@ -205,14 +214,22 @@ int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid, struct wlp *wlp = container_of(wss, struct wlp, wss); struct device *dev = &wlp->rc->uwb_dev.dev; struct wlp_neighbor_e *neighbor; + char buf[WLP_WSS_UUID_STRSIZE]; int result = -ENXIO; struct uwb_dev_addr *dev_addr; + wlp_wss_uuid_print(buf, sizeof(buf), wssid); + d_fnstart(5, dev, "wss %p, wssid %s, registrar %02x:%02x \n", + wss, buf, dest->data[1], dest->data[0]); mutex_lock(&wlp->nbmutex); list_for_each_entry(neighbor, &wlp->neighbors, node) { dev_addr = &neighbor->uwb_dev->dev_addr; if (!memcmp(dest, dev_addr, sizeof(*dest))) { - result = wlp_enroll_neighbor(wlp, neighbor, wss, wssid); + d_printf(5, dev, "Neighbor %02x:%02x is valid, " + "enrolling. \n", + dev_addr->data[1], dev_addr->data[0]); + result = wlp_enroll_neighbor(wlp, neighbor, wss, + wssid); break; } } @@ -220,6 +237,8 @@ int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid, dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n", dest->data[1], dest->data[0]); mutex_unlock(&wlp->nbmutex); + d_fnend(5, dev, "wss %p, wssid %s, registrar %02x:%02x, result %d \n", + wss, buf, dest->data[1], dest->data[0], result); return result; } @@ -241,11 +260,16 @@ int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid) char buf[WLP_WSS_UUID_STRSIZE]; int result = -ENXIO; - + wlp_wss_uuid_print(buf, sizeof(buf), wssid); + d_fnstart(5, dev, "wss %p, wssid %s \n", wss, buf); mutex_lock(&wlp->nbmutex); list_for_each_entry(neighbor, &wlp->neighbors, node) { list_for_each_entry(wssid_e, &neighbor->wssid, node) { if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) { + d_printf(5, dev, "Found WSSID %s in neighbor " + "%02x:%02x cache. \n", buf, + neighbor->uwb_dev->dev_addr.data[1], + neighbor->uwb_dev->dev_addr.data[0]); result = wlp_enroll_neighbor(wlp, neighbor, wss, wssid); if (result == 0) /* enrollment success */ @@ -255,11 +279,10 @@ int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid) } } out: - if (result == -ENXIO) { - wlp_wss_uuid_print(buf, sizeof(buf), wssid); + if (result == -ENXIO) dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf); - } mutex_unlock(&wlp->nbmutex); + d_fnend(5, dev, "wss %p, wssid %s, result %d \n", wss, buf, result); return result; } @@ -284,22 +307,27 @@ int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid, struct uwb_dev_addr bcast = {.data = {0xff, 0xff} }; wlp_wss_uuid_print(buf, sizeof(buf), wssid); - if (wss->state != WLP_WSS_STATE_NONE) { dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf); result = -EEXIST; goto error; } - if (!memcmp(&bcast, devaddr, sizeof(bcast))) + if (!memcmp(&bcast, devaddr, sizeof(bcast))) { + d_printf(5, dev, "Request to enroll in discovered WSS " + "with WSSID %s \n", buf); result = wlp_wss_enroll_discovered(wss, wssid); - else + } else { + d_printf(5, dev, "Request to enroll in WSSID %s with " + "registrar %02x:%02x\n", buf, devaddr->data[1], + devaddr->data[0]); result = wlp_wss_enroll_target(wss, wssid, devaddr); + } if (result < 0) { dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n", buf, result); goto error; } - dev_dbg(dev, "Successfully enrolled into WSS %s \n", buf); + d_printf(2, dev, "Successfully enrolled into WSS %s \n", buf); result = wlp_wss_sysfs_add(wss, buf); if (result < 0) { dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n"); @@ -335,6 +363,7 @@ int wlp_wss_activate(struct wlp_wss *wss) u8 hash; /* only include one hash */ } ie_data; + d_fnstart(5, dev, "Activating WSS %p. \n", wss); BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED); wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid); wss->tag = wss->hash; @@ -353,6 +382,7 @@ int wlp_wss_activate(struct wlp_wss *wss) wss->state = WLP_WSS_STATE_ACTIVE; result = 0; error_wlp_ie: + d_fnend(5, dev, "Activating WSS %p, result = %d \n", wss, result); return result; } @@ -375,6 +405,7 @@ int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, int result = 0; char buf[WLP_WSS_UUID_STRSIZE]; + d_fnstart(5, dev, "Enrollment and activation requested. \n"); mutex_lock(&wss->mutex); result = wlp_wss_enroll(wss, wssid, devaddr); if (result < 0) { @@ -393,6 +424,7 @@ int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, error_activate: error_enroll: mutex_unlock(&wss->mutex); + d_fnend(5, dev, "Completed. result = %d \n", result); return result; } @@ -415,9 +447,11 @@ int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, struct device *dev = &wlp->rc->uwb_dev.dev; int result = 0; char buf[WLP_WSS_UUID_STRSIZE]; - + d_fnstart(5, dev, "Request to create new WSS.\n"); result = wlp_wss_uuid_print(buf, sizeof(buf), wssid); - + d_printf(5, dev, "Request to create WSS: WSSID=%s, name=%s, " + "sec_status=%u, accepting enrollment=%u \n", + buf, name, sec_status, accept); if (!mutex_trylock(&wss->mutex)) { dev_err(dev, "WLP: WLP association session in progress.\n"); return -EBUSY; @@ -464,6 +498,7 @@ int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, result = 0; out: mutex_unlock(&wss->mutex); + d_fnend(5, dev, "Completed. result = %d \n", result); return result; } @@ -485,12 +520,16 @@ int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss, { int result = 0; struct device *dev = &wlp->rc->uwb_dev.dev; + char buf[WLP_WSS_UUID_STRSIZE]; DECLARE_COMPLETION_ONSTACK(completion); struct wlp_session session; struct sk_buff *skb; struct wlp_frame_assoc *resp; struct wlp_uuid wssid; + wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); + d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", + wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); mutex_lock(&wlp->mutex); /* Send C1 association frame */ result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1); @@ -526,6 +565,8 @@ int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss, /* Parse message in session->data: it will be either C2 or F0 */ skb = session.data; resp = (void *) skb->data; + d_printf(5, dev, "Received response to C1 frame. \n"); + d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len); if (resp->type == WLP_ASSOC_F0) { result = wlp_parse_f0(wlp, skb); if (result < 0) @@ -543,9 +584,11 @@ int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss, result = 0; goto error_resp_parse; } - if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))) + if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))) { + d_printf(5, dev, "WSSID in C2 frame matches local " + "active WSS.\n"); result = 1; - else { + } else { dev_err(dev, "WLP: Received a C2 frame without matching " "WSSID.\n"); result = 0; @@ -555,6 +598,8 @@ int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss, out: wlp->session = NULL; mutex_unlock(&wlp->mutex); + d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", + wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); return result; } @@ -575,8 +620,16 @@ int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss, { struct device *dev = &wlp->rc->uwb_dev.dev; int result = 0; + char buf[WLP_WSS_UUID_STRSIZE]; + wlp_wss_uuid_print(buf, sizeof(buf), wssid); + d_fnstart(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual " + "%02x:%02x:%02x:%02x:%02x:%02x \n", wlp, wss, buf, *tag, + virt_addr->data[0], virt_addr->data[1], virt_addr->data[2], + virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]); if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) { + d_printf(5, dev, "WSSID from neighbor frame matches local " + "active WSS.\n"); /* Update EDA cache */ result = wlp_eda_update_node(&wlp->eda, dev_addr, wss, (void *) virt_addr->data, *tag, @@ -585,9 +638,18 @@ int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss, dev_err(dev, "WLP: Unable to update EDA cache " "with new connected neighbor information.\n"); } else { - dev_err(dev, "WLP: Neighbor does not have matching WSSID.\n"); + dev_err(dev, "WLP: Neighbor does not have matching " + "WSSID.\n"); result = -EINVAL; } + + d_fnend(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual " + "%02x:%02x:%02x:%02x:%02x:%02x, result = %d \n", + wlp, wss, buf, *tag, + virt_addr->data[0], virt_addr->data[1], virt_addr->data[2], + virt_addr->data[3], virt_addr->data[4], virt_addr->data[5], + result); + return result; } @@ -603,6 +665,7 @@ int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss, { int result; struct device *dev = &wlp->rc->uwb_dev.dev; + char buf[WLP_WSS_UUID_STRSIZE]; struct wlp_uuid wssid; u8 tag; struct uwb_mac_addr virt_addr; @@ -611,6 +674,9 @@ int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss, struct wlp_frame_assoc *resp; struct sk_buff *skb; + wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); + d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", + wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); mutex_lock(&wlp->mutex); /* Send C3 association frame */ result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3); @@ -645,6 +711,8 @@ int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss, /* Parse message in session->data: it will be either C4 or F0 */ skb = session.data; resp = (void *) skb->data; + d_printf(5, dev, "Received response to C3 frame. \n"); + d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len); if (resp->type == WLP_ASSOC_F0) { result = wlp_parse_f0(wlp, skb); if (result < 0) @@ -676,6 +744,8 @@ int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss, WLP_WSS_CONNECT_FAILED); wlp->session = NULL; mutex_unlock(&wlp->mutex); + d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", + wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); return result; } @@ -710,8 +780,12 @@ void wlp_wss_connect_send(struct work_struct *ws) struct wlp_wss *wss = &wlp->wss; int result; struct device *dev = &wlp->rc->uwb_dev.dev; + char buf[WLP_WSS_UUID_STRSIZE]; mutex_lock(&wss->mutex); + wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); + d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", + wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); if (wss->state < WLP_WSS_STATE_ACTIVE) { if (printk_ratelimit()) dev_err(dev, "WLP: Attempting to connect with " @@ -762,6 +836,7 @@ void wlp_wss_connect_send(struct work_struct *ws) BUG_ON(wlp->start_queue == NULL); wlp->start_queue(wlp); mutex_unlock(&wss->mutex); + d_fnend(5, dev, "wlp %p, wss %p (wssid %s)\n", wlp, wss, buf); } /** @@ -780,6 +855,7 @@ int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry, struct sk_buff *skb = _skb; struct wlp_frame_std_abbrv_hdr *std_hdr; + d_fnstart(6, dev, "wlp %p \n", wlp); if (eda_entry->state == WLP_WSS_CONNECTED) { /* Add WLP header */ BUG_ON(skb_headroom(skb) < sizeof(*std_hdr)); @@ -797,6 +873,7 @@ int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry, dev_addr->data[0]); result = -EINVAL; } + d_fnend(6, dev, "wlp %p \n", wlp); return result; } @@ -816,9 +893,16 @@ int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry, { int result = 0; struct device *dev = &wlp->rc->uwb_dev.dev; + struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; + unsigned char *eth_addr = eda_entry->eth_addr; struct sk_buff *skb = _skb; struct wlp_assoc_conn_ctx *conn_ctx; + d_fnstart(5, dev, "wlp %p\n", wlp); + d_printf(5, dev, "To neighbor %02x:%02x with eth " + "%02x:%02x:%02x:%02x:%02x:%02x\n", dev_addr->data[1], + dev_addr->data[0], eth_addr[0], eth_addr[1], eth_addr[2], + eth_addr[3], eth_addr[4], eth_addr[5]); if (eda_entry->state == WLP_WSS_UNCONNECTED) { /* We don't want any more packets while we set up connection */ BUG_ON(wlp->stop_queue == NULL); @@ -845,9 +929,12 @@ int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry, "previously. Not retrying. \n"); result = -ENONET; goto out; - } else /* eda_entry->state == WLP_WSS_CONNECTED */ + } else { /* eda_entry->state == WLP_WSS_CONNECTED */ + d_printf(5, dev, "Neighbor is connected, preparing frame.\n"); result = wlp_wss_prep_hdr(wlp, eda_entry, skb); + } out: + d_fnend(5, dev, "wlp %p, result = %d \n", wlp, result); return result; } @@ -870,6 +957,8 @@ int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry, struct sk_buff *copy; struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; + d_fnstart(5, dev, "to neighbor %02x:%02x, skb (%p) \n", + dev_addr->data[1], dev_addr->data[0], skb); copy = skb_copy(skb, GFP_ATOMIC); if (copy == NULL) { if (printk_ratelimit()) @@ -899,6 +988,8 @@ int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry, dev_kfree_skb_irq(copy);/*we need to free if tx fails */ } out: + d_fnend(5, dev, "to neighbor %02x:%02x \n", dev_addr->data[1], + dev_addr->data[0]); return result; } @@ -914,7 +1005,7 @@ int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss) struct wlp *wlp = container_of(wss, struct wlp, wss); struct device *dev = &wlp->rc->uwb_dev.dev; int result = 0; - + d_fnstart(5, dev, "wss (%p) \n", wss); mutex_lock(&wss->mutex); wss->kobj.parent = &net_dev->dev.kobj; if (!is_valid_ether_addr(net_dev->dev_addr)) { @@ -927,6 +1018,7 @@ int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss) sizeof(wss->virtual_addr.data)); out: mutex_unlock(&wss->mutex); + d_fnend(5, dev, "wss (%p) \n", wss); return result; } EXPORT_SYMBOL_GPL(wlp_wss_setup); @@ -943,7 +1035,8 @@ EXPORT_SYMBOL_GPL(wlp_wss_setup); void wlp_wss_remove(struct wlp_wss *wss) { struct wlp *wlp = container_of(wss, struct wlp, wss); - + struct device *dev = &wlp->rc->uwb_dev.dev; + d_fnstart(5, dev, "wss (%p) \n", wss); mutex_lock(&wss->mutex); if (wss->state == WLP_WSS_STATE_ACTIVE) uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP); @@ -957,5 +1050,6 @@ void wlp_wss_remove(struct wlp_wss *wss) wlp_eda_release(&wlp->eda); wlp_eda_init(&wlp->eda); mutex_unlock(&wss->mutex); + d_fnend(5, dev, "wss (%p) \n", wss); } EXPORT_SYMBOL_GPL(wlp_wss_remove); diff --git a/trunk/fs/devpts/inode.c b/trunk/fs/devpts/inode.c index fff96e152c0c..5d61b7c06e13 100644 --- a/trunk/fs/devpts/inode.c +++ b/trunk/fs/devpts/inode.c @@ -27,32 +27,25 @@ #define DEVPTS_SUPER_MAGIC 0x1cd1 #define DEVPTS_DEFAULT_MODE 0600 -/* - * ptmx is a new node in /dev/pts and will be unused in legacy (single- - * instance) mode. To prevent surprises in user space, set permissions of - * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful - * permissions. - */ -#define DEVPTS_DEFAULT_PTMX_MODE 0000 #define PTMX_MINOR 2 extern int pty_limit; /* Config limit on Unix98 ptys */ +static DEFINE_IDA(allocated_ptys); static DEFINE_MUTEX(allocated_ptys_lock); static struct vfsmount *devpts_mnt; +static struct dentry *devpts_root; -struct pts_mount_opts { +static struct { int setuid; int setgid; uid_t uid; gid_t gid; umode_t mode; - umode_t ptmxmode; - int newinstance; -}; +} config = {.mode = DEVPTS_DEFAULT_MODE}; enum { - Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, + Opt_uid, Opt_gid, Opt_mode, Opt_err }; @@ -60,50 +53,18 @@ static const match_table_t tokens = { {Opt_uid, "uid=%u"}, {Opt_gid, "gid=%u"}, {Opt_mode, "mode=%o"}, -#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES - {Opt_ptmxmode, "ptmxmode=%o"}, - {Opt_newinstance, "newinstance"}, -#endif {Opt_err, NULL} }; -struct pts_fs_info { - struct ida allocated_ptys; - struct pts_mount_opts mount_opts; - struct dentry *ptmx_dentry; -}; - -static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -static inline struct super_block *pts_sb_from_inode(struct inode *inode) -{ -#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES - if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) - return inode->i_sb; -#endif - return devpts_mnt->mnt_sb; -} - -#define PARSE_MOUNT 0 -#define PARSE_REMOUNT 1 - -static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) +static int devpts_remount(struct super_block *sb, int *flags, char *data) { char *p; - opts->setuid = 0; - opts->setgid = 0; - opts->uid = 0; - opts->gid = 0; - opts->mode = DEVPTS_DEFAULT_MODE; - opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; - - /* newinstance makes sense only on initial mount */ - if (op == PARSE_MOUNT) - opts->newinstance = 0; + config.setuid = 0; + config.setgid = 0; + config.uid = 0; + config.gid = 0; + config.mode = DEVPTS_DEFAULT_MODE; while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -118,32 +79,20 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) case Opt_uid: if (match_int(&args[0], &option)) return -EINVAL; - opts->uid = option; - opts->setuid = 1; + config.uid = option; + config.setuid = 1; break; case Opt_gid: if (match_int(&args[0], &option)) return -EINVAL; - opts->gid = option; - opts->setgid = 1; + config.gid = option; + config.setgid = 1; break; case Opt_mode: if (match_octal(&args[0], &option)) return -EINVAL; - opts->mode = option & S_IALLUGO; - break; -#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES - case Opt_ptmxmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->ptmxmode = option & S_IALLUGO; - break; - case Opt_newinstance: - /* newinstance makes sense only on initial mount */ - if (op == PARSE_MOUNT) - opts->newinstance = 1; + config.mode = option & S_IALLUGO; break; -#endif default: printk(KERN_ERR "devpts: called with bogus options\n"); return -EINVAL; @@ -153,108 +102,13 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) return 0; } -#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES -static int mknod_ptmx(struct super_block *sb) -{ - int mode; - int rc = -ENOMEM; - struct dentry *dentry; - struct inode *inode; - struct dentry *root = sb->s_root; - struct pts_fs_info *fsi = DEVPTS_SB(sb); - struct pts_mount_opts *opts = &fsi->mount_opts; - - mutex_lock(&root->d_inode->i_mutex); - - /* If we have already created ptmx node, return */ - if (fsi->ptmx_dentry) { - rc = 0; - goto out; - } - - dentry = d_alloc_name(root, "ptmx"); - if (!dentry) { - printk(KERN_NOTICE "Unable to alloc dentry for ptmx node\n"); - goto out; - } - - /* - * Create a new 'ptmx' node in this mount of devpts. - */ - inode = new_inode(sb); - if (!inode) { - printk(KERN_ERR "Unable to alloc inode for ptmx node\n"); - dput(dentry); - goto out; - } - - inode->i_ino = 2; - inode->i_uid = inode->i_gid = 0; - inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - - mode = S_IFCHR|opts->ptmxmode; - init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2)); - - d_add(dentry, inode); - - fsi->ptmx_dentry = dentry; - rc = 0; - - printk(KERN_DEBUG "Created ptmx node in devpts ino %lu\n", - inode->i_ino); -out: - mutex_unlock(&root->d_inode->i_mutex); - return rc; -} - -static void update_ptmx_mode(struct pts_fs_info *fsi) -{ - struct inode *inode; - if (fsi->ptmx_dentry) { - inode = fsi->ptmx_dentry->d_inode; - inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode; - } -} -#else -static inline void update_ptmx_mode(struct pts_fs_info *fsi) -{ - return; -} -#endif - -static int devpts_remount(struct super_block *sb, int *flags, char *data) -{ - int err; - struct pts_fs_info *fsi = DEVPTS_SB(sb); - struct pts_mount_opts *opts = &fsi->mount_opts; - - err = parse_mount_options(data, PARSE_REMOUNT, opts); - - /* - * parse_mount_options() restores options to default values - * before parsing and may have changed ptmxmode. So, update the - * mode in the inode too. Bogus options don't fail the remount, - * so do this even on error return. - */ - update_ptmx_mode(fsi); - - return err; -} - static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs) { - struct pts_fs_info *fsi = DEVPTS_SB(vfs->mnt_sb); - struct pts_mount_opts *opts = &fsi->mount_opts; - - if (opts->setuid) - seq_printf(seq, ",uid=%u", opts->uid); - if (opts->setgid) - seq_printf(seq, ",gid=%u", opts->gid); - seq_printf(seq, ",mode=%03o", opts->mode); -#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES - seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); -#endif + if (config.setuid) + seq_printf(seq, ",uid=%u", config.uid); + if (config.setgid) + seq_printf(seq, ",gid=%u", config.gid); + seq_printf(seq, ",mode=%03o", config.mode); return 0; } @@ -265,25 +119,10 @@ static const struct super_operations devpts_sops = { .show_options = devpts_show_options, }; -static void *new_pts_fs_info(void) -{ - struct pts_fs_info *fsi; - - fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL); - if (!fsi) - return NULL; - - ida_init(&fsi->allocated_ptys); - fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE; - fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; - - return fsi; -} - static int devpts_fill_super(struct super_block *s, void *data, int silent) { - struct inode *inode; + struct inode * inode; s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -291,13 +130,9 @@ devpts_fill_super(struct super_block *s, void *data, int silent) s->s_op = &devpts_sops; s->s_time_gran = 1; - s->s_fs_info = new_pts_fs_info(); - if (!s->s_fs_info) - goto fail; - inode = new_inode(s); if (!inode) - goto free_fsi; + goto fail; inode->i_ino = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = 0; @@ -307,226 +142,27 @@ devpts_fill_super(struct super_block *s, void *data, int silent) inode->i_fop = &simple_dir_operations; inode->i_nlink = 2; - s->s_root = d_alloc_root(inode); + devpts_root = s->s_root = d_alloc_root(inode); if (s->s_root) return 0; - - printk(KERN_ERR "devpts: get root dentry failed\n"); + + printk("devpts: get root dentry failed\n"); iput(inode); - -free_fsi: - kfree(s->s_fs_info); fail: return -ENOMEM; } -#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES -static int compare_init_pts_sb(struct super_block *s, void *p) -{ - if (devpts_mnt) - return devpts_mnt->mnt_sb == s; - return 0; -} - -/* - * Safely parse the mount options in @data and update @opts. - * - * devpts ends up parsing options two times during mount, due to the - * two modes of operation it supports. The first parse occurs in - * devpts_get_sb() when determining the mode (single-instance or - * multi-instance mode). The second parse happens in devpts_remount() - * or new_pts_mount() depending on the mode. - * - * Parsing of options modifies the @data making subsequent parsing - * incorrect. So make a local copy of @data and parse it. - * - * Return: 0 On success, -errno on error - */ -static int safe_parse_mount_options(void *data, struct pts_mount_opts *opts) -{ - int rc; - void *datacp; - - if (!data) - return 0; - - /* Use kstrdup() ? */ - datacp = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!datacp) - return -ENOMEM; - - memcpy(datacp, data, PAGE_SIZE); - rc = parse_mount_options((char *)datacp, PARSE_MOUNT, opts); - kfree(datacp); - - return rc; -} - -/* - * Mount a new (private) instance of devpts. PTYs created in this - * instance are independent of the PTYs in other devpts instances. - */ -static int new_pts_mount(struct file_system_type *fs_type, int flags, - void *data, struct vfsmount *mnt) -{ - int err; - struct pts_fs_info *fsi; - struct pts_mount_opts *opts; - - printk(KERN_NOTICE "devpts: newinstance mount\n"); - - err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt); - if (err) - return err; - - fsi = DEVPTS_SB(mnt->mnt_sb); - opts = &fsi->mount_opts; - - err = parse_mount_options(data, PARSE_MOUNT, opts); - if (err) - goto fail; - - err = mknod_ptmx(mnt->mnt_sb); - if (err) - goto fail; - - return 0; - -fail: - dput(mnt->mnt_sb->s_root); - deactivate_super(mnt->mnt_sb); - return err; -} - -/* - * Check if 'newinstance' mount option was specified in @data. - * - * Return: -errno on error (eg: invalid mount options specified) - * : 1 if 'newinstance' mount option was specified - * : 0 if 'newinstance' mount option was NOT specified - */ -static int is_new_instance_mount(void *data) -{ - int rc; - struct pts_mount_opts opts; - - if (!data) - return 0; - - rc = safe_parse_mount_options(data, &opts); - if (!rc) - rc = opts.newinstance; - - return rc; -} - -/* - * get_init_pts_sb() - * - * This interface is needed to support multiple namespace semantics in - * devpts while preserving backward compatibility of the current 'single- - * namespace' semantics. i.e all mounts of devpts without the 'newinstance' - * mount option should bind to the initial kernel mount, like - * get_sb_single(). - * - * Mounts with 'newinstance' option create a new private namespace. - * - * But for single-mount semantics, devpts cannot use get_sb_single(), - * because get_sb_single()/sget() find and use the super-block from - * the most recent mount of devpts. But that recent mount may be a - * 'newinstance' mount and get_sb_single() would pick the newinstance - * super-block instead of the initial super-block. - * - * This interface is identical to get_sb_single() except that it - * consistently selects the 'single-namespace' superblock even in the - * presence of the private namespace (i.e 'newinstance') super-blocks. - */ -static int get_init_pts_sb(struct file_system_type *fs_type, int flags, - void *data, struct vfsmount *mnt) -{ - struct super_block *s; - int error; - - s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); - if (IS_ERR(s)) - return PTR_ERR(s); - - if (!s->s_root) { - s->s_flags = flags; - error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); - if (error) { - up_write(&s->s_umount); - deactivate_super(s); - return error; - } - s->s_flags |= MS_ACTIVE; - } - do_remount_sb(s, flags, data, 0); - return simple_set_mnt(mnt, s); -} - -/* - * Mount or remount the initial kernel mount of devpts. This type of - * mount maintains the legacy, single-instance semantics, while the - * kernel still allows multiple-instances. - */ -static int init_pts_mount(struct file_system_type *fs_type, int flags, - void *data, struct vfsmount *mnt) -{ - int err; - - err = get_init_pts_sb(fs_type, flags, data, mnt); - if (err) - return err; - - err = mknod_ptmx(mnt->mnt_sb); - if (err) { - dput(mnt->mnt_sb->s_root); - deactivate_super(mnt->mnt_sb); - } - - return err; -} - static int devpts_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) -{ - int new; - - new = is_new_instance_mount(data); - if (new < 0) - return new; - - if (new) - return new_pts_mount(fs_type, flags, data, mnt); - - return init_pts_mount(fs_type, flags, data, mnt); -} -#else -/* - * This supports only the legacy single-instance semantics (no - * multiple-instance semantics) - */ -static int devpts_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) { return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt); } -#endif - -static void devpts_kill_sb(struct super_block *sb) -{ - struct pts_fs_info *fsi = DEVPTS_SB(sb); - - kfree(fsi); - kill_litter_super(sb); -} static struct file_system_type devpts_fs_type = { .owner = THIS_MODULE, .name = "devpts", .get_sb = devpts_get_sb, - .kill_sb = devpts_kill_sb, + .kill_sb = kill_anon_super, }; /* @@ -536,17 +172,16 @@ static struct file_system_type devpts_fs_type = { int devpts_new_index(struct inode *ptmx_inode) { - struct super_block *sb = pts_sb_from_inode(ptmx_inode); - struct pts_fs_info *fsi = DEVPTS_SB(sb); int index; int ida_ret; retry: - if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL)) + if (!ida_pre_get(&allocated_ptys, GFP_KERNEL)) { return -ENOMEM; + } mutex_lock(&allocated_ptys_lock); - ida_ret = ida_get_new(&fsi->allocated_ptys, &index); + ida_ret = ida_get_new(&allocated_ptys, &index); if (ida_ret < 0) { mutex_unlock(&allocated_ptys_lock); if (ida_ret == -EAGAIN) @@ -555,7 +190,7 @@ int devpts_new_index(struct inode *ptmx_inode) } if (index >= pty_limit) { - ida_remove(&fsi->allocated_ptys, index); + ida_remove(&allocated_ptys, index); mutex_unlock(&allocated_ptys_lock); return -EIO; } @@ -565,26 +200,18 @@ int devpts_new_index(struct inode *ptmx_inode) void devpts_kill_index(struct inode *ptmx_inode, int idx) { - struct super_block *sb = pts_sb_from_inode(ptmx_inode); - struct pts_fs_info *fsi = DEVPTS_SB(sb); - mutex_lock(&allocated_ptys_lock); - ida_remove(&fsi->allocated_ptys, idx); + ida_remove(&allocated_ptys, idx); mutex_unlock(&allocated_ptys_lock); } int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) { - /* tty layer puts index from devpts_new_index() in here */ - int number = tty->index; + int number = tty->index; /* tty layer puts index from devpts_new_index() in here */ struct tty_driver *driver = tty->driver; dev_t device = MKDEV(driver->major, driver->minor_start+number); struct dentry *dentry; - struct super_block *sb = pts_sb_from_inode(ptmx_inode); - struct inode *inode = new_inode(sb); - struct dentry *root = sb->s_root; - struct pts_fs_info *fsi = DEVPTS_SB(sb); - struct pts_mount_opts *opts = &fsi->mount_opts; + struct inode *inode = new_inode(devpts_mnt->mnt_sb); char s[12]; /* We're supposed to be given the slave end of a pty */ @@ -594,25 +221,25 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) if (!inode) return -ENOMEM; - inode->i_ino = number + 3; - inode->i_uid = opts->setuid ? opts->uid : current_fsuid(); - inode->i_gid = opts->setgid ? opts->gid : current_fsgid(); + inode->i_ino = number+2; + inode->i_uid = config.setuid ? config.uid : current_fsuid(); + inode->i_gid = config.setgid ? config.gid : current_fsgid(); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - init_special_inode(inode, S_IFCHR|opts->mode, device); + init_special_inode(inode, S_IFCHR|config.mode, device); inode->i_private = tty; tty->driver_data = inode; sprintf(s, "%d", number); - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&devpts_root->d_inode->i_mutex); - dentry = d_alloc_name(root, s); + dentry = d_alloc_name(devpts_root, s); if (!IS_ERR(dentry)) { d_add(dentry, inode); - fsnotify_create(root->d_inode, dentry); + fsnotify_create(devpts_root->d_inode, dentry); } - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&devpts_root->d_inode->i_mutex); return 0; } @@ -629,27 +256,20 @@ struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number) void devpts_pty_kill(struct tty_struct *tty) { struct inode *inode = tty->driver_data; - struct super_block *sb = pts_sb_from_inode(inode); - struct dentry *root = sb->s_root; struct dentry *dentry; BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&devpts_root->d_inode->i_mutex); dentry = d_find_alias(inode); - if (IS_ERR(dentry)) - goto out; - - if (dentry) { + if (dentry && !IS_ERR(dentry)) { inode->i_nlink--; d_delete(dentry); - dput(dentry); /* d_alloc_name() in devpts_pty_new() */ + dput(dentry); } - dput(dentry); /* d_find_alias above */ -out: - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&devpts_root->d_inode->i_mutex); } static int __init init_devpts_fs(void) diff --git a/trunk/include/linux/8250_pci.h b/trunk/include/linux/8250_pci.h index b24ff086a662..3209dd46ea7d 100644 --- a/trunk/include/linux/8250_pci.h +++ b/trunk/include/linux/8250_pci.h @@ -31,7 +31,7 @@ struct pciserial_board { struct serial_private; struct serial_private * -pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board); +pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board); void pciserial_remove_ports(struct serial_private *priv); void pciserial_suspend_ports(struct serial_private *priv); void pciserial_resume_ports(struct serial_private *priv); diff --git a/trunk/include/linux/compiler-gcc.h b/trunk/include/linux/compiler-gcc.h index af40f8eb86f0..5c8351b859f0 100644 --- a/trunk/include/linux/compiler-gcc.h +++ b/trunk/include/linux/compiler-gcc.h @@ -61,8 +61,3 @@ #define noinline __attribute__((noinline)) #define __attribute_const__ __attribute__((__const__)) #define __maybe_unused __attribute__((unused)) - -#define __gcc_header(x) #x -#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) -#define gcc_header(x) _gcc_header(x) -#include gcc_header(__GNUC__) diff --git a/trunk/include/linux/compiler-gcc3.h b/trunk/include/linux/compiler-gcc3.h index 2befe6513ce4..e5eb795f78a1 100644 --- a/trunk/include/linux/compiler-gcc3.h +++ b/trunk/include/linux/compiler-gcc3.h @@ -2,6 +2,9 @@ #error "Please don't include directly, include instead." #endif +/* These definitions are for GCC v3.x. */ +#include + #if __GNUC_MINOR__ >= 3 # define __used __attribute__((__used__)) #else diff --git a/trunk/include/linux/compiler-gcc4.h b/trunk/include/linux/compiler-gcc4.h index 09992718f9e8..974f5b7bb205 100644 --- a/trunk/include/linux/compiler-gcc4.h +++ b/trunk/include/linux/compiler-gcc4.h @@ -2,10 +2,8 @@ #error "Please don't include directly, include instead." #endif -/* GCC 4.1.[01] miscompiles __weak */ -#if __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1 -# error Your version of gcc miscompiles the __weak directive -#endif +/* These definitions are for GCC v4.x. */ +#include #define __used __attribute__((__used__)) #define __must_check __attribute__((warn_unused_result)) @@ -18,7 +16,7 @@ */ #define uninitialized_var(x) x = x -#if __GNUC_MINOR__ >= 3 +#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 3) /* Mark functions as cold. gcc will assume any path leading to a call to them will be unlikely. This means a lot of manual unlikely()s are unnecessary now for any paths leading to the usual suspects diff --git a/trunk/include/linux/compiler.h b/trunk/include/linux/compiler.h index d95da1020f1c..ea7c6be354b7 100644 --- a/trunk/include/linux/compiler.h +++ b/trunk/include/linux/compiler.h @@ -36,8 +36,12 @@ extern void __chk_io_ptr(const volatile void __iomem *); #ifdef __KERNEL__ -#ifdef __GNUC__ -#include +#if __GNUC__ >= 4 +# include +#elif __GNUC__ == 3 && __GNUC_MINOR__ >= 2 +# include +#else +# error Sorry, your compiler is too old/not recognized. #endif #define notrace __attribute__((no_instrument_function)) diff --git a/trunk/include/linux/generic_serial.h b/trunk/include/linux/generic_serial.h index fadff28505bb..4cc913939817 100644 --- a/trunk/include/linux/generic_serial.h +++ b/trunk/include/linux/generic_serial.h @@ -21,6 +21,7 @@ struct real_driver { void (*enable_tx_interrupts) (void *); void (*disable_rx_interrupts) (void *); void (*enable_rx_interrupts) (void *); + int (*get_CD) (void *); void (*shutdown_port) (void*); int (*set_real_termios) (void*); int (*chars_in_buffer) (void*); diff --git a/trunk/include/linux/istallion.h b/trunk/include/linux/istallion.h index 7faca98c7d14..0d1840723249 100644 --- a/trunk/include/linux/istallion.h +++ b/trunk/include/linux/istallion.h @@ -59,7 +59,9 @@ struct stliport { unsigned int devnr; int baud_base; int custom_divisor; + int close_delay; int closing_wait; + int openwaitcnt; int rc; int argsize; void *argp; diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 218c73b1e6d4..b6e694454280 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -1766,7 +1766,6 @@ #define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081 #define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 -#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530 #define PCI_VENDOR_ID_RADISYS 0x1331 @@ -1796,7 +1795,6 @@ #define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202 #define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401 #define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801 -#define PCI_DEVICE_ID_SEALEVEL_7803 0x7803 #define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804 #define PCI_VENDOR_ID_HYPERCOPE 0x1365 diff --git a/trunk/include/linux/serial.h b/trunk/include/linux/serial.h index 9136cc5608c3..1ea8d9265bf6 100644 --- a/trunk/include/linux/serial.h +++ b/trunk/include/linux/serial.h @@ -10,9 +10,8 @@ #ifndef _LINUX_SERIAL_H #define _LINUX_SERIAL_H -#include - #ifdef __KERNEL__ +#include #include /* diff --git a/trunk/include/linux/serial_8250.h b/trunk/include/linux/serial_8250.h index d4d2a78ad43e..3d37c94abbc8 100644 --- a/trunk/include/linux/serial_8250.h +++ b/trunk/include/linux/serial_8250.h @@ -28,9 +28,6 @@ struct plat_serial8250_port { unsigned char iotype; /* UPIO_* */ unsigned char hub6; upf_t flags; /* UPF_* flags */ - unsigned int type; /* If UPF_FIXED_TYPE */ - unsigned int (*serial_in)(struct uart_port *, int); - void (*serial_out)(struct uart_port *, int, int); }; /* diff --git a/trunk/include/linux/serial_core.h b/trunk/include/linux/serial_core.h index b4199841f1fc..feb3b939ec4b 100644 --- a/trunk/include/linux/serial_core.h +++ b/trunk/include/linux/serial_core.h @@ -40,8 +40,7 @@ #define PORT_NS16550A 14 #define PORT_XSCALE 15 #define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */ -#define PORT_OCTEON 17 /* Cavium OCTEON internal UART */ -#define PORT_MAX_8250 17 /* max port ID */ +#define PORT_MAX_8250 16 /* max port ID */ /* * ARM specific type numbers. These are not currently guaranteed @@ -249,8 +248,6 @@ struct uart_port { spinlock_t lock; /* port lock */ unsigned long iobase; /* in/out[bwl] */ unsigned char __iomem *membase; /* read/write[bwl] */ - unsigned int (*serial_in)(struct uart_port *, int); - void (*serial_out)(struct uart_port *, int, int); unsigned int irq; /* irq number */ unsigned int uartclk; /* base uart clock */ unsigned int fifosize; /* tx fifo size */ @@ -296,8 +293,6 @@ struct uart_port { #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) -/* The exact UART type is known and should not be probed. */ -#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) #define UPF_FIXED_PORT ((__force upf_t) (1 << 29)) #define UPF_DEAD ((__force upf_t) (1 << 30)) @@ -320,14 +315,36 @@ struct uart_port { void *private_data; /* generic platform data pointer */ }; +/* + * This is the state information which is persistent across opens. + * The low level driver must not to touch any elements contained + * within. + */ +struct uart_state { + unsigned int close_delay; /* msec */ + unsigned int closing_wait; /* msec */ + +#define USF_CLOSING_WAIT_INF (0) +#define USF_CLOSING_WAIT_NONE (~0U) + + int count; + int pm_state; + struct uart_info *info; + struct uart_port *port; + + struct mutex mutex; +}; + +#define UART_XMIT_SIZE PAGE_SIZE + +typedef unsigned int __bitwise__ uif_t; + /* * This is the state information which is only valid when the port - * is open; it may be cleared the core driver once the device has + * is open; it may be freed by the core driver once the device has * been closed. Either the low level driver or the core can modify * stuff here. */ -typedef unsigned int __bitwise__ uif_t; - struct uart_info { struct tty_port port; struct circ_buf xmit; @@ -349,29 +366,6 @@ struct uart_info { wait_queue_head_t delta_msr_wait; }; -/* - * This is the state information which is persistent across opens. - * The low level driver must not to touch any elements contained - * within. - */ -struct uart_state { - unsigned int close_delay; /* msec */ - unsigned int closing_wait; /* msec */ - -#define USF_CLOSING_WAIT_INF (0) -#define USF_CLOSING_WAIT_NONE (~0U) - - int count; - int pm_state; - struct uart_info info; - struct uart_port *port; - - struct mutex mutex; -}; - -#define UART_XMIT_SIZE PAGE_SIZE - - /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -445,13 +439,8 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port); #define uart_circ_chars_free(circ) \ (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) -static inline int uart_tx_stopped(struct uart_port *port) -{ - struct tty_struct *tty = port->info->port.tty; - if(tty->stopped || tty->hw_stopped) - return 1; - return 0; -} +#define uart_tx_stopped(portp) \ + ((portp)->info->port.tty->stopped || (portp)->info->port.tty->hw_stopped) /* * The following are helper functions for the low level drivers. @@ -462,7 +451,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) #ifdef SUPPORT_SYSRQ if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, port->info->port.tty); + handle_sysrq(ch, port->info ? port->info->port.tty : NULL); port->sysrq = 0; return 1; } diff --git a/trunk/include/linux/tty.h b/trunk/include/linux/tty.h index fc39db95499f..3f4954c55e53 100644 --- a/trunk/include/linux/tty.h +++ b/trunk/include/linux/tty.h @@ -180,17 +180,8 @@ struct signal_struct; * until a hangup so don't use the wrong path. */ -struct tty_port; - -struct tty_port_operations { - /* Return 1 if the carrier is raised */ - int (*carrier_raised)(struct tty_port *port); - void (*raise_dtr_rts)(struct tty_port *port); -}; - struct tty_port { struct tty_struct *tty; /* Back pointer */ - const struct tty_port_operations *ops; /* Port operations */ spinlock_t lock; /* Lock protecting tty field */ int blocked_open; /* Waiting to open */ int count; /* Usage count */ @@ -262,7 +253,6 @@ struct tty_struct { unsigned int column; unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; unsigned char closing:1; - unsigned char echo_overrun:1; unsigned short minimum_to_wake; unsigned long overrun_time; int num_overrun; @@ -272,16 +262,11 @@ struct tty_struct { int read_tail; int read_cnt; unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))]; - unsigned char *echo_buf; - unsigned int echo_pos; - unsigned int echo_cnt; int canon_data; unsigned long canon_head; unsigned int canon_column; struct mutex atomic_read_lock; struct mutex atomic_write_lock; - struct mutex output_lock; - struct mutex echo_lock; unsigned char *write_buf; int write_cnt; spinlock_t read_lock; @@ -310,7 +295,6 @@ struct tty_struct { #define TTY_PUSH 6 /* n_tty private */ #define TTY_CLOSING 7 /* ->close() in progress */ #define TTY_LDISC 9 /* Line discipline attached */ -#define TTY_LDISC_CHANGING 10 /* Line discipline changing */ #define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */ #define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */ #define TTY_PTY_LOCK 16 /* pty private */ @@ -370,7 +354,8 @@ extern int tty_write_room(struct tty_struct *tty); extern void tty_driver_flush_buffer(struct tty_struct *tty); extern void tty_throttle(struct tty_struct *tty); extern void tty_unthrottle(struct tty_struct *tty); -extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws); +extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws); extern void tty_shutdown(struct tty_struct *tty); extern void tty_free_termios(struct tty_struct *tty); extern int is_current_pgrp_orphaned(void); @@ -436,14 +421,6 @@ extern int tty_port_alloc_xmit_buf(struct tty_port *port); extern void tty_port_free_xmit_buf(struct tty_port *port); extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); -extern int tty_port_carrier_raised(struct tty_port *port); -extern void tty_port_raise_dtr_rts(struct tty_port *port); -extern void tty_port_hangup(struct tty_port *port); -extern int tty_port_block_til_ready(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern int tty_port_close_start(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); diff --git a/trunk/include/linux/tty_driver.h b/trunk/include/linux/tty_driver.h index 08e088334dba..78416b901589 100644 --- a/trunk/include/linux/tty_driver.h +++ b/trunk/include/linux/tty_driver.h @@ -196,7 +196,8 @@ * Optional: If not provided then the write method is called under * the atomic write lock to keep it serialized with the ldisc. * - * int (*resize)(struct tty_struct *tty, struct winsize *ws) + * int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, + * unsigned int rows, unsigned int cols); * * Called when a termios request is issued which changes the * requested terminal geometry. @@ -257,7 +258,8 @@ struct tty_operations { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); - int (*resize)(struct tty_struct *tty, struct winsize *ws); + int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws); int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); #ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); diff --git a/trunk/include/linux/usb/wusb-wa.h b/trunk/include/linux/usb/wusb-wa.h index fb7c359bdfba..a102561e7026 100644 --- a/trunk/include/linux/usb/wusb-wa.h +++ b/trunk/include/linux/usb/wusb-wa.h @@ -51,7 +51,6 @@ enum { WUSB_REQ_GET_TIME = 25, WUSB_REQ_SET_STREAM_IDX = 26, WUSB_REQ_SET_WUSB_MAS = 27, - WUSB_REQ_CHAN_STOP = 28, }; diff --git a/trunk/include/linux/uwb.h b/trunk/include/linux/uwb.h index c02128991ff7..f9ccbd9a2ced 100644 --- a/trunk/include/linux/uwb.h +++ b/trunk/include/linux/uwb.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -67,7 +66,6 @@ struct uwb_dev { struct uwb_dev_addr dev_addr; int beacon_slot; DECLARE_BITMAP(streams, UWB_NUM_STREAMS); - DECLARE_BITMAP(last_availability_bm, UWB_NUM_MAS); }; #define to_uwb_dev(d) container_of(d, struct uwb_dev, dev) @@ -88,31 +86,12 @@ struct uwb_notifs_chain { struct mutex mutex; }; -/* Beacon cache list */ -struct uwb_beca { - struct list_head list; - size_t entries; - struct mutex mutex; -}; - -/* Event handling thread. */ -struct uwbd { - int pid; - struct task_struct *task; - wait_queue_head_t wq; - struct list_head event_list; - spinlock_t event_list_lock; -}; - /** * struct uwb_mas_bm - a bitmap of all MAS in a superframe * @bm: a bitmap of length #UWB_NUM_MAS */ struct uwb_mas_bm { DECLARE_BITMAP(bm, UWB_NUM_MAS); - DECLARE_BITMAP(unsafe_bm, UWB_NUM_MAS); - int safe; - int unsafe; }; /** @@ -138,24 +117,14 @@ struct uwb_mas_bm { * FIXME: further target states TBD. */ enum uwb_rsv_state { - UWB_RSV_STATE_NONE = 0, + UWB_RSV_STATE_NONE, UWB_RSV_STATE_O_INITIATED, UWB_RSV_STATE_O_PENDING, UWB_RSV_STATE_O_MODIFIED, UWB_RSV_STATE_O_ESTABLISHED, - UWB_RSV_STATE_O_TO_BE_MOVED, - UWB_RSV_STATE_O_MOVE_EXPANDING, - UWB_RSV_STATE_O_MOVE_COMBINING, - UWB_RSV_STATE_O_MOVE_REDUCING, UWB_RSV_STATE_T_ACCEPTED, UWB_RSV_STATE_T_DENIED, - UWB_RSV_STATE_T_CONFLICT, UWB_RSV_STATE_T_PENDING, - UWB_RSV_STATE_T_EXPANDING_ACCEPTED, - UWB_RSV_STATE_T_EXPANDING_CONFLICT, - UWB_RSV_STATE_T_EXPANDING_PENDING, - UWB_RSV_STATE_T_EXPANDING_DENIED, - UWB_RSV_STATE_T_RESIZED, UWB_RSV_STATE_LAST, }; @@ -180,12 +149,6 @@ struct uwb_rsv_target { }; }; -struct uwb_rsv_move { - struct uwb_mas_bm final_mas; - struct uwb_ie_drp *companion_drp_ie; - struct uwb_mas_bm companion_mas; -}; - /* * Number of streams reserved for reservations targeted at DevAddrs. */ @@ -223,7 +186,6 @@ typedef void (*uwb_rsv_cb_f)(struct uwb_rsv *rsv); * * @status: negotiation status * @stream: stream index allocated for this reservation - * @tiebreaker: conflict tiebreaker for this reservation * @mas: reserved MAS * @drp_ie: the DRP IE * @ie_valid: true iff the DRP IE matches the reservation parameters @@ -239,29 +201,25 @@ struct uwb_rsv { struct uwb_rc *rc; struct list_head rc_node; struct list_head pal_node; - struct kref kref; struct uwb_dev *owner; struct uwb_rsv_target target; enum uwb_drp_type type; int max_mas; int min_mas; - int max_interval; + int sparsity; bool is_multicast; uwb_rsv_cb_f callback; void *pal_priv; enum uwb_rsv_state state; - bool needs_release_companion_mas; u8 stream; - u8 tiebreaker; struct uwb_mas_bm mas; struct uwb_ie_drp *drp_ie; - struct uwb_rsv_move mv; bool ie_valid; struct timer_list timer; - struct work_struct handle_timeout_work; + bool expired; }; static const @@ -303,13 +261,6 @@ struct uwb_drp_avail { bool ie_valid; }; -struct uwb_drp_backoff_win { - u8 window; - u8 n; - int total_expired; - struct timer_list timer; - bool can_reserve_extra_mases; -}; const char *uwb_rsv_state_str(enum uwb_rsv_state state); const char *uwb_rsv_type_str(enum uwb_drp_type type); @@ -325,8 +276,6 @@ void uwb_rsv_terminate(struct uwb_rsv *rsv); void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv); -void uwb_rsv_get_usable_mas(struct uwb_rsv *orig_rsv, struct uwb_mas_bm *mas); - /** * Radio Control Interface instance * @@ -388,33 +337,23 @@ struct uwb_rc { u8 ctx_roll; int beaconing; /* Beaconing state [channel number] */ - int beaconing_forced; int scanning; enum uwb_scan_type scan_type:3; unsigned ready:1; struct uwb_notifs_chain notifs_chain; - struct uwb_beca uwb_beca; - - struct uwbd uwbd; - struct uwb_drp_backoff_win bow; struct uwb_drp_avail drp_avail; struct list_head reservations; - struct list_head cnflt_alien_list; - struct uwb_mas_bm cnflt_alien_bitmap; struct mutex rsvs_mutex; - spinlock_t rsvs_lock; struct workqueue_struct *rsv_workq; + struct work_struct rsv_update_work; - struct delayed_work rsv_update_work; - struct delayed_work rsv_alien_bp_work; - int set_drp_ie_pending; struct mutex ies_mutex; struct uwb_rc_cmd_set_ie *ies; size_t ies_capacity; + spinlock_t pal_lock; struct list_head pals; - int active_pals; struct uwb_dbg *dbg; }; @@ -422,19 +361,11 @@ struct uwb_rc { /** * struct uwb_pal - a UWB PAL - * @name: descriptive name for this PAL (wusbhc, wlp, etc.). + * @name: descriptive name for this PAL (wushc, wlp, etc.). * @device: a device for the PAL. Used to link the PAL and the radio * controller in sysfs. - * @rc: the radio controller the PAL uses. - * @channel_changed: called when the channel used by the radio changes. - * A channel of -1 means the channel has been stopped. * @new_rsv: called when a peer requests a reservation (may be NULL if * the PAL cannot accept reservation requests). - * @channel: channel being used by the PAL; 0 if the PAL isn't using - * the radio; -1 if the PAL wishes to use the radio but - * cannot. - * @debugfs_dir: a debugfs directory which the PAL can use for its own - * debugfs files. * * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP). @@ -453,21 +384,12 @@ struct uwb_pal { struct list_head node; const char *name; struct device *device; - struct uwb_rc *rc; - - void (*channel_changed)(struct uwb_pal *pal, int channel); - void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv); - - int channel; - struct dentry *debugfs_dir; + void (*new_rsv)(struct uwb_rsv *rsv); }; void uwb_pal_init(struct uwb_pal *pal); -int uwb_pal_register(struct uwb_pal *pal); -void uwb_pal_unregister(struct uwb_pal *pal); - -int uwb_radio_start(struct uwb_pal *pal); -void uwb_radio_stop(struct uwb_pal *pal); +int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal); +void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal); /* * General public API @@ -521,6 +443,8 @@ ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name, struct uwb_rccb *cmd, size_t cmd_size, u8 expected_type, u16 expected_event, struct uwb_rceb **preply); +ssize_t uwb_rc_get_ie(struct uwb_rc *, struct uwb_rc_evt_get_ie **); +int uwb_bg_joined(struct uwb_rc *rc); size_t __uwb_addr_print(char *, size_t, const unsigned char *, int); @@ -596,8 +520,6 @@ void uwb_rc_rm(struct uwb_rc *); void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t); void uwb_rc_neh_error(struct uwb_rc *, int); void uwb_rc_reset_all(struct uwb_rc *rc); -void uwb_rc_pre_reset(struct uwb_rc *rc); -void uwb_rc_post_reset(struct uwb_rc *rc); /** * uwb_rsv_is_owner - is the owner of this reservation the RC? @@ -609,9 +531,7 @@ static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv) } /** - * enum uwb_notifs - UWB events that can be passed to any listeners - * @UWB_NOTIF_ONAIR: a new neighbour has joined the beacon group. - * @UWB_NOTIF_OFFAIR: a neighbour has left the beacon group. + * Events generated by UWB that can be passed to any listeners * * Higher layers can register callback functions with the radio * controller using uwb_notifs_register(). The radio controller @@ -619,6 +539,8 @@ static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv) * nodes when an event occurs. */ enum uwb_notifs { + UWB_NOTIF_BG_JOIN = 0, /* radio controller joined a beacon group */ + UWB_NOTIF_BG_LEAVE = 1, /* radio controller left a beacon group */ UWB_NOTIF_ONAIR, UWB_NOTIF_OFFAIR, }; @@ -730,9 +652,22 @@ static inline int edc_inc(struct edc *err_hist, u16 max_err, u16 timeframe) /* Information Element handling */ +/* For representing the state of writing to a buffer when iterating */ +struct uwb_buf_ctx { + char *buf; + size_t bytes, size; +}; + +typedef int (*uwb_ie_f)(struct uwb_dev *, const struct uwb_ie_hdr *, + size_t, void *); struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len); -int uwb_rc_ie_add(struct uwb_rc *uwb_rc, const struct uwb_ie_hdr *ies, size_t size); -int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id); +ssize_t uwb_ie_for_each(struct uwb_dev *uwb_dev, uwb_ie_f fn, void *data, + const void *buf, size_t size); +int uwb_ie_dump_hex(struct uwb_dev *, const struct uwb_ie_hdr *, + size_t, void *); +int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *); +struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len); + /* * Transmission statistics diff --git a/trunk/include/linux/uwb/debug-cmd.h b/trunk/include/linux/uwb/debug-cmd.h index 8da004e25628..1141f41bab5c 100644 --- a/trunk/include/linux/uwb/debug-cmd.h +++ b/trunk/include/linux/uwb/debug-cmd.h @@ -32,10 +32,6 @@ enum uwb_dbg_cmd_type { UWB_DBG_CMD_RSV_ESTABLISH = 1, UWB_DBG_CMD_RSV_TERMINATE = 2, - UWB_DBG_CMD_IE_ADD = 3, - UWB_DBG_CMD_IE_RM = 4, - UWB_DBG_CMD_RADIO_START = 5, - UWB_DBG_CMD_RADIO_STOP = 6, }; struct uwb_dbg_cmd_rsv_establish { @@ -43,25 +39,18 @@ struct uwb_dbg_cmd_rsv_establish { __u8 type; __u16 max_mas; __u16 min_mas; - __u8 max_interval; + __u8 sparsity; }; struct uwb_dbg_cmd_rsv_terminate { int index; }; -struct uwb_dbg_cmd_ie { - __u8 data[128]; - int len; -}; - struct uwb_dbg_cmd { __u32 type; union { struct uwb_dbg_cmd_rsv_establish rsv_establish; struct uwb_dbg_cmd_rsv_terminate rsv_terminate; - struct uwb_dbg_cmd_ie ie_add; - struct uwb_dbg_cmd_ie ie_rm; }; }; diff --git a/trunk/include/linux/uwb/debug.h b/trunk/include/linux/uwb/debug.h new file mode 100644 index 000000000000..a86a73fe303f --- /dev/null +++ b/trunk/include/linux/uwb/debug.h @@ -0,0 +1,82 @@ +/* + * Ultra Wide Band + * Debug Support + * + * Copyright (C) 2005-2006 Intel Corporation + * Inaky Perez-Gonzalez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * 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. + * + * + * FIXME: doc + * Invoke like: + * + * #define D_LOCAL 4 + * #include + * + * At the end of your include files. + */ +#include + +struct device; +extern void dump_bytes(struct device *dev, const void *_buf, size_t rsize); + +/* Master debug switch; !0 enables, 0 disables */ +#define D_MASTER (!0) + +/* Local (per-file) debug switch; #define before #including */ +#ifndef D_LOCAL +#define D_LOCAL 0 +#endif + +#undef __d_printf +#undef d_fnstart +#undef d_fnend +#undef d_printf +#undef d_dump + +#define __d_printf(l, _tag, _dev, f, a...) \ +do { \ + struct device *__dev = (_dev); \ + if (D_MASTER && D_LOCAL >= (l)) { \ + char __head[64] = ""; \ + if (_dev != NULL) { \ + if ((unsigned long)__dev < 4096) \ + printk(KERN_ERR "E: Corrupt dev %p\n", \ + __dev); \ + else \ + snprintf(__head, sizeof(__head), \ + "%s %s: ", \ + dev_driver_string(__dev), \ + __dev->bus_id); \ + } \ + printk(KERN_ERR "%s%s" _tag ": " f, __head, \ + __func__, ## a); \ + } \ +} while (0 && _dev) + +#define d_fnstart(l, _dev, f, a...) \ + __d_printf(l, " FNSTART", _dev, f, ## a) +#define d_fnend(l, _dev, f, a...) \ + __d_printf(l, " FNEND", _dev, f, ## a) +#define d_printf(l, _dev, f, a...) \ + __d_printf(l, "", _dev, f, ## a) +#define d_dump(l, _dev, ptr, size) \ +do { \ + struct device *__dev = _dev; \ + if (D_MASTER && D_LOCAL >= (l)) \ + dump_bytes(__dev, ptr, size); \ +} while (0 && _dev) +#define d_test(l) (D_MASTER && D_LOCAL >= (l)) diff --git a/trunk/include/linux/uwb/spec.h b/trunk/include/linux/uwb/spec.h index b52e44f1bd33..198c15f8e251 100644 --- a/trunk/include/linux/uwb/spec.h +++ b/trunk/include/linux/uwb/spec.h @@ -58,11 +58,6 @@ enum { UWB_NUM_ZONES = 16 }; */ #define UWB_MAS_PER_ZONE (UWB_NUM_MAS / UWB_NUM_ZONES) -/* - * Number of MAS required before a row can be considered available. - */ -#define UWB_USABLE_MAS_PER_ROW (UWB_NUM_ZONES - 1) - /* * Number of streams per DRP reservation between a pair of devices. * @@ -98,26 +93,6 @@ enum { UWB_BEACON_SLOT_LENGTH_US = 85 }; */ enum { UWB_MAX_LOST_BEACONS = 3 }; -/* - * mDRPBackOffWinMin - * - * The minimum number of superframes to wait before trying to reserve - * extra MAS. - * - * [ECMA-368] section 17.16 - */ -enum { UWB_DRP_BACKOFF_WIN_MIN = 2 }; - -/* - * mDRPBackOffWinMax - * - * The maximum number of superframes to wait before trying to reserve - * extra MAS. - * - * [ECMA-368] section 17.16 - */ -enum { UWB_DRP_BACKOFF_WIN_MAX = 16 }; - /* * Length of a superframe in microseconds. */ @@ -225,12 +200,6 @@ enum uwb_drp_reason { UWB_DRP_REASON_MODIFIED, }; -/** Relinquish Request Reason Codes ([ECMA-368] table 113) */ -enum uwb_relinquish_req_reason { - UWB_RELINQUISH_REQ_REASON_NON_SPECIFIC = 0, - UWB_RELINQUISH_REQ_REASON_OVER_ALLOCATION, -}; - /** * DRP Notification Reason Codes (WHCI 0.95 [3.1.4.9]) */ @@ -283,7 +252,6 @@ enum uwb_ie { UWB_APP_SPEC_PROBE_IE = 15, UWB_IDENTIFICATION_IE = 19, UWB_MASTER_KEY_ID_IE = 20, - UWB_RELINQUISH_REQUEST_IE = 21, UWB_IE_WLP = 250, /* WiMedia Logical Link Control Protocol WLP 0.99 */ UWB_APP_SPEC_IE = 255, }; @@ -397,27 +365,6 @@ struct uwb_ie_drp_avail { DECLARE_BITMAP(bmp, UWB_NUM_MAS); } __attribute__((packed)); -/* Relinqish Request IE ([ECMA-368] section 16.8.19). */ -struct uwb_relinquish_request_ie { - struct uwb_ie_hdr hdr; - __le16 relinquish_req_control; - struct uwb_dev_addr dev_addr; - struct uwb_drp_alloc allocs[]; -} __attribute__((packed)); - -static inline int uwb_ie_relinquish_req_reason_code(struct uwb_relinquish_request_ie *ie) -{ - return (le16_to_cpu(ie->relinquish_req_control) >> 0) & 0xf; -} - -static inline void uwb_ie_relinquish_req_set_reason_code(struct uwb_relinquish_request_ie *ie, - int reason_code) -{ - u16 ctrl = le16_to_cpu(ie->relinquish_req_control); - ctrl = (ctrl & ~(0xf << 0)) | (reason_code << 0); - ie->relinquish_req_control = cpu_to_le16(ctrl); -} - /** * The Vendor ID is set to an OUI that indicates the vendor of the device. * ECMA-368 [16.8.10] diff --git a/trunk/include/linux/uwb/umc.h b/trunk/include/linux/uwb/umc.h index 4b4fc0f43855..36a39e34f8d7 100644 --- a/trunk/include/linux/uwb/umc.h +++ b/trunk/include/linux/uwb/umc.h @@ -89,8 +89,6 @@ struct umc_driver { void (*remove)(struct umc_dev *); int (*suspend)(struct umc_dev *, pm_message_t state); int (*resume)(struct umc_dev *); - int (*pre_reset)(struct umc_dev *); - int (*post_reset)(struct umc_dev *); struct device_driver driver; }; diff --git a/trunk/include/linux/wlp.h b/trunk/include/linux/wlp.h index ac95ce6606ac..033545e145c7 100644 --- a/trunk/include/linux/wlp.h +++ b/trunk/include/linux/wlp.h @@ -646,7 +646,6 @@ struct wlp_wss { struct wlp { struct mutex mutex; struct uwb_rc *rc; /* UWB radio controller */ - struct net_device *ndev; struct uwb_pal pal; struct wlp_eda eda; struct wlp_uuid uuid; @@ -676,7 +675,7 @@ struct wlp_wss_attribute { static struct wlp_wss_attribute wss_attr_##_name = __ATTR(_name, _mode, \ _show, _store) -extern int wlp_setup(struct wlp *, struct uwb_rc *, struct net_device *ndev); +extern int wlp_setup(struct wlp *, struct uwb_rc *); extern void wlp_remove(struct wlp *); extern ssize_t wlp_neighborhood_show(struct wlp *, char *); extern int wlp_wss_setup(struct net_device *, struct wlp_wss *); diff --git a/trunk/init/main.c b/trunk/init/main.c index ad8f9f53f8d1..f5e64f20d2b0 100644 --- a/trunk/init/main.c +++ b/trunk/init/main.c @@ -75,6 +75,15 @@ #include #endif +/* + * This is one of the first .c files built. Error out early if we have compiler + * trouble. + */ + +#if __GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 0 +#warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended. +#endif + static int kernel_init(void *); extern void init_IRQ(void); diff --git a/trunk/net/irda/ircomm/ircomm_tty.c b/trunk/net/irda/ircomm/ircomm_tty.c index 086d5ef098fd..e4e2caeb9d82 100644 --- a/trunk/net/irda/ircomm/ircomm_tty.c +++ b/trunk/net/irda/ircomm/ircomm_tty.c @@ -371,8 +371,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) IRDA_DEBUG(2, "%s()\n", __func__ ); line = tty->index; - if (line >= IRCOMM_TTY_PORTS) + if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) { return -ENODEV; + } /* Check if instance already exists */ self = hashbin_lock_find(ircomm_tty, line, NULL); @@ -404,8 +405,6 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) * Force TTY into raw mode by default which is usually what * we want for IrCOMM and IrLPT. This way applications will * not have to twiddle with printcap etc. - * - * Note this is completely usafe and doesn't work properly */ tty->termios->c_iflag = 0; tty->termios->c_oflag = 0;