From 15cf53c0f7c56b7e5b7cbc82d8c9bba46f6bb2d6 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Tue, 4 Mar 2003 10:23:29 -0800 Subject: [Bluetooth] Use very short disconnect timeout for SCO connections. They cannot be reused and therefor there is no need to keep them around. --- include/net/bluetooth/hci_core.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 044df634d3bd..dc2b71fbe092 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -262,7 +262,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); int hci_conn_auth(struct hci_conn *conn); int hci_conn_encrypt(struct hci_conn *conn); -static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout) +static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout) { mod_timer(&conn->timer, jiffies + timeout); } @@ -280,8 +280,11 @@ static inline void hci_conn_hold(struct hci_conn *conn) static inline void hci_conn_put(struct hci_conn *conn) { - if (atomic_dec_and_test(&conn->refcnt) && conn->out) - hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); + if (atomic_dec_and_test(&conn->refcnt) && conn->out) { + unsigned long timeo = (conn->type == ACL_LINK) ? + HCI_DISCONN_TIMEOUT : HZ / 100; + hci_conn_set_timer(conn, timeo); + } } /* ----- HCI tasks ----- */ -- cgit v1.2.3 From 54a6836473e8e895693044a2703a621c43c3eb60 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Wed, 19 Mar 2003 01:38:14 -0800 Subject: [Bluetooth] Kill incoming SCO connection when SCO socket is closed --- include/net/bluetooth/hci_core.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index dc2b71fbe092..5bf98447775c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -280,10 +280,11 @@ static inline void hci_conn_hold(struct hci_conn *conn) static inline void hci_conn_put(struct hci_conn *conn) { - if (atomic_dec_and_test(&conn->refcnt) && conn->out) { - unsigned long timeo = (conn->type == ACL_LINK) ? - HCI_DISCONN_TIMEOUT : HZ / 100; - hci_conn_set_timer(conn, timeo); + if (atomic_dec_and_test(&conn->refcnt)) { + if (conn->type == SCO_LINK) + hci_conn_set_timer(conn, HZ / 100); + else if (conn->out) + hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); } } -- cgit v1.2.3 From a8fe9cc76282897b513ff87435dc886973e27b92 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 21 Mar 2003 01:34:38 +0100 Subject: [Bluetooth] Add support for the Ultraport Module from IBM This patch adds the specific vendor and product id's for the Bluetooth Ultraport Module from IBM. This is needed, because the device itself don't uses the USB Bluetooth class id. --- drivers/bluetooth/hci_usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 4f8cec4fedee..5925011faa47 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -80,6 +80,9 @@ static struct usb_device_id bluetooth_ids[] = { /* Ericsson with non-standard id */ { USB_DEVICE(0x0bdb, 0x1002) }, + /* Bluetooth Ultraport Module from IBM */ + { USB_DEVICE(0x04bf, 0x030a) }, + { } /* Terminating entry */ }; -- cgit v1.2.3 From d3d1da7005ff1deaeddd2a11e7f85d13676e9316 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 21 Mar 2003 23:38:30 +0100 Subject: [Bluetooth] Use R1 for default value of pscan_rep_mode Most devices seem to use R1 for pscan_rep_mode to save power consumption, so R1 is preferable for default value, if there is no entry in the inquiry cache. Using R1 will improve the average of connect time in many cases. --- net/bluetooth/hci_conn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 416b164db547..dca73e34a16f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *conn) memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); + cp.pscan_rep_mode = 0x01; if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { -- cgit v1.2.3 From 2dbbab6f2dc6b63fe6e8fe2ad6fac0352a2af166 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 23 Mar 2003 21:03:28 -0800 Subject: [Bluetooth] HCI USB driver update. Support for SCO over HCI USB. URB and buffer managment rewrite. --- drivers/bluetooth/Kconfig | 9 +- drivers/bluetooth/hci_usb.c | 821 ++++++++++++++++++++++++++------------------ drivers/bluetooth/hci_usb.h | 99 ++++-- 3 files changed, 572 insertions(+), 357 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index c047c90251ea..30d099c33aee 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -13,11 +13,18 @@ config BT_HCIUSB Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (hci_usb). +config BT_USB_SCO + bool "SCO over HCI USB support" + depends on BT_HCIUSB + help + This option enables the SCO support in the HCI USB driver. You need this + to transmit voice data with your Bluetooth USB device. + Say Y here to compile support for SCO over HCI USB. + config BT_USB_ZERO_PACKET bool "USB zero packet support" depends on BT_HCIUSB help - Support for USB zero packets. This option is provided only as a work around for buggy Bluetooth USB devices. Do _not_ enable it unless you know for sure that your device requires zero packets. diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 4f8cec4fedee..296f2e2ca4c2 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -1,9 +1,10 @@ /* - BlueZ - Bluetooth protocol stack for Linux + HCI USB driver for Linux Bluetooth protocol stack (BlueZ) Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky + Copyright (C) 2003 Maxim Krasnyansky + 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; @@ -23,20 +24,17 @@ */ /* - * Bluetooth HCI USB driver. * Based on original USB Bluetooth driver for Linux kernel * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $ */ -#define VERSION "2.1" +#define VERSION "2.4" #include #include -#define __KERNEL_SYSCALLS__ - #include #include #include @@ -49,17 +47,15 @@ #include #include #include -#include #include #include #include -#include "hci_usb.h" -#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1) +#include "hci_usb.h" -#ifndef CONFIG_BT_HCIUSB_DEBUG +#ifndef HCI_USB_DEBUG #undef BT_DBG #define BT_DBG( A... ) #undef BT_DMP @@ -67,8 +63,8 @@ #endif #ifndef CONFIG_BT_USB_ZERO_PACKET -#undef URB_ZERO_PACKET -#define URB_ZERO_PACKET 0 +#undef USB_ZERO_PACKET +#define USB_ZERO_PACKET 0 #endif static struct usb_driver hci_usb_driver; @@ -80,6 +76,9 @@ static struct usb_device_id bluetooth_ids[] = { /* Ericsson with non-standard id */ { USB_DEVICE(0x0bdb, 0x1002) }, + /* Bluetooth Ultraport Module from IBM */ + { USB_DEVICE(0x04bf, 0x030a) }, + { } /* Terminating entry */ }; @@ -92,108 +91,196 @@ static struct usb_device_id ignore_ids[] = { { } /* Terminating entry */ }; -static void hci_usb_interrupt(struct urb *urb, struct pt_regs *regs); +struct _urb *_urb_alloc(int isoc, int gfp) +{ + struct _urb *_urb = kmalloc(sizeof(struct _urb) + + sizeof(struct usb_iso_packet_descriptor) * isoc, gfp); + if (_urb) { + memset(_urb, 0, sizeof(*_urb)); + _urb->urb.count = (atomic_t)ATOMIC_INIT(1); + spin_lock_init(&_urb->urb.lock); + } + return _urb; +} + +struct _urb *_urb_dequeue(struct _urb_queue *q) +{ + struct _urb *_urb = NULL; + unsigned long flags; + spin_lock_irqsave(&q->lock, flags); + { + struct list_head *head = &q->head; + struct list_head *next = head->next; + if (next != head) { + _urb = list_entry(next, struct _urb, list); + list_del(next); _urb->queue = NULL; + } + } + spin_unlock_irqrestore(&q->lock, flags); + return _urb; +} + static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs); static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs); -static struct urb *hci_usb_get_completed(struct hci_usb *husb) +#define __pending_tx(husb, type) (&husb->pending_tx[type-1]) +#define __pending_q(husb, type) (&husb->pending_q[type-1]) +#define __completed_q(husb, type) (&husb->completed_q[type-1]) +#define __transmit_q(husb, type) (&husb->transmit_q[type-1]) +#define __reassembly(husb, type) (husb->reassembly[type-1]) + +static inline struct _urb *__get_completed(struct hci_usb *husb, int type) { - struct sk_buff *skb; - struct urb *urb = NULL; + return _urb_dequeue(__completed_q(husb, type)); +} - skb = skb_dequeue(&husb->completed_q); - if (skb) { - urb = ((struct hci_usb_scb *) skb->cb)->urb; - kfree_skb(skb); - } +#ifdef CONFIG_BT_USB_SCO +static void __fill_isoc_desc(struct urb *urb, int len, int mtu) +{ + int offset = 0, i; - BT_DBG("%s urb %p", husb->hdev.name, urb); - return urb; + BT_DBG("len %d mtu %d", len, mtu); + + for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length = mtu; + BT_DBG("desc %d offset %d len %d", i, offset, mtu); + } + if (len && i < HCI_MAX_ISOC_FRAMES) { + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length = len; + BT_DBG("desc %d offset %d len %d", i, offset, len); + i++; + } + urb->number_of_packets = i; } +#endif -static int hci_usb_enable_intr(struct hci_usb *husb) +static int hci_usb_intr_rx_submit(struct hci_usb *husb) { + struct _urb *_urb; struct urb *urb; - int pipe, size; + int err, pipe, interval, size; void *buf; BT_DBG("%s", husb->hdev.name); - if (!(urb = usb_alloc_urb(0, GFP_KERNEL))) + size = husb->intr_in_ep->desc.wMaxPacketSize; + + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) return -ENOMEM; - if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) { - usb_free_urb(urb); + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) { + kfree(buf); return -ENOMEM; } + _urb->type = HCI_EVENT_PKT; + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - husb->intr_urb = urb; - - pipe = usb_rcvintpipe(husb->udev, husb->intr_ep); - size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe)); - usb_fill_int_urb(urb, husb->udev, pipe, buf, size, - hci_usb_interrupt, husb, husb->intr_interval); + urb = &_urb->urb; + pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->desc.bEndpointAddress); + interval = husb->intr_in_ep->desc.bInterval; + usb_fill_int_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); - return usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s intr rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + _urb_unlink(_urb); + _urb_free(_urb); + kfree(buf); + } + return err; } -static int hci_usb_disable_intr(struct hci_usb *husb) +static int hci_usb_bulk_rx_submit(struct hci_usb *husb) { - struct urb *urb = husb->intr_urb; - struct sk_buff *skb; - - BT_DBG("%s", husb->hdev.name); + struct _urb *_urb; + struct urb *urb; + int err, pipe, size = HCI_MAX_FRAME_SIZE; + void *buf; - usb_unlink_urb(urb); usb_free_urb(urb); - husb->intr_urb = NULL; + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) + return -ENOMEM; - skb = husb->intr_skb; - if (skb) { - husb->intr_skb = NULL; - kfree_skb(skb); + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) { + kfree(buf); + return -ENOMEM; } + _urb->type = HCI_ACLDATA_PKT; + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - return 0; + urb = &_urb->urb; + pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->desc.bEndpointAddress); + usb_fill_bulk_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); + urb->transfer_flags = 0; + + BT_DBG("%s urb %p", husb->hdev.name, urb); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s bulk rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + _urb_unlink(_urb); + _urb_free(_urb); + kfree(buf); + } + return err; } -static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb) +#ifdef CONFIG_BT_USB_SCO +static int hci_usb_isoc_rx_submit(struct hci_usb *husb) { - struct hci_usb_scb *scb; - struct sk_buff *skb; - int pipe, size, err; + struct _urb *_urb; + struct urb *urb; + int err, mtu, size; + void *buf; - if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) - return -ENOMEM; + mtu = husb->isoc_in_ep->desc.wMaxPacketSize; + size = mtu * HCI_MAX_ISOC_FRAMES; - size = HCI_MAX_FRAME_SIZE; + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) + return -ENOMEM; - if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) { - usb_free_urb(urb); + _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); + if (!_urb) { + kfree(buf); return -ENOMEM; } - - BT_DBG("%s urb %p", husb->hdev.name, urb); + _urb->type = HCI_SCODATA_PKT; + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_ACLDATA_PKT; + urb = &_urb->urb; - scb = (struct hci_usb_scb *) skb->cb; - scb->urb = urb; + urb->context = husb; + urb->dev = husb->udev; + urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->desc.bEndpointAddress); + urb->complete = hci_usb_rx_complete; - pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep); + urb->transfer_buffer_length = size; + urb->transfer_buffer = buf; + urb->transfer_flags = URB_ISO_ASAP; - usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb); + __fill_isoc_desc(urb, size, mtu); + + BT_DBG("%s urb %p", husb->hdev.name, urb); - skb_queue_tail(&husb->pending_q, skb); err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { - BT_ERR("%s bulk rx submit failed urb %p err %d", + BT_ERR("%s isoc rx submit failed urb %p err %d", husb->hdev.name, urb, err); - skb_unlink(skb); - usb_free_urb(urb); + _urb_unlink(_urb); + _urb_free(_urb); + kfree(buf); } return err; } +#endif /* Initialize device */ static int hci_usb_open(struct hci_dev *hdev) @@ -209,13 +296,17 @@ static int hci_usb_open(struct hci_dev *hdev) write_lock_irqsave(&husb->completion_lock, flags); - err = hci_usb_enable_intr(husb); + err = hci_usb_intr_rx_submit(husb); if (!err) { for (i = 0; i < HCI_MAX_BULK_RX; i++) - hci_usb_rx_submit(husb, NULL); - } else + hci_usb_bulk_rx_submit(husb); + +#ifdef CONFIG_BT_USB_SCO + hci_usb_isoc_rx_submit(husb); +#endif + } else { clear_bit(HCI_RUNNING, &hdev->flags); - + } write_unlock_irqrestore(&husb->completion_lock, flags); return err; @@ -225,29 +316,52 @@ static int hci_usb_open(struct hci_dev *hdev) static int hci_usb_flush(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int i; BT_DBG("%s", hdev->name); - skb_queue_purge(&husb->cmd_q); - skb_queue_purge(&husb->acl_q); + for (i=0; i < 4; i++) + skb_queue_purge(&husb->transmit_q[i]); return 0; } -static inline void hci_usb_unlink_urbs(struct hci_usb *husb) +static void hci_usb_unlink_urbs(struct hci_usb *husb) { - struct sk_buff *skb; - struct urb *urb; + int i; BT_DBG("%s", husb->hdev.name); - while ((skb = skb_dequeue(&husb->pending_q))) { - urb = ((struct hci_usb_scb *) skb->cb)->urb; - usb_unlink_urb(urb); - kfree_skb(skb); - } + for (i=0; i < 4; i++) { + struct _urb *_urb; + struct urb *urb; + + /* Kill pending requests */ + while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { + urb = &_urb->urb; + BT_DBG("%s unlinking _urb %p type %d urb %p", + husb->hdev.name, _urb, _urb->type, urb); + usb_unlink_urb(urb); + _urb_queue_tail(__completed_q(husb, _urb->type), _urb); + } - while ((urb = hci_usb_get_completed(husb))) - usb_free_urb(urb); + /* Release completed requests */ + while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { + urb = &_urb->urb; + BT_DBG("%s freeing _urb %p type %d urb %p", + husb->hdev.name, _urb, _urb->type, urb); + if (urb->setup_packet) + kfree(urb->setup_packet); + if (urb->transfer_buffer) + kfree(urb->transfer_buffer); + _urb_free(_urb); + } + + /* Release reassembly buffers */ + if (husb->reassembly[i]) { + kfree_skb(husb->reassembly[i]); + husb->reassembly[i] = NULL; + } + } } /* Close device */ @@ -263,7 +377,6 @@ static int hci_usb_close(struct hci_dev *hdev) write_lock_irqsave(&husb->completion_lock, flags); - hci_usb_disable_intr(husb); hci_usb_unlink_urbs(husb); hci_usb_flush(hdev); @@ -271,104 +384,157 @@ static int hci_usb_close(struct hci_dev *hdev) return 0; } -static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) +static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) { - struct hci_usb_scb *scb = (void *) skb->cb; - struct urb *urb = hci_usb_get_completed(husb); - struct usb_ctrlrequest *cr; - int pipe, err; - - if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) - return -ENOMEM; + struct urb *urb = &_urb->urb; + int err; - if (!(cr = kmalloc(sizeof(*cr), GFP_ATOMIC))) { - usb_free_urb(urb); - return -ENOMEM; - } + BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type); - pipe = usb_sndctrlpipe(husb->udev, 0); + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + BT_ERR("%s tx submit failed urb %p type %d err %d", + husb->hdev.name, urb, _urb->type, err); + _urb_unlink(_urb); + _urb_queue_tail(__completed_q(husb, _urb->type), _urb); + } else + atomic_inc(__pending_tx(husb, _urb->type)); - cr->bRequestType = HCI_CTRL_REQ; - cr->bRequest = 0; - cr->wIndex = 0; - cr->wValue = 0; - cr->wLength = __cpu_to_le16(skb->len); + return err; +} - usb_fill_control_urb(urb, husb->udev, pipe, (void *) cr, - skb->data, skb->len, hci_usb_tx_complete, skb); +static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) +{ + struct _urb *_urb = __get_completed(husb, skb->pkt_type); + struct usb_ctrlrequest *dr; + struct urb *urb; - BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); + if (!_urb) { + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) + return -ENOMEM; + _urb->type = skb->pkt_type; - scb->urb = urb; + dr = kmalloc(sizeof(*dr), GFP_ATOMIC); + if (!dr) { + _urb_free(_urb); + return -ENOMEM; + } + } else + dr = (void *) _urb->urb.setup_packet; - skb_queue_tail(&husb->pending_q, skb); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s ctrl tx submit failed urb %p err %d", - husb->hdev.name, urb, err); - skb_unlink(skb); - usb_free_urb(urb); kfree(cr); - } - return err; + dr->bRequestType = HCI_CTRL_REQ; + dr->bRequest = 0; + dr->wIndex = 0; + dr->wValue = 0; + dr->wLength = __cpu_to_le16(skb->len); + + urb = &_urb->urb; + usb_fill_control_urb(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), + (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); + + BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + + _urb->priv = skb; + return __tx_submit(husb, _urb); } static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) { - struct hci_usb_scb *scb = (void *) skb->cb; - struct urb *urb = hci_usb_get_completed(husb); - int pipe, err; + struct _urb *_urb = __get_completed(husb, skb->pkt_type); + struct urb *urb; + int pipe; - if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) - return -ENOMEM; + if (!_urb) { + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) + return -ENOMEM; + _urb->type = skb->pkt_type; + } - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep); - - usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_tx_complete, skb); - urb->transfer_flags = URB_ZERO_PACKET; + urb = &_urb->urb; + pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress); + usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, + hci_usb_tx_complete, husb); + urb->transfer_flags = USB_ZERO_PACKET; - BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); + BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); - scb->urb = urb; + _urb->priv = skb; + return __tx_submit(husb, _urb); +} - skb_queue_tail(&husb->pending_q, skb); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s bulk tx submit failed urb %p err %d", - husb->hdev.name, urb, err); - skb_unlink(skb); - usb_free_urb(urb); +#ifdef CONFIG_BT_USB_SCO +static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) +{ + struct _urb *_urb = __get_completed(husb, skb->pkt_type); + struct urb *urb; + + if (!_urb) { + _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); + if (!_urb) + return -ENOMEM; + _urb->type = skb->pkt_type; } - return err; + + BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + + urb = &_urb->urb; + + urb->context = husb; + urb->dev = husb->udev; + urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->desc.bEndpointAddress); + urb->complete = hci_usb_tx_complete; + urb->transfer_flags = URB_ISO_ASAP; + + urb->transfer_buffer = skb->data; + urb->transfer_buffer_length = skb->len; + + __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->desc.wMaxPacketSize); + + _urb->priv = skb; + return __tx_submit(husb, _urb); } +#endif static void hci_usb_tx_process(struct hci_usb *husb) { + struct sk_buff_head *q; struct sk_buff *skb; BT_DBG("%s", husb->hdev.name); do { clear_bit(HCI_USB_TX_WAKEUP, &husb->state); + + /* Process command queue */ + q = __transmit_q(husb, HCI_COMMAND_PKT); + if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && + (skb = skb_dequeue(q))) { + if (hci_usb_send_ctrl(husb, skb) < 0) + skb_queue_head(q, skb); + } + +#ifdef CONFIG_BT_USB_SCO + /* Process SCO queue */ + q = __transmit_q(husb, HCI_SCODATA_PKT); + if (!atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) && + (skb = skb_dequeue(q))) { + if (hci_usb_send_isoc(husb, skb) < 0) + skb_queue_head(q, skb); + } +#endif /* Process ACL queue */ - while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING && - (skb = skb_dequeue(&husb->acl_q))) { + q = __transmit_q(husb, HCI_ACLDATA_PKT); + while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && + (skb = skb_dequeue(q))) { if (hci_usb_send_bulk(husb, skb) < 0) { - skb_queue_head(&husb->acl_q, skb); + skb_queue_head(q, skb); break; } } - - /* Process command queue */ - if (!test_bit(HCI_USB_CTRL_TX, &husb->state) && - (skb = skb_dequeue(&husb->cmd_q)) != NULL) { - set_bit(HCI_USB_CTRL_TX, &husb->state); - if (hci_usb_send_ctrl(husb, skb) < 0) { - skb_queue_head(&husb->cmd_q, skb); - clear_bit(HCI_USB_CTRL_TX, &husb->state); - } - } } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); } @@ -383,7 +549,7 @@ static inline void hci_usb_tx_wakeup(struct hci_usb *husb) } /* Send frames from HCI layer */ -int hci_usb_send_frame(struct sk_buff *skb) +static int hci_usb_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct hci_usb *husb; @@ -396,247 +562,227 @@ int hci_usb_send_frame(struct sk_buff *skb) if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; - husb = (struct hci_usb *) hdev->driver_data; - BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - read_lock(&husb->completion_lock); + husb = (struct hci_usb *) hdev->driver_data; switch (skb->pkt_type) { case HCI_COMMAND_PKT: - skb_queue_tail(&husb->cmd_q, skb); hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: - skb_queue_tail(&husb->acl_q, skb); hdev->stat.acl_tx++; break; +#ifdef CONFIG_BT_USB_SCO case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; +#endif + default: kfree_skb(skb); - break; + return 0; } + + read_lock(&husb->completion_lock); + + skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb); hci_usb_tx_wakeup(husb); read_unlock(&husb->completion_lock); return 0; } -static void hci_usb_interrupt(struct urb *urb, struct pt_regs *regs) +static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count) { - struct hci_usb *husb = (void *) urb->context; - struct hci_usb_scb *scb; - struct sk_buff *skb; - struct hci_event_hdr *eh; - __u8 *data = urb->transfer_buffer; - int count = urb->actual_length; - int len = HCI_EVENT_HDR_SIZE; - int status; + BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count); - BT_DBG("%s urb %p count %d", husb->hdev.name, urb, count); + husb->hdev.stat.byte_rx += count; - if (!test_bit(HCI_RUNNING, &husb->hdev.flags)) - return; + while (count) { + struct sk_buff *skb = __reassembly(husb, type); + struct { int expect; } *scb; + int len = 0; + + if (!skb) { + /* Start of the frame */ + + switch (type) { + case HCI_EVENT_PKT: + if (count >= HCI_EVENT_HDR_SIZE) { + struct hci_event_hdr *h = data; + len = HCI_EVENT_HDR_SIZE + h->plen; + } else + return -EILSEQ; + break; - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - BT_DBG("%s urb shutting down with status: %d", - husb->hdev.name, urb->status); - return; - default: - BT_ERR("%s nonzero urb status received: %d", - husb->hdev.name, urb->status); - goto exit; - } + case HCI_ACLDATA_PKT: + if (count >= HCI_ACL_HDR_SIZE) { + struct hci_acl_hdr *h = data; + len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen); + } else + return -EILSEQ; + break; +#ifdef CONFIG_BT_USB_SCO + case HCI_SCODATA_PKT: + if (count >= HCI_SCO_HDR_SIZE) { + struct hci_sco_hdr *h = data; + len = HCI_SCO_HDR_SIZE + h->dlen; + } else + return -EILSEQ; + break; +#endif + } + BT_DBG("new packet len %d", len); + + skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!skb) { + BT_ERR("%s no memory for the packet", husb->hdev.name); + return -ENOMEM; + } + skb->dev = (void *) &husb->hdev; + skb->pkt_type = type; + + __reassembly(husb, type) = skb; + + scb = (void *) skb->cb; + scb->expect = len; + } else { + /* Continuation */ + scb = (void *) skb->cb; + len = scb->expect; + } - if (!count) { - BT_DBG("%s intr status %d, count %d", - husb->hdev.name, urb->status, count); - goto exit; - } + len = min(len, count); + + memcpy(skb_put(skb, len), data, len); - read_lock(&husb->completion_lock); - - husb->hdev.stat.byte_rx += count; + scb->expect -= len; + if (!scb->expect) { + /* Complete frame */ + __reassembly(husb, type) = NULL; + hci_recv_frame(skb); + } + + count -= len; data += len; + } + return 0; +} - if (!(skb = husb->intr_skb)) { - /* Start of the frame */ - if (count < HCI_EVENT_HDR_SIZE) - goto bad_len; +static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs) +{ + struct _urb *_urb = container_of(urb, struct _urb, urb); + struct hci_usb *husb = (void *) urb->context; + struct hci_dev *hdev = &husb->hdev; + int err, count = urb->actual_length; - eh = (struct hci_event_hdr *) data; - len = eh->plen + HCI_EVENT_HDR_SIZE; + BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, + _urb->type, urb->status, count, urb->transfer_flags); - if (count > len) - goto bad_len; + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return; - skb = bt_skb_alloc(len, GFP_ATOMIC); - if (!skb) { - BT_ERR("%s no memory for event packet", husb->hdev.name); - goto done; - } - scb = (void *) skb->cb; + read_lock(&husb->completion_lock); - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_EVENT_PKT; + if (urb->status || !count) + goto resubmit; - husb->intr_skb = skb; - scb->intr_len = len; + if (_urb->type == HCI_SCODATA_PKT) { +#ifdef CONFIG_BT_USB_SCO + int i; + for (i=0; i < urb->number_of_packets; i++) { + BT_DBG("desc %d status %d offset %d len %d", i, + urb->iso_frame_desc[i].status, + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + + if (!urb->iso_frame_desc[i].status) + __recv_frame(husb, _urb->type, + urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } +#else + ; +#endif } else { - /* Continuation */ - scb = (void *) skb->cb; - len = scb->intr_len; - if (count > len) { - husb->intr_skb = NULL; - kfree_skb(skb); - goto bad_len; + err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count); + if (err < 0) { + BT_ERR("%s corrupted packet: type %d count %d", + husb->hdev.name, _urb->type, count); + hdev->stat.err_rx++; } } - memcpy(skb_put(skb, count), data, count); - scb->intr_len -= count; - - if (!scb->intr_len) { - /* Complete frame */ - husb->intr_skb = NULL; - hci_recv_frame(skb); - } - -done: - read_unlock(&husb->completion_lock); - goto exit; +resubmit: + urb->dev = husb->udev; + err = usb_submit_urb(urb, GFP_ATOMIC); + BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, + _urb->type, err); -bad_len: - BT_ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len); - husb->hdev.stat.err_rx++; read_unlock(&husb->completion_lock); - -exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - BT_ERR ("%s usb_submit_urb failed with result %d", - husb->hdev.name, status); } static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + struct _urb *_urb = container_of(urb, struct _urb, urb); + struct hci_usb *husb = (void *) urb->context; + struct hci_dev *hdev = &husb->hdev; - BT_DBG("%s urb %p status %d flags %x", husb->hdev.name, urb, + BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, urb->status, urb->transfer_flags); - if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) { - kfree(urb->setup_packet); - clear_bit(HCI_USB_CTRL_TX, &husb->state); - } + atomic_dec(__pending_tx(husb, _urb->type)); + + urb->transfer_buffer = NULL; + kfree_skb((struct sk_buff *) _urb->priv); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; - read_lock(&husb->completion_lock); - if (!urb->status) - husb->hdev.stat.byte_tx += skb->len; + hdev->stat.byte_tx += urb->transfer_buffer_length; else - husb->hdev.stat.err_tx++; - - skb_unlink(skb); - skb_queue_tail(&husb->completed_q, skb); - hci_usb_tx_wakeup(husb); - - read_unlock(&husb->completion_lock); - return; -} - -static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int status, count = urb->actual_length; - struct hci_acl_hdr *ah; - int dlen, size; - - BT_DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb, - urb->status, count, urb->transfer_flags); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; + hdev->stat.err_tx++; read_lock(&husb->completion_lock); - if (urb->status || !count) - goto resubmit; - - husb->hdev.stat.byte_rx += count; + _urb_unlink(_urb); + _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - ah = (struct hci_acl_hdr *) skb->data; - dlen = __le16_to_cpu(ah->dlen); - size = HCI_ACL_HDR_SIZE + dlen; - - /* Verify frame len and completeness */ - if (count != size) { - BT_ERR("%s corrupted ACL packet: count %d, dlen %d", - husb->hdev.name, count, dlen); - bt_dump("hci_usb", skb->data, count); - husb->hdev.stat.err_rx++; - goto resubmit; - } - - skb_unlink(skb); - skb_put(skb, count); - hci_recv_frame(skb); - - hci_usb_rx_submit(husb, urb); - - read_unlock(&husb->completion_lock); - return; - -resubmit: - urb->dev = husb->udev; - status = usb_submit_urb(urb, GFP_ATOMIC); - BT_DBG("%s URB resubmit status %d", husb->hdev.name, status); + hci_usb_tx_wakeup(husb); + read_unlock(&husb->completion_lock); } static void hci_usb_destruct(struct hci_dev *hdev) { - struct hci_usb *husb; - - if (!hdev) return; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; BT_DBG("%s", hdev->name); - husb = (struct hci_usb *) hdev->driver_data; kfree(husb); } int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(intf); + struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_endpoint *bulk_out_ep[HCI_MAX_IFACE_NUM]; struct usb_host_endpoint *isoc_out_ep[HCI_MAX_IFACE_NUM]; struct usb_host_endpoint *bulk_in_ep[HCI_MAX_IFACE_NUM]; struct usb_host_endpoint *isoc_in_ep[HCI_MAX_IFACE_NUM]; struct usb_host_endpoint *intr_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_host_endpoint *ep; struct usb_host_interface *uif; - struct usb_host_endpoint *ep; struct usb_interface *iface, *isoc_iface; struct hci_usb *husb; struct hci_dev *hdev; int i, a, e, size, ifn, isoc_ifnum, isoc_alts; - BT_DBG("intf %p", intf); + BT_DBG("udev %p ifnum %d", udev, ifnum); + + iface = &udev->actconfig->interface[0]; /* Check our black list */ if (usb_match_id(intf, ignore_ids)) @@ -679,6 +825,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) bulk_out_ep[i] = ep; break; +#ifdef CONFIG_BT_USB_SCO case USB_ENDPOINT_XFER_ISOC: if (ep->desc.wMaxPacketSize < size) break; @@ -693,6 +840,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) else isoc_out_ep[i] = ep; break; +#endif } } } @@ -703,10 +851,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) goto done; } +#ifdef CONFIG_BT_USB_SCO if (!isoc_in_ep[1] || !isoc_out_ep[1]) { BT_DBG("Isoc endpoints not found"); isoc_iface = NULL; } +#endif if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { BT_ERR("Can't allocate: control structure"); @@ -716,35 +866,36 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) memset(husb, 0, sizeof(struct hci_usb)); husb->udev = udev; - husb->bulk_out_ep = bulk_out_ep[0]->desc.bEndpointAddress; - husb->bulk_in_ep = bulk_in_ep[0]->desc.bEndpointAddress; - - husb->intr_ep = intr_in_ep[0]->desc.bEndpointAddress; - husb->intr_interval = intr_in_ep[0]->desc.bInterval; + husb->bulk_out_ep = bulk_out_ep[0]; + husb->bulk_in_ep = bulk_in_ep[0]; + husb->intr_in_ep = intr_in_ep[0]; +#ifdef CONFIG_BT_USB_SCO if (isoc_iface) { + BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { BT_ERR("Can't set isoc interface settings"); isoc_iface = NULL; } usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); husb->isoc_iface = isoc_iface; - - husb->isoc_in_ep = isoc_in_ep[1]->desc.bEndpointAddress; - husb->isoc_out_ep = isoc_in_ep[1]->desc.bEndpointAddress; + husb->isoc_in_ep = isoc_in_ep[isoc_ifnum]; + husb->isoc_out_ep = isoc_out_ep[isoc_ifnum]; } - - husb->completion_lock = RW_LOCK_UNLOCKED; +#endif - skb_queue_head_init(&husb->acl_q); - skb_queue_head_init(&husb->cmd_q); - skb_queue_head_init(&husb->pending_q); - skb_queue_head_init(&husb->completed_q); + husb->completion_lock = RW_LOCK_UNLOCKED; + + for (i = 0; i < 4; i++) { + skb_queue_head_init(&husb->transmit_q[i]); + _urb_queue_init(&husb->pending_q[i]); + _urb_queue_init(&husb->completed_q[i]); + } /* Initialize and register HCI device */ hdev = &husb->hdev; - hdev->type = HCI_USB; + hdev->type = HCI_USB; hdev->driver_data = husb; hdev->open = hci_usb_open; @@ -753,8 +904,6 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) hdev->send = hci_usb_send_frame; hdev->destruct = hci_usb_destruct; - hdev->owner = THIS_MODULE; - if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); goto probe_error; @@ -773,13 +922,12 @@ done: static void hci_usb_disconnect(struct usb_interface *intf) { struct hci_usb *husb = usb_get_intfdata(intf); - struct hci_dev *hdev; + struct hci_dev *hdev = &husb->hdev; if (!husb) return; usb_set_intfdata(intf, NULL); - hdev = &husb->hdev; BT_DBG("%s", hdev->name); hci_usb_close(hdev); @@ -792,17 +940,20 @@ static void hci_usb_disconnect(struct usb_interface *intf) } static struct usb_driver hci_usb_driver = { - .name = "hci_usb", - .probe = hci_usb_probe, - .disconnect = hci_usb_disconnect, - .id_table = bluetooth_ids + .owner = THIS_MODULE, + .name = "hci_usb", + .probe = hci_usb_probe, + .disconnect = hci_usb_disconnect, + .id_table = bluetooth_ids, }; int hci_usb_init(void) { int err; - BT_INFO("HCI USB driver ver %s", VERSION); + BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); + BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); if ((err = usb_register(&hci_usb_driver)) < 0) BT_ERR("Failed to register HCI USB driver"); @@ -819,5 +970,5 @@ module_init(hci_usb_init); module_exit(hci_usb_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); +MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h index 4e7e80d08196..1e7306286e56 100644 --- a/drivers/bluetooth/hci_usb.h +++ b/drivers/bluetooth/hci_usb.h @@ -1,9 +1,10 @@ /* - BlueZ - Bluetooth protocol stack for Linux + HCI USB driver for Linux Bluetooth protocol stack (BlueZ) Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky + Copyright (C) 2003 Maxim Krasnyansky + 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; @@ -40,40 +41,96 @@ #define HCI_MAX_BULK_TX 4 #define HCI_MAX_BULK_RX 1 +#define HCI_MAX_ISOC_FRAMES 10 + +struct _urb_queue { + struct list_head head; + spinlock_t lock; +}; + +struct _urb { + struct list_head list; + struct _urb_queue *queue; + int type; + void *priv; + struct urb urb; +}; + +struct _urb *_urb_alloc(int isoc, int gfp); + +static inline void _urb_free(struct _urb *_urb) +{ + kfree(_urb); +} + +static inline void _urb_queue_init(struct _urb_queue *q) +{ + INIT_LIST_HEAD(&q->head); + spin_lock_init(&q->lock); +} + +static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) +{ + unsigned long flags; + spin_lock_irqsave(&q->lock, flags); + list_add(&_urb->list, &q->head); _urb->queue = q; + spin_unlock_irqrestore(&q->lock, flags); +} + +static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) +{ + unsigned long flags; + spin_lock_irqsave(&q->lock, flags); + list_add_tail(&_urb->list, &q->head); _urb->queue = q; + spin_unlock_irqrestore(&q->lock, flags); +} + +static inline void _urb_unlink(struct _urb *_urb) +{ + struct _urb_queue *q = _urb->queue; + unsigned long flags; + if (q) { + spin_lock_irqsave(&q->lock, flags); + list_del(&_urb->list); _urb->queue = NULL; + spin_unlock_irqrestore(&q->lock, flags); + } +} + +struct _urb *_urb_dequeue(struct _urb_queue *q); + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + struct hci_usb { struct hci_dev hdev; unsigned long state; struct usb_device *udev; - struct usb_interface *isoc_iface; - __u8 bulk_out_ep; - __u8 bulk_in_ep; - __u8 isoc_out_ep; - __u8 isoc_in_ep; + struct usb_host_endpoint *bulk_in_ep; + struct usb_host_endpoint *bulk_out_ep; + struct usb_host_endpoint *intr_in_ep; + + struct usb_interface *isoc_iface; + struct usb_host_endpoint *isoc_out_ep; + struct usb_host_endpoint *isoc_in_ep; - __u8 intr_ep; - __u8 intr_interval; - struct urb *intr_urb; - struct sk_buff *intr_skb; + struct sk_buff_head transmit_q[4]; + struct sk_buff *reassembly[4]; // Reassembly buffers rwlock_t completion_lock; - - struct sk_buff_head cmd_q; // TX Commands - struct sk_buff_head acl_q; // TX ACLs - struct sk_buff_head pending_q; // Pending requests - struct sk_buff_head completed_q; // Completed requests -}; -struct hci_usb_scb { - struct urb *urb; - int intr_len; + atomic_t pending_tx[4]; // Number of pending requests + struct _urb_queue pending_q[4]; // Pending requests + struct _urb_queue completed_q[4]; // Completed requests }; /* States */ #define HCI_USB_TX_PROCESS 1 #define HCI_USB_TX_WAKEUP 2 -#define HCI_USB_CTRL_TX 3 #endif /* __KERNEL__ */ -- cgit v1.2.3 From 6ebecd19c9f2f833724044263c26dc08385bceb4 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 23 Mar 2003 22:43:01 -0800 Subject: [Bluetooth] Don't forget to set HCI device owner in USB driver. --- drivers/bluetooth/hci_usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 296f2e2ca4c2..7ad1a3dddcad 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -904,6 +904,8 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) hdev->send = hci_usb_send_frame; hdev->destruct = hci_usb_destruct; + hdev->owner = THIS_MODULE; + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); goto probe_error; @@ -940,7 +942,6 @@ static void hci_usb_disconnect(struct usb_interface *intf) } static struct usb_driver hci_usb_driver = { - .owner = THIS_MODULE, .name = "hci_usb", .probe = hci_usb_probe, .disconnect = hci_usb_disconnect, -- cgit v1.2.3 From 55ce9e7c77ed6624fc72b030e1486112e0ad6a0b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 31 Mar 2003 00:49:53 +0200 Subject: [Bluetooth] Respond correctly to RLS packets This patch adds the recognition and correct responding to the RFCOMM RLS packets to fulfil the requirements of the Bluetooth specification. --- include/net/bluetooth/rfcomm.h | 5 +++++ net/bluetooth/rfcomm/core.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 73d85aae16f9..3393e95c7e0f 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -146,6 +146,11 @@ struct rfcomm_rpn { u16 param_mask; } __attribute__ ((packed)); +struct rfcomm_rls { + u8 dlci; + u8 status; +} __attribute__ ((packed)); + struct rfcomm_msc { u8 dlci; u8 v24_sig; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 413d02561309..5795735a4f08 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -798,6 +798,33 @@ static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, return rfcomm_send_frame(s, buf, ptr - buf); } +static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) +{ + struct rfcomm_hdr *hdr; + struct rfcomm_mcc *mcc; + struct rfcomm_rls *rls; + u8 buf[16], *ptr = buf; + + BT_DBG("%p cr %d status 0x%x", s, cr, status); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = __addr(s->initiator, 0); + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + hdr->len = __len8(sizeof(*mcc) + sizeof(*rls)); + + mcc = (void *) ptr; ptr += sizeof(*mcc); + mcc->type = __mcc_type(cr, RFCOMM_RLS); + mcc->len = __len8(sizeof(*rls)); + + rls = (void *) ptr; ptr += sizeof(*rls); + rls->dlci = __addr(1, dlci); + rls->status = status; + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) { struct rfcomm_hdr *hdr; @@ -1229,6 +1256,26 @@ rpn_out: return 0; } +static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) +{ + struct rfcomm_rls *rls = (void *) skb->data; + u8 dlci = __get_dlci(rls->dlci); + + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) + return 0; + + /* FIXME: We should probably do something with this + information here. But for now it's sufficient just + to reply -- Bluetooth 1.1 says it's mandatory to + recognise and respond to RLS */ + + rfcomm_send_rls(s, 0, dlci, rls->status); + + return 0; +} + static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) { struct rfcomm_msc *msc = (void *) skb->data; @@ -1279,6 +1326,10 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) rfcomm_recv_rpn(s, cr, len, skb); break; + case RFCOMM_RLS: + rfcomm_recv_rls(s, cr, skb); + break; + case RFCOMM_MSC: rfcomm_recv_msc(s, cr, skb); break; -- cgit v1.2.3 From 0d1ddd83b240100cbae559606647030d4fb484e1 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sat, 5 Apr 2003 21:46:45 -0700 Subject: [Bluetooth] Update BT PCMCIA drivers to use pcmcia_register_driver(). Patch from Christoph Hellwig --- drivers/bluetooth/bluecard_cs.c | 35 ++++++++++++++--------------------- drivers/bluetooth/bt3c_cs.c | 35 ++++++++++++++--------------------- drivers/bluetooth/btuart_cs.c | 35 ++++++++++++++--------------------- drivers/bluetooth/dtl1_cs.c | 35 ++++++++++++++--------------------- 4 files changed, 56 insertions(+), 84 deletions(-) diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index f2dbb950c8ce..39e2cd68c48e 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -1075,36 +1075,29 @@ int bluecard_event(event_t event, int priority, event_callback_args_t *args) return 0; } - - -/* ======================== Module initialization ======================== */ - - -int __init init_bluecard_cs(void) +static struct pcmcia_driver bluecard_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "bluecard_cs", + }, + .attach = bluecard_attach, + .detach = bluecard_detach, +}; + +static int __init init_bluecard_cs(void) { - servinfo_t serv; - int err; - - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n"); - return -1; - } - - err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach); - - return err; + return pcmcia_register_driver(&bluecard_driver); } -void __exit exit_bluecard_cs(void) +static void __exit exit_bluecard_cs(void) { - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&bluecard_driver); + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) bluecard_detach(dev_list); } - module_init(init_bluecard_cs); module_exit(exit_bluecard_cs); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 6fdeb612da0d..bf7c41a41e4d 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -861,36 +861,29 @@ int bt3c_event(event_t event, int priority, event_callback_args_t *args) return 0; } - - -/* ======================== Module initialization ======================== */ - - -int __init init_bt3c_cs(void) +static struct pcmcia_driver bt3c_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "bt3c_cs", + }, + .attach = bt3c_attach, + .detach = bt3c_detach, +}; + +static int __init init_bt3c_cs(void) { - servinfo_t serv; - int err; - - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n"); - return -1; - } - - err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach); - - return err; + return pcmcia_register_driver(&bt3c_driver); } -void __exit exit_bt3c_cs(void) +static void __exit exit_bt3c_cs(void) { - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&bt3c_driver); + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) bt3c_detach(dev_list); } - module_init(init_bt3c_cs); module_exit(exit_bt3c_cs); diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index afc6e99ab7a2..5a10bae6804e 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -868,36 +868,29 @@ int btuart_event(event_t event, int priority, event_callback_args_t *args) return 0; } - - -/* ======================== Module initialization ======================== */ - - -int __init init_btuart_cs(void) +static struct pcmcia_driver btuart_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "btuart_cs", + }, + .attach = btuart_attach, + .detach = btuart_detach, +}; + +static int __init init_btuart_cs(void) { - servinfo_t serv; - int err; - - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n"); - return -1; - } - - err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach); - - return err; + return pcmcia_register_driver(&btuart_driver); } -void __exit exit_btuart_cs(void) +static void __exit exit_btuart_cs(void) { - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&btuart_driver); + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) btuart_detach(dev_list); } - module_init(init_btuart_cs); module_exit(exit_btuart_cs); diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 9791be7e8a80..4f6449532800 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -820,36 +820,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args) return 0; } - - -/* ======================== Module initialization ======================== */ - - -int __init init_dtl1_cs(void) +static struct pcmcia_driver dtl1_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "dtl1_cs", + }, + .attach = dtl1_attach, + .detach = dtl1_detach, +}; + +static int __init init_dtl1_cs(void) { - servinfo_t serv; - int err; - - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); - return -1; - } - - err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); - - return err; + return pcmcia_register_driver(&dtl1_driver); } -void __exit exit_dtl1_cs(void) +static void __exit exit_dtl1_cs(void) { - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&dtl1_driver); + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) dtl1_detach(dev_list); } - module_init(init_dtl1_cs); module_exit(exit_dtl1_cs); -- cgit v1.2.3 From edceec87de49c19232f4b114a11ee99105662ada Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 23 Apr 2003 17:55:48 +0200 Subject: [Bluetooth] Fix L2CAP binding to local address In the function l2cap_connect_ind() we compare the bounded address with the address of an incoming connection, but we have to compare it with the local address of the HCI device. --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e91c20ad1b16..c34222f74c23 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1788,7 +1788,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) if (sk->state != BT_LISTEN) continue; - if (!bacmp(&bt_sk(sk)->src, bdaddr)) { + if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) -- cgit v1.2.3 From a04eefa17e8d7677fabe9eecdaa29a1d2f3cee67 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 24 Apr 2003 01:18:52 +0200 Subject: [Bluetooth] Correction of the HCI USB driver description This patch reverts the module description and other comments. --- drivers/bluetooth/hci_usb.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 7ad1a3dddcad..2b173dfe5f9e 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -24,6 +24,7 @@ */ /* + * Bluetooth HCI USB driver. * Based on original USB Bluetooth driver for Linux kernel * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner @@ -952,9 +953,7 @@ int hci_usb_init(void) { int err; - BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("HCI USB driver ver %s", VERSION); if ((err = usb_register(&hci_usb_driver)) < 0) BT_ERR("Failed to register HCI USB driver"); @@ -971,5 +970,5 @@ module_init(hci_usb_init); module_exit(hci_usb_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION); +MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 46acabae966702def20e1a35e5064487747953a4 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 27 Apr 2003 03:08:49 -0700 Subject: [Bluetooth] Improved RFCOMM TTY TX buffer management. Don't buffer more data than we have credits for. Patch from David Woodhouse --- net/bluetooth/rfcomm/tty.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index ccc1237945c0..f5e64494886d 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -72,7 +72,6 @@ struct rfcomm_dev { struct tasklet_struct wakeup_task; atomic_t wmem_alloc; - unsigned int sndbuf; }; static LIST_HEAD(rfcomm_dev_list); @@ -200,8 +199,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) dev->flags = req->flags & ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); - dev->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; - init_waitqueue_head(&dev->wait); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); @@ -238,6 +235,13 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev) } /* ---- Send buffer ---- */ +static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc) +{ + /* We can't let it be zero, because we don't get a callback + when tx_credits becomes nonzero, hence we'd never wake up */ + return dlc->mtu * (dlc->tx_credits?:1); +} + static void rfcomm_wfree(struct sk_buff *skb) { struct rfcomm_dev *dev = (void *) skb->sk; @@ -257,7 +261,7 @@ static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *de static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority) { - if (atomic_read(&dev->wmem_alloc) < dev->sndbuf) { + if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) { struct sk_buff *skb = alloc_skb(size, priority); if (skb) { rfcomm_set_owner_w(skb, dev); @@ -651,11 +655,14 @@ static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigne static int rfcomm_tty_write_room(struct tty_struct *tty) { struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; - struct rfcomm_dlc *dlc = dev->dlc; + int room; BT_DBG("tty %p", tty); - return dlc->mtu * (dlc->tx_credits ? : 10); + room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc); + if (room < 0) + room = 0; + return room; } static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status) -- cgit v1.2.3 From 7c4efa6921c7af943b6951db1e116a16263c5277 Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 27 Apr 2003 03:18:09 -0700 Subject: [Bluetooth] Fix race condition in RFCOMM session and dcl scheduler. This fixes random RFCOMM freezes reported by some people. --- include/net/bluetooth/rfcomm.h | 5 ++--- net/bluetooth/rfcomm/core.c | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 3393e95c7e0f..2efdc72f4193 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -220,10 +220,9 @@ static inline void rfcomm_schedule(uint event) { if (!rfcomm_thread) return; - //set_bit(event, &rfcomm_event); - if (!test_and_set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) - wake_up_process(rfcomm_thread); + set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); + wake_up_process(rfcomm_thread); } extern struct semaphore rfcomm_sem; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5795735a4f08..397f265daa51 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1483,9 +1483,9 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) d->rx_credits = d->credits; } } else { - /* CFC disabled. + /* CFC disabled. * Give ourselves some credits */ - d->tx_credits = RFCOMM_MAX_CREDITS; + d->tx_credits = 5; } if (test_bit(RFCOMM_TX_THROTTLED, &d->flags)) @@ -1651,7 +1651,7 @@ static void rfcomm_worker(void) BT_DBG(""); while (!atomic_read(&terminate)) { - if (!test_and_clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { + if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { /* No pending events. Let's sleep. * Incomming connections and data will wake us up. */ set_current_state(TASK_INTERRUPTIBLE); @@ -1659,6 +1659,7 @@ static void rfcomm_worker(void) } /* Process stuff */ + clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); rfcomm_process_sessions(); } set_current_state(TASK_RUNNING); -- cgit v1.2.3 From 526e4dcf9e7df62a816d553b05daa976b77fe8ed Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 27 Apr 2003 07:33:46 -0700 Subject: [Bluetooth] USB drivers cannot call usb_unlink_urb() under spin lock. --- drivers/bluetooth/hci_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 2b173dfe5f9e..66d7146c6135 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -376,12 +376,12 @@ static int hci_usb_close(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + /* Synchronize with completion handlers */ write_lock_irqsave(&husb->completion_lock, flags); + write_unlock_irqrestore(&husb->completion_lock, flags); hci_usb_unlink_urbs(husb); hci_usb_flush(hdev); - - write_unlock_irqrestore(&husb->completion_lock, flags); return 0; } -- cgit v1.2.3 From e823eaedcfa27e751208788df66783e6d29d292e Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 27 Apr 2003 07:43:10 -0700 Subject: [Bluetooth] Initialize net_proto_family->owner field. This covers only HCI sockets. Other protocols cannot be fixes at this point because current net_proto_family code does not support "family owner != socket owner" case. --- net/bluetooth/af_bluetooth.c | 1 + net/bluetooth/hci_sock.c | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index bc2aa9b7453c..991a0fd7b23b 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -321,6 +321,7 @@ int bt_sock_w4_connect(struct sock *sk, int flags) } struct net_proto_family bt_sock_family_ops = { + .owner = THIS_MODULE, .family = PF_BLUETOOTH, .create = bt_sock_create, }; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 7f88db9e62ba..952f6de9d8b5 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -161,8 +161,6 @@ static int hci_sock_release(struct socket *sock) skb_queue_purge(&sk->write_queue); sock_put(sk); - - MOD_DEC_USE_COUNT; return 0; } @@ -591,8 +589,6 @@ static int hci_sock_create(struct socket *sock, int protocol) sk->state = BT_OPEN; bt_sock_link(&hci_sk_list, sk); - - MOD_INC_USE_COUNT; return 0; } -- cgit v1.2.3 From 2d6ed7812e266327470f5f4f2d142077b588f15a Mon Sep 17 00:00:00 2001 From: Maksim Krasnyanskiy Date: Sun, 27 Apr 2003 07:51:21 -0700 Subject: [Bluetooth] Initialize ->owner field of the RFCOMM tty driver. In order to fix all MOD_INC/DECs in the RFCOMM code we need __module_get(). --- net/bluetooth/rfcomm/tty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index f5e64494886d..f7589f707c52 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -856,6 +856,8 @@ static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS]; static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS]; static struct tty_driver rfcomm_tty_driver = { + .owner = THIS_MODULE, + .magic = TTY_DRIVER_MAGIC, .driver_name = "rfcomm", #ifdef CONFIG_DEVFS_FS -- cgit v1.2.3