Commit 8feb324f authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-bt.bkbits.net/bt-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 204048de 2d6ed781
...@@ -13,11 +13,18 @@ config BT_HCIUSB ...@@ -13,11 +13,18 @@ config BT_HCIUSB
Say Y here to compile support for Bluetooth USB devices into the Say Y here to compile support for Bluetooth USB devices into the
kernel or say M to compile it as module (hci_usb). kernel or say M to compile it as module (hci_usb).
config BT_USB_SCO
bool "SCO over HCI USB support"
depends on BT_HCIUSB
help
This option enables the SCO support in the HCI USB driver. You need this
to transmit voice data with your Bluetooth USB device.
Say Y here to compile support for SCO over HCI USB.
config BT_USB_ZERO_PACKET config BT_USB_ZERO_PACKET
bool "USB zero packet support" bool "USB zero packet support"
depends on BT_HCIUSB depends on BT_HCIUSB
help help
Support for USB zero packets.
This option is provided only as a work around for buggy Bluetooth USB 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 devices. Do _not_ enable it unless you know for sure that your device
requires zero packets. requires zero packets.
......
...@@ -1075,36 +1075,29 @@ int bluecard_event(event_t event, int priority, event_callback_args_t *args) ...@@ -1075,36 +1075,29 @@ int bluecard_event(event_t event, int priority, event_callback_args_t *args)
return 0; return 0;
} }
static struct pcmcia_driver bluecard_driver = {
.owner = THIS_MODULE,
/* ======================== Module initialization ======================== */ .drv = {
.name = "bluecard_cs",
},
int __init init_bluecard_cs(void) .attach = bluecard_attach,
.detach = bluecard_detach,
};
static int __init init_bluecard_cs(void)
{ {
servinfo_t serv; return pcmcia_register_driver(&bluecard_driver);
int err;
CardServices(GetCardServicesInfo, &serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
return -1;
}
err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
return err;
} }
void __exit exit_bluecard_cs(void) static void __exit exit_bluecard_cs(void)
{ {
unregister_pccard_driver(&dev_info); pcmcia_unregister_driver(&bluecard_driver);
/* XXX: this really needs to move into generic code.. */
while (dev_list != NULL) while (dev_list != NULL)
bluecard_detach(dev_list); bluecard_detach(dev_list);
} }
module_init(init_bluecard_cs); module_init(init_bluecard_cs);
module_exit(exit_bluecard_cs); module_exit(exit_bluecard_cs);
...@@ -861,36 +861,29 @@ int bt3c_event(event_t event, int priority, event_callback_args_t *args) ...@@ -861,36 +861,29 @@ int bt3c_event(event_t event, int priority, event_callback_args_t *args)
return 0; return 0;
} }
static struct pcmcia_driver bt3c_driver = {
.owner = THIS_MODULE,
/* ======================== Module initialization ======================== */ .drv = {
.name = "bt3c_cs",
},
int __init init_bt3c_cs(void) .attach = bt3c_attach,
.detach = bt3c_detach,
};
static int __init init_bt3c_cs(void)
{ {
servinfo_t serv; return pcmcia_register_driver(&bt3c_driver);
int err;
CardServices(GetCardServicesInfo, &serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
return -1;
}
err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
return err;
} }
void __exit exit_bt3c_cs(void) static void __exit exit_bt3c_cs(void)
{ {
unregister_pccard_driver(&dev_info); pcmcia_unregister_driver(&bt3c_driver);
/* XXX: this really needs to move into generic code.. */
while (dev_list != NULL) while (dev_list != NULL)
bt3c_detach(dev_list); bt3c_detach(dev_list);
} }
module_init(init_bt3c_cs); module_init(init_bt3c_cs);
module_exit(exit_bt3c_cs); module_exit(exit_bt3c_cs);
...@@ -868,36 +868,29 @@ int btuart_event(event_t event, int priority, event_callback_args_t *args) ...@@ -868,36 +868,29 @@ int btuart_event(event_t event, int priority, event_callback_args_t *args)
return 0; return 0;
} }
static struct pcmcia_driver btuart_driver = {
.owner = THIS_MODULE,
/* ======================== Module initialization ======================== */ .drv = {
.name = "btuart_cs",
},
int __init init_btuart_cs(void) .attach = btuart_attach,
.detach = btuart_detach,
};
static int __init init_btuart_cs(void)
{ {
servinfo_t serv; return pcmcia_register_driver(&btuart_driver);
int err;
CardServices(GetCardServicesInfo, &serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
return -1;
}
err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
return err;
} }
void __exit exit_btuart_cs(void) static void __exit exit_btuart_cs(void)
{ {
unregister_pccard_driver(&dev_info); pcmcia_unregister_driver(&btuart_driver);
/* XXX: this really needs to move into generic code.. */
while (dev_list != NULL) while (dev_list != NULL)
btuart_detach(dev_list); btuart_detach(dev_list);
} }
module_init(init_btuart_cs); module_init(init_btuart_cs);
module_exit(exit_btuart_cs); module_exit(exit_btuart_cs);
...@@ -820,36 +820,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args) ...@@ -820,36 +820,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args)
return 0; return 0;
} }
static struct pcmcia_driver dtl1_driver = {
.owner = THIS_MODULE,
/* ======================== Module initialization ======================== */ .drv = {
.name = "dtl1_cs",
},
int __init init_dtl1_cs(void) .attach = dtl1_attach,
.detach = dtl1_detach,
};
static int __init init_dtl1_cs(void)
{ {
servinfo_t serv; return pcmcia_register_driver(&dtl1_driver);
int err;
CardServices(GetCardServicesInfo, &serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
return -1;
}
err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
return err;
} }
void __exit exit_dtl1_cs(void) static void __exit exit_dtl1_cs(void)
{ {
unregister_pccard_driver(&dev_info); pcmcia_unregister_driver(&dtl1_driver);
/* XXX: this really needs to move into generic code.. */
while (dev_list != NULL) while (dev_list != NULL)
dtl1_detach(dev_list); dtl1_detach(dev_list);
} }
module_init(init_dtl1_cs); module_init(init_dtl1_cs);
module_exit(exit_dtl1_cs); module_exit(exit_dtl1_cs);
This diff is collapsed.
/* /*
BlueZ - Bluetooth protocol stack for Linux HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation; published by the Free Software Foundation;
...@@ -40,40 +41,96 @@ ...@@ -40,40 +41,96 @@
#define HCI_MAX_BULK_TX 4 #define HCI_MAX_BULK_TX 4
#define HCI_MAX_BULK_RX 1 #define HCI_MAX_BULK_RX 1
#define HCI_MAX_ISOC_FRAMES 10
struct _urb_queue {
struct list_head head;
spinlock_t lock;
};
struct _urb {
struct list_head list;
struct _urb_queue *queue;
int type;
void *priv;
struct urb urb;
};
struct _urb *_urb_alloc(int isoc, int gfp);
static inline void _urb_free(struct _urb *_urb)
{
kfree(_urb);
}
static inline void _urb_queue_init(struct _urb_queue *q)
{
INIT_LIST_HEAD(&q->head);
spin_lock_init(&q->lock);
}
static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
list_add(&_urb->list, &q->head); _urb->queue = q;
spin_unlock_irqrestore(&q->lock, flags);
}
static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
list_add_tail(&_urb->list, &q->head); _urb->queue = q;
spin_unlock_irqrestore(&q->lock, flags);
}
static inline void _urb_unlink(struct _urb *_urb)
{
struct _urb_queue *q = _urb->queue;
unsigned long flags;
if (q) {
spin_lock_irqsave(&q->lock, flags);
list_del(&_urb->list); _urb->queue = NULL;
spin_unlock_irqrestore(&q->lock, flags);
}
}
struct _urb *_urb_dequeue(struct _urb_queue *q);
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
struct hci_usb { struct hci_usb {
struct hci_dev hdev; struct hci_dev hdev;
unsigned long state; unsigned long state;
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *isoc_iface;
__u8 bulk_out_ep; struct usb_host_endpoint *bulk_in_ep;
__u8 bulk_in_ep; struct usb_host_endpoint *bulk_out_ep;
__u8 isoc_out_ep; struct usb_host_endpoint *intr_in_ep;
__u8 isoc_in_ep;
struct usb_interface *isoc_iface;
struct usb_host_endpoint *isoc_out_ep;
struct usb_host_endpoint *isoc_in_ep;
__u8 intr_ep; struct sk_buff_head transmit_q[4];
__u8 intr_interval; struct sk_buff *reassembly[4]; // Reassembly buffers
struct urb *intr_urb;
struct sk_buff *intr_skb;
rwlock_t completion_lock; rwlock_t completion_lock;
struct sk_buff_head cmd_q; // TX Commands
struct sk_buff_head acl_q; // TX ACLs
struct sk_buff_head pending_q; // Pending requests
struct sk_buff_head completed_q; // Completed requests
};
struct hci_usb_scb { atomic_t pending_tx[4]; // Number of pending requests
struct urb *urb; struct _urb_queue pending_q[4]; // Pending requests
int intr_len; struct _urb_queue completed_q[4]; // Completed requests
}; };
/* States */ /* States */
#define HCI_USB_TX_PROCESS 1 #define HCI_USB_TX_PROCESS 1
#define HCI_USB_TX_WAKEUP 2 #define HCI_USB_TX_WAKEUP 2
#define HCI_USB_CTRL_TX 3
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
...@@ -262,7 +262,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); ...@@ -262,7 +262,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
int hci_conn_auth(struct hci_conn *conn); int hci_conn_auth(struct hci_conn *conn);
int hci_conn_encrypt(struct hci_conn *conn); int hci_conn_encrypt(struct hci_conn *conn);
static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout) static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout)
{ {
mod_timer(&conn->timer, jiffies + timeout); mod_timer(&conn->timer, jiffies + timeout);
} }
...@@ -280,8 +280,12 @@ static inline void hci_conn_hold(struct hci_conn *conn) ...@@ -280,8 +280,12 @@ static inline void hci_conn_hold(struct hci_conn *conn)
static inline void hci_conn_put(struct hci_conn *conn) static inline void hci_conn_put(struct hci_conn *conn)
{ {
if (atomic_dec_and_test(&conn->refcnt) && conn->out) if (atomic_dec_and_test(&conn->refcnt)) {
hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); if (conn->type == SCO_LINK)
hci_conn_set_timer(conn, HZ / 100);
else if (conn->out)
hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT);
}
} }
/* ----- HCI tasks ----- */ /* ----- HCI tasks ----- */
......
...@@ -146,6 +146,11 @@ struct rfcomm_rpn { ...@@ -146,6 +146,11 @@ struct rfcomm_rpn {
u16 param_mask; u16 param_mask;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct rfcomm_rls {
u8 dlci;
u8 status;
} __attribute__ ((packed));
struct rfcomm_msc { struct rfcomm_msc {
u8 dlci; u8 dlci;
u8 v24_sig; u8 v24_sig;
...@@ -215,10 +220,9 @@ static inline void rfcomm_schedule(uint event) ...@@ -215,10 +220,9 @@ static inline void rfcomm_schedule(uint event)
{ {
if (!rfcomm_thread) if (!rfcomm_thread)
return; return;
//set_bit(event, &rfcomm_event); //set_bit(event, &rfcomm_event);
if (!test_and_set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread); wake_up_process(rfcomm_thread);
} }
extern struct semaphore rfcomm_sem; extern struct semaphore rfcomm_sem;
......
...@@ -321,6 +321,7 @@ int bt_sock_w4_connect(struct sock *sk, int flags) ...@@ -321,6 +321,7 @@ int bt_sock_w4_connect(struct sock *sk, int flags)
} }
struct net_proto_family bt_sock_family_ops = { struct net_proto_family bt_sock_family_ops = {
.owner = THIS_MODULE,
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
.create = bt_sock_create, .create = bt_sock_create,
}; };
......
...@@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *conn) ...@@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *conn)
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst); bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x01;
if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
......
...@@ -161,8 +161,6 @@ static int hci_sock_release(struct socket *sock) ...@@ -161,8 +161,6 @@ static int hci_sock_release(struct socket *sock)
skb_queue_purge(&sk->write_queue); skb_queue_purge(&sk->write_queue);
sock_put(sk); sock_put(sk);
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -591,8 +589,6 @@ static int hci_sock_create(struct socket *sock, int protocol) ...@@ -591,8 +589,6 @@ static int hci_sock_create(struct socket *sock, int protocol)
sk->state = BT_OPEN; sk->state = BT_OPEN;
bt_sock_link(&hci_sk_list, sk); bt_sock_link(&hci_sk_list, sk);
MOD_INC_USE_COUNT;
return 0; return 0;
} }
......
...@@ -1788,7 +1788,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ...@@ -1788,7 +1788,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
if (sk->state != BT_LISTEN) if (sk->state != BT_LISTEN)
continue; continue;
if (!bacmp(&bt_sk(sk)->src, bdaddr)) { if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
exact++; exact++;
} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
......
...@@ -798,6 +798,33 @@ static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, ...@@ -798,6 +798,33 @@ static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
return rfcomm_send_frame(s, buf, ptr - buf); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
{
struct rfcomm_hdr *hdr;
struct rfcomm_mcc *mcc;
struct rfcomm_rls *rls;
u8 buf[16], *ptr = buf;
BT_DBG("%p cr %d status 0x%x", s, cr, status);
hdr = (void *) ptr; ptr += sizeof(*hdr);
hdr->addr = __addr(s->initiator, 0);
hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
hdr->len = __len8(sizeof(*mcc) + sizeof(*rls));
mcc = (void *) ptr; ptr += sizeof(*mcc);
mcc->type = __mcc_type(cr, RFCOMM_RLS);
mcc->len = __len8(sizeof(*rls));
rls = (void *) ptr; ptr += sizeof(*rls);
rls->dlci = __addr(1, dlci);
rls->status = status;
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
{ {
struct rfcomm_hdr *hdr; struct rfcomm_hdr *hdr;
...@@ -1229,6 +1256,26 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ ...@@ -1229,6 +1256,26 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
return 0; return 0;
} }
static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
{
struct rfcomm_rls *rls = (void *) skb->data;
u8 dlci = __get_dlci(rls->dlci);
BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
if (!cr)
return 0;
/* FIXME: We should probably do something with this
information here. But for now it's sufficient just
to reply -- Bluetooth 1.1 says it's mandatory to
recognise and respond to RLS */
rfcomm_send_rls(s, 0, dlci, rls->status);
return 0;
}
static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
{ {
struct rfcomm_msc *msc = (void *) skb->data; struct rfcomm_msc *msc = (void *) skb->data;
...@@ -1279,6 +1326,10 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) ...@@ -1279,6 +1326,10 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
rfcomm_recv_rpn(s, cr, len, skb); rfcomm_recv_rpn(s, cr, len, skb);
break; break;
case RFCOMM_RLS:
rfcomm_recv_rls(s, cr, skb);
break;
case RFCOMM_MSC: case RFCOMM_MSC:
rfcomm_recv_msc(s, cr, skb); rfcomm_recv_msc(s, cr, skb);
break; break;
...@@ -1432,9 +1483,9 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ...@@ -1432,9 +1483,9 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
d->rx_credits = d->credits; d->rx_credits = d->credits;
} }
} else { } else {
/* CFC disabled. /* CFC disabled.
* Give ourselves some credits */ * Give ourselves some credits */
d->tx_credits = RFCOMM_MAX_CREDITS; d->tx_credits = 5;
} }
if (test_bit(RFCOMM_TX_THROTTLED, &d->flags)) if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
...@@ -1600,7 +1651,7 @@ static void rfcomm_worker(void) ...@@ -1600,7 +1651,7 @@ static void rfcomm_worker(void)
BT_DBG(""); BT_DBG("");
while (!atomic_read(&terminate)) { while (!atomic_read(&terminate)) {
if (!test_and_clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
/* No pending events. Let's sleep. /* No pending events. Let's sleep.
* Incomming connections and data will wake us up. */ * Incomming connections and data will wake us up. */
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
...@@ -1608,6 +1659,7 @@ static void rfcomm_worker(void) ...@@ -1608,6 +1659,7 @@ static void rfcomm_worker(void)
} }
/* Process stuff */ /* Process stuff */
clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
rfcomm_process_sessions(); rfcomm_process_sessions();
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
......
...@@ -72,7 +72,6 @@ struct rfcomm_dev { ...@@ -72,7 +72,6 @@ struct rfcomm_dev {
struct tasklet_struct wakeup_task; struct tasklet_struct wakeup_task;
atomic_t wmem_alloc; atomic_t wmem_alloc;
unsigned int sndbuf;
}; };
static LIST_HEAD(rfcomm_dev_list); static LIST_HEAD(rfcomm_dev_list);
...@@ -200,8 +199,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) ...@@ -200,8 +199,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
dev->flags = req->flags & dev->flags = req->flags &
((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
dev->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
init_waitqueue_head(&dev->wait); init_waitqueue_head(&dev->wait);
tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
...@@ -238,6 +235,13 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev) ...@@ -238,6 +235,13 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
} }
/* ---- Send buffer ---- */ /* ---- Send buffer ---- */
static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
{
/* We can't let it be zero, because we don't get a callback
when tx_credits becomes nonzero, hence we'd never wake up */
return dlc->mtu * (dlc->tx_credits?:1);
}
static void rfcomm_wfree(struct sk_buff *skb) static void rfcomm_wfree(struct sk_buff *skb)
{ {
struct rfcomm_dev *dev = (void *) skb->sk; struct rfcomm_dev *dev = (void *) skb->sk;
...@@ -257,7 +261,7 @@ static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *de ...@@ -257,7 +261,7 @@ static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *de
static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority) static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
{ {
if (atomic_read(&dev->wmem_alloc) < dev->sndbuf) { if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
struct sk_buff *skb = alloc_skb(size, priority); struct sk_buff *skb = alloc_skb(size, priority);
if (skb) { if (skb) {
rfcomm_set_owner_w(skb, dev); rfcomm_set_owner_w(skb, dev);
...@@ -651,11 +655,14 @@ static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigne ...@@ -651,11 +655,14 @@ static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigne
static int rfcomm_tty_write_room(struct tty_struct *tty) static int rfcomm_tty_write_room(struct tty_struct *tty)
{ {
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
struct rfcomm_dlc *dlc = dev->dlc; int room;
BT_DBG("tty %p", tty); BT_DBG("tty %p", tty);
return dlc->mtu * (dlc->tx_credits ? : 10); room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
if (room < 0)
room = 0;
return room;
} }
static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status) static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
...@@ -849,6 +856,8 @@ static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS]; ...@@ -849,6 +856,8 @@ static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS]; static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
static struct tty_driver rfcomm_tty_driver = { static struct tty_driver rfcomm_tty_driver = {
.owner = THIS_MODULE,
.magic = TTY_DRIVER_MAGIC, .magic = TTY_DRIVER_MAGIC,
.driver_name = "rfcomm", .driver_name = "rfcomm",
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
......
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