Commit 03810346 authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6

into kernel.bkbits.net:/home/davem/net-2.6
parents 72aa1a62 96cc3e57
...@@ -93,12 +93,12 @@ static u32 rcon_tab[RC_LENGTH]; ...@@ -93,12 +93,12 @@ static u32 rcon_tab[RC_LENGTH];
u32 ft_tab[4][256]; u32 ft_tab[4][256];
u32 fl_tab[4][256]; u32 fl_tab[4][256];
u32 ls_tab[4][256]; static u32 ls_tab[4][256];
u32 im_tab[4][256]; static u32 im_tab[4][256];
u32 il_tab[4][256]; u32 il_tab[4][256];
u32 it_tab[4][256]; u32 it_tab[4][256];
void gen_tabs(void) static void gen_tabs(void)
{ {
u32 i, w; u32 i, w;
u8 pow[512], log[256]; u8 pow[512], log[256];
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/wait.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -1089,13 +1090,11 @@ static inline void rx_bus_master_complete_handler (hrz_dev * dev) { ...@@ -1089,13 +1090,11 @@ static inline void rx_bus_master_complete_handler (hrz_dev * dev) {
/********** (queue to) become the next TX thread **********/ /********** (queue to) become the next TX thread **********/
static inline int tx_hold (hrz_dev * dev) { static inline int tx_hold (hrz_dev * dev) {
while (test_and_set_bit (tx_busy, &dev->flags)) {
PRINTD (DBG_TX, "sleeping at tx lock %p %lu", dev, dev->flags); PRINTD (DBG_TX, "sleeping at tx lock %p %lu", dev, dev->flags);
interruptible_sleep_on (&dev->tx_queue); wait_event_interruptible(dev->tx_queue, (!test_and_set_bit(tx_busy, &dev->flags)));
PRINTD (DBG_TX, "woken at tx lock %p %lu", dev, dev->flags); PRINTD (DBG_TX, "woken at tx lock %p %lu", dev, dev->flags);
if (signal_pending (current)) if (signal_pending (current))
return -1; return -1;
}
PRINTD (DBG_TX, "set tx_busy for dev %p", dev); PRINTD (DBG_TX, "set tx_busy for dev %p", dev);
return 0; return 0;
} }
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/wait.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/atomic.h> #include <asm/atomic.h>
...@@ -2587,13 +2588,13 @@ static int __init ia_start(struct atm_dev *dev) ...@@ -2587,13 +2588,13 @@ static int __init ia_start(struct atm_dev *dev)
static void ia_close(struct atm_vcc *vcc) static void ia_close(struct atm_vcc *vcc)
{ {
DEFINE_WAIT(wait);
u16 *vc_table; u16 *vc_table;
IADEV *iadev; IADEV *iadev;
struct ia_vcc *ia_vcc; struct ia_vcc *ia_vcc;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct sk_buff_head tmp_tx_backlog, tmp_vcc_backlog; struct sk_buff_head tmp_tx_backlog, tmp_vcc_backlog;
unsigned long closetime, flags; unsigned long closetime, flags;
int ctimeout;
iadev = INPH_IA_DEV(vcc->dev); iadev = INPH_IA_DEV(vcc->dev);
ia_vcc = INPH_IA_VCC(vcc); ia_vcc = INPH_IA_VCC(vcc);
...@@ -2606,7 +2607,9 @@ static void ia_close(struct atm_vcc *vcc) ...@@ -2606,7 +2607,9 @@ static void ia_close(struct atm_vcc *vcc)
skb_queue_head_init (&tmp_vcc_backlog); skb_queue_head_init (&tmp_vcc_backlog);
if (vcc->qos.txtp.traffic_class != ATM_NONE) { if (vcc->qos.txtp.traffic_class != ATM_NONE) {
iadev->close_pending++; iadev->close_pending++;
sleep_on_timeout(&iadev->timeout_wait, 50); prepare_to_wait(&iadev->timeout_wait, &wait, TASK_UNINTERRUPTIBLE);
schedule_timeout(50);
finish_wait(&iadev->timeout_wait, &wait);
spin_lock_irqsave(&iadev->tx_lock, flags); spin_lock_irqsave(&iadev->tx_lock, flags);
while((skb = skb_dequeue(&iadev->tx_backlog))) { while((skb = skb_dequeue(&iadev->tx_backlog))) {
if (ATM_SKB(skb)->vcc == vcc){ if (ATM_SKB(skb)->vcc == vcc){
...@@ -2619,17 +2622,12 @@ static void ia_close(struct atm_vcc *vcc) ...@@ -2619,17 +2622,12 @@ static void ia_close(struct atm_vcc *vcc)
while((skb = skb_dequeue(&tmp_tx_backlog))) while((skb = skb_dequeue(&tmp_tx_backlog)))
skb_queue_tail(&iadev->tx_backlog, skb); skb_queue_tail(&iadev->tx_backlog, skb);
IF_EVENT(printk("IA TX Done decs_cnt = %d\n", ia_vcc->vc_desc_cnt);) IF_EVENT(printk("IA TX Done decs_cnt = %d\n", ia_vcc->vc_desc_cnt);)
closetime = jiffies; closetime = 300000 / ia_vcc->pcr;
ctimeout = 300000 / ia_vcc->pcr; if (closetime == 0)
if (ctimeout == 0) closetime = 1;
ctimeout = 1;
while (ia_vcc->vc_desc_cnt > 0){
if ((jiffies - closetime) >= ctimeout)
break;
spin_unlock_irqrestore(&iadev->tx_lock, flags); spin_unlock_irqrestore(&iadev->tx_lock, flags);
sleep_on(&iadev->close_wait); wait_event_timeout(iadev->close_wait, (ia_vcc->vc_desc_cnt <= 0), closetime);
spin_lock_irqsave(&iadev->tx_lock, flags); spin_lock_irqsave(&iadev->tx_lock, flags);
}
iadev->close_pending--; iadev->close_pending--;
iadev->testTable[vcc->vci]->lastTime = 0; iadev->testTable[vcc->vci]->lastTime = 0;
iadev->testTable[vcc->vci]->fract = 0; iadev->testTable[vcc->vci]->fract = 0;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/atm_zatm.h> #include <linux/atm_zatm.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/wait.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/string.h> #include <asm/string.h>
...@@ -867,31 +868,21 @@ static void close_tx(struct atm_vcc *vcc) ...@@ -867,31 +868,21 @@ static void close_tx(struct atm_vcc *vcc)
struct zatm_vcc *zatm_vcc; struct zatm_vcc *zatm_vcc;
unsigned long flags; unsigned long flags;
int chan; int chan;
struct sk_buff *skb;
int once = 1;
zatm_vcc = ZATM_VCC(vcc); zatm_vcc = ZATM_VCC(vcc);
zatm_dev = ZATM_DEV(vcc->dev); zatm_dev = ZATM_DEV(vcc->dev);
chan = zatm_vcc->tx_chan; chan = zatm_vcc->tx_chan;
if (!chan) return; if (!chan) return;
DPRINTK("close_tx\n"); DPRINTK("close_tx\n");
while (skb_peek(&zatm_vcc->backlog)) { if (skb_peek(&zatm_vcc->backlog)) {
if (once) { printk("waiting for backlog to drain ...\n");
printk("waiting for backlog to drain ...\n"); event_dump();
event_dump(); wait_event(zatm_vcc->tx_wait, !skb_peek(&zatm_vcc->backlog));
once = 0; }
} if (skb_peek(&zatm_vcc->tx_queue)) {
sleep_on(&zatm_vcc->tx_wait); printk("waiting for TX queue to drain ...\n");
} event_dump();
once = 1; wait_event(zatm_vcc->tx_wait, !skb_peek(&zatm_vcc->tx_queue));
while ((skb = skb_peek(&zatm_vcc->tx_queue))) {
if (once) {
printk("waiting for TX queue to drain ... %p\n",skb);
event_dump();
once = 0;
}
DPRINTK("waiting for TX queue to drain ... %p\n",skb);
sleep_on(&zatm_vcc->tx_wait);
} }
spin_lock_irqsave(&zatm_dev->lock, flags); spin_lock_irqsave(&zatm_dev->lock, flags);
#if 0 #if 0
......
...@@ -75,6 +75,17 @@ config BT_HCIBCM203X ...@@ -75,6 +75,17 @@ config BT_HCIBCM203X
Say Y here to compile support for HCI BCM203x devices into the Say Y here to compile support for HCI BCM203x devices into the
kernel or say M to compile it as module (bcm203x). kernel or say M to compile it as module (bcm203x).
config BT_HCIBPA10X
tristate "HCI BPA10x USB driver"
depends on USB
help
Bluetooth HCI BPA10x USB driver.
This driver provides support for the Digianswer BPA 100/105 Bluetooth
sniffer devices.
Say Y here to compile support for HCI BPA10x devices into the
kernel or say M to compile it as module (bpa10x).
config BT_HCIBFUSB config BT_HCIBFUSB
tristate "HCI BlueFRITZ! USB driver" tristate "HCI BlueFRITZ! USB driver"
depends on USB depends on USB
......
...@@ -6,6 +6,7 @@ obj-$(CONFIG_BT_HCIUSB) += hci_usb.o ...@@ -6,6 +6,7 @@ obj-$(CONFIG_BT_HCIUSB) += hci_usb.o
obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o
obj-$(CONFIG_BT_HCIUART) += hci_uart.o obj-$(CONFIG_BT_HCIUART) += hci_uart.o
obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o
obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o
obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
......
/*
*
* Digianswer Bluetooth USB driver
*
* Copyright (C) 2004-2005 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/usb.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#ifndef CONFIG_BT_HCIBPA10X_DEBUG
#undef BT_DBG
#define BT_DBG(D...)
#endif
#define VERSION "0.8"
static int ignore = 0;
static struct usb_device_id bpa10x_table[] = {
/* Tektronix BPA 100/105 (Digianswer) */
{ USB_DEVICE(0x08fd, 0x0002) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, bpa10x_table);
#define BPA10X_CMD_EP 0x00
#define BPA10X_EVT_EP 0x81
#define BPA10X_TX_EP 0x02
#define BPA10X_RX_EP 0x82
#define BPA10X_CMD_BUF_SIZE 252
#define BPA10X_EVT_BUF_SIZE 16
#define BPA10X_TX_BUF_SIZE 384
#define BPA10X_RX_BUF_SIZE 384
struct bpa10x_data {
struct hci_dev *hdev;
struct usb_device *udev;
rwlock_t lock;
struct sk_buff_head cmd_queue;
struct urb *cmd_urb;
struct urb *evt_urb;
struct sk_buff *evt_skb;
unsigned int evt_len;
struct sk_buff_head tx_queue;
struct urb *tx_urb;
struct urb *rx_urb;
};
#define HCI_VENDOR_HDR_SIZE 5
struct hci_vendor_hdr {
__u8 type;
__u16 snum;
__u16 dlen;
} __attribute__ ((packed));
static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
{
struct hci_acl_hdr *ah;
struct hci_sco_hdr *sh;
struct hci_vendor_hdr *vh;
struct sk_buff *skb;
int len;
while (count) {
switch (*buf++) {
case HCI_ACLDATA_PKT:
ah = (struct hci_acl_hdr *) buf;
len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen);
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (skb) {
memcpy(skb_put(skb, len), buf, len);
skb->dev = (void *) data->hdev;
skb->pkt_type = HCI_ACLDATA_PKT;
hci_recv_frame(skb);
}
break;
case HCI_SCODATA_PKT:
sh = (struct hci_sco_hdr *) buf;
len = HCI_SCO_HDR_SIZE + sh->dlen;
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (skb) {
memcpy(skb_put(skb, len), buf, len);
skb->dev = (void *) data->hdev;
skb->pkt_type = HCI_SCODATA_PKT;
hci_recv_frame(skb);
}
break;
case HCI_VENDOR_PKT:
vh = (struct hci_vendor_hdr *) buf;
len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen);
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (skb) {
memcpy(skb_put(skb, len), buf, len);
skb->dev = (void *) data->hdev;
skb->pkt_type = HCI_VENDOR_PKT;
hci_recv_frame(skb);
}
break;
default:
len = count - 1;
break;
}
buf += len;
count -= (len + 1);
}
}
static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size)
{
BT_DBG("data %p buf %p size %d", data, buf, size);
if (data->evt_skb) {
struct sk_buff *skb = data->evt_skb;
memcpy(skb_put(skb, size), buf, size);
if (skb->len == data->evt_len) {
data->evt_skb = NULL;
data->evt_len = 0;
hci_recv_frame(skb);
}
} else {
struct sk_buff *skb;
struct hci_event_hdr *hdr;
unsigned char pkt_type;
int pkt_len = 0;
if (size < HCI_EVENT_HDR_SIZE + 1) {
BT_ERR("%s event packet block with size %d is too short",
data->hdev->name, size);
return -EILSEQ;
}
pkt_type = *buf++;
size--;
if (pkt_type != HCI_EVENT_PKT) {
BT_ERR("%s unexpected event packet start byte 0x%02x",
data->hdev->name, pkt_type);
return -EPROTO;
}
hdr = (struct hci_event_hdr *) buf;
pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
if (!skb) {
BT_ERR("%s no memory for new event packet",
data->hdev->name);
return -ENOMEM;
}
skb->dev = (void *) data->hdev;
skb->pkt_type = pkt_type;
memcpy(skb_put(skb, size), buf, size);
if (pkt_len == size) {
hci_recv_frame(skb);
} else {
data->evt_skb = skb;
data->evt_len = pkt_len;
}
}
return 0;
}
static void bpa10x_wakeup(struct bpa10x_data *data)
{
struct urb *urb;
struct sk_buff *skb;
int err;
BT_DBG("data %p", data);
urb = data->cmd_urb;
if (urb->status == -EINPROGRESS)
skb = NULL;
else
skb = skb_dequeue(&data->cmd_queue);
if (skb) {
struct usb_ctrlrequest *cr;
if (skb->len > BPA10X_CMD_BUF_SIZE) {
BT_ERR("%s command packet with size %d is too big",
data->hdev->name, skb->len);
kfree_skb(skb);
return;
}
cr = (struct usb_ctrlrequest *) urb->setup_packet;
cr->wLength = __cpu_to_le16(skb->len);
memcpy(urb->transfer_buffer, skb->data, skb->len);
urb->transfer_buffer_length = skb->len;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0 && err != -ENODEV) {
BT_ERR("%s submit failed for command urb %p with error %d",
data->hdev->name, urb, err);
skb_queue_head(&data->cmd_queue, skb);
} else
kfree_skb(skb);
}
urb = data->tx_urb;
if (urb->status == -EINPROGRESS)
skb = NULL;
else
skb = skb_dequeue(&data->tx_queue);
if (skb) {
memcpy(urb->transfer_buffer, skb->data, skb->len);
urb->transfer_buffer_length = skb->len;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0 && err != -ENODEV) {
BT_ERR("%s submit failed for command urb %p with error %d",
data->hdev->name, urb, err);
skb_queue_head(&data->tx_queue, skb);
} else
kfree_skb(skb);
}
}
static void bpa10x_complete(struct urb *urb, struct pt_regs *regs)
{
struct bpa10x_data *data = urb->context;
unsigned char *buf = urb->transfer_buffer;
int err, count = urb->actual_length;
BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count);
read_lock(&data->lock);
if (!test_bit(HCI_RUNNING, &data->hdev->flags))
goto unlock;
if (urb->status < 0 || !count)
goto resubmit;
if (usb_pipein(urb->pipe)) {
data->hdev->stat.byte_rx += count;
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
bpa10x_recv_event(data, buf, count);
if (usb_pipetype(urb->pipe) == PIPE_BULK)
bpa10x_recv_bulk(data, buf, count);
} else {
data->hdev->stat.byte_tx += count;
bpa10x_wakeup(data);
}
resubmit:
if (usb_pipein(urb->pipe)) {
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0 && err != -ENODEV) {
BT_ERR("%s urb %p type %d resubmit status %d",
data->hdev->name, urb, usb_pipetype(urb->pipe), err);
}
}
unlock:
read_unlock(&data->lock);
}
static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe, size_t size, int flags, void *data)
{
struct urb *urb;
struct usb_ctrlrequest *cr;
unsigned char *buf;
BT_DBG("udev %p data %p", udev, data);
urb = usb_alloc_urb(0, flags);
if (!urb)
return NULL;
buf = kmalloc(size, flags);
if (!buf) {
usb_free_urb(urb);
return NULL;
}
switch (usb_pipetype(pipe)) {
case PIPE_CONTROL:
cr = kmalloc(sizeof(*cr), flags);
if (!cr) {
kfree(buf);
usb_free_urb(urb);
return NULL;
}
cr->bRequestType = USB_TYPE_VENDOR;
cr->bRequest = 0;
cr->wIndex = 0;
cr->wValue = 0;
cr->wLength = __cpu_to_le16(0);
usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data);
break;
case PIPE_INTERRUPT:
usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1);
break;
case PIPE_BULK:
usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data);
break;
default:
kfree(buf);
usb_free_urb(urb);
return NULL;
}
return urb;
}
static inline void bpa10x_free_urb(struct urb *urb)
{
BT_DBG("urb %p", urb);
if (!urb)
return;
if (urb->setup_packet)
kfree(urb->setup_packet);
if (urb->transfer_buffer)
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
static int bpa10x_open(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
struct usb_device *udev = data->udev;
unsigned long flags;
int err;
BT_DBG("hdev %p data %p", hdev, data);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP),
BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data);
if (!data->cmd_urb) {
err = -ENOMEM;
goto done;
}
data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP),
BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data);
if (!data->evt_urb) {
bpa10x_free_urb(data->cmd_urb);
err = -ENOMEM;
goto done;
}
data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP),
BPA10X_RX_BUF_SIZE, GFP_KERNEL, data);
if (!data->rx_urb) {
bpa10x_free_urb(data->evt_urb);
bpa10x_free_urb(data->cmd_urb);
err = -ENOMEM;
goto done;
}
data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP),
BPA10X_TX_BUF_SIZE, GFP_KERNEL, data);
if (!data->rx_urb) {
bpa10x_free_urb(data->rx_urb);
bpa10x_free_urb(data->evt_urb);
bpa10x_free_urb(data->cmd_urb);
err = -ENOMEM;
goto done;
}
write_lock_irqsave(&data->lock, flags);
err = usb_submit_urb(data->evt_urb, GFP_ATOMIC);
if (err < 0) {
BT_ERR("%s submit failed for event urb %p with error %d",
data->hdev->name, data->evt_urb, err);
} else {
err = usb_submit_urb(data->rx_urb, GFP_ATOMIC);
if (err < 0) {
BT_ERR("%s submit failed for rx urb %p with error %d",
data->hdev->name, data->evt_urb, err);
usb_kill_urb(data->evt_urb);
}
}
write_unlock_irqrestore(&data->lock, flags);
done:
if (err < 0)
clear_bit(HCI_RUNNING, &hdev->flags);
return err;
}
static int bpa10x_close(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
unsigned long flags;
BT_DBG("hdev %p data %p", hdev, data);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
write_lock_irqsave(&data->lock, flags);
skb_queue_purge(&data->cmd_queue);
usb_kill_urb(data->cmd_urb);
usb_kill_urb(data->evt_urb);
usb_kill_urb(data->rx_urb);
usb_kill_urb(data->tx_urb);
write_unlock_irqrestore(&data->lock, flags);
bpa10x_free_urb(data->cmd_urb);
bpa10x_free_urb(data->evt_urb);
bpa10x_free_urb(data->rx_urb);
bpa10x_free_urb(data->tx_urb);
return 0;
}
static int bpa10x_flush(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
BT_DBG("hdev %p data %p", hdev, data);
skb_queue_purge(&data->cmd_queue);
return 0;
}
static int bpa10x_send_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
struct bpa10x_data *data;
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");
return -ENODEV;
}
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
data = hdev->driver_data;
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
switch (skb->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
skb_queue_tail(&data->cmd_queue, skb);
break;
case HCI_ACLDATA_PKT:
hdev->stat.acl_tx++;
skb_queue_tail(&data->tx_queue, skb);
break;
case HCI_SCODATA_PKT:
hdev->stat.sco_tx++;
skb_queue_tail(&data->tx_queue, skb);
break;
};
read_lock(&data->lock);
bpa10x_wakeup(data);
read_unlock(&data->lock);
return 0;
}
static void bpa10x_destruct(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
BT_DBG("hdev %p data %p", hdev, data);
kfree(data);
}
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct hci_dev *hdev;
struct bpa10x_data *data;
int err;
BT_DBG("intf %p id %p", intf, id);
if (ignore)
return -ENODEV;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate data structure");
return -ENOMEM;
}
memset(data, 0, sizeof(*data));
data->udev = udev;
rwlock_init(&data->lock);
skb_queue_head_init(&data->cmd_queue);
skb_queue_head_init(&data->tx_queue);
hdev = hci_alloc_dev();
if (!hdev) {
BT_ERR("Can't allocate HCI device");
kfree(data);
return -ENOMEM;
}
data->hdev = hdev;
hdev->type = HCI_USB;
hdev->driver_data = data;
SET_HCIDEV_DEV(hdev, &intf->dev);
hdev->open = bpa10x_open;
hdev->close = bpa10x_close;
hdev->flush = bpa10x_flush;
hdev->send = bpa10x_send_frame;
hdev->destruct = bpa10x_destruct;
hdev->owner = THIS_MODULE;
err = hci_register_dev(hdev);
if (err < 0) {
BT_ERR("Can't register HCI device");
kfree(data);
hci_free_dev(hdev);
return err;
}
usb_set_intfdata(intf, data);
return 0;
}
static void bpa10x_disconnect(struct usb_interface *intf)
{
struct bpa10x_data *data = usb_get_intfdata(intf);
struct hci_dev *hdev = data->hdev;
BT_DBG("intf %p", intf);
if (!hdev)
return;
usb_set_intfdata(intf, NULL);
if (hci_unregister_dev(hdev) < 0)
BT_ERR("Can't unregister HCI device %s", hdev->name);
hci_free_dev(hdev);
}
static struct usb_driver bpa10x_driver = {
.owner = THIS_MODULE,
.name = "bpa10x",
.probe = bpa10x_probe,
.disconnect = bpa10x_disconnect,
.id_table = bpa10x_table,
};
static int __init bpa10x_init(void)
{
int err;
BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
err = usb_register(&bpa10x_driver);
if (err < 0)
BT_ERR("Failed to register USB driver");
return err;
}
static void __exit bpa10x_exit(void)
{
usb_deregister(&bpa10x_driver);
}
module_init(bpa10x_init);
module_exit(bpa10x_exit);
module_param(ignore, bool, 0644);
MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
...@@ -73,7 +73,7 @@ static int reset = 0; ...@@ -73,7 +73,7 @@ static int reset = 0;
static int isoc = 2; static int isoc = 2;
#endif #endif
#define VERSION "2.7" #define VERSION "2.8"
static struct usb_driver hci_usb_driver; static struct usb_driver hci_usb_driver;
...@@ -104,11 +104,11 @@ static struct usb_device_id blacklist_ids[] = { ...@@ -104,11 +104,11 @@ static struct usb_device_id blacklist_ids[] = {
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
/* Broadcom BCM2035 */ /* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */ /* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_BCM92035 },
/* ISSC Bluetooth Adapter v3.1 */ /* ISSC Bluetooth Adapter v3.1 */
{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
...@@ -977,6 +977,17 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -977,6 +977,17 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
} }
if (id->driver_info & HCI_BCM92035) {
unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 };
struct sk_buff *skb;
skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
if (skb) {
memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
skb_queue_tail(&hdev->driver_init, skb);
}
}
if (hci_register_dev(hdev) < 0) { if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device"); BT_ERR("Can't register HCI device");
hci_free_dev(hdev); hci_free_dev(hdev);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define HCI_DIGIANSWER 0x04 #define HCI_DIGIANSWER 0x04
#define HCI_SNIFFER 0x08 #define HCI_SNIFFER 0x08
#define HCI_BROKEN_ISOC 0x10 #define HCI_BROKEN_ISOC 0x10
#define HCI_BCM92035 0x20
#define HCI_MAX_IFACE_NUM 3 #define HCI_MAX_IFACE_NUM 3
......
...@@ -41,6 +41,7 @@ struct ip_ct_tcp ...@@ -41,6 +41,7 @@ struct ip_ct_tcp
u_int8_t retrans; /* Number of retransmitted packets */ u_int8_t retrans; /* Number of retransmitted packets */
u_int8_t last_index; /* Index of the last packet */ u_int8_t last_index; /* Index of the last packet */
u_int32_t last_seq; /* Last sequence number seen in dir */ u_int32_t last_seq; /* Last sequence number seen in dir */
u_int32_t last_ack; /* Last sequence number seen in opposite dir */
u_int32_t last_end; /* Last seq + len */ u_int32_t last_end; /* Last seq + len */
}; };
......
...@@ -64,10 +64,10 @@ struct ip_conntrack_tuple ...@@ -64,10 +64,10 @@ struct ip_conntrack_tuple
} u; } u;
/* The protocol. */ /* The protocol. */
u8 protonum; u_int8_t protonum;
/* The direction (for tuplehash) */ /* The direction (for tuplehash) */
u8 dir; u_int8_t dir;
} dst; } dst;
}; };
......
...@@ -133,10 +133,9 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); ...@@ -133,10 +133,9 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
/* /*
* skb should fit one page. This choice is good for headerless malloc. * skb should fit one page. This choice is good for headerless malloc.
*
* FIXME: What is the best size for SLAB???? --ANK
*/ */
#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF)) #define NLMSG_GOODORDER 0
#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
struct netlink_callback struct netlink_callback
......
...@@ -119,6 +119,8 @@ struct hci_dev { ...@@ -119,6 +119,8 @@ struct hci_dev {
struct hci_dev_stats stat; struct hci_dev_stats stat;
struct sk_buff_head driver_init;
void *driver_data; void *driver_data;
void *core_data; void *core_data;
......
...@@ -183,10 +183,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) ...@@ -183,10 +183,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
static void hci_init_req(struct hci_dev *hdev, unsigned long opt) static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
{ {
struct sk_buff *skb;
__u16 param; __u16 param;
BT_DBG("%s %ld", hdev->name, opt); BT_DBG("%s %ld", hdev->name, opt);
/* Driver initialization */
/* Special commands */
while ((skb = skb_dequeue(&hdev->driver_init))) {
skb->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb);
hci_sched_cmd(hdev);
}
skb_queue_purge(&hdev->driver_init);
/* Mandatory initialization */ /* Mandatory initialization */
/* Reset */ /* Reset */
...@@ -792,6 +804,8 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -792,6 +804,8 @@ struct hci_dev *hci_alloc_dev(void)
memset(hdev, 0, sizeof(struct hci_dev)); memset(hdev, 0, sizeof(struct hci_dev));
skb_queue_head_init(&hdev->driver_init);
return hdev; return hdev;
} }
EXPORT_SYMBOL(hci_alloc_dev); EXPORT_SYMBOL(hci_alloc_dev);
...@@ -799,6 +813,8 @@ EXPORT_SYMBOL(hci_alloc_dev); ...@@ -799,6 +813,8 @@ EXPORT_SYMBOL(hci_alloc_dev);
/* Free HCI device */ /* Free HCI device */
void hci_free_dev(struct hci_dev *hdev) void hci_free_dev(struct hci_dev *hdev)
{ {
skb_queue_purge(&hdev->driver_init);
/* will free via class release */ /* will free via class release */
class_device_put(&hdev->class_dev); class_device_put(&hdev->class_dev);
} }
......
...@@ -1232,7 +1232,7 @@ u32 __init root_nfs_parse_addr(char *name) ...@@ -1232,7 +1232,7 @@ u32 __init root_nfs_parse_addr(char *name)
if (*cp == ':') if (*cp == ':')
*cp++ = '\0'; *cp++ = '\0';
addr = in_aton(name); addr = in_aton(name);
strcpy(name, cp); memmove(name, cp, strlen(cp) + 1);
} else } else
addr = INADDR_NONE; addr = INADDR_NONE;
......
...@@ -373,9 +373,8 @@ static int help(struct sk_buff **pskb, ...@@ -373,9 +373,8 @@ static int help(struct sk_buff **pskb,
goto out_update_nl; goto out_update_nl;
} }
DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n", DEBUGP("conntrack_ftp: match `%s' (%u bytes at %u)\n",
(int)matchlen, data + matchoff, fb_ptr + matchoff, matchlen, ntohl(th->seq) + matchoff);
matchlen, ntohl(th->seq) + matchoff);
/* Allocate expectation which will be inserted */ /* Allocate expectation which will be inserted */
exp = ip_conntrack_expect_alloc(); exp = ip_conntrack_expect_alloc();
......
...@@ -665,11 +665,13 @@ static int tcp_in_window(struct ip_ct_tcp *state, ...@@ -665,11 +665,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
if (*index == TCP_ACK_SET) { if (*index == TCP_ACK_SET) {
if (state->last_dir == dir if (state->last_dir == dir
&& state->last_seq == seq && state->last_seq == seq
&& state->last_ack == ack
&& state->last_end == end) && state->last_end == end)
state->retrans++; state->retrans++;
else { else {
state->last_dir = dir; state->last_dir = dir;
state->last_seq = seq; state->last_seq = seq;
state->last_ack = ack;
state->last_end = end; state->last_end = end;
state->retrans = 0; state->retrans = 0;
} }
......
...@@ -543,6 +543,7 @@ int __init ip_nat_init(void) ...@@ -543,6 +543,7 @@ int __init ip_nat_init(void)
static int clean_nat(struct ip_conntrack *i, void *data) static int clean_nat(struct ip_conntrack *i, void *data)
{ {
memset(&i->nat, 0, sizeof(i->nat)); memset(&i->nat, 0, sizeof(i->nat));
i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
return 0; return 0;
} }
......
...@@ -570,7 +570,7 @@ static void *dl_seq_start(struct seq_file *s, loff_t *pos) ...@@ -570,7 +570,7 @@ static void *dl_seq_start(struct seq_file *s, loff_t *pos)
if (*pos >= htable->cfg.size) if (*pos >= htable->cfg.size)
return NULL; return NULL;
bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL); bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
if (!bucket) if (!bucket)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -180,10 +180,10 @@ ip6ip6_tnl_link(struct ip6_tnl *t) ...@@ -180,10 +180,10 @@ ip6ip6_tnl_link(struct ip6_tnl *t)
{ {
struct ip6_tnl **tp = ip6ip6_bucket(&t->parms); struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
write_lock_bh(&ip6ip6_lock);
t->next = *tp; t->next = *tp;
write_unlock_bh(&ip6ip6_lock); write_lock_bh(&ip6ip6_lock);
*tp = t; *tp = t;
write_unlock_bh(&ip6ip6_lock);
} }
/** /**
......
...@@ -207,6 +207,11 @@ tcf_ipt(struct sk_buff **pskb, struct tc_action *a) ...@@ -207,6 +207,11 @@ tcf_ipt(struct sk_buff **pskb, struct tc_action *a)
struct tcf_ipt *p = PRIV(a, ipt); struct tcf_ipt *p = PRIV(a, ipt);
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
if (skb_cloned(skb)) {
if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
return TC_ACT_UNSPEC;
}
spin_lock(&p->lock); spin_lock(&p->lock);
p->tm.lastuse = jiffies; p->tm.lastuse = jiffies;
......
...@@ -177,6 +177,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) ...@@ -177,6 +177,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
pr_debug("netem_enqueue: random loss\n"); pr_debug("netem_enqueue: random loss\n");
sch->qstats.drops++; sch->qstats.drops++;
kfree_skb(skb);
return 0; /* lie about loss so TCP doesn't know */ return 0; /* lie about loss so TCP doesn't know */
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment