From ebc772b22b1a0cc00ce0cf99853fbf22833a072b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:22:17 -0500 Subject: [PATCH] Linux 2.2.18pre6 o Fix the IDE PCI not compiling bug (Dag Wieers) o Kill an escaped reference to vger.rutgers (Dave Miller) o Small rtl8139 fixups (Jeff Garzik) o Add USB bluetooth driver (Greg Kroah-Hartman) o Fix oops in visor driver (Greg Kroah-Hartman) o Remove some unneeded ext2 includes,fix a bug (Andreas Dilger) in the UFS code o Fix rtc race between timer and rtc irq (Andrea Arcangeli) o Fix slow gettimeofday SMP race (Andrea Arcangeli) o Check lost_ticks in settimeofday to be more (Andrea Arcangeli) precise --- Documentation/nmi_watchdog.txt | 2 +- Makefile | 2 +- arch/alpha/kernel/alpha_ksyms.c | 3 + arch/alpha/kernel/time.c | 4 + arch/i386/kernel/i386_ksyms.c | 3 + arch/i386/kernel/time.c | 22 +- drivers/ap1000/ap.c | 1 - drivers/ap1000/ddv.c | 1 - drivers/block/ide-pci.c | 4 +- drivers/char/rtc.c | 79 +- drivers/net/rtl8139.c | 19 +- drivers/usb/Config.in | 1 + drivers/usb/Makefile | 1 + drivers/usb/bluetooth.c | 1234 +++++++++++++++++++++++++++++++ drivers/usb/serial/visor.c | 11 +- fs/ufs/ialloc.c | 4 +- include/linux/ext2_fs_sb.h | 1 - kernel/ksyms.c | 2 - 18 files changed, 1328 insertions(+), 66 deletions(-) create mode 100644 drivers/usb/bluetooth.c diff --git a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt index 58303e947f39..f156029ca44b 100644 --- a/Documentation/nmi_watchdog.txt +++ b/Documentation/nmi_watchdog.txt @@ -30,5 +30,5 @@ http://people.redhat.com/mingo/NMI-watchdog-patches/ [ feel free to send bug reports, suggestions and patches to Ingo Molnar or the Linux SMP mailing - list at ] + list at ] diff --git a/Makefile b/Makefile index 7cfa63258605..7c76248187b9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 18 -EXTRAVERSION = pre5 +EXTRAVERSION = pre6 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 88ecc2aec688..04c9256db25c 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -37,6 +37,7 @@ extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); +extern spinlock_t rtc_lock; /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -188,6 +189,8 @@ EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); #endif /* __SMP__ */ +EXPORT_SYMBOL(rtc_lock); + /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index ebe39e330e69..0791ca7e7177 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -47,6 +47,7 @@ extern volatile unsigned long lost_ticks; /* kernel/sched.c */ static int set_rtc_mmss(unsigned long); +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; /* * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting @@ -455,6 +456,8 @@ set_rtc_mmss(unsigned long nowtime) int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* irq are locally disabled here */ + spin_lock(&rtc_lock); /* Tell the clock it's being set */ save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -504,6 +507,7 @@ set_rtc_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index d0ff4f3b3e10..23fa07d021d1 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -20,6 +20,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); +extern spinlock_t rtc_lock; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) extern struct drive_info_struct drive_info; @@ -119,3 +120,5 @@ EXPORT_SYMBOL(mca_is_adapter_used); #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + +EXPORT_SYMBOL(rtc_lock); diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index fd5d4e028b67..78dbaa8d36c3 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -77,6 +77,9 @@ static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ unsigned long fast_gettimeoffset_quotient=0; extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; + +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; static inline unsigned long do_fast_gettimeoffset(void) { @@ -112,6 +115,8 @@ static inline unsigned long do_fast_gettimeoffset(void) #ifndef CONFIG_X86_TSC +spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; + /* This function must be called with interrupts disabled * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs * @@ -156,6 +161,8 @@ static unsigned long do_slow_gettimeoffset(void) */ unsigned long jiffies_t; + /* gets recalled with irq locally disabled */ + spin_lock(&i8253_lock); /* timer count may underflow right here */ outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -214,6 +221,7 @@ static unsigned long do_slow_gettimeoffset(void) } } else jiffies_p = jiffies_t; + spin_unlock(&i8253_lock); count_p = count; @@ -237,7 +245,6 @@ static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; */ void do_gettimeofday(struct timeval *tv) { - extern volatile unsigned long lost_ticks; unsigned long flags; unsigned long usec, sec; @@ -271,6 +278,7 @@ void do_settimeofday(struct timeval *tv) * would have done, and then undo it! */ tv->tv_usec -= do_gettimeoffset(); + tv->tv_usec -= lost_ticks * (1000000 / HZ); while (tv->tv_usec < 0) { tv->tv_usec += 1000000; @@ -301,6 +309,8 @@ static int set_rtc_mmss(unsigned long nowtime) int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* gets recalled with irq locally disabled */ + spin_lock(&rtc_lock); save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -346,6 +356,7 @@ static int set_rtc_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } @@ -447,10 +458,19 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) rdtscl(last_tsc_low); +#if 0 /* + * SUBTLE: this is not necessary from here because it's implicit in the + * write xtime_lock. + */ + spin_lock(&i8253_lock); +#endif outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; +#if 0 + spin_unlock(&i8253_lock); +#endif count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; diff --git a/drivers/ap1000/ap.c b/drivers/ap1000/ap.c index ce50c5edb319..c79386e15985 100644 --- a/drivers/ap1000/ap.c +++ b/drivers/ap1000/ap.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c index 4a21a588212e..901a971acdca 100644 --- a/drivers/ap1000/ddv.c +++ b/drivers/ap1000/ddv.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index d9104b2dd0ed..ea09ecbffc4b 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -467,12 +467,12 @@ __initfunc(void ide_scan_pcibus (void)) /* * Don't try and tune a VIA 82C586 or 586A */ - if (IDE_PCI_DEVID_RQ(devid, DEVID_VP_IDE)) + if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_IDE)) { autodma_default = 0; break; } - if (IDE_PCI_DEVID_RQ(devid, DEVID_VP_OLDIDE)) + if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_OLDIDE)) { autodma_default = 0; break; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 6425f1dc940f..9b14e6af65b5 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -113,10 +113,15 @@ static unsigned long epoch = 1900; /* year corresponding to 0x00 */ unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +extern spinlock_t rtc_lock; + /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, - * so that there is no possibility of conflicting with the - * set_rtc_mmss() call that happens during some timer interrupts. + * but there is possibility of conflicting with the set_rtc_mmss() + * call (the rtc irq and the timer irq can easily run at the same + * time in two different CPUs). So we need to serializes + * accesses to the chip with the rtc_lock spinlock that each + * architecture should implement in the timer code. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) */ @@ -131,7 +136,10 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) rtc_irq_data += 0x100; rtc_irq_data &= ~0xff; + /* runs with irq locally disabled (see SA_INTERRUPT flag). */ + spin_lock(&rtc_lock); rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); + spin_unlock(&rtc_lock); wake_up_interruptible(&rtc_wait); if (rtc_status & RTC_TIMER_ON) @@ -276,8 +284,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (sec >= 60) sec = 0xff; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -288,7 +295,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -336,12 +343,11 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if ((yrs -= epoch) > 255) /* They are unsigned */ return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (yrs > 169) { - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return -EINVAL; } if (yrs >= 100) @@ -370,7 +376,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ @@ -405,12 +411,11 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, rtc_freq = arg; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; val |= (16 - tmp); CMOS_WRITE(val, RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } #ifdef __alpha__ @@ -465,15 +470,14 @@ static int rtc_release(struct inode *inode, struct file *file) unsigned char tmp; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); tmp = CMOS_READ(RTC_CONTROL); tmp &= ~RTC_PIE; tmp &= ~RTC_AIE; tmp &= ~RTC_UIE; CMOS_WRITE(tmp, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (rtc_status & RTC_TIMER_ON) { rtc_status &= ~RTC_TIMER_ON; @@ -546,11 +550,10 @@ __initfunc(int rtc_init(void)) while (jiffies - uip_watchdog < 2*HZ/100) barrier(); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ @@ -568,11 +571,10 @@ __initfunc(int rtc_init(void)) init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); rtc_freq = 1024; return 0; } @@ -596,12 +598,11 @@ void rtc_dropped_irq(unsigned long data) printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq); mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); rtc_irq_data += ((rtc_freq/HZ)<<8); rtc_irq_data &= ~0xff; rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); } /* @@ -615,11 +616,10 @@ int get_rtc_status(char *buf) unsigned char batt, ctrl; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); batt = CMOS_READ(RTC_VALID) & RTC_VRT; ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); p = buf; @@ -690,10 +690,9 @@ static inline unsigned char rtc_is_updating(void) unsigned long flags; unsigned char uip; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return uip; } @@ -723,8 +722,7 @@ void get_rtc_time(struct rtc_time *rtc_tm) * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated * by the RTC when initially set to a non-zero value. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); @@ -732,7 +730,7 @@ void get_rtc_time(struct rtc_time *rtc_tm) rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); rtc_tm->tm_year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -763,13 +761,12 @@ void get_rtc_alm_time(struct rtc_time *alm_tm) * Only the values that we read from the RTC are set. That * means only tm_hour, tm_min, and tm_sec. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -794,13 +791,12 @@ void mask_rtc_irq_bit(unsigned char bit) unsigned char val; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_CONTROL); val &= ~bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); rtc_irq_data = 0; } @@ -809,12 +805,11 @@ void set_rtc_irq_bit(unsigned char bit) unsigned char val; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_CONTROL); val |= bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); } diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 4f1e965853c4..03270e5725c8 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -1235,8 +1235,9 @@ static int rtl8129_rx(struct device *dev) /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ struct sk_buff *skb; + int pkt_size = rx_size - 4; - skb = dev_alloc_skb(rx_size + 2); + skb = dev_alloc_skb(pkt_size + 2); if (skb == NULL) { printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", dev->name); @@ -1247,12 +1248,12 @@ static int rtl8129_rx(struct device *dev) } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size+4 > RX_BUF_LEN) { + if (ring_offset+rx_size > RX_BUF_LEN) { int semi_count = RX_BUF_LEN - ring_offset - 4; memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], semi_count); - memcpy(skb_put(skb, rx_size-semi_count), rx_ring, - rx_size-semi_count); + memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, + pkt_size-semi_count); if (rtl8129_debug > 4) { int i; printk(KERN_DEBUG"%s: Frame wrap @%d", @@ -1265,17 +1266,17 @@ static int rtl8129_rx(struct device *dev) } else { #if 1 /* USE_IP_COPYSUM */ eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - rx_size - 4, 0); - skb_put(skb, rx_size - 4); + pkt_size, 0); + skb_put(skb, pkt_size); #else - memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4], - rx_size); + memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4], + pkt_size); #endif } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); #if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += rx_size; + tp->stats.rx_bytes += pkt_size; #endif tp->stats.rx_packets++; } diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 70dc742f0a5b..b46b6bea9189 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -69,6 +69,7 @@ comment 'USB Devices' dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_SCSI + dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB fi dep_tristate ' Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a729900d00e1..cf91f2acc0d7 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_MICROTEK) += microtek.o obj-$(CONFIG_USB_KAWETH) += kaweth.o +obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c new file mode 100644 index 000000000000..1b02b021dd24 --- /dev/null +++ b/drivers/usb/bluetooth.c @@ -0,0 +1,1234 @@ +/* + * bluetooth.c Version 0.5 + * + * Copyright (c) 2000 Greg Kroah-Hartman + * Copyright (c) 2000 Mark Douglas Corner + * + * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B + * + * (08/06/2000) Version 0.5 gkh + * Fixed problem of not resubmitting the bulk read urb if there is + * an error in the callback. Ericsson devices seem to need this. + * + * (07/11/2000) Version 0.4 gkh + * Fixed bug in disconnect for when we call tty_hangup + * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not + * getting attached to the control urb properly. + * Fixed bug in bluetooth_write where we pay attention to the result + * of bluetooth_ctrl_msg. + * + * (08/03/2000) Version 0.3 gkh mdc + * Merged in Mark's changes to make the driver play nice with the Axis + * stack. + * Made the write bulk use an urb pool to enable larger transfers with + * fewer calls to the driver. + * Fixed off by one bug in acl pkt receive + * Made packet counters specific to each bluetooth device + * Added checks for zero length callbacks + * Added buffers for int and bulk packets. Had to do this otherwise + * packet types could intermingle. + * Made a control urb pool for the control messages. + * + * (07/11/2000) Version 0.2 gkh + * Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe + * function. + * + * (07/09/2000) Version 0.1 gkh + * Initial release. Has support for sending ACL data (which is really just + * a HCI frame.) Raw HCI commands and HCI events are not supported. + * A ioctl will probably be needed for the HCI commands and events in the + * future. All isoch endpoints are ignored at this time also. + * This driver should work for all currently shipping USB Bluetooth + * devices at this time :) + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG +#include + +/* Module information */ +MODULE_AUTHOR("Greg Kroah-Hartman, Mark Douglas Corner"); +MODULE_DESCRIPTION("USB Bluetooth driver"); + +/* define this if you have hardware that is not good */ +/*#define BTBUGGYHARDWARE */ + +/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ +#define WIRELESS_CLASS_CODE 0xe0 +#define RF_SUBCLASS_CODE 0x01 +#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE 0x01 + + +#define BLUETOOTH_TTY_MAJOR 240 /* Prototype number for now */ +#define BLUETOOTH_TTY_MINORS 8 + +#define USB_BLUETOOTH_MAGIC 0x6d02 /* magic number for bluetooth struct */ + +#define BLUETOOTH_CONTROL_REQUEST_TYPE 0x20 + +/* Bluetooth packet types */ +#define CMD_PKT 0x01 +#define ACL_PKT 0x02 +#define SCO_PKT 0x03 +#define EVENT_PKT 0x04 +#define ERROR_PKT 0x05 +#define NEG_PKT 0x06 + +/* Message sizes */ +#define MAX_EVENT_SIZE 0xFF +#define EVENT_HDR_SIZE 3 /* 2 for the header + 1 for the type indicator */ +#define EVENT_BUFFER_SIZE (MAX_EVENT_SIZE + EVENT_HDR_SIZE) + +#define MAX_ACL_SIZE 0xFFFF +#define ACL_HDR_SIZE 5 /* 4 for the header + 1 for the type indicator */ +#define ACL_BUFFER_SIZE (MAX_ACL_SIZE + ACL_HDR_SIZE) + +/* parity check flag */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +#define CHAR2INT16(c1,c0) (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff)) +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#define NUM_BULK_URBS 24 +#define NUM_CONTROL_URBS 16 + +struct usb_bluetooth { + int magic; + struct usb_device * dev; + struct tty_driver * tty_driver; /* the tty_driver for this device */ + struct tty_struct * tty; /* the coresponding tty for this port */ + + unsigned char minor; /* the starting minor number for this device */ + char active; /* someone has this device open */ + int throttle; /* throttled by tty layer */ + + __u8 control_out_bInterfaceNum; + struct urb * control_urb_pool[NUM_CONTROL_URBS]; + devrequest dr[NUM_CONTROL_URBS]; + + unsigned char * interrupt_in_buffer; + struct urb * interrupt_in_urb; + + unsigned char * bulk_in_buffer; + struct urb * read_urb; + + int bulk_out_size; + struct urb * write_urb_pool[NUM_BULK_URBS]; + __u8 bulk_out_endpointAddress; + + wait_queue_head_t write_wait; + + struct tq_struct tqueue; /* task queue for line discipline waking up */ + + unsigned int int_packet_pos; + unsigned char int_buffer[EVENT_BUFFER_SIZE]; + unsigned int bulk_packet_pos; + unsigned char bulk_buffer[ACL_BUFFER_SIZE]; /* 64k preallocated, fix? */ +}; + + +/* local function prototypes */ +static int bluetooth_open (struct tty_struct *tty, struct file *filp); +static void bluetooth_close (struct tty_struct *tty, struct file *filp); +static int bluetooth_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static int bluetooth_write_room (struct tty_struct *tty); +static int bluetooth_chars_in_buffer (struct tty_struct *tty); +static void bluetooth_throttle (struct tty_struct *tty); +static void bluetooth_unthrottle (struct tty_struct *tty); +static int bluetooth_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +static void bluetooth_set_termios (struct tty_struct *tty, struct termios *old); + +static void bluetooth_int_callback (struct urb *urb); +static void bluetooth_ctrl_callback (struct urb *urb); +static void bluetooth_read_bulk_callback (struct urb *urb); +static void bluetooth_write_bulk_callback (struct urb *urb); + +static void * usb_bluetooth_probe (struct usb_device *dev, unsigned int ifnum); +static void usb_bluetooth_disconnect (struct usb_device *dev, void *ptr); + + +static struct usb_driver usb_bluetooth_driver = { + name: "bluetooth", + probe: usb_bluetooth_probe, + disconnect: usb_bluetooth_disconnect, +}; + +static int bluetooth_refcount; +static struct tty_driver bluetooth_tty_driver; +static struct tty_struct * bluetooth_tty[BLUETOOTH_TTY_MINORS]; +static struct termios * bluetooth_termios[BLUETOOTH_TTY_MINORS]; +static struct termios * bluetooth_termios_locked[BLUETOOTH_TTY_MINORS]; +static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, }; + + + +static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function) +{ + if (!bluetooth) { + dbg("%s - bluetooth == NULL", function); + return -1; + } + if (bluetooth->magic != USB_BLUETOOTH_MAGIC) { + dbg("%s - bad magic number for bluetooth", function); + return -1; + } + + return 0; +} + + +static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function) +{ + if (!bluetooth || + bluetooth_paranoia_check (bluetooth, function)) { + /* then say that we dont have a valid usb_bluetooth thing, which will + * end up generating -ENODEV return values */ + return NULL; + } + + return bluetooth; +} + + +static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor) +{ + return bluetooth_table[minor]; +} + + +static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, void *buf, int len) +{ + struct urb *urb = NULL; + devrequest *dr = NULL; + int i; + int status; + + dbg (__FUNCTION__); + + /* try to find a free urb in our list */ + for (i = 0; i < NUM_CONTROL_URBS; ++i) { + if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) { + urb = bluetooth->control_urb_pool[i]; + dr = &bluetooth->dr[i]; + break; + } + } + if (urb == NULL) { + dbg (__FUNCTION__ " - no free urbs"); + return -ENOMEM; + } + + /* free up the last buffer that this urb used */ + if (urb->transfer_buffer != NULL) { + kfree(urb->transfer_buffer); + urb->transfer_buffer = NULL; + } + + dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE; + dr->request = request; + dr->value = cpu_to_le16p(&value); + dr->index = cpu_to_le16p(&bluetooth->control_out_bInterfaceNum); + dr->length = cpu_to_le16p(&len); + + FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0), + (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth); + + /* send it down the pipe */ + status = usb_submit_urb(urb); + if (status) + dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status); + + return 0; +} + + + + + +/***************************************************************************** + * Driver tty interface functions + *****************************************************************************/ +static int bluetooth_open (struct tty_struct *tty, struct file * filp) +{ + struct usb_bluetooth *bluetooth; + int result; + + dbg(__FUNCTION__); + + /* initialize the pointer incase something fails */ + tty->driver_data = NULL; + + /* get the bluetooth object associated with this tty pointer */ + bluetooth = get_bluetooth_by_minor (MINOR(tty->device)); + + if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) { + return -ENODEV; + } + + if (bluetooth->active) { + dbg (__FUNCTION__ " - device already open"); + return -EINVAL; + } + + /* set up our structure making the tty driver remember our object, and us it */ + tty->driver_data = bluetooth; + bluetooth->tty = tty; + + bluetooth->active = 1; + + /* Reset the packet position counters */ + bluetooth->int_packet_pos = 0; + bluetooth->bulk_packet_pos = 0; + +#ifndef BTBUGGYHARDWARE + /* Start reading from the device */ + result = usb_submit_urb(bluetooth->read_urb); + if (result) + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result); +#endif + result = usb_submit_urb(bluetooth->interrupt_in_urb); + if (result) + dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result); + + return 0; +} + + +static void bluetooth_close (struct tty_struct *tty, struct file * filp) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + int i; + + if (!bluetooth) { + return; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not opened"); + return; + } + + /* shutdown any bulk reads and writes that might be going on */ + for (i = 0; i < NUM_BULK_URBS; ++i) + usb_unlink_urb (bluetooth->write_urb_pool[i]); + usb_unlink_urb (bluetooth->read_urb); + + bluetooth->active = 0; +} + + +static int bluetooth_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + struct urb *urb = NULL; + unsigned char *new_buffer; + const unsigned char *current_position; + int status; + int bytes_sent; + int buffer_size; + int i; + + if (!bluetooth) { + return -ENODEV; + } + + dbg(__FUNCTION__ " - %d byte(s)", count); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not opened"); + return -EINVAL; + } + + if (count == 0) { + dbg(__FUNCTION__ " - write request of 0 bytes"); + return 0; + } + if (count == 1) { + dbg(__FUNCTION__ " - write request only included type %d", buf[0]); + return 1; + } + +#ifdef DEBUG + printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); + for (i = 0; i < count; ++i) { + printk ("%.2x ", buf[i]); + } + printk ("\n"); +#endif + + switch (*buf) { + /* First byte indicates the type of packet */ + case CMD_PKT: + /* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/ + + if (in_interrupt()){ + printk("cmd_pkt from interrupt!\n"); + return count; + } + + new_buffer = kmalloc (count-1, GFP_KERNEL); + + if (!new_buffer) { + err (__FUNCTION__ "- out of memory."); + return -ENOMEM; + } + + if (from_user) + copy_from_user (new_buffer, buf+1, count-1); + else + memcpy (new_buffer, buf+1, count-1); + + if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) { + kfree (new_buffer); + return 0; + } + + /* need to free new_buffer somehow... FIXME */ + return count; + + case ACL_PKT: + current_position = buf; + ++current_position; + --count; + bytes_sent = 0; + + while (count > 0) { + urb = NULL; + + /* try to find a free urb in our list */ + for (i = 0; i < NUM_BULK_URBS; ++i) { + if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) { + urb = bluetooth->write_urb_pool[i]; + break; + } + } + if (urb == NULL) { + dbg (__FUNCTION__ " - no free urbs"); + return bytes_sent; + } + + /* free up the last buffer that this urb used */ + if (urb->transfer_buffer != NULL) { + kfree(urb->transfer_buffer); + urb->transfer_buffer = NULL; + } + + buffer_size = MIN (count, bluetooth->bulk_out_size); + + new_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (new_buffer == NULL) { + err(__FUNCTION__" no more kernel memory..."); + return bytes_sent; + } + + if (from_user) + copy_from_user(new_buffer, current_position, buffer_size); + else + memcpy (new_buffer, current_position, buffer_size); + + /* build up our urb */ + FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress), + new_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth); + urb->transfer_flags |= USB_QUEUE_BULK; + + /* send it down the pipe */ + status = usb_submit_urb(urb); + if (status) + dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); +#ifdef BTBUGGYHARDWARE + /* A workaround for the stalled data bug */ + /* May or may not be needed...*/ + if (count != 0) { + udelay(500); + } +#endif + current_position += buffer_size; + bytes_sent += buffer_size; + count -= buffer_size; + } + + return bytes_sent + 1; + + default : + dbg(__FUNCTION__" - unsupported (at this time) write type"); + } + + return 0; +} + + +static int bluetooth_write_room (struct tty_struct *tty) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + int room = 0; + int i; + + if (!bluetooth) { + return -ENODEV; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return -EINVAL; + } + + for (i = 0; i < NUM_BULK_URBS; ++i) { + if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) { + room += bluetooth->bulk_out_size; + } + } + + dbg(__FUNCTION__ " - returns %d", room); + return room; +} + + +static int bluetooth_chars_in_buffer (struct tty_struct *tty) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + int chars = 0; + int i; + + if (!bluetooth) { + return -ENODEV; + } + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return -EINVAL; + } + + for (i = 0; i < NUM_BULK_URBS; ++i) { + if (bluetooth->write_urb_pool[i]->status == -EINPROGRESS) { + chars += bluetooth->write_urb_pool[i]->transfer_buffer_length; + } + } + + dbg (__FUNCTION__ " - returns %d", chars); + return chars; +} + + +static void bluetooth_throttle (struct tty_struct * tty) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + + if (!bluetooth) { + return; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return; + } + + dbg(__FUNCTION__ " unsupported (at this time)"); + + return; +} + + +static void bluetooth_unthrottle (struct tty_struct * tty) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + + if (!bluetooth) { + return; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return; + } + + dbg(__FUNCTION__ " unsupported (at this time)"); +} + + +static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + + if (!bluetooth) { + return -ENODEV; + } + + dbg(__FUNCTION__ " - cmd 0x%.4x", cmd); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return -ENODEV; + } + + /* FIXME!!! */ + return -ENOIOCTLCMD; +} + + +static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + + if (!bluetooth) { + return; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return; + } + + /* FIXME!!! */ + + return; +} + + +#ifdef BTBUGGYHARDWARE +void btusb_enable_bulk_read(struct tty_struct *tty){ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + + if (!bluetooth) { + return; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return; + } + + if (bluetooth->read_urb) + if (usb_submit_urb(bluetooth->read_urb)) + dbg (__FUNCTION__ " - usb_submit_urb(read bulk) failed"); +} + +void btusb_disable_bulk_read(struct tty_struct *tty){ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); + + if (!bluetooth) { + return; + } + + dbg(__FUNCTION__); + + if (!bluetooth->active) { + dbg (__FUNCTION__ " - device not open"); + return; + } + + if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length)) + usb_unlink_urb(bluetooth->read_urb); +} +#endif + + +/***************************************************************************** + * urb callback functions + *****************************************************************************/ + + +static void bluetooth_int_callback (struct urb *urb) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); + unsigned char *data = urb->transfer_buffer; + unsigned int i; + unsigned int count = urb->actual_length; + unsigned int packet_size; + + dbg(__FUNCTION__); + + if (!bluetooth) { + dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + return; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status); + return; + } + + if (!count) { + dbg(__FUNCTION__ " - zero length int"); + return; + } + + +#ifdef DEBUG + if (count) { + printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count); + for (i = 0; i < count; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); + } +#endif + +#ifdef BTBUGGYHARDWARE + if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) { + data += 2; + count -= 2; + } + if (count == 0) { + urb->actual_length = 0; + return; + } +#endif + /* We add a packet type identifier to the beginning of each + HCI frame. This makes the data in the tty look like a + serial USB devices. Each HCI frame can be broken across + multiple URBs so we buffer them until we have a full hci + packet */ + + if (!bluetooth->int_packet_pos) { + bluetooth->int_buffer[0] = EVENT_PKT; + bluetooth->int_packet_pos++; + } + + if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) { + err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE"); + bluetooth->int_packet_pos = 0; + return; + } + + memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos], + urb->transfer_buffer, count); + bluetooth->int_packet_pos += count; + urb->actual_length = 0; + + if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE) + packet_size = bluetooth->int_buffer[2]; + else + return; + + if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) { + err(__FUNCTION__ " - packet was too long"); + bluetooth->int_packet_pos = 0; + return; + } + + if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){ + for (i = 0; i < bluetooth->int_packet_pos; ++i) + tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0); + tty_flip_buffer_push(bluetooth->tty); + + bluetooth->int_packet_pos = 0; + } +} + + +static void bluetooth_ctrl_callback (struct urb *urb) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); + + dbg(__FUNCTION__); + + if (!bluetooth) { + dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + return; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + return; + } +} + + +static void bluetooth_read_bulk_callback (struct urb *urb) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); + unsigned char *data = urb->transfer_buffer; + unsigned int count = urb->actual_length; + unsigned int i; + uint packet_size; + +#ifdef BTBUGGYHARDWARE + if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00) + && (data[2] == 0x00) && (data[3] == 0x00)) { + urb->actual_length = 0; + if (usb_submit_urb(urb)) + dbg(__FUNCTION__ " - failed resubmitting read urb"); + + return; + } +#endif + + dbg(__FUNCTION__); + + if (!bluetooth) { + dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + goto exit; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + goto exit; + } + + if (!count) { + dbg(__FUNCTION__ " - zero length read bulk"); + goto exit; + } + +#ifdef DEBUG + if (count) { + printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count); + for (i = 0; i < count; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); + } +#endif + /* We add a packet type identifier to the beginning of each + HCI frame. This makes the data in the tty look like a + serial USB devices. Each HCI frame can be broken across + multiple URBs so we buffer them until we have a full hci + packet */ + + if (!bluetooth->bulk_packet_pos) { + bluetooth->bulk_buffer[0] = ACL_PKT; + bluetooth->bulk_packet_pos++; + } + + if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) { + err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE"); + bluetooth->bulk_packet_pos = 0; + goto exit; + } + + memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos], + urb->transfer_buffer, count); + bluetooth->bulk_packet_pos += count; + urb->actual_length = 0; + + if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) { + packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]); + } else { + goto exit; + } + + if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) { + err(__FUNCTION__ " - packet was too long"); + bluetooth->bulk_packet_pos = 0; + goto exit; + } + + if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) { + for (i = 0; i < bluetooth->bulk_packet_pos; ++i) + tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0); + tty_flip_buffer_push(bluetooth->tty); + bluetooth->bulk_packet_pos = 0; + } + +exit: + if (usb_submit_urb(urb)) + dbg(__FUNCTION__ " - failed resubmitting read urb"); + + return; +} + + +static void bluetooth_write_bulk_callback (struct urb *urb) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); + + dbg(__FUNCTION__); + + if (!bluetooth) { + dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); + return; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + return; + } + + /* wake up our little function to let the tty layer know that something happened */ + queue_task(&bluetooth->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; +} + + +static void bluetooth_softint(void *private) +{ + struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__); + struct tty_struct *tty; + + dbg(__FUNCTION__); + + if (!bluetooth) { + return; + } + + tty = bluetooth->tty; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { + dbg(__FUNCTION__ " - write wakeup call."); + (tty->ldisc.write_wakeup)(tty); + } + + wake_up_interruptible(&tty->write_wait); +} + + +static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_bluetooth *bluetooth = NULL; + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_endpoint_descriptor *interrupt_in_endpoint[8]; + struct usb_endpoint_descriptor *bulk_in_endpoint[8]; + struct usb_endpoint_descriptor *bulk_out_endpoint[8]; + int control_out_endpoint; + + int minor; + int buffer_size; + int i; + int num_interrupt_in = 0; + int num_bulk_in = 0; + int num_bulk_out = 0; + + /* see if this device has the proper class signature */ + if ((dev->descriptor.bDeviceClass != WIRELESS_CLASS_CODE) || + (dev->descriptor.bDeviceSubClass != RF_SUBCLASS_CODE) || + (dev->descriptor.bDeviceProtocol != BLUETOOTH_PROGRAMMING_PROTOCOL_CODE)) { + dbg (__FUNCTION__ " - class signature %d, %d, %d did not match", + dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass, + dev->descriptor.bDeviceProtocol); + return NULL; + } + + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + control_out_endpoint = interface->bInterfaceNumber; + + /* find the endpoints that we need */ + for (i = 0; i < interface->bNumEndpoints; ++i) { + endpoint = &interface->endpoint[i]; + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + dbg("found bulk in"); + bulk_in_endpoint[num_bulk_in] = endpoint; + ++num_bulk_in; + } + + if (((endpoint->bEndpointAddress & 0x80) == 0x00) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk out endpoint */ + dbg("found bulk out"); + bulk_out_endpoint[num_bulk_out] = endpoint; + ++num_bulk_out; + } + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x03)) { + /* we found a interrupt in endpoint */ + dbg("found interrupt in"); + interrupt_in_endpoint[num_interrupt_in] = endpoint; + ++num_interrupt_in; + } + } + + /* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */ + if ((num_bulk_in != 1) || + (num_bulk_out != 1) || + (num_interrupt_in != 1)) { + dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound."); + return NULL; + } + + MOD_INC_USE_COUNT; + info("USB Bluetooth converter detected"); + + for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor) + ; + if (bluetooth_table[minor]) { + err("No more free Bluetooth devices"); + MOD_DEC_USE_COUNT; + return NULL; + } + + if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) { + err("Out of memory"); + MOD_DEC_USE_COUNT; + return NULL; + } + + memset(bluetooth, 0, sizeof(struct usb_bluetooth)); + + bluetooth->magic = USB_BLUETOOTH_MAGIC; + bluetooth->dev = dev; + bluetooth->minor = minor; + bluetooth->tqueue.routine = bluetooth_softint; + bluetooth->tqueue.data = bluetooth; + + /* record the interface number for the control out */ + bluetooth->control_out_bInterfaceNum = control_out_endpoint; + + /* create our control out urb pool */ + for (i = 0; i < NUM_CONTROL_URBS; ++i) { + struct urb *urb = usb_alloc_urb(0); + if (urb == NULL) { + err("No free urbs available"); + goto probe_error; + } + urb->transfer_buffer = NULL; + bluetooth->control_urb_pool[i] = urb; + } + + /* set up the endpoint information */ + endpoint = bulk_in_endpoint[0]; + bluetooth->read_urb = usb_alloc_urb (0); + if (!bluetooth->read_urb) { + err("No free urbs available"); + goto probe_error; + } + buffer_size = endpoint->wMaxPacketSize; + bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!bluetooth->bulk_in_buffer) { + err("Couldn't allocate bulk_in_buffer"); + goto probe_error; + } + FILL_BULK_URB(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), + bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth); + + endpoint = bulk_out_endpoint[0]; + bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress; + + /* create our write urb pool */ + for (i = 0; i < NUM_BULK_URBS; ++i) { + struct urb *urb = usb_alloc_urb(0); + if (urb == NULL) { + err("No free urbs available"); + goto probe_error; + } + urb->transfer_buffer = NULL; + bluetooth->write_urb_pool[i] = urb; + } + + bluetooth->bulk_out_size = endpoint->wMaxPacketSize * 2; + + endpoint = interrupt_in_endpoint[0]; + bluetooth->interrupt_in_urb = usb_alloc_urb(0); + if (!bluetooth->interrupt_in_urb) { + err("No free urbs available"); + goto probe_error; + } + buffer_size = endpoint->wMaxPacketSize; + bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!bluetooth->interrupt_in_buffer) { + err("Couldn't allocate interrupt_in_buffer"); + goto probe_error; + } + FILL_INT_URB(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), + bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback, + bluetooth, endpoint->bInterval); + + /* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */ + tty_register_devfs (&bluetooth_tty_driver, 0, minor); + info("Bluetooth converter now attached to ttyBLUE%d (or usb/ttblue/%d for devfs)", minor, minor); + + bluetooth_table[minor] = bluetooth; + + return bluetooth; /* success */ + +probe_error: + if (bluetooth->read_urb) + usb_free_urb (bluetooth->read_urb); + if (bluetooth->bulk_in_buffer) + kfree (bluetooth->bulk_in_buffer); + if (bluetooth->interrupt_in_urb) + usb_free_urb (bluetooth->interrupt_in_urb); + if (bluetooth->interrupt_in_buffer) + kfree (bluetooth->interrupt_in_buffer); + for (i = 0; i < NUM_BULK_URBS; ++i) + if (bluetooth->write_urb_pool[i]) + usb_free_urb (bluetooth->write_urb_pool[i]); + for (i = 0; i < NUM_CONTROL_URBS; ++i) + if (bluetooth->control_urb_pool[i]) + usb_free_urb (bluetooth->control_urb_pool[i]); + + bluetooth_table[minor] = NULL; + + /* free up any memory that we allocated */ + kfree (bluetooth); + MOD_DEC_USE_COUNT; + return NULL; +} + + +static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_bluetooth *bluetooth = (struct usb_bluetooth *) ptr; + int i; + + if (bluetooth) { + if ((bluetooth->active) && (bluetooth->tty)) + tty_hangup(bluetooth->tty); + + bluetooth->active = 0; + + if (bluetooth->read_urb) { + usb_unlink_urb (bluetooth->read_urb); + usb_free_urb (bluetooth->read_urb); + } + if (bluetooth->bulk_in_buffer) + kfree (bluetooth->bulk_in_buffer); + + if (bluetooth->interrupt_in_urb) { + usb_unlink_urb (bluetooth->interrupt_in_urb); + usb_free_urb (bluetooth->interrupt_in_urb); + } + if (bluetooth->interrupt_in_buffer) + kfree (bluetooth->interrupt_in_buffer); + + tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor); + + for (i = 0; i < NUM_BULK_URBS; ++i) { + if (bluetooth->write_urb_pool[i]) { + usb_unlink_urb (bluetooth->write_urb_pool[i]); + if (bluetooth->write_urb_pool[i]->transfer_buffer) + kfree (bluetooth->write_urb_pool[i]->transfer_buffer); + usb_free_urb (bluetooth->write_urb_pool[i]); + } + } + for (i = 0; i < NUM_CONTROL_URBS; ++i) { + if (bluetooth->control_urb_pool[i]) { + usb_unlink_urb (bluetooth->control_urb_pool[i]); + if (bluetooth->control_urb_pool[i]->transfer_buffer) + kfree (bluetooth->control_urb_pool[i]->transfer_buffer); + usb_free_urb (bluetooth->control_urb_pool[i]); + } + } + + info("Bluetooth converter now disconnected from ttyBLUE%d", bluetooth->minor); + + bluetooth_table[bluetooth->minor] = NULL; + + /* free up any memory that we allocated */ + kfree (bluetooth); + + } else { + info("device disconnected"); + } + + MOD_DEC_USE_COUNT; +} + + +static struct tty_driver bluetooth_tty_driver = { + magic: TTY_DRIVER_MAGIC, + driver_name: "usb-bluetooth", + name: "usb/ttblue/%d", + major: BLUETOOTH_TTY_MAJOR, + minor_start: 0, + num: BLUETOOTH_TTY_MINORS, + type: TTY_DRIVER_TYPE_SERIAL, + subtype: SERIAL_TYPE_NORMAL, + flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, + + refcount: &bluetooth_refcount, + table: bluetooth_tty, + termios: bluetooth_termios, + termios_locked: bluetooth_termios_locked, + + open: bluetooth_open, + close: bluetooth_close, + write: bluetooth_write, + write_room: bluetooth_write_room, + ioctl: bluetooth_ioctl, + set_termios: bluetooth_set_termios, + throttle: bluetooth_throttle, + unthrottle: bluetooth_unthrottle, + chars_in_buffer: bluetooth_chars_in_buffer, +}; + + +int usb_bluetooth_init(void) +{ + int i; + int result; + + /* Initalize our global data */ + for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) { + bluetooth_table[i] = NULL; + } + + info ("USB Bluetooth support registered"); + + /* register the tty driver */ + bluetooth_tty_driver.init_termios = tty_std_termios; + bluetooth_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + if (tty_register_driver (&bluetooth_tty_driver)) { + err(__FUNCTION__ " - failed to register tty driver"); + return -1; + } + + /* register the USB driver */ + result = usb_register(&usb_bluetooth_driver); + if (result < 0) { + tty_unregister_driver(&bluetooth_tty_driver); + err("usb_register failed for the USB bluetooth driver. Error number %d", result); + return -1; + } + + return 0; +} + + +void usb_bluetooth_exit(void) +{ + usb_deregister(&usb_bluetooth_driver); + tty_unregister_driver(&bluetooth_tty_driver); +} + + +module_init(usb_bluetooth_init); +module_exit(usb_bluetooth_exit); + + diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index bc0ea807a40b..49c152c4365a 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -10,7 +10,11 @@ * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver - * + * + * (09/06/2000) gkh + * Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ + * the host controller drivers set urb->dev = NULL when the urb is finished. + * * (08/08/2000) gkh * Fixed endian problem in visor_startup. * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more @@ -457,7 +461,10 @@ void visor_exit (void) usb_serial_deregister (&handspring_device); for (i = 0; i < NUM_URBS; ++i) { - usb_unlink_urb(write_urb_pool[i]); + /* FIXME - uncomment the following usb_unlink_urb call when + * the host controllers get fixed to set urb->dev = NULL after + * the urb is finished. Otherwise this call oopses. */ + /* usb_unlink_urb(write_urb_pool[i]); */ if (write_urb_pool[i]->transfer_buffer) kfree(write_urb_pool[i]->transfer_buffer); usb_free_urb (write_urb_pool[i]); diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index fa4dfa06afdd..5d974fa7a750 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -275,9 +275,7 @@ cg_found: inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; - if (test_opt (sb, GRPID)) - inode->i_gid = dir->i_gid; - else if (dir->i_mode & S_ISGID) { + if (dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h index 207216323d18..9dd7f86892ec 100644 --- a/include/linux/ext2_fs_sb.h +++ b/include/linux/ext2_fs_sb.h @@ -16,7 +16,6 @@ #ifndef _LINUX_EXT2_FS_SB #define _LINUX_EXT2_FS_SB -#include /* * The following is not needed anymore since the descriptors buffer diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 89e3bc6a5093..f66a22980ddb 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include #include -- 2.39.5