Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 23488 Details for
Bug 37696
Bluez-bluefw won't compile in newer 2.6 kernels
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Latest bluetooth development
patch-2.6.0-mh2 (text/plain), 87.64 KB, created by
Gustavo Michels
on 2004-01-09 09:19:57 UTC
(
hide
)
Description:
Latest bluetooth development
Filename:
MIME Type:
Creator:
Gustavo Michels
Created:
2004-01-09 09:19:57 UTC
Size:
87.64 KB
patch
obsolete
>diff -urN linux-2.6.0/CREDITS linux-2.6.0-mh2/CREDITS >--- linux-2.6.0/CREDITS 2003-12-18 03:59:06.000000000 +0100 >+++ linux-2.6.0-mh2/CREDITS 2004-01-02 11:46:31.000000000 +0100 >@@ -1395,6 +1395,7 @@ > E: marcel@holtmann.org > W: http://www.holtmann.org > D: Author and maintainer of the various Bluetooth HCI drivers >+D: Author and maintainer of the CAPI message transport protocol driver > D: Various other Bluetooth related patches, cleanups and fixes > S: Germany > >diff -urN linux-2.6.0/drivers/bluetooth/bcm203x.c linux-2.6.0-mh2/drivers/bluetooth/bcm203x.c >--- linux-2.6.0/drivers/bluetooth/bcm203x.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/bcm203x.c 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,309 @@ >+/* >+ * >+ * Broadcom Blutonium firmware driver >+ * >+ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> >+ * >+ * >+ * 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 <linux/config.h> >+#include <linux/module.h> >+ >+#include <linux/kernel.h> >+#include <linux/init.h> >+#include <linux/slab.h> >+#include <linux/types.h> >+#include <linux/errno.h> >+#include <linux/timer.h> >+ >+#include <linux/device.h> >+#include <linux/firmware.h> >+ >+#include <linux/usb.h> >+ >+#include <net/bluetooth/bluetooth.h> >+ >+#ifndef CONFIG_BT_HCIBCM203X_DEBUG >+#undef BT_DBG >+#define BT_DBG(D...) >+#endif >+ >+#define VERSION "1.0" >+ >+static struct usb_device_id bcm203x_table[] = { >+ /* Broadcom Blutonium (BCM2033) */ >+ { USB_DEVICE(0x0a5c, 0x2033) }, >+ >+ { } /* Terminating entry */ >+}; >+ >+MODULE_DEVICE_TABLE(usb, bcm203x_table); >+ >+ >+#define BCM203X_ERROR 0 >+#define BCM203X_RESET 1 >+#define BCM203X_LOAD_MINIDRV 2 >+#define BCM203X_SELECT_MEMORY 3 >+#define BCM203X_CHECK_MEMORY 4 >+#define BCM203X_LOAD_FIRMWARE 5 >+#define BCM203X_CHECK_FIRMWARE 6 >+ >+#define BCM203X_IN_EP 0x81 >+#define BCM203X_OUT_EP 0x02 >+ >+struct bcm203x_data { >+ struct usb_device *udev; >+ >+ unsigned long state; >+ >+ struct timer_list timer; >+ >+ struct urb *urb; >+ unsigned char buffer[4096]; >+ >+ unsigned char *fw_data; >+ unsigned int fw_size; >+ unsigned int fw_sent; >+}; >+ >+static void bcm203x_complete(struct urb *urb, struct pt_regs *regs) >+{ >+ struct bcm203x_data *data = urb->context; >+ struct usb_device *udev = urb->dev; >+ int len; >+ >+ BT_DBG("udev %p urb %p", udev, urb); >+ >+ if (urb->status) { >+ BT_ERR("URB failed with status %d", urb->status); >+ data->state = BCM203X_ERROR; >+ return; >+ } >+ >+ switch (data->state) { >+ case BCM203X_LOAD_MINIDRV: >+ memcpy(data->buffer, "#", 1); >+ >+ usb_fill_bulk_urb(urb, udev, >+ usb_sndbulkpipe(udev, BCM203X_OUT_EP), >+ data->buffer, 1, bcm203x_complete, data); >+ >+ data->state = BCM203X_SELECT_MEMORY; >+ >+ mod_timer(&data->timer, jiffies + (HZ / 10)); >+ break; >+ >+ case BCM203X_SELECT_MEMORY: >+ usb_fill_int_urb(urb, udev, >+ usb_rcvintpipe(udev, BCM203X_IN_EP), >+ data->buffer, 32, bcm203x_complete, data, 1); >+ >+ data->state = BCM203X_CHECK_MEMORY; >+ >+ if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) >+ BT_ERR("Can't submit URB"); >+ break; >+ >+ case BCM203X_CHECK_MEMORY: >+ if (data->buffer[0] != '#') { >+ BT_ERR("Memory select failed"); >+ data->state = BCM203X_ERROR; >+ break; >+ } >+ >+ data->state = BCM203X_LOAD_FIRMWARE; >+ >+ case BCM203X_LOAD_FIRMWARE: >+ if (data->fw_sent == data->fw_size) { >+ usb_fill_int_urb(urb, udev, >+ usb_rcvintpipe(udev, BCM203X_IN_EP), >+ data->buffer, 32, >+ bcm203x_complete, data, 1); >+ >+ data->state = BCM203X_CHECK_FIRMWARE; >+ } else { >+ len = min_t(uint, data->fw_size - data->fw_sent, >+ sizeof(data->buffer)); >+ >+ usb_fill_bulk_urb(urb, udev, >+ usb_sndbulkpipe(udev, BCM203X_OUT_EP), >+ data->fw_data + data->fw_sent, len, >+ bcm203x_complete, data); >+ >+ data->fw_sent += len; >+ } >+ >+ if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) >+ BT_ERR("Can't submit URB"); >+ break; >+ >+ case BCM203X_CHECK_FIRMWARE: >+ if (data->buffer[0] != '.') { >+ BT_ERR("Firmware loading failed"); >+ data->state = BCM203X_ERROR; >+ break; >+ } >+ >+ data->state = BCM203X_RESET; >+ break; >+ } >+} >+ >+static void bcm203x_timer(unsigned long user_data) >+{ >+ struct bcm203x_data *data = (struct bcm203x_data *) user_data; >+ >+ if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) >+ BT_ERR("Can't submit URB"); >+} >+ >+static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) >+{ >+ const struct firmware *firmware; >+ struct usb_device *udev = interface_to_usbdev(intf); >+ struct bcm203x_data *data; >+ >+ BT_DBG("intf %p id %p", intf, id); >+ >+ if (intf->altsetting->desc.bInterfaceNumber != 0) >+ return -ENODEV; >+ >+ data = kmalloc(sizeof(*data), GFP_KERNEL); >+ if (!data) { >+ BT_ERR("Can't allocate memory for data structure"); >+ return -ENOMEM; >+ } >+ >+ memset(data, 0, sizeof(*data)); >+ >+ data->udev = udev; >+ data->state = BCM203X_LOAD_MINIDRV; >+ >+ data->urb = usb_alloc_urb(0, GFP_KERNEL); >+ if (!data->urb) { >+ BT_ERR("Can't allocate URB"); >+ kfree(data); >+ return -ENOMEM; >+ } >+ >+ if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { >+ BT_ERR("Mini driver request failed"); >+ usb_free_urb(data->urb); >+ kfree(data); >+ return -EIO; >+ } >+ >+ BT_DBG("minidrv data %p size %d", firmware->data, firmware->size); >+ >+ if (firmware->size > sizeof(data->buffer)) { >+ BT_ERR("Mini driver exceeds size of buffer"); >+ release_firmware(firmware); >+ usb_free_urb(data->urb); >+ kfree(data); >+ return -EIO; >+ } >+ >+ memcpy(data->buffer, firmware->data, firmware->size); >+ >+ usb_fill_bulk_urb(data->urb, udev, >+ usb_sndbulkpipe(udev, BCM203X_OUT_EP), >+ data->buffer, firmware->size, bcm203x_complete, data); >+ >+ release_firmware(firmware); >+ >+ if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { >+ BT_ERR("Firmware request failed"); >+ usb_free_urb(data->urb); >+ kfree(data); >+ return -EIO; >+ } >+ >+ BT_DBG("firmware data %p size %d", firmware->data, firmware->size); >+ >+ data->fw_data = kmalloc(firmware->size, GFP_KERNEL); >+ if (!data->fw_data) { >+ BT_ERR("Can't allocate memory for firmware image"); >+ usb_free_urb(data->urb); >+ kfree(data); >+ return -ENOMEM; >+ } >+ >+ memcpy(data->fw_data, firmware->data, firmware->size); >+ data->fw_size = firmware->size; >+ data->fw_sent = 0; >+ >+ release_firmware(firmware); >+ >+ init_timer(&data->timer); >+ data->timer.function = bcm203x_timer; >+ data->timer.data = (unsigned long) data; >+ >+ usb_set_intfdata(intf, data); >+ >+ mod_timer(&data->timer, jiffies + HZ); >+ >+ return 0; >+} >+ >+static void bcm203x_disconnect(struct usb_interface *intf) >+{ >+ struct bcm203x_data *data = usb_get_intfdata(intf); >+ >+ BT_DBG("intf %p", intf); >+ >+ usb_unlink_urb(data->urb); >+ >+ usb_set_intfdata(intf, NULL); >+ >+ usb_free_urb(data->urb); >+ kfree(data->fw_data); >+ kfree(data); >+} >+ >+static struct usb_driver bcm203x_driver = { >+ .owner = THIS_MODULE, >+ .name = "bcm203x", >+ .probe = bcm203x_probe, >+ .disconnect = bcm203x_disconnect, >+ .id_table = bcm203x_table, >+}; >+ >+static int __init bcm203x_init(void) >+{ >+ int err; >+ >+ BT_INFO("Broadcom Blutonium firmware driver ver %s", VERSION); >+ >+ err = usb_register(&bcm203x_driver); >+ if (err < 0) >+ BT_ERR("Failed to register USB driver"); >+ >+ return err; >+} >+ >+static void __exit bcm203x_cleanup(void) >+{ >+ usb_deregister(&bcm203x_driver); >+} >+ >+module_init(bcm203x_init); >+module_exit(bcm203x_cleanup); >+ >+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); >+MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); >+MODULE_LICENSE("GPL"); >diff -urN linux-2.6.0/drivers/bluetooth/bfusb.c linux-2.6.0-mh2/drivers/bluetooth/bfusb.c >--- linux-2.6.0/drivers/bluetooth/bfusb.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/bfusb.c 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,782 @@ >+/* >+ * >+ * AVM BlueFRITZ! USB driver >+ * >+ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> >+ * >+ * >+ * 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 <linux/config.h> >+#include <linux/module.h> >+ >+#include <linux/kernel.h> >+#include <linux/init.h> >+#include <linux/slab.h> >+#include <linux/types.h> >+#include <linux/sched.h> >+#include <linux/errno.h> >+#include <linux/skbuff.h> >+ >+#include <linux/device.h> >+#include <linux/firmware.h> >+ >+#include <linux/usb.h> >+ >+#include <net/bluetooth/bluetooth.h> >+#include <net/bluetooth/hci_core.h> >+ >+#ifndef CONFIG_BT_HCIBFUSB_DEBUG >+#undef BT_DBG >+#define BT_DBG(D...) >+#endif >+ >+#define VERSION "1.1" >+ >+static struct usb_driver bfusb_driver; >+ >+static struct usb_device_id bfusb_table[] = { >+ /* AVM BlueFRITZ! USB */ >+ { USB_DEVICE(0x057c, 0x2200) }, >+ >+ { } /* Terminating entry */ >+}; >+ >+MODULE_DEVICE_TABLE(usb, bfusb_table); >+ >+ >+#define BFUSB_MAX_BLOCK_SIZE 256 >+ >+#define BFUSB_BLOCK_TIMEOUT (HZ * 3) >+ >+#define BFUSB_TX_PROCESS 1 >+#define BFUSB_TX_WAKEUP 2 >+ >+#define BFUSB_MAX_BULK_TX 2 >+#define BFUSB_MAX_BULK_RX 2 >+ >+struct bfusb { >+ struct hci_dev hdev; >+ >+ unsigned long state; >+ >+ struct usb_device *udev; >+ >+ unsigned int bulk_in_ep; >+ unsigned int bulk_out_ep; >+ unsigned int bulk_pkt_size; >+ >+ rwlock_t lock; >+ >+ struct sk_buff_head transmit_q; >+ >+ struct sk_buff *reassembly; >+ >+ atomic_t pending_tx; >+ struct sk_buff_head pending_q; >+ struct sk_buff_head completed_q; >+}; >+ >+struct bfusb_scb { >+ struct urb *urb; >+}; >+ >+static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs); >+static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs); >+ >+static struct urb *bfusb_get_completed(struct bfusb *bfusb) >+{ >+ struct sk_buff *skb; >+ struct urb *urb = NULL; >+ >+ BT_DBG("bfusb %p", bfusb); >+ >+ skb = skb_dequeue(&bfusb->completed_q); >+ if (skb) { >+ urb = ((struct bfusb_scb *) skb->cb)->urb; >+ kfree_skb(skb); >+ } >+ >+ return urb; >+} >+ >+static inline void bfusb_unlink_urbs(struct bfusb *bfusb) >+{ >+ struct sk_buff *skb; >+ struct urb *urb; >+ >+ BT_DBG("bfusb %p", bfusb); >+ >+ while ((skb = skb_dequeue(&bfusb->pending_q))) { >+ urb = ((struct bfusb_scb *) skb->cb)->urb; >+ usb_unlink_urb(urb); >+ skb_queue_tail(&bfusb->completed_q, skb); >+ } >+ >+ while ((urb = bfusb_get_completed(bfusb))) >+ usb_free_urb(urb); >+} >+ >+ >+static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb) >+{ >+ struct bfusb_scb *scb = (void *) skb->cb; >+ struct urb *urb = bfusb_get_completed(bfusb); >+ int err, pipe; >+ >+ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len); >+ >+ if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) >+ return -ENOMEM; >+ >+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); >+ >+ usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, skb->len, >+ bfusb_tx_complete, skb); >+ >+ scb->urb = urb; >+ >+ skb_queue_tail(&bfusb->pending_q, skb); >+ >+ err = usb_submit_urb(urb, GFP_ATOMIC); >+ if (err) { >+ BT_ERR("%s bulk tx submit failed urb %p err %d", >+ bfusb->hdev.name, urb, err); >+ skb_unlink(skb); >+ usb_free_urb(urb); >+ } else >+ atomic_inc(&bfusb->pending_tx); >+ >+ return err; >+} >+ >+static void bfusb_tx_wakeup(struct bfusb *bfusb) >+{ >+ struct sk_buff *skb; >+ >+ BT_DBG("bfusb %p", bfusb); >+ >+ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) { >+ set_bit(BFUSB_TX_WAKEUP, &bfusb->state); >+ return; >+ } >+ >+ do { >+ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state); >+ >+ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) && >+ (skb = skb_dequeue(&bfusb->transmit_q))) { >+ if (bfusb_send_bulk(bfusb, skb) < 0) { >+ skb_queue_head(&bfusb->transmit_q, skb); >+ break; >+ } >+ } >+ >+ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state)); >+ >+ clear_bit(BFUSB_TX_PROCESS, &bfusb->state); >+} >+ >+static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs) >+{ >+ struct sk_buff *skb = (struct sk_buff *) urb->context; >+ struct bfusb *bfusb = (struct bfusb *) skb->dev; >+ >+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); >+ >+ atomic_dec(&bfusb->pending_tx); >+ >+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) >+ return; >+ >+ if (!urb->status) >+ bfusb->hdev.stat.byte_tx += skb->len; >+ else >+ bfusb->hdev.stat.err_tx++; >+ >+ read_lock(&bfusb->lock); >+ >+ skb_unlink(skb); >+ skb_queue_tail(&bfusb->completed_q, skb); >+ >+ bfusb_tx_wakeup(bfusb); >+ >+ read_unlock(&bfusb->lock); >+} >+ >+ >+static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb) >+{ >+ struct bfusb_scb *scb; >+ struct sk_buff *skb; >+ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32; >+ >+ BT_DBG("bfusb %p urb %p", bfusb, urb); >+ >+ if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) >+ return -ENOMEM; >+ >+ if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) { >+ usb_free_urb(urb); >+ return -ENOMEM; >+ } >+ >+ skb->dev = (void *) bfusb; >+ >+ scb = (struct bfusb_scb *) skb->cb; >+ scb->urb = urb; >+ >+ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep); >+ >+ usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size, >+ bfusb_rx_complete, skb); >+ >+ skb_queue_tail(&bfusb->pending_q, skb); >+ >+ err = usb_submit_urb(urb, GFP_ATOMIC); >+ if (err) { >+ BT_ERR("%s bulk rx submit failed urb %p err %d", >+ bfusb->hdev.name, urb, err); >+ skb_unlink(skb); >+ kfree_skb(skb); >+ usb_free_urb(urb); >+ } >+ >+ return err; >+} >+ >+static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len) >+{ >+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len); >+ >+ if (hdr & 0x10) { >+ BT_ERR("%s error in block", bfusb->hdev.name); >+ if (bfusb->reassembly) >+ kfree_skb(bfusb->reassembly); >+ bfusb->reassembly = NULL; >+ return -EIO; >+ } >+ >+ if (hdr & 0x04) { >+ struct sk_buff *skb; >+ unsigned char pkt_type; >+ int pkt_len = 0; >+ >+ if (bfusb->reassembly) { >+ BT_ERR("%s unexpected start block", bfusb->hdev.name); >+ kfree_skb(bfusb->reassembly); >+ bfusb->reassembly = NULL; >+ } >+ >+ if (len < 1) { >+ BT_ERR("%s no packet type found", bfusb->hdev.name); >+ return -EPROTO; >+ } >+ >+ pkt_type = *data++; len--; >+ >+ switch (pkt_type) { >+ case HCI_EVENT_PKT: >+ if (len >= HCI_EVENT_HDR_SIZE) { >+ struct hci_event_hdr *hdr = (struct hci_event_hdr *) data; >+ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; >+ } else { >+ BT_ERR("%s event block is too short", bfusb->hdev.name); >+ return -EILSEQ; >+ } >+ break; >+ >+ case HCI_ACLDATA_PKT: >+ if (len >= HCI_ACL_HDR_SIZE) { >+ struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data; >+ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen); >+ } else { >+ BT_ERR("%s data block is too short", bfusb->hdev.name); >+ return -EILSEQ; >+ } >+ break; >+ >+ case HCI_SCODATA_PKT: >+ if (len >= HCI_SCO_HDR_SIZE) { >+ struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data; >+ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen; >+ } else { >+ BT_ERR("%s audio block is too short", bfusb->hdev.name); >+ return -EILSEQ; >+ } >+ break; >+ } >+ >+ skb = bt_skb_alloc(pkt_len, GFP_ATOMIC); >+ if (!skb) { >+ BT_ERR("%s no memory for the packet", bfusb->hdev.name); >+ return -ENOMEM; >+ } >+ >+ skb->dev = (void *) &bfusb->hdev; >+ skb->pkt_type = pkt_type; >+ >+ bfusb->reassembly = skb; >+ } else { >+ if (!bfusb->reassembly) { >+ BT_ERR("%s unexpected continuation block", bfusb->hdev.name); >+ return -EIO; >+ } >+ } >+ >+ if (len > 0) >+ memcpy(skb_put(bfusb->reassembly, len), data, len); >+ >+ if (hdr & 0x08) { >+ hci_recv_frame(bfusb->reassembly); >+ bfusb->reassembly = NULL; >+ } >+ >+ return 0; >+} >+ >+static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs) >+{ >+ struct sk_buff *skb = (struct sk_buff *) urb->context; >+ struct bfusb *bfusb = (struct bfusb *) skb->dev; >+ unsigned char *buf = urb->transfer_buffer; >+ int count = urb->actual_length; >+ int err, hdr, len; >+ >+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); >+ >+ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) >+ return; >+ >+ read_lock(&bfusb->lock); >+ >+ if (urb->status || !count) >+ goto resubmit; >+ >+ bfusb->hdev.stat.byte_rx += count; >+ >+ skb_put(skb, count); >+ >+ while (count) { >+ hdr = buf[0] | (buf[1] << 8); >+ >+ if (hdr & 0x4000) { >+ len = 0; >+ count -= 2; >+ buf += 2; >+ } else { >+ len = (buf[2] == 0) ? 256 : buf[2]; >+ count -= 3; >+ buf += 3; >+ } >+ >+ if (count < len) { >+ BT_ERR("%s block extends over URB buffer ranges", >+ bfusb->hdev.name); >+ } >+ >+ if ((hdr & 0xe1) == 0xc1) >+ bfusb_recv_block(bfusb, hdr, buf, len); >+ >+ count -= len; >+ buf += len; >+ } >+ >+ skb_unlink(skb); >+ kfree_skb(skb); >+ >+ bfusb_rx_submit(bfusb, urb); >+ >+ read_unlock(&bfusb->lock); >+ >+ return; >+ >+resubmit: >+ urb->dev = bfusb->udev; >+ >+ err = usb_submit_urb(urb, GFP_ATOMIC); >+ if (err) { >+ BT_ERR("%s bulk resubmit failed urb %p err %d", >+ bfusb->hdev.name, urb, err); >+ } >+ >+ read_unlock(&bfusb->lock); >+} >+ >+ >+static int bfusb_open(struct hci_dev *hdev) >+{ >+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; >+ unsigned long flags; >+ int i, err; >+ >+ BT_DBG("hdev %p bfusb %p", hdev, bfusb); >+ >+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) >+ return 0; >+ >+ write_lock_irqsave(&bfusb->lock, flags); >+ >+ err = bfusb_rx_submit(bfusb, NULL); >+ if (!err) { >+ for (i = 1; i < BFUSB_MAX_BULK_RX; i++) >+ bfusb_rx_submit(bfusb, NULL); >+ } else { >+ clear_bit(HCI_RUNNING, &hdev->flags); >+ } >+ >+ write_unlock_irqrestore(&bfusb->lock, flags); >+ >+ return err; >+} >+ >+static int bfusb_flush(struct hci_dev *hdev) >+{ >+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; >+ >+ BT_DBG("hdev %p bfusb %p", hdev, bfusb); >+ >+ skb_queue_purge(&bfusb->transmit_q); >+ >+ return 0; >+} >+ >+static int bfusb_close(struct hci_dev *hdev) >+{ >+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; >+ unsigned long flags; >+ >+ BT_DBG("hdev %p bfusb %p", hdev, bfusb); >+ >+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) >+ return 0; >+ >+ write_lock_irqsave(&bfusb->lock, flags); >+ write_unlock_irqrestore(&bfusb->lock, flags); >+ >+ bfusb_unlink_urbs(bfusb); >+ bfusb_flush(hdev); >+ >+ return 0; >+} >+ >+static int bfusb_send_frame(struct sk_buff *skb) >+{ >+ struct hci_dev *hdev = (struct hci_dev *) skb->dev; >+ struct bfusb *bfusb; >+ struct sk_buff *nskb; >+ unsigned char buf[3]; >+ int sent = 0, size, count; >+ >+ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len); >+ >+ if (!hdev) { >+ BT_ERR("Frame for unknown HCI device (hdev=NULL)"); >+ return -ENODEV; >+ } >+ >+ if (!test_bit(HCI_RUNNING, &hdev->flags)) >+ return -EBUSY; >+ >+ bfusb = (struct bfusb *) hdev->driver_data; >+ >+ switch (skb->pkt_type) { >+ case HCI_COMMAND_PKT: >+ hdev->stat.cmd_tx++; >+ break; >+ case HCI_ACLDATA_PKT: >+ hdev->stat.acl_tx++; >+ break; >+ case HCI_SCODATA_PKT: >+ hdev->stat.sco_tx++; >+ break; >+ }; >+ >+ /* Prepend skb with frame type */ >+ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); >+ >+ count = skb->len; >+ >+ /* Max HCI frame size seems to be 1511 + 1 */ >+ if (!(nskb = bt_skb_alloc(count + 32, GFP_ATOMIC))) { >+ BT_ERR("Can't allocate memory for new packet"); >+ return -ENOMEM; >+ } >+ >+ nskb->dev = (void *) bfusb; >+ >+ while (count) { >+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE); >+ >+ buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0); >+ buf[1] = 0x00; >+ buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; >+ >+ memcpy(skb_put(nskb, 3), buf, 3); >+ memcpy(skb_put(nskb, size), skb->data + sent, size); >+ >+ sent += size; >+ count -= size; >+ } >+ >+ /* Don't send frame with multiple size of bulk max packet */ >+ if ((nskb->len % bfusb->bulk_pkt_size) == 0) { >+ buf[0] = 0xdd; >+ buf[1] = 0x00; >+ memcpy(skb_put(nskb, 2), buf, 2); >+ } >+ >+ read_lock(&bfusb->lock); >+ >+ skb_queue_tail(&bfusb->transmit_q, nskb); >+ bfusb_tx_wakeup(bfusb); >+ >+ read_unlock(&bfusb->lock); >+ >+ kfree_skb(skb); >+ >+ return 0; >+} >+ >+static void bfusb_destruct(struct hci_dev *hdev) >+{ >+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; >+ >+ BT_DBG("hdev %p bfusb %p", hdev, bfusb); >+ >+ kfree(bfusb); >+} >+ >+static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) >+{ >+ return -ENOIOCTLCMD; >+} >+ >+ >+static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count) >+{ >+ unsigned char *buf; >+ int err, pipe, len, size, sent = 0; >+ >+ BT_DBG("bfusb %p udev %p", bfusb, bfusb->udev); >+ >+ BT_INFO("BlueFRITZ! USB loading firmware"); >+ >+ pipe = usb_sndctrlpipe(bfusb->udev, 0); >+ >+ if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, >+ 0, 1, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT) < 0) { >+ BT_ERR("Can't change to loading configuration"); >+ return -EBUSY; >+ } >+ >+ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); >+ if (!buf) { >+ BT_ERR("Can't allocate memory chunk for firmware"); >+ return -ENOMEM; >+ } >+ >+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); >+ >+ while (count) { >+ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3); >+ >+ memcpy(buf, firmware + sent, size); >+ >+ err = usb_bulk_msg(bfusb->udev, pipe, buf, size, >+ &len, BFUSB_BLOCK_TIMEOUT); >+ >+ if (err || (len != size)) { >+ BT_ERR("Error in firmware loading"); >+ goto error; >+ } >+ >+ sent += size; >+ count -= size; >+ } >+ >+ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0, >+ &len, BFUSB_BLOCK_TIMEOUT)) < 0) { >+ BT_ERR("Error in null packet request"); >+ goto error; >+ } >+ >+ pipe = usb_sndctrlpipe(bfusb->udev, 0); >+ >+ if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, >+ 0, 2, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) { >+ BT_ERR("Can't change to running configuration"); >+ goto error; >+ } >+ >+ BT_INFO("BlueFRITZ! USB device ready"); >+ >+ kfree(buf); >+ return 0; >+ >+error: >+ kfree(buf); >+ >+ pipe = usb_sndctrlpipe(bfusb->udev, 0); >+ >+ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, >+ 0, 0, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); >+ >+ return err; >+} >+ >+static int bfusb_probe(struct usb_interface *iface, const struct usb_device_id *id) >+{ >+ const struct firmware *firmware; >+ struct usb_device *udev = interface_to_usbdev(iface); >+ struct usb_host_endpoint *bulk_out_ep; >+ struct usb_host_endpoint *bulk_in_ep; >+ struct hci_dev *hdev; >+ struct bfusb *bfusb; >+ >+ BT_DBG("iface %p id %p", iface, id); >+ >+ /* Check number of endpoints */ >+ if (iface->altsetting[0].desc.bNumEndpoints < 2) >+ return -EIO; >+ >+ bulk_out_ep = &iface->altsetting[0].endpoint[0]; >+ bulk_in_ep = &iface->altsetting[0].endpoint[1]; >+ >+ if (!bulk_out_ep || !bulk_in_ep) { >+ BT_ERR("Bulk endpoints not found"); >+ goto done; >+ } >+ >+ /* Initialize control structure and load firmware */ >+ if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) { >+ BT_ERR("Can't allocate memory for control structure"); >+ goto done; >+ } >+ >+ memset(bfusb, 0, sizeof(struct bfusb)); >+ >+ bfusb->udev = udev; >+ bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress; >+ bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress; >+ bfusb->bulk_pkt_size = bulk_out_ep->desc.wMaxPacketSize; >+ >+ bfusb->lock = RW_LOCK_UNLOCKED; >+ >+ bfusb->reassembly = NULL; >+ >+ skb_queue_head_init(&bfusb->transmit_q); >+ skb_queue_head_init(&bfusb->pending_q); >+ skb_queue_head_init(&bfusb->completed_q); >+ >+ if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) { >+ BT_ERR("Firmware request failed"); >+ goto error; >+ } >+ >+ BT_DBG("firmware data %p size %d", firmware->data, firmware->size); >+ >+ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) { >+ BT_ERR("Firmware loading failed"); >+ goto release; >+ } >+ >+ release_firmware(firmware); >+ >+ /* Initialize and register HCI device */ >+ hdev = &bfusb->hdev; >+ >+ hdev->type = HCI_USB; >+ hdev->driver_data = bfusb; >+ >+ hdev->open = bfusb_open; >+ hdev->close = bfusb_close; >+ hdev->flush = bfusb_flush; >+ hdev->send = bfusb_send_frame; >+ hdev->destruct = bfusb_destruct; >+ hdev->ioctl = bfusb_ioctl; >+ >+ hdev->owner = THIS_MODULE; >+ >+ if (hci_register_dev(hdev) < 0) { >+ BT_ERR("Can't register HCI device"); >+ goto error; >+ } >+ >+ usb_set_intfdata(iface, bfusb); >+ >+ return 0; >+ >+release: >+ release_firmware(firmware); >+ >+error: >+ kfree(bfusb); >+ >+done: >+ return -EIO; >+} >+ >+static void bfusb_disconnect(struct usb_interface *iface) >+{ >+ struct bfusb *bfusb = usb_get_intfdata(iface); >+ struct hci_dev *hdev = &bfusb->hdev; >+ >+ BT_DBG("iface %p", iface); >+ >+ if (!hdev) >+ return; >+ >+ usb_set_intfdata(iface, NULL); >+ >+ bfusb_close(hdev); >+ >+ if (hci_unregister_dev(hdev) < 0) >+ BT_ERR("Can't unregister HCI device %s", hdev->name); >+} >+ >+static struct usb_driver bfusb_driver = { >+ .owner = THIS_MODULE, >+ .name = "bfusb", >+ .probe = bfusb_probe, >+ .disconnect = bfusb_disconnect, >+ .id_table = bfusb_table, >+}; >+ >+static int __init bfusb_init(void) >+{ >+ int err; >+ >+ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION); >+ >+ if ((err = usb_register(&bfusb_driver)) < 0) >+ BT_ERR("Failed to register BlueFRITZ! USB driver"); >+ >+ return err; >+} >+ >+static void __exit bfusb_cleanup(void) >+{ >+ usb_deregister(&bfusb_driver); >+} >+ >+module_init(bfusb_init); >+module_exit(bfusb_cleanup); >+ >+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); >+MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); >+MODULE_LICENSE("GPL"); >diff -urN linux-2.6.0/drivers/bluetooth/bluecard_cs.c linux-2.6.0-mh2/drivers/bluetooth/bluecard_cs.c >--- linux-2.6.0/drivers/bluetooth/bluecard_cs.c 2003-12-18 03:58:49.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/bluecard_cs.c 2004-01-02 11:46:31.000000000 +0100 >@@ -499,7 +499,7 @@ > } > > >-void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) >+static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) > { > bluecard_info_t *info = dev_inst; > unsigned int iobase; >@@ -507,11 +507,11 @@ > > if (!info) { > printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq); >- return; >+ return IRQ_NONE; > } > > if (!test_bit(CARD_READY, &(info->hw_state))) >- return; >+ return IRQ_NONE; > > iobase = info->link.io.BasePort1; > >@@ -556,6 +556,8 @@ > outb(info->ctrl_reg, iobase + REG_CONTROL); > > spin_unlock(&(info->lock)); >+ >+ return IRQ_HANDLED; > } > > >diff -urN linux-2.6.0/drivers/bluetooth/bt3c_cs.c linux-2.6.0-mh2/drivers/bluetooth/bt3c_cs.c >--- linux-2.6.0/drivers/bluetooth/bt3c_cs.c 2003-12-18 03:59:55.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/bt3c_cs.c 2004-01-02 11:46:31.000000000 +0100 >@@ -355,7 +355,7 @@ > } > > >-void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) >+static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) > { > bt3c_info_t *info = dev_inst; > unsigned int iobase; >@@ -363,7 +363,7 @@ > > if (!info) { > printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq); >- return; >+ return IRQ_NONE; > } > > iobase = info->link.io.BasePort1; >@@ -396,6 +396,8 @@ > } > > spin_unlock(&(info->lock)); >+ >+ return IRQ_HANDLED; > } > > >diff -urN linux-2.6.0/drivers/bluetooth/btuart_cs.c linux-2.6.0-mh2/drivers/bluetooth/btuart_cs.c >--- linux-2.6.0/drivers/bluetooth/btuart_cs.c 2003-12-18 03:59:55.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/btuart_cs.c 2004-01-02 11:46:31.000000000 +0100 >@@ -301,7 +301,7 @@ > } > > >-void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) >+static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) > { > btuart_info_t *info = dev_inst; > unsigned int iobase; >@@ -310,7 +310,7 @@ > > if (!info) { > printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq); >- return; >+ return IRQ_NONE; > } > > iobase = info->link.io.BasePort1; >@@ -351,6 +351,8 @@ > } > > spin_unlock(&(info->lock)); >+ >+ return IRQ_HANDLED; > } > > >diff -urN linux-2.6.0/drivers/bluetooth/dtl1_cs.c linux-2.6.0-mh2/drivers/bluetooth/dtl1_cs.c >--- linux-2.6.0/drivers/bluetooth/dtl1_cs.c 2003-12-18 03:58:46.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/dtl1_cs.c 2004-01-02 11:46:31.000000000 +0100 >@@ -304,7 +304,7 @@ > } > > >-void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) >+static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) > { > dtl1_info_t *info = dev_inst; > unsigned int iobase; >@@ -314,7 +314,7 @@ > > if (!info) { > printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); >- return; >+ return IRQ_NONE; > } > > iobase = info->link.io.BasePort1; >@@ -363,6 +363,8 @@ > } > > spin_unlock(&(info->lock)); >+ >+ return IRQ_HANDLED; > } > > >diff -urN linux-2.6.0/drivers/bluetooth/hci_usb.c linux-2.6.0-mh2/drivers/bluetooth/hci_usb.c >--- linux-2.6.0/drivers/bluetooth/hci_usb.c 2003-12-18 03:59:40.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/hci_usb.c 2004-01-02 11:46:31.000000000 +0100 >@@ -62,7 +62,7 @@ > #define BT_DMP( A... ) > #endif > >-#ifndef CONFIG_BT_USB_ZERO_PACKET >+#ifndef CONFIG_BT_HCIUSB_ZERO_PACKET > #undef URB_ZERO_PACKET > #define URB_ZERO_PACKET 0 > #endif >@@ -70,12 +70,21 @@ > static struct usb_driver hci_usb_driver; > > static struct usb_device_id bluetooth_ids[] = { >+ /* Broadcom BCM2033 without firmware */ >+ { USB_DEVICE(0x0a5c, 0x2033), driver_info: HCI_IGNORE }, >+ >+ /* Digianswer device */ >+ { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER }, >+ > /* Generic Bluetooth USB device */ > { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, > > /* Ericsson with non-standard id */ > { USB_DEVICE(0x0bdb, 0x1002) }, > >+ /* ALPS Module with non-standard id */ >+ { USB_DEVICE(0x044e, 0x3002) }, >+ > /* Bluetooth Ultraport Module from IBM */ > { USB_DEVICE(0x04bf, 0x030a) }, > >@@ -84,13 +93,6 @@ > > MODULE_DEVICE_TABLE (usb, bluetooth_ids); > >-static struct usb_device_id ignore_ids[] = { >- /* Broadcom BCM2033 without firmware */ >- { USB_DEVICE(0x0a5c, 0x2033) }, >- >- { } /* Terminating entry */ >-}; >- > struct _urb *_urb_alloc(int isoc, int gfp) > { > struct _urb *_urb = kmalloc(sizeof(struct _urb) + >@@ -134,7 +136,7 @@ > return _urb_dequeue(__completed_q(husb, type)); > } > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > static void __fill_isoc_desc(struct urb *urb, int len, int mtu) > { > int offset = 0, i; >@@ -232,7 +234,7 @@ > return err; > } > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > static int hci_usb_isoc_rx_submit(struct hci_usb *husb) > { > struct _urb *_urb; >@@ -301,9 +303,10 @@ > for (i = 0; i < HCI_MAX_BULK_RX; i++) > hci_usb_bulk_rx_submit(husb); > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > if (husb->isoc_iface) >- hci_usb_isoc_rx_submit(husb); >+ for (i = 0; i < HCI_MAX_ISOC_RX; i++) >+ hci_usb_isoc_rx_submit(husb); > #endif > } else { > clear_bit(HCI_RUNNING, &hdev->flags); >@@ -425,7 +428,7 @@ > } else > dr = (void *) _urb->urb.setup_packet; > >- dr->bRequestType = HCI_CTRL_REQ; >+ dr->bRequestType = husb->ctrl_req; > dr->bRequest = 0; > dr->wIndex = 0; > dr->wValue = 0; >@@ -466,7 +469,7 @@ > return __tx_submit(husb, _urb); > } > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_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); >@@ -517,10 +520,10 @@ > skb_queue_head(q, skb); > } > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > /* Process SCO queue */ > q = __transmit_q(husb, HCI_SCODATA_PKT); >- if (!atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) && >+ if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX && > (skb = skb_dequeue(q))) { > if (hci_usb_send_isoc(husb, skb) < 0) > skb_queue_head(q, skb); >@@ -576,7 +579,7 @@ > hdev->stat.acl_tx++; > break; > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > case HCI_SCODATA_PKT: > hdev->stat.sco_tx++; > break; >@@ -626,7 +629,7 @@ > } else > return -EILSEQ; > break; >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > case HCI_SCODATA_PKT: > if (count >= HCI_SCO_HDR_SIZE) { > struct hci_sco_hdr *h = data; >@@ -691,7 +694,7 @@ > goto resubmit; > > if (_urb->type == HCI_SCODATA_PKT) { >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > int i; > for (i=0; i < urb->number_of_packets; i++) { > BT_DBG("desc %d status %d offset %d len %d", i, >@@ -785,9 +788,11 @@ > > iface = udev->actconfig->interface[0]; > >- /* Check our black list */ >- if (usb_match_id(intf, ignore_ids)) >- return -EIO; >+ if (id->driver_info & HCI_IGNORE) >+ return -ENODEV; >+ >+ if (intf->altsetting->desc.bInterfaceNumber > 0) >+ return -ENODEV; > > /* Check number of endpoints */ > if (intf->altsetting[0].desc.bNumEndpoints < 3) >@@ -826,9 +831,9 @@ > bulk_out_ep[i] = ep; > break; > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > case USB_ENDPOINT_XFER_ISOC: >- if (ep->desc.wMaxPacketSize < size) >+ if (ep->desc.wMaxPacketSize < size || a > 2) > break; > size = ep->desc.wMaxPacketSize; > >@@ -852,7 +857,7 @@ > goto done; > } > >-#ifdef CONFIG_BT_USB_SCO >+#ifdef CONFIG_BT_HCIUSB_SCO > if (!isoc_in_ep[1] || !isoc_out_ep[1]) { > BT_DBG("Isoc endpoints not found"); > isoc_iface = NULL; >@@ -871,7 +876,12 @@ > husb->bulk_in_ep = bulk_in_ep[0]; > husb->intr_in_ep = intr_in_ep[0]; > >-#ifdef CONFIG_BT_USB_SCO >+ if (id->driver_info & HCI_DIGIANSWER) >+ husb->ctrl_req = HCI_DIGI_REQ; >+ else >+ husb->ctrl_req = HCI_CTRL_REQ; >+ >+#ifdef CONFIG_BT_HCIUSB_SCO > if (isoc_iface) { > BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); > if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { >diff -urN linux-2.6.0/drivers/bluetooth/hci_usb.h linux-2.6.0-mh2/drivers/bluetooth/hci_usb.h >--- linux-2.6.0/drivers/bluetooth/hci_usb.h 2003-12-18 03:59:18.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/hci_usb.h 2004-01-02 11:46:31.000000000 +0100 >@@ -35,12 +35,19 @@ > #define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ > > #define HCI_CTRL_REQ 0x20 >+#define HCI_DIGI_REQ 0x40 >+ >+#define HCI_IGNORE 0x01 >+#define HCI_DIGIANSWER 0x02 > > #define HCI_MAX_IFACE_NUM 3 > > #define HCI_MAX_BULK_TX 4 > #define HCI_MAX_BULK_RX 1 > >+#define HCI_MAX_ISOC_RX 2 >+#define HCI_MAX_ISOC_TX 2 >+ > #define HCI_MAX_ISOC_FRAMES 10 > > struct _urb_queue { >@@ -119,6 +126,8 @@ > struct usb_host_endpoint *isoc_out_ep; > struct usb_host_endpoint *isoc_in_ep; > >+ __u8 ctrl_req; >+ > struct sk_buff_head transmit_q[4]; > struct sk_buff *reassembly[4]; // Reassembly buffers > >diff -urN linux-2.6.0/drivers/bluetooth/Kconfig linux-2.6.0-mh2/drivers/bluetooth/Kconfig >--- linux-2.6.0/drivers/bluetooth/Kconfig 2003-12-18 03:58:46.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/Kconfig 2004-01-02 11:46:31.000000000 +0100 >@@ -13,22 +13,14 @@ > 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" >+config BT_HCIUSB_SCO >+ bool "SCO (voice) 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. >+ to transmit voice data with your Bluetooth USB device. > >-config BT_USB_ZERO_PACKET >- bool "USB zero packet support" >- depends on BT_HCIUSB >- help >- 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. >- Most people should say N here. >+ Say Y here to compile support for SCO over HCI USB. > > config BT_HCIUART > tristate "HCI UART driver" >@@ -65,13 +57,38 @@ > Say Y here to compile support for HCI BCSP protocol. > > config BT_HCIUART_BCSP_TXCRC >- bool "Transmit CRC with every BCSP packet" >- depends on BT_HCIUART_BCSP >- help >+ bool "Transmit CRC with every BCSP packet" >+ depends on BT_HCIUART_BCSP >+ help > If you say Y here, a 16-bit CRC checksum will be transmitted along with > every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. > This increases reliability, but slightly reduces efficiency. > >+config BT_HCIBCM203X >+ tristate "HCI BCM203x USB driver" >+ depends on USB && BT >+ select FW_LOADER >+ help >+ Bluetooth HCI BCM203x USB driver. >+ This driver provides the firmware loading mechanism for the Broadcom >+ Blutonium based devices. >+ >+ Say Y here to compile support for HCI BCM203x devices into the >+ kernel or say M to compile it as module (bcm203x). >+ >+config BT_HCIBFUSB >+ tristate "HCI BlueFRITZ! USB driver" >+ depends on USB && BT >+ select FW_LOADER >+ help >+ Bluetooth HCI BlueFRITZ! USB driver. >+ This driver provides support for Bluetooth USB devices with AVM >+ interface: >+ AVM BlueFRITZ! USB >+ >+ Say Y here to compile support for HCI BFUSB devices into the >+ kernel or say M to compile it as module (bfusb). >+ > config BT_HCIDTL1 > tristate "HCI DTL1 (PC Card) driver" > depends on PCMCIA && BT >diff -urN linux-2.6.0/drivers/bluetooth/Makefile linux-2.6.0-mh2/drivers/bluetooth/Makefile >--- linux-2.6.0/drivers/bluetooth/Makefile 2003-12-18 03:59:53.000000000 +0100 >+++ linux-2.6.0-mh2/drivers/bluetooth/Makefile 2004-01-02 11:46:31.000000000 +0100 >@@ -5,6 +5,8 @@ > obj-$(CONFIG_BT_HCIUSB) += hci_usb.o > obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o > obj-$(CONFIG_BT_HCIUART) += hci_uart.o >+obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o >+obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o > obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o > obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o > obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o >diff -urN linux-2.6.0/include/net/bluetooth/bluetooth.h linux-2.6.0-mh2/include/net/bluetooth/bluetooth.h >--- linux-2.6.0/include/net/bluetooth/bluetooth.h 2003-12-18 03:58:47.000000000 +0100 >+++ linux-2.6.0-mh2/include/net/bluetooth/bluetooth.h 2004-01-02 11:46:31.000000000 +0100 >@@ -47,7 +47,8 @@ > #define BTPROTO_HCI 1 > #define BTPROTO_SCO 2 > #define BTPROTO_RFCOMM 3 >-#define BTPROTO_BNEP 4 >+#define BTPROTO_BNEP 4 >+#define BTPROTO_CMTP 5 > > #define SOL_HCI 0 > #define SOL_L2CAP 6 >diff -urN linux-2.6.0/include/net/bluetooth/hci.h linux-2.6.0-mh2/include/net/bluetooth/hci.h >--- linux-2.6.0/include/net/bluetooth/hci.h 2003-12-18 03:59:37.000000000 +0100 >+++ linux-2.6.0-mh2/include/net/bluetooth/hci.h 2004-01-02 11:46:30.000000000 +0100 >@@ -408,6 +408,16 @@ > __u16 clock_offset; > } __attribute__ ((packed)); > >+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 >+struct inquiry_info_with_rssi { >+ bdaddr_t bdaddr; >+ __u8 pscan_rep_mode; >+ __u8 pscan_period_mode; >+ __u8 dev_class[3]; >+ __u16 clock_offset; >+ __u8 rssi; >+} __attribute__ ((packed)); >+ > #define HCI_EV_CONN_COMPLETE 0x03 > struct hci_ev_conn_complete { > __u8 status; >diff -urN linux-2.6.0/include/net/bluetooth/rfcomm.h linux-2.6.0-mh2/include/net/bluetooth/rfcomm.h >--- linux-2.6.0/include/net/bluetooth/rfcomm.h 2003-12-18 03:59:18.000000000 +0100 >+++ linux-2.6.0-mh2/include/net/bluetooth/rfcomm.h 2004-01-02 11:46:30.000000000 +0100 >@@ -167,8 +167,8 @@ > int initiator; > > /* Default DLC parameters */ >+ int cfc; > uint mtu; >- uint credits; > > struct list_head dlcs; > }; >@@ -190,7 +190,7 @@ > u8 mscex; > > uint mtu; >- uint credits; >+ uint cfc; > uint rx_credits; > uint tx_credits; > >@@ -219,6 +219,11 @@ > #define RFCOMM_MSCEX_RX 2 > #define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) > >+/* CFC states */ >+#define RFCOMM_CFC_UNKNOWN -1 >+#define RFCOMM_CFC_DISABLED 0 >+#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS >+ > extern struct task_struct *rfcomm_thread; > extern unsigned long rfcomm_event; > >diff -urN linux-2.6.0/MAINTAINERS linux-2.6.0-mh2/MAINTAINERS >--- linux-2.6.0/MAINTAINERS 2003-12-18 03:58:57.000000000 +0100 >+++ linux-2.6.0-mh2/MAINTAINERS 2004-01-02 11:46:31.000000000 +0100 >@@ -355,6 +355,12 @@ > W: http://bluez.sf.net > S: Maintained > >+BLUETOOTH CMTP LAYER >+P: Marcel Holtmann >+M: marcel@holtmann.org >+W: http://www.holtmann.org/linux/bluetooth/ >+S: Maintained >+ > BLUETOOTH HCI USB DRIVER > P: Maxim Krasnyansky > M: maxk@qualcomm.com >@@ -367,6 +373,18 @@ > W: http://bluez.sf.net > S: Maintained > >+BLUETOOTH HCI BCM203X DRIVER >+P: Marcel Holtmann >+M: marcel@holtmann.org >+W: http://www.holtmann.org/linux/bluetooth/ >+S: Maintained >+ >+BLUETOOTH HCI BFUSB DRIVER >+P: Marcel Holtmann >+M: marcel@holtmann.org >+W: http://www.holtmann.org/linux/bluetooth/ >+S: Maintained >+ > BLUETOOTH HCI DTL1 DRIVER > P: Marcel Holtmann > M: marcel@holtmann.org >diff -urN linux-2.6.0/Makefile linux-2.6.0-mh2/Makefile >--- linux-2.6.0/Makefile 2003-12-18 03:59:05.000000000 +0100 >+++ linux-2.6.0-mh2/Makefile 2004-01-02 11:46:31.000000000 +0100 >@@ -1,7 +1,7 @@ > VERSION = 2 > PATCHLEVEL = 6 > SUBLEVEL = 0 >-EXTRAVERSION = >+EXTRAVERSION = -mh2 > > # *DOCUMENTATION* > # To see a list of typical targets execute "make help" >diff -urN linux-2.6.0/net/bluetooth/af_bluetooth.c linux-2.6.0-mh2/net/bluetooth/af_bluetooth.c >--- linux-2.6.0/net/bluetooth/af_bluetooth.c 2003-12-18 03:58:17.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/af_bluetooth.c 2004-01-02 11:46:31.000000000 +0100 >@@ -59,7 +59,7 @@ > struct proc_dir_entry *proc_bt; > > /* Bluetooth sockets */ >-#define BT_MAX_PROTO 5 >+#define BT_MAX_PROTO 6 > static struct net_proto_family *bt_proto[BT_MAX_PROTO]; > > static kmem_cache_t *bt_sock_cache; >@@ -360,3 +360,4 @@ > MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); > MODULE_DESCRIPTION("Bluetooth Core ver " VERSION); > MODULE_LICENSE("GPL"); >+MODULE_ALIAS_NETPROTO(PF_BLUETOOTH); >diff -urN linux-2.6.0/net/bluetooth/bnep/core.c linux-2.6.0-mh2/net/bluetooth/bnep/core.c >--- linux-2.6.0/net/bluetooth/bnep/core.c 2003-12-18 03:59:05.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/bnep/core.c 2004-01-02 11:46:31.000000000 +0100 >@@ -707,4 +707,4 @@ > MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION); > MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>"); > MODULE_LICENSE("GPL"); >-MODULE_ALIAS_NETPROTO(PF_BLUETOOTH); >+MODULE_ALIAS("bt-proto-4"); >diff -urN linux-2.6.0/net/bluetooth/cmtp/capi.c linux-2.6.0-mh2/net/bluetooth/cmtp/capi.c >--- linux-2.6.0/net/bluetooth/cmtp/capi.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/cmtp/capi.c 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,630 @@ >+/* >+ CMTP implementation for Linux Bluetooth stack (BlueZ). >+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> >+ >+ 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; >+ >+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS >+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. >+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY >+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES >+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >+ >+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, >+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS >+ SOFTWARE IS DISCLAIMED. >+*/ >+ >+#include <linux/config.h> >+#include <linux/module.h> >+ >+#include <linux/types.h> >+#include <linux/errno.h> >+#include <linux/kernel.h> >+#include <linux/major.h> >+#include <linux/sched.h> >+#include <linux/slab.h> >+#include <linux/poll.h> >+#include <linux/fcntl.h> >+#include <linux/skbuff.h> >+#include <linux/socket.h> >+#include <linux/ioctl.h> >+#include <linux/file.h> >+#include <net/sock.h> >+ >+#include <linux/isdn/capilli.h> >+#include <linux/isdn/capicmd.h> >+#include <linux/isdn/capiutil.h> >+ >+#include "cmtp.h" >+ >+#ifndef CONFIG_BT_CMTP_DEBUG >+#undef BT_DBG >+#define BT_DBG(D...) >+#endif >+ >+#define CAPI_INTEROPERABILITY 0x20 >+ >+#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ) >+#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF) >+#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND) >+#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP) >+ >+#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2) >+#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4) >+#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2) >+#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2) >+ >+#define CAPI_FUNCTION_REGISTER 0 >+#define CAPI_FUNCTION_RELEASE 1 >+#define CAPI_FUNCTION_GET_PROFILE 2 >+#define CAPI_FUNCTION_GET_MANUFACTURER 3 >+#define CAPI_FUNCTION_GET_VERSION 4 >+#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5 >+#define CAPI_FUNCTION_MANUFACTURER 6 >+#define CAPI_FUNCTION_LOOPBACK 7 >+ >+ >+#define CMTP_MSGNUM 1 >+#define CMTP_APPLID 2 >+#define CMTP_MAPPING 3 >+ >+static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl) >+{ >+ struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL); >+ >+ BT_DBG("session %p application %p appl %d", session, app, appl); >+ >+ if (!app) >+ return NULL; >+ >+ memset(app, 0, sizeof(*app)); >+ >+ app->state = BT_OPEN; >+ app->appl = appl; >+ >+ list_add_tail(&app->list, &session->applications); >+ >+ return app; >+} >+ >+static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app) >+{ >+ BT_DBG("session %p application %p", session, app); >+ >+ if (app) { >+ list_del(&app->list); >+ kfree(app); >+ } >+} >+ >+static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value) >+{ >+ struct cmtp_application *app; >+ struct list_head *p, *n; >+ >+ list_for_each_safe(p, n, &session->applications) { >+ app = list_entry(p, struct cmtp_application, list); >+ switch (pattern) { >+ case CMTP_MSGNUM: >+ if (app->msgnum == value) >+ return app; >+ break; >+ case CMTP_APPLID: >+ if (app->appl == value) >+ return app; >+ break; >+ case CMTP_MAPPING: >+ if (app->mapping == value) >+ return app; >+ break; >+ } >+ } >+ >+ return NULL; >+} >+ >+static int cmtp_msgnum_get(struct cmtp_session *session) >+{ >+ session->msgnum++; >+ >+ if ((session->msgnum & 0xff) > 200) >+ session->msgnum = CMTP_INITIAL_MSGNUM + 1; >+ >+ return session->msgnum; >+} >+ >+ >+static void cmtp_send_interopmsg(struct cmtp_session *session, >+ __u8 subcmd, __u16 appl, __u16 msgnum, >+ __u16 function, unsigned char *buf, int len) >+{ >+ struct sk_buff *skb; >+ unsigned char *s; >+ >+ BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum); >+ >+ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) { >+ BT_ERR("Can't allocate memory for interoperability packet"); >+ return; >+ } >+ >+ s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len); >+ >+ capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len); >+ capimsg_setu16(s, 2, appl); >+ capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY); >+ capimsg_setu8 (s, 5, subcmd); >+ capimsg_setu16(s, 6, msgnum); >+ >+ /* Interoperability selector (Bluetooth Device Management) */ >+ capimsg_setu16(s, 8, 0x0001); >+ >+ capimsg_setu8 (s, 10, 3 + len); >+ capimsg_setu16(s, 11, function); >+ capimsg_setu8 (s, 13, len); >+ >+ if (len > 0) >+ memcpy(s + 14, buf, len); >+ >+ cmtp_send_capimsg(session, skb); >+} >+ >+static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb) >+{ >+ struct capi_ctr *ctrl = &session->ctrl; >+ struct cmtp_application *application; >+ __u16 appl, msgnum, func, info; >+ __u32 controller; >+ >+ BT_DBG("session %p skb %p len %d", session, skb, skb->len); >+ >+ switch (CAPIMSG_SUBCOMMAND(skb->data)) { >+ case CAPI_CONF: >+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); >+ info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); >+ >+ switch (func) { >+ case CAPI_FUNCTION_REGISTER: >+ msgnum = CAPIMSG_MSGID(skb->data); >+ >+ application = cmtp_application_get(session, CMTP_MSGNUM, msgnum); >+ if (application) { >+ application->state = BT_CONNECTED; >+ application->msgnum = 0; >+ application->mapping = CAPIMSG_APPID(skb->data); >+ wake_up_interruptible(&session->wait); >+ } >+ >+ break; >+ >+ case CAPI_FUNCTION_RELEASE: >+ appl = CAPIMSG_APPID(skb->data); >+ >+ application = cmtp_application_get(session, CMTP_MAPPING, appl); >+ if (application) { >+ application->state = BT_CLOSED; >+ application->msgnum = 0; >+ wake_up_interruptible(&session->wait); >+ } >+ >+ break; >+ >+ case CAPI_FUNCTION_GET_PROFILE: >+ controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11); >+ msgnum = CAPIMSG_MSGID(skb->data); >+ >+ if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) { >+ session->ncontroller = controller; >+ wake_up_interruptible(&session->wait); >+ break; >+ } >+ >+ if (!info && ctrl) { >+ memcpy(&ctrl->profile, >+ skb->data + CAPI_MSG_BASELEN + 11, >+ sizeof(capi_profile)); >+ session->state = BT_CONNECTED; >+ capi_ctr_ready(ctrl); >+ } >+ >+ break; >+ >+ case CAPI_FUNCTION_GET_MANUFACTURER: >+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10); >+ >+ if (!info && ctrl) { >+ strncpy(ctrl->manu, >+ skb->data + CAPI_MSG_BASELEN + 15, >+ skb->data[CAPI_MSG_BASELEN + 14]); >+ } >+ >+ break; >+ >+ case CAPI_FUNCTION_GET_VERSION: >+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); >+ >+ if (!info && ctrl) { >+ ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16); >+ ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20); >+ ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24); >+ ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28); >+ } >+ >+ break; >+ >+ case CAPI_FUNCTION_GET_SERIAL_NUMBER: >+ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); >+ >+ if (!info && ctrl) { >+ memset(ctrl->serial, 0, CAPI_SERIAL_LEN); >+ strncpy(ctrl->serial, >+ skb->data + CAPI_MSG_BASELEN + 17, >+ skb->data[CAPI_MSG_BASELEN + 16]); >+ } >+ >+ break; >+ } >+ >+ break; >+ >+ case CAPI_IND: >+ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); >+ >+ if (func == CAPI_FUNCTION_LOOPBACK) { >+ appl = CAPIMSG_APPID(skb->data); >+ msgnum = CAPIMSG_MSGID(skb->data); >+ cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, >+ skb->data + CAPI_MSG_BASELEN + 6, >+ skb->data[CAPI_MSG_BASELEN + 5]); >+ } >+ >+ break; >+ } >+ >+ kfree_skb(skb); >+} >+ >+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) >+{ >+ struct capi_ctr *ctrl = &session->ctrl; >+ struct cmtp_application *application; >+ __u16 cmd, appl; >+ __u32 contr; >+ >+ BT_DBG("session %p skb %p len %d", session, skb, skb->len); >+ >+ if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) { >+ cmtp_recv_interopmsg(session, skb); >+ return; >+ } >+ >+ if (session->flags & (1 << CMTP_LOOPBACK)) { >+ kfree_skb(skb); >+ return; >+ } >+ >+ cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)); >+ appl = CAPIMSG_APPID(skb->data); >+ contr = CAPIMSG_CONTROL(skb->data); >+ >+ application = cmtp_application_get(session, CMTP_MAPPING, appl); >+ if (application) { >+ appl = application->appl; >+ CAPIMSG_SETAPPID(skb->data, appl); >+ } else { >+ BT_ERR("Can't find application with id %d", appl); >+ kfree_skb(skb); >+ return; >+ } >+ >+ if ((contr & 0x7f) == 0x01) { >+ contr = (contr & 0xffffff80) | session->num; >+ CAPIMSG_SETCONTROL(skb->data, contr); >+ } >+ >+ if (!ctrl) { >+ BT_ERR("Can't find controller %d for message", session->num); >+ kfree_skb(skb); >+ return; >+ } >+ >+ capi_ctr_handle_message(ctrl, appl, skb); >+} >+ >+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) >+{ >+ struct cmtp_scb *scb = (void *) skb->cb; >+ >+ BT_DBG("session %p skb %p len %d", session, skb, skb->len); >+ >+ scb->id = -1; >+ scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3); >+ >+ skb_queue_tail(&session->transmit, skb); >+ >+ cmtp_schedule(session); >+} >+ >+ >+static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) >+{ >+ BT_DBG("ctrl %p data %p", ctrl, data); >+ >+ return 0; >+} >+ >+static void cmtp_reset_ctr(struct capi_ctr *ctrl) >+{ >+ struct cmtp_session *session = ctrl->driverdata; >+ >+ BT_DBG("ctrl %p", ctrl); >+ >+ capi_ctr_reseted(ctrl); >+ >+ atomic_inc(&session->terminate); >+ cmtp_schedule(session); >+} >+ >+static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) >+{ >+ DECLARE_WAITQUEUE(wait, current); >+ struct cmtp_session *session = ctrl->driverdata; >+ struct cmtp_application *application; >+ unsigned long timeo = CMTP_INTEROP_TIMEOUT; >+ unsigned char buf[8]; >+ int err = 0, nconn, want = rp->level3cnt; >+ >+ BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d", >+ ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen); >+ >+ application = cmtp_application_add(session, appl); >+ if (!application) { >+ BT_ERR("Can't allocate memory for new application"); >+ return; >+ } >+ >+ if (want < 0) >+ nconn = ctrl->profile.nbchannel * -want; >+ else >+ nconn = want; >+ >+ if (nconn == 0) >+ nconn = ctrl->profile.nbchannel; >+ >+ capimsg_setu16(buf, 0, nconn); >+ capimsg_setu16(buf, 2, rp->datablkcnt); >+ capimsg_setu16(buf, 4, rp->datablklen); >+ >+ application->state = BT_CONFIG; >+ application->msgnum = cmtp_msgnum_get(session); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum, >+ CAPI_FUNCTION_REGISTER, buf, 6); >+ >+ add_wait_queue(&session->wait, &wait); >+ while (1) { >+ set_current_state(TASK_INTERRUPTIBLE); >+ >+ if (!timeo) { >+ err = -EAGAIN; >+ break; >+ } >+ >+ if (application->state == BT_CLOSED) { >+ err = -application->err; >+ break; >+ } >+ >+ if (application->state == BT_CONNECTED) >+ break; >+ >+ if (signal_pending(current)) { >+ err = -EINTR; >+ break; >+ } >+ >+ timeo = schedule_timeout(timeo); >+ } >+ set_current_state(TASK_RUNNING); >+ remove_wait_queue(&session->wait, &wait); >+ >+ if (err) { >+ cmtp_application_del(session, application); >+ return; >+ } >+} >+ >+static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl) >+{ >+ DECLARE_WAITQUEUE(wait, current); >+ struct cmtp_session *session = ctrl->driverdata; >+ struct cmtp_application *application; >+ unsigned long timeo = CMTP_INTEROP_TIMEOUT; >+ >+ BT_DBG("ctrl %p appl %d", ctrl, appl); >+ >+ application = cmtp_application_get(session, CMTP_APPLID, appl); >+ if (!application) { >+ BT_ERR("Can't find application"); >+ return; >+ } >+ >+ application->msgnum = cmtp_msgnum_get(session); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum, >+ CAPI_FUNCTION_RELEASE, NULL, 0); >+ >+ add_wait_queue(&session->wait, &wait); >+ while (timeo) { >+ set_current_state(TASK_INTERRUPTIBLE); >+ >+ if (application->state == BT_CLOSED) >+ break; >+ >+ if (signal_pending(current)) >+ break; >+ >+ timeo = schedule_timeout(timeo); >+ } >+ set_current_state(TASK_RUNNING); >+ remove_wait_queue(&session->wait, &wait); >+ >+ cmtp_application_del(session, application); >+} >+ >+static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) >+{ >+ struct cmtp_session *session = ctrl->driverdata; >+ struct cmtp_application *application; >+ __u16 appl; >+ __u32 contr; >+ >+ BT_DBG("ctrl %p skb %p", ctrl, skb); >+ >+ appl = CAPIMSG_APPID(skb->data); >+ contr = CAPIMSG_CONTROL(skb->data); >+ >+ application = cmtp_application_get(session, CMTP_APPLID, appl); >+ if ((!application) || (application->state != BT_CONNECTED)) { >+ BT_ERR("Can't find application with id %d", appl); >+ kfree_skb(skb); >+ return CAPI_ILLAPPNR; >+ } >+ >+ CAPIMSG_SETAPPID(skb->data, application->mapping); >+ >+ if ((contr & 0x7f) == session->num) { >+ contr = (contr & 0xffffff80) | 0x01; >+ CAPIMSG_SETCONTROL(skb->data, contr); >+ } >+ >+ cmtp_send_capimsg(session, skb); >+ >+ return CAPI_NOERROR; >+} >+ >+static char *cmtp_procinfo(struct capi_ctr *ctrl) >+{ >+ return "CAPI Message Transport Protocol"; >+} >+ >+static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl) >+{ >+ struct cmtp_session *session = ctrl->driverdata; >+ struct cmtp_application *app; >+ struct list_head *p, *n; >+ int len = 0; >+ >+ len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl)); >+ len += sprintf(page + len, "addr %s\n", session->name); >+ len += sprintf(page + len, "ctrl %d\n", session->num); >+ >+ list_for_each_safe(p, n, &session->applications) { >+ app = list_entry(p, struct cmtp_application, list); >+ len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping); >+ } >+ >+ if (off + count >= len) >+ *eof = 1; >+ >+ if (len < off) >+ return 0; >+ >+ *start = page + off; >+ >+ return ((count < len - off) ? count : len - off); >+} >+ >+ >+int cmtp_attach_device(struct cmtp_session *session) >+{ >+ DECLARE_WAITQUEUE(wait, current); >+ unsigned long timeo = CMTP_INTEROP_TIMEOUT; >+ unsigned char buf[4]; >+ >+ BT_DBG("session %p", session); >+ >+ capimsg_setu32(buf, 0, 0); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM, >+ CAPI_FUNCTION_GET_PROFILE, buf, 4); >+ >+ add_wait_queue(&session->wait, &wait); >+ while (timeo) { >+ set_current_state(TASK_INTERRUPTIBLE); >+ >+ if (session->ncontroller) >+ break; >+ >+ if (signal_pending(current)) >+ break; >+ >+ timeo = schedule_timeout(timeo); >+ } >+ set_current_state(TASK_RUNNING); >+ remove_wait_queue(&session->wait, &wait); >+ >+ BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name); >+ >+ if (!timeo) >+ return -ETIMEDOUT; >+ >+ if (!session->ncontroller) >+ return -ENODEV; >+ >+ >+ if (session->ncontroller > 1) >+ BT_INFO("Setting up only CAPI controller 1"); >+ >+ session->ctrl.owner = THIS_MODULE; >+ session->ctrl.driverdata = session; >+ strcpy(session->ctrl.name, session->name); >+ >+ session->ctrl.driver_name = "cmtp"; >+ session->ctrl.load_firmware = cmtp_load_firmware; >+ session->ctrl.reset_ctr = cmtp_reset_ctr; >+ session->ctrl.register_appl = cmtp_register_appl; >+ session->ctrl.release_appl = cmtp_release_appl; >+ session->ctrl.send_message = cmtp_send_message; >+ >+ session->ctrl.procinfo = cmtp_procinfo; >+ session->ctrl.ctr_read_proc = cmtp_ctr_read_proc; >+ >+ if (attach_capi_ctr(&session->ctrl) < 0) { >+ BT_ERR("Can't attach new controller"); >+ return -EBUSY; >+ } >+ >+ session->num = session->ctrl.cnr; >+ >+ BT_DBG("session %p num %d", session, session->num); >+ >+ capimsg_setu32(buf, 0, 1); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), >+ CAPI_FUNCTION_GET_MANUFACTURER, buf, 4); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), >+ CAPI_FUNCTION_GET_VERSION, buf, 4); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), >+ CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4); >+ >+ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), >+ CAPI_FUNCTION_GET_PROFILE, buf, 4); >+ >+ return 0; >+} >+ >+void cmtp_detach_device(struct cmtp_session *session) >+{ >+ BT_DBG("session %p", session); >+ >+ detach_capi_ctr(&session->ctrl); >+} >diff -urN linux-2.6.0/net/bluetooth/cmtp/cmtp.h linux-2.6.0-mh2/net/bluetooth/cmtp/cmtp.h >--- linux-2.6.0/net/bluetooth/cmtp/cmtp.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/cmtp/cmtp.h 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,136 @@ >+/* >+ CMTP implementation for Linux Bluetooth stack (BlueZ). >+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> >+ >+ 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; >+ >+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS >+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. >+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY >+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES >+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >+ >+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, >+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS >+ SOFTWARE IS DISCLAIMED. >+*/ >+ >+#ifndef __CMTP_H >+#define __CMTP_H >+ >+#include <linux/types.h> >+#include <net/bluetooth/bluetooth.h> >+ >+#define BTNAMSIZ 18 >+ >+/* CMTP ioctl defines */ >+#define CMTPCONNADD _IOW('C', 200, int) >+#define CMTPCONNDEL _IOW('C', 201, int) >+#define CMTPGETCONNLIST _IOR('C', 210, int) >+#define CMTPGETCONNINFO _IOR('C', 211, int) >+ >+#define CMTP_LOOPBACK 0 >+ >+struct cmtp_connadd_req { >+ int sock; // Connected socket >+ __u32 flags; >+}; >+ >+struct cmtp_conndel_req { >+ bdaddr_t bdaddr; >+ __u32 flags; >+}; >+ >+struct cmtp_conninfo { >+ bdaddr_t bdaddr; >+ __u32 flags; >+ __u16 state; >+ int num; >+}; >+ >+struct cmtp_connlist_req { >+ __u32 cnum; >+ struct cmtp_conninfo *ci; >+}; >+ >+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock); >+int cmtp_del_connection(struct cmtp_conndel_req *req); >+int cmtp_get_connlist(struct cmtp_connlist_req *req); >+int cmtp_get_conninfo(struct cmtp_conninfo *ci); >+ >+/* CMTP session defines */ >+#define CMTP_INTEROP_TIMEOUT (HZ * 5) >+#define CMTP_INITIAL_MSGNUM 0xff00 >+ >+struct cmtp_session { >+ struct list_head list; >+ >+ struct socket *sock; >+ >+ bdaddr_t bdaddr; >+ >+ unsigned long state; >+ unsigned long flags; >+ >+ uint mtu; >+ >+ char name[BTNAMSIZ]; >+ >+ atomic_t terminate; >+ >+ wait_queue_head_t wait; >+ >+ int ncontroller; >+ int num; >+ struct capi_ctr ctrl; >+ >+ struct list_head applications; >+ >+ unsigned long blockids; >+ int msgnum; >+ >+ struct sk_buff_head transmit; >+ >+ struct sk_buff *reassembly[16]; >+}; >+ >+struct cmtp_application { >+ struct list_head list; >+ >+ unsigned long state; >+ int err; >+ >+ __u16 appl; >+ __u16 mapping; >+ >+ __u16 msgnum; >+}; >+ >+struct cmtp_scb { >+ int id; >+ int data; >+}; >+ >+int cmtp_attach_device(struct cmtp_session *session); >+void cmtp_detach_device(struct cmtp_session *session); >+ >+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); >+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb); >+ >+static inline void cmtp_schedule(struct cmtp_session *session) >+{ >+ struct sock *sk = session->sock->sk; >+ >+ wake_up_interruptible(sk->sk_sleep); >+} >+ >+/* CMTP init defines */ >+int cmtp_init_sockets(void); >+void cmtp_cleanup_sockets(void); >+ >+#endif /* __CMTP_H */ >diff -urN linux-2.6.0/net/bluetooth/cmtp/core.c linux-2.6.0-mh2/net/bluetooth/cmtp/core.c >--- linux-2.6.0/net/bluetooth/cmtp/core.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/cmtp/core.c 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,507 @@ >+/* >+ CMTP implementation for Linux Bluetooth stack (BlueZ). >+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> >+ >+ 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; >+ >+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS >+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. >+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY >+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES >+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >+ >+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, >+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS >+ SOFTWARE IS DISCLAIMED. >+*/ >+ >+#include <linux/config.h> >+#include <linux/module.h> >+ >+#include <linux/types.h> >+#include <linux/errno.h> >+#include <linux/kernel.h> >+#include <linux/major.h> >+#include <linux/sched.h> >+#include <linux/slab.h> >+#include <linux/poll.h> >+#include <linux/fcntl.h> >+#include <linux/skbuff.h> >+#include <linux/socket.h> >+#include <linux/ioctl.h> >+#include <linux/file.h> >+#include <linux/init.h> >+#include <net/sock.h> >+ >+#include <linux/isdn/capilli.h> >+ >+#include <net/bluetooth/bluetooth.h> >+#include <net/bluetooth/l2cap.h> >+ >+#include "cmtp.h" >+ >+#ifndef CONFIG_BT_CMTP_DEBUG >+#undef BT_DBG >+#define BT_DBG(D...) >+#endif >+ >+#define VERSION "1.0" >+ >+static DECLARE_RWSEM(cmtp_session_sem); >+static LIST_HEAD(cmtp_session_list); >+ >+static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr) >+{ >+ struct cmtp_session *session; >+ struct list_head *p; >+ >+ BT_DBG(""); >+ >+ list_for_each(p, &cmtp_session_list) { >+ session = list_entry(p, struct cmtp_session, list); >+ if (!bacmp(bdaddr, &session->bdaddr)) >+ return session; >+ } >+ return NULL; >+} >+ >+static void __cmtp_link_session(struct cmtp_session *session) >+{ >+ __module_get(THIS_MODULE); >+ list_add(&session->list, &cmtp_session_list); >+} >+ >+static void __cmtp_unlink_session(struct cmtp_session *session) >+{ >+ list_del(&session->list); >+ module_put(THIS_MODULE); >+} >+ >+static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) >+{ >+ bacpy(&ci->bdaddr, &session->bdaddr); >+ >+ ci->flags = session->flags; >+ ci->state = session->state; >+ >+ ci->num = session->num; >+} >+ >+ >+static inline int cmtp_alloc_block_id(struct cmtp_session *session) >+{ >+ int i, id = -1; >+ >+ for (i = 0; i < 16; i++) >+ if (!test_and_set_bit(i, &session->blockids)) { >+ id = i; >+ break; >+ } >+ >+ return id; >+} >+ >+static inline void cmtp_free_block_id(struct cmtp_session *session, int id) >+{ >+ clear_bit(id, &session->blockids); >+} >+ >+static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count) >+{ >+ struct sk_buff *skb = session->reassembly[id], *nskb; >+ int size; >+ >+ BT_DBG("session %p buf %p count %d", session, buf, count); >+ >+ size = (skb) ? skb->len + count : count; >+ >+ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) { >+ BT_ERR("Can't allocate memory for CAPI message"); >+ return; >+ } >+ >+ if (skb && (skb->len > 0)) >+ memcpy(skb_put(nskb, skb->len), skb->data, skb->len); >+ >+ memcpy(skb_put(nskb, count), buf, count); >+ >+ session->reassembly[id] = nskb; >+ >+ if (skb) >+ kfree_skb(skb); >+} >+ >+static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb) >+{ >+ __u8 hdr, hdrlen, id; >+ __u16 len; >+ >+ BT_DBG("session %p skb %p len %d", session, skb, skb->len); >+ >+ while (skb->len > 0) { >+ hdr = skb->data[0]; >+ >+ switch (hdr & 0xc0) { >+ case 0x40: >+ hdrlen = 2; >+ len = skb->data[1]; >+ break; >+ case 0x80: >+ hdrlen = 3; >+ len = skb->data[1] | (skb->data[2] << 8); >+ break; >+ default: >+ hdrlen = 1; >+ len = 0; >+ break; >+ } >+ >+ id = (hdr & 0x3c) >> 2; >+ >+ BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id); >+ >+ if (hdrlen + len > skb->len) { >+ BT_ERR("Wrong size or header information in CMTP frame"); >+ break; >+ } >+ >+ if (len == 0) { >+ skb_pull(skb, hdrlen); >+ continue; >+ } >+ >+ switch (hdr & 0x03) { >+ case 0x00: >+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len); >+ cmtp_recv_capimsg(session, session->reassembly[id]); >+ session->reassembly[id] = NULL; >+ break; >+ case 0x01: >+ cmtp_add_msgpart(session, id, skb->data + hdrlen, len); >+ break; >+ default: >+ if (session->reassembly[id] != NULL) >+ kfree_skb(session->reassembly[id]); >+ session->reassembly[id] = NULL; >+ break; >+ } >+ >+ skb_pull(skb, hdrlen + len); >+ } >+ >+ kfree_skb(skb); >+ return 0; >+} >+ >+static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len) >+{ >+ struct socket *sock = session->sock; >+ struct iovec iv = { data, len }; >+ struct msghdr msg; >+ >+ BT_DBG("session %p data %p len %d", session, data, len); >+ >+ if (!len) >+ return 0; >+ >+ memset(&msg, 0, sizeof(msg)); >+ msg.msg_iovlen = 1; >+ msg.msg_iov = &iv; >+ >+ return sock_sendmsg(sock, &msg, len); >+} >+ >+static int cmtp_process_transmit(struct cmtp_session *session) >+{ >+ struct sk_buff *skb, *nskb; >+ unsigned char *hdr; >+ unsigned int size, tail; >+ >+ BT_DBG("session %p", session); >+ >+ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) { >+ BT_ERR("Can't allocate memory for new frame"); >+ return -ENOMEM; >+ } >+ >+ while ((skb = skb_dequeue(&session->transmit))) { >+ struct cmtp_scb *scb = (void *) skb->cb; >+ >+ if ((tail = (session->mtu - nskb->len)) < 5) { >+ cmtp_send_frame(session, nskb->data, nskb->len); >+ skb_trim(nskb, 0); >+ tail = session->mtu; >+ } >+ >+ size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); >+ >+ if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { >+ skb_queue_head(&session->transmit, skb); >+ break; >+ } >+ >+ if (size < 256) { >+ hdr = skb_put(nskb, 2); >+ hdr[0] = 0x40 >+ | ((scb->id << 2) & 0x3c) >+ | ((skb->len == size) ? 0x00 : 0x01); >+ hdr[1] = size; >+ } else { >+ hdr = skb_put(nskb, 3); >+ hdr[0] = 0x80 >+ | ((scb->id << 2) & 0x3c) >+ | ((skb->len == size) ? 0x00 : 0x01); >+ hdr[1] = size & 0xff; >+ hdr[2] = size >> 8; >+ } >+ >+ memcpy(skb_put(nskb, size), skb->data, size); >+ skb_pull(skb, size); >+ >+ if (skb->len > 0) { >+ skb_queue_head(&session->transmit, skb); >+ } else { >+ cmtp_free_block_id(session, scb->id); >+ if (scb->data) { >+ cmtp_send_frame(session, nskb->data, nskb->len); >+ skb_trim(nskb, 0); >+ } >+ kfree_skb(skb); >+ } >+ } >+ >+ cmtp_send_frame(session, nskb->data, nskb->len); >+ >+ kfree_skb(nskb); >+ >+ return skb_queue_len(&session->transmit); >+} >+ >+static int cmtp_session(void *arg) >+{ >+ struct cmtp_session *session = arg; >+ struct sock *sk = session->sock->sk; >+ struct sk_buff *skb; >+ wait_queue_t wait; >+ >+ BT_DBG("session %p", session); >+ >+ daemonize("kcmtpd_ctr_%d", session->num); >+ set_user_nice(current, -15); >+ current->flags |= PF_IOTHREAD; >+ >+ set_fs(KERNEL_DS); >+ >+ init_waitqueue_entry(&wait, current); >+ add_wait_queue(sk->sk_sleep, &wait); >+ while (!atomic_read(&session->terminate)) { >+ set_current_state(TASK_INTERRUPTIBLE); >+ >+ if (sk->sk_state != BT_CONNECTED) >+ break; >+ >+ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { >+ skb_orphan(skb); >+ cmtp_recv_frame(session, skb); >+ } >+ >+ cmtp_process_transmit(session); >+ >+ schedule(); >+ } >+ set_current_state(TASK_RUNNING); >+ remove_wait_queue(sk->sk_sleep, &wait); >+ >+ down_write(&cmtp_session_sem); >+ >+ if (!(session->flags & (1 << CMTP_LOOPBACK))) >+ cmtp_detach_device(session); >+ >+ fput(session->sock->file); >+ >+ __cmtp_unlink_session(session); >+ >+ up_write(&cmtp_session_sem); >+ >+ kfree(session); >+ return 0; >+} >+ >+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) >+{ >+ struct cmtp_session *session, *s; >+ bdaddr_t src, dst; >+ int i, err; >+ >+ BT_DBG(""); >+ >+ baswap(&src, &bt_sk(sock->sk)->src); >+ baswap(&dst, &bt_sk(sock->sk)->dst); >+ >+ session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL); >+ if (!session) >+ return -ENOMEM; >+ memset(session, 0, sizeof(struct cmtp_session)); >+ >+ down_write(&cmtp_session_sem); >+ >+ s = __cmtp_get_session(&bt_sk(sock->sk)->dst); >+ if (s && s->state == BT_CONNECTED) { >+ err = -EEXIST; >+ goto failed; >+ } >+ >+ bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); >+ >+ session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); >+ >+ BT_DBG("mtu %d", session->mtu); >+ >+ sprintf(session->name, "%s", batostr(&dst)); >+ >+ session->sock = sock; >+ session->state = BT_CONFIG; >+ >+ init_waitqueue_head(&session->wait); >+ >+ session->msgnum = CMTP_INITIAL_MSGNUM; >+ >+ INIT_LIST_HEAD(&session->applications); >+ >+ skb_queue_head_init(&session->transmit); >+ >+ for (i = 0; i < 16; i++) >+ session->reassembly[i] = NULL; >+ >+ session->flags = req->flags; >+ >+ __cmtp_link_session(session); >+ >+ err = kernel_thread(cmtp_session, session, CLONE_KERNEL); >+ if (err < 0) >+ goto unlink; >+ >+ if (!(session->flags & (1 << CMTP_LOOPBACK))) { >+ err = cmtp_attach_device(session); >+ if (err < 0) >+ goto detach; >+ } >+ >+ up_write(&cmtp_session_sem); >+ return 0; >+ >+detach: >+ cmtp_detach_device(session); >+ >+unlink: >+ __cmtp_unlink_session(session); >+ >+failed: >+ up_write(&cmtp_session_sem); >+ kfree(session); >+ return err; >+} >+ >+int cmtp_del_connection(struct cmtp_conndel_req *req) >+{ >+ struct cmtp_session *session; >+ int err = 0; >+ >+ BT_DBG(""); >+ >+ down_read(&cmtp_session_sem); >+ >+ session = __cmtp_get_session(&req->bdaddr); >+ if (session) { >+ /* Flush the transmit queue */ >+ skb_queue_purge(&session->transmit); >+ >+ /* Kill session thread */ >+ atomic_inc(&session->terminate); >+ cmtp_schedule(session); >+ } else >+ err = -ENOENT; >+ >+ up_read(&cmtp_session_sem); >+ return err; >+} >+ >+int cmtp_get_connlist(struct cmtp_connlist_req *req) >+{ >+ struct list_head *p; >+ int err = 0, n = 0; >+ >+ BT_DBG(""); >+ >+ down_read(&cmtp_session_sem); >+ >+ list_for_each(p, &cmtp_session_list) { >+ struct cmtp_session *session; >+ struct cmtp_conninfo ci; >+ >+ session = list_entry(p, struct cmtp_session, list); >+ >+ __cmtp_copy_session(session, &ci); >+ >+ if (copy_to_user(req->ci, &ci, sizeof(ci))) { >+ err = -EFAULT; >+ break; >+ } >+ >+ if (++n >= req->cnum) >+ break; >+ >+ req->ci++; >+ } >+ req->cnum = n; >+ >+ up_read(&cmtp_session_sem); >+ return err; >+} >+ >+int cmtp_get_conninfo(struct cmtp_conninfo *ci) >+{ >+ struct cmtp_session *session; >+ int err = 0; >+ >+ down_read(&cmtp_session_sem); >+ >+ session = __cmtp_get_session(&ci->bdaddr); >+ if (session) >+ __cmtp_copy_session(session, ci); >+ else >+ err = -ENOENT; >+ >+ up_read(&cmtp_session_sem); >+ return err; >+} >+ >+ >+int __init init_cmtp(void) >+{ >+ l2cap_load(); >+ >+ BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION); >+ >+ cmtp_init_sockets(); >+ >+ return 0; >+} >+ >+void __exit exit_cmtp(void) >+{ >+ cmtp_cleanup_sockets(); >+} >+ >+module_init(init_cmtp); >+module_exit(exit_cmtp); >+ >+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); >+MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION); >+MODULE_LICENSE("GPL"); >+MODULE_ALIAS("bt-proto-5"); >diff -urN linux-2.6.0/net/bluetooth/cmtp/Kconfig linux-2.6.0-mh2/net/bluetooth/cmtp/Kconfig >--- linux-2.6.0/net/bluetooth/cmtp/Kconfig 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/cmtp/Kconfig 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,11 @@ >+config BT_CMTP >+ tristate "CMTP protocol support" >+ depends on BT && BT_L2CAP && ISDN_CAPI >+ help >+ CMTP (CAPI Message Transport Protocol) is a transport layer >+ for CAPI messages. CMTP is required for the Bluetooth Common >+ ISDN Access Profile. >+ >+ Say Y here to compile CMTP support into the kernel or say M to >+ compile it as module (cmtp). >+ >diff -urN linux-2.6.0/net/bluetooth/cmtp/Makefile linux-2.6.0-mh2/net/bluetooth/cmtp/Makefile >--- linux-2.6.0/net/bluetooth/cmtp/Makefile 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/cmtp/Makefile 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,7 @@ >+# >+# Makefile for the Linux Bluetooth CMTP layer >+# >+ >+obj-$(CONFIG_BT_CMTP) += cmtp.o >+ >+cmtp-objs := core.o sock.o capi.o >diff -urN linux-2.6.0/net/bluetooth/cmtp/sock.c linux-2.6.0-mh2/net/bluetooth/cmtp/sock.c >--- linux-2.6.0/net/bluetooth/cmtp/sock.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/cmtp/sock.c 2004-01-02 11:46:31.000000000 +0100 >@@ -0,0 +1,198 @@ >+/* >+ CMTP implementation for Linux Bluetooth stack (BlueZ). >+ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> >+ >+ 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; >+ >+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS >+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. >+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY >+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES >+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >+ >+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, >+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS >+ SOFTWARE IS DISCLAIMED. >+*/ >+ >+#include <linux/config.h> >+#include <linux/module.h> >+ >+#include <linux/types.h> >+#include <linux/errno.h> >+#include <linux/kernel.h> >+#include <linux/major.h> >+#include <linux/sched.h> >+#include <linux/slab.h> >+#include <linux/poll.h> >+#include <linux/fcntl.h> >+#include <linux/skbuff.h> >+#include <linux/socket.h> >+#include <linux/ioctl.h> >+#include <linux/file.h> >+#include <net/sock.h> >+ >+#include <linux/isdn/capilli.h> >+ >+#include <asm/system.h> >+#include <asm/uaccess.h> >+ >+#include "cmtp.h" >+ >+#ifndef CONFIG_BT_CMTP_DEBUG >+#undef BT_DBG >+#define BT_DBG(D...) >+#endif >+ >+static int cmtp_sock_release(struct socket *sock) >+{ >+ struct sock *sk = sock->sk; >+ >+ BT_DBG("sock %p sk %p", sock, sk); >+ >+ if (!sk) >+ return 0; >+ >+ sock_orphan(sk); >+ sock_put(sk); >+ >+ return 0; >+} >+ >+static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) >+{ >+ struct cmtp_connadd_req ca; >+ struct cmtp_conndel_req cd; >+ struct cmtp_connlist_req cl; >+ struct cmtp_conninfo ci; >+ struct socket *nsock; >+ int err; >+ >+ BT_DBG("cmd %x arg %lx", cmd, arg); >+ >+ switch (cmd) { >+ case CMTPCONNADD: >+ if (!capable(CAP_NET_ADMIN)) >+ return -EACCES; >+ >+ if (copy_from_user(&ca, (void *) arg, sizeof(ca))) >+ return -EFAULT; >+ >+ nsock = sockfd_lookup(ca.sock, &err); >+ if (!nsock) >+ return err; >+ >+ if (nsock->sk->sk_state != BT_CONNECTED) >+ return -EBADFD; >+ >+ err = cmtp_add_connection(&ca, nsock); >+ if (!err) { >+ if (copy_to_user((void *) arg, &ca, sizeof(ca))) >+ err = -EFAULT; >+ } else >+ fput(nsock->file); >+ >+ return err; >+ >+ case CMTPCONNDEL: >+ if (!capable(CAP_NET_ADMIN)) >+ return -EACCES; >+ >+ if (copy_from_user(&cd, (void *) arg, sizeof(cd))) >+ return -EFAULT; >+ >+ return cmtp_del_connection(&cd); >+ >+ case CMTPGETCONNLIST: >+ if (copy_from_user(&cl, (void *) arg, sizeof(cl))) >+ return -EFAULT; >+ >+ if (cl.cnum <= 0) >+ return -EINVAL; >+ >+ err = cmtp_get_connlist(&cl); >+ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) >+ return -EFAULT; >+ >+ return err; >+ >+ case CMTPGETCONNINFO: >+ if (copy_from_user(&ci, (void *) arg, sizeof(ci))) >+ return -EFAULT; >+ >+ err = cmtp_get_conninfo(&ci); >+ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) >+ return -EFAULT; >+ >+ return err; >+ } >+ >+ return -EINVAL; >+} >+ >+static struct proto_ops cmtp_sock_ops = { >+ .family = PF_BLUETOOTH, >+ .owner = THIS_MODULE, >+ .release = cmtp_sock_release, >+ .ioctl = cmtp_sock_ioctl, >+ .bind = sock_no_bind, >+ .getname = sock_no_getname, >+ .sendmsg = sock_no_sendmsg, >+ .recvmsg = sock_no_recvmsg, >+ .poll = sock_no_poll, >+ .listen = sock_no_listen, >+ .shutdown = sock_no_shutdown, >+ .setsockopt = sock_no_setsockopt, >+ .getsockopt = sock_no_getsockopt, >+ .connect = sock_no_connect, >+ .socketpair = sock_no_socketpair, >+ .accept = sock_no_accept, >+ .mmap = sock_no_mmap >+}; >+ >+static int cmtp_sock_create(struct socket *sock, int protocol) >+{ >+ struct sock *sk; >+ >+ BT_DBG("sock %p", sock); >+ >+ if (sock->type != SOCK_RAW) >+ return -ESOCKTNOSUPPORT; >+ >+ sock->ops = &cmtp_sock_ops; >+ >+ if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL))) >+ return -ENOMEM; >+ >+ sock->ops = &cmtp_sock_ops; >+ >+ sock->state = SS_UNCONNECTED; >+ >+ sk->sk_destruct = NULL; >+ sk->sk_protocol = protocol; >+ >+ return 0; >+} >+ >+static struct net_proto_family cmtp_sock_family_ops = { >+ .family = PF_BLUETOOTH, >+ .create = cmtp_sock_create >+}; >+ >+int cmtp_init_sockets(void) >+{ >+ bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops); >+ >+ return 0; >+} >+ >+void cmtp_cleanup_sockets(void) >+{ >+ if (bt_sock_unregister(BTPROTO_CMTP)) >+ BT_ERR("Can't unregister CMTP socket"); >+} >diff -urN linux-2.6.0/net/bluetooth/hci_event.c linux-2.6.0-mh2/net/bluetooth/hci_event.c >--- linux-2.6.0/net/bluetooth/hci_event.c 2003-12-18 03:58:04.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/hci_event.c 2004-01-02 11:46:30.000000000 +0100 >@@ -452,6 +452,29 @@ > hci_dev_unlock(hdev); > } > >+/* Inquiry Result With RSSI */ >+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb) >+{ >+ struct inquiry_info_with_rssi *info = (struct inquiry_info_with_rssi *) (skb->data + 1); >+ int num_rsp = *((__u8 *) skb->data); >+ >+ BT_DBG("%s num_rsp %d", hdev->name, num_rsp); >+ >+ hci_dev_lock(hdev); >+ for (; num_rsp; num_rsp--) { >+ struct inquiry_info tmp; >+ bacpy(&tmp.bdaddr, &info->bdaddr); >+ tmp.pscan_rep_mode = info->pscan_rep_mode; >+ tmp.pscan_period_mode = info->pscan_period_mode; >+ tmp.pscan_mode = 0x00; >+ memcpy(tmp.dev_class, &info->dev_class, 3); >+ tmp.clock_offset = info->clock_offset; >+ info++; >+ inquiry_cache_update(hdev, &tmp); >+ } >+ hci_dev_unlock(hdev); >+} >+ > /* Connect Request */ > static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) > { >@@ -744,6 +767,10 @@ > hci_inquiry_result_evt(hdev, skb); > break; > >+ case HCI_EV_INQUIRY_RESULT_WITH_RSSI: >+ hci_inquiry_result_with_rssi_evt(hdev, skb); >+ break; >+ > case HCI_EV_CONN_REQUEST: > hci_conn_request_evt(hdev, skb); > break; >diff -urN linux-2.6.0/net/bluetooth/hci_sock.c linux-2.6.0-mh2/net/bluetooth/hci_sock.c >--- linux-2.6.0/net/bluetooth/hci_sock.c 2003-12-18 03:58:57.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/hci_sock.c 2004-01-02 11:46:30.000000000 +0100 >@@ -66,20 +66,20 @@ > /* Packet types */ > 0x10, > /* Events */ >- { 0xd9fe, 0x0 }, >+ { 0x1000d9fe, 0x0000300c }, > /* Commands */ > { > { 0x0 }, > /* OGF_LINK_CTL */ >- { 0x2a000002, 0x0, 0x0, 0x0 }, >+ { 0xbe000006, 0x00000001, 0x0000, 0x00 }, > /* OGF_LINK_POLICY */ >- { 0x1200, 0x0, 0x0, 0x0 }, >+ { 0x00005200, 0x00000000, 0x0000, 0x00 }, > /* OGF_HOST_CTL */ >- { 0x80100000, 0x202a, 0x0, 0x0 }, >+ { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 }, > /* OGF_INFO_PARAM */ >- { 0x22a, 0x0, 0x0, 0x0 }, >+ { 0x000002be, 0x00000000, 0x0000, 0x00 }, > /* OGF_STATUS_PARAM */ >- { 0x2e, 0x0, 0x0, 0x0 } >+ { 0x000000ea, 0x00000000, 0x0000, 0x00 } > } > }; > >diff -urN linux-2.6.0/net/bluetooth/Kconfig linux-2.6.0-mh2/net/bluetooth/Kconfig >--- linux-2.6.0/net/bluetooth/Kconfig 2003-12-18 03:59:29.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/Kconfig 2004-01-02 11:46:31.000000000 +0100 >@@ -21,6 +21,7 @@ > SCO Module (SCO links) > RFCOMM Module (RFCOMM protocol) > BNEP Module (BNEP protocol) >+ CMTP Module (CMTP protocol) > > Say Y here to enable Linux Bluetooth support and to build Bluetooth Core > layer. >@@ -57,6 +58,8 @@ > > source "net/bluetooth/bnep/Kconfig" > >+source "net/bluetooth/cmtp/Kconfig" >+ > source "drivers/bluetooth/Kconfig" > > endmenu >diff -urN linux-2.6.0/net/bluetooth/l2cap.c linux-2.6.0-mh2/net/bluetooth/l2cap.c >--- linux-2.6.0/net/bluetooth/l2cap.c 2003-12-18 03:59:05.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/l2cap.c 2004-01-02 11:46:31.000000000 +0100 >@@ -2201,3 +2201,4 @@ > MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); > MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); > MODULE_LICENSE("GPL"); >+MODULE_ALIAS("bt-proto-0"); >diff -urN linux-2.6.0/net/bluetooth/Makefile linux-2.6.0-mh2/net/bluetooth/Makefile >--- linux-2.6.0/net/bluetooth/Makefile 2003-12-18 03:58:16.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/Makefile 2004-01-02 11:46:31.000000000 +0100 >@@ -7,5 +7,6 @@ > obj-$(CONFIG_BT_SCO) += sco.o > obj-$(CONFIG_BT_RFCOMM) += rfcomm/ > obj-$(CONFIG_BT_BNEP) += bnep/ >+obj-$(CONFIG_BT_CMTP) += cmtp/ > > bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_proc.o lib.o syms.o >diff -urN linux-2.6.0/net/bluetooth/rfcomm/core.c linux-2.6.0-mh2/net/bluetooth/rfcomm/core.c >--- linux-2.6.0/net/bluetooth/rfcomm/core.c 2003-12-18 03:57:59.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/rfcomm/core.c 2004-01-02 11:46:31.000000000 +0100 >@@ -52,7 +52,7 @@ > #include <net/bluetooth/l2cap.h> > #include <net/bluetooth/rfcomm.h> > >-#define VERSION "1.0" >+#define VERSION "1.1" > > #ifndef CONFIG_BT_RFCOMM_DEBUG > #undef BT_DBG >@@ -207,7 +207,7 @@ > d->mtu = RFCOMM_DEFAULT_MTU; > d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; > >- d->credits = RFCOMM_MAX_CREDITS; >+ d->cfc = RFCOMM_CFC_DISABLED; > d->rx_credits = RFCOMM_DEFAULT_CREDITS; > } > >@@ -314,8 +314,8 @@ > d->state = BT_CONFIG; > rfcomm_dlc_link(s, d); > >- d->mtu = s->mtu; >- d->credits = s->credits; >+ d->mtu = s->mtu; >+ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc; > > if (s->state == BT_CONNECTED) > rfcomm_send_pn(s, 1, d); >@@ -415,7 +415,7 @@ > { > BT_DBG("dlc %p state %ld", d, d->state); > >- if (!d->credits) { >+ if (!d->cfc) { > d->v24_sig |= RFCOMM_V24_FC; > set_bit(RFCOMM_MSC_PENDING, &d->flags); > } >@@ -426,7 +426,7 @@ > { > BT_DBG("dlc %p state %ld", d, d->state); > >- if (!d->credits) { >+ if (!d->cfc) { > d->v24_sig &= ~RFCOMM_V24_FC; > set_bit(RFCOMM_MSC_PENDING, &d->flags); > } >@@ -479,8 +479,8 @@ > s->state = state; > s->sock = sock; > >- s->mtu = RFCOMM_DEFAULT_MTU; >- s->credits = RFCOMM_MAX_CREDITS; >+ s->mtu = RFCOMM_DEFAULT_MTU; >+ s->cfc = RFCOMM_CFC_UNKNOWN; > > list_add(&s->list, &session_list); > >@@ -752,7 +752,7 @@ > pn->ack_timer = 0; > pn->max_retrans = 0; > >- if (d->credits) { >+ if (s->cfc) { > pn->flow_ctrl = cr ? 0xf0 : 0xe0; > pn->credits = RFCOMM_DEFAULT_CREDITS; > } else { >@@ -1142,28 +1142,22 @@ > > static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) > { >+ struct rfcomm_session *s = d->session; >+ > BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", > d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits); > >- if (cr) { >- if (pn->flow_ctrl == 0xf0) { >- d->tx_credits = pn->credits; >- } else { >- set_bit(RFCOMM_TX_THROTTLED, &d->flags); >- d->credits = 0; >- } >+ if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) { >+ d->cfc = s->cfc = RFCOMM_CFC_ENABLED; >+ d->tx_credits = pn->credits; > } else { >- if (pn->flow_ctrl == 0xe0) { >- d->tx_credits = pn->credits; >- } else { >- set_bit(RFCOMM_TX_THROTTLED, &d->flags); >- d->credits = 0; >- } >+ d->cfc = s->cfc = RFCOMM_CFC_DISABLED; >+ set_bit(RFCOMM_TX_THROTTLED, &d->flags); > } > > d->priority = pn->priority; > >- d->mtu = btohs(pn->mtu); >+ d->mtu = s->mtu = btohs(pn->mtu); > > return 0; > } >@@ -1353,7 +1347,7 @@ > return 0; > > if (cr) { >- if (msc->v24_sig & RFCOMM_V24_FC && !d->credits) >+ if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc) > set_bit(RFCOMM_TX_THROTTLED, &d->flags); > else > clear_bit(RFCOMM_TX_THROTTLED, &d->flags); >@@ -1444,7 +1438,7 @@ > goto drop; > } > >- if (pf && d->credits) { >+ if (pf && d->cfc) { > u8 credits = *(u8 *) skb->data; skb_pull(skb, 1); > > d->tx_credits += credits; >@@ -1549,20 +1543,20 @@ > struct sk_buff *skb; > int err; > >- BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", >- d, d->state, d->credits, d->rx_credits, d->tx_credits); >+ BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d", >+ d, d->state, d->cfc, d->rx_credits, d->tx_credits); > > /* Send pending MSC */ > if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags)) > rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); > >- if (d->credits) { >+ if (d->cfc) { > /* CFC enabled. > * Give them some credits */ > if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) && >- d->rx_credits <= (d->credits >> 2)) { >- rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits); >- d->rx_credits = d->credits; >+ d->rx_credits <= (d->cfc >> 2)) { >+ rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits); >+ d->rx_credits = d->cfc; > } > } else { > /* CFC disabled. >@@ -1583,7 +1577,7 @@ > d->tx_credits--; > } > >- if (d->credits && !d->tx_credits) { >+ if (d->cfc && !d->tx_credits) { > /* We're out of TX credits. > * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */ > set_bit(RFCOMM_TX_THROTTLED, &d->flags); >@@ -1998,3 +1992,4 @@ > MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); > MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION); > MODULE_LICENSE("GPL"); >+MODULE_ALIAS("bt-proto-3"); >diff -urN linux-2.6.0/net/bluetooth/sco.c linux-2.6.0-mh2/net/bluetooth/sco.c >--- linux-2.6.0/net/bluetooth/sco.c 2003-12-18 03:58:28.000000000 +0100 >+++ linux-2.6.0-mh2/net/bluetooth/sco.c 2004-01-02 11:46:31.000000000 +0100 >@@ -1054,3 +1054,4 @@ > MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); > MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); > MODULE_LICENSE("GPL"); >+MODULE_ALIAS("bt-proto-2");
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 37696
: 23488