Commit 1cdd77fe authored by David S. Miller's avatar David S. Miller

Merge http://linux-mh.bkbits.net/bluetooth-2.6

into nuts.davemloft.net:/disk1/BK/net-2.6
parents e0512113 0d8b93d0
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#define VERSION "1.0" #define VERSION "1.0"
static int ignore = 0;
static struct usb_device_id bcm203x_table[] = { static struct usb_device_id bcm203x_table[] = {
/* Broadcom Blutonium (BCM2033) */ /* Broadcom Blutonium (BCM2033) */
{ USB_DEVICE(0x0a5c, 0x2033) }, { USB_DEVICE(0x0a5c, 0x2033) },
...@@ -55,7 +57,6 @@ static struct usb_device_id bcm203x_table[] = { ...@@ -55,7 +57,6 @@ static struct usb_device_id bcm203x_table[] = {
MODULE_DEVICE_TABLE(usb, bcm203x_table); MODULE_DEVICE_TABLE(usb, bcm203x_table);
#define BCM203X_ERROR 0 #define BCM203X_ERROR 0
#define BCM203X_RESET 1 #define BCM203X_RESET 1
#define BCM203X_LOAD_MINIDRV 2 #define BCM203X_LOAD_MINIDRV 2
...@@ -175,7 +176,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -175,7 +176,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
BT_DBG("intf %p id %p", intf, id); BT_DBG("intf %p id %p", intf, id);
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) if (ignore || (intf->cur_altsetting->desc.bInterfaceNumber != 0))
return -ENODEV; return -ENODEV;
data = kmalloc(sizeof(*data), GFP_KERNEL); data = kmalloc(sizeof(*data), GFP_KERNEL);
...@@ -304,6 +305,9 @@ static void __exit bcm203x_exit(void) ...@@ -304,6 +305,9 @@ static void __exit bcm203x_exit(void)
module_init(bcm203x_init); module_init(bcm203x_init);
module_exit(bcm203x_exit); module_exit(bcm203x_exit);
module_param(ignore, bool, 0644);
MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
#define VERSION "1.1" #define VERSION "1.1"
static int ignore = 0;
static struct usb_driver bfusb_driver; static struct usb_driver bfusb_driver;
static struct usb_device_id bfusb_table[] = { static struct usb_device_id bfusb_table[] = {
...@@ -655,6 +657,9 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -655,6 +657,9 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
BT_DBG("intf %p id %p", intf, id); BT_DBG("intf %p id %p", intf, id);
if (ignore)
return -ENODEV;
/* Check number of endpoints */ /* Check number of endpoints */
if (intf->cur_altsetting->desc.bNumEndpoints < 2) if (intf->cur_altsetting->desc.bNumEndpoints < 2)
return -EIO; return -EIO;
...@@ -792,6 +797,9 @@ static void __exit bfusb_exit(void) ...@@ -792,6 +797,9 @@ static void __exit bfusb_exit(void)
module_init(bfusb_init); module_init(bfusb_init);
module_exit(bfusb_exit); module_exit(bfusb_exit);
module_param(ignore, bool, 0644);
MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
...@@ -265,7 +265,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, ...@@ -265,7 +265,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
/* This is a rewrite of pkt_avail in ABCSP */ /* This is a rewrite of pkt_avail in ABCSP */
static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
{ {
struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; struct bcsp_struct *bcsp = hu->priv;
unsigned long flags; unsigned long flags;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -629,7 +629,7 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count) ...@@ -629,7 +629,7 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count)
static void bcsp_timed_event(unsigned long arg) static void bcsp_timed_event(unsigned long arg)
{ {
struct hci_uart *hu = (struct hci_uart *) arg; struct hci_uart *hu = (struct hci_uart *) arg;
struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; struct bcsp_struct *bcsp = hu->priv;
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags; unsigned long flags;
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include "hci_uart.h" #include "hci_uart.h"
#ifndef CONFIG_BT_HCIUART_DEBUG #ifndef CONFIG_BT_HCIUART_DEBUG
...@@ -60,6 +61,8 @@ ...@@ -60,6 +61,8 @@
#define BT_DMP( A... ) #define BT_DMP( A... )
#endif #endif
static int reset = 0;
static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
int hci_uart_register_proto(struct hci_uart_proto *p) int hci_uart_register_proto(struct hci_uart_proto *p)
...@@ -412,7 +415,10 @@ static int hci_uart_register_dev(struct hci_uart *hu) ...@@ -412,7 +415,10 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hdev->destruct = hci_uart_destruct; hdev->destruct = hci_uart_destruct;
hdev->owner = THIS_MODULE; hdev->owner = THIS_MODULE;
if (reset)
set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
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);
...@@ -577,7 +583,10 @@ static void __exit hci_uart_exit(void) ...@@ -577,7 +583,10 @@ static void __exit hci_uart_exit(void)
module_init(hci_uart_init); module_init(hci_uart_init);
module_exit(hci_uart_exit); module_exit(hci_uart_exit);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); module_param(reset, bool, 0644);
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -66,6 +66,9 @@ ...@@ -66,6 +66,9 @@
#define URB_ZERO_PACKET 0 #define URB_ZERO_PACKET 0
#endif #endif
static int ignore = 0;
static int reset = 0;
#ifdef CONFIG_BT_HCIUSB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
static int isoc = 2; static int isoc = 2;
#endif #endif
...@@ -827,7 +830,7 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -827,7 +830,7 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
id = match; id = match;
} }
if (id->driver_info & HCI_IGNORE) if (ignore || id->driver_info & HCI_IGNORE)
return -ENODEV; return -ENODEV;
if (intf->cur_altsetting->desc.bInterfaceNumber > 0) if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
...@@ -963,7 +966,7 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -963,7 +966,7 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
hdev->owner = THIS_MODULE; hdev->owner = THIS_MODULE;
if (id->driver_info & HCI_RESET) if (reset || id->driver_info & HCI_RESET)
set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
if (hci_register_dev(hdev) < 0) { if (hci_register_dev(hdev) < 0) {
...@@ -1036,6 +1039,12 @@ static void __exit hci_usb_exit(void) ...@@ -1036,6 +1039,12 @@ static void __exit hci_usb_exit(void)
module_init(hci_usb_init); module_init(hci_usb_init);
module_exit(hci_usb_exit); module_exit(hci_usb_exit);
module_param(ignore, bool, 0644);
MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
module_param(reset, bool, 0644);
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
#ifdef CONFIG_BT_HCIUSB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
module_param(isoc, int, 0644); module_param(isoc, int, 0644);
MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support"); MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support");
......
...@@ -277,7 +277,6 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, ...@@ -277,7 +277,6 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
return NULL; return NULL;
} }
void hci_acl_connect(struct hci_conn *conn);
void hci_acl_disconn(struct hci_conn *conn, __u8 reason); void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
void hci_add_sco(struct hci_conn *conn, __u16 handle); void hci_add_sco(struct hci_conn *conn, __u16 handle);
...@@ -589,6 +588,5 @@ struct hci_sec_filter { ...@@ -589,6 +588,5 @@ struct hci_sec_filter {
#define hci_req_unlock(d) up(&d->req_lock) #define hci_req_unlock(d) up(&d->req_lock)
void hci_req_complete(struct hci_dev *hdev, int result); void hci_req_complete(struct hci_dev *hdev, int result);
void hci_req_cancel(struct hci_dev *hdev, int err);
#endif /* __HCI_CORE_H */ #endif /* __HCI_CORE_H */
...@@ -38,17 +38,19 @@ struct sockaddr_l2 { ...@@ -38,17 +38,19 @@ struct sockaddr_l2 {
bdaddr_t l2_bdaddr; bdaddr_t l2_bdaddr;
}; };
/* Socket options */ /* L2CAP socket options */
#define L2CAP_OPTIONS 0x01 #define L2CAP_OPTIONS 0x01
struct l2cap_options { struct l2cap_options {
__u16 omtu; __u16 omtu;
__u16 imtu; __u16 imtu;
__u16 flush_to; __u16 flush_to;
__u8 mode;
}; };
#define L2CAP_CONNINFO 0x02 #define L2CAP_CONNINFO 0x02
struct l2cap_conninfo { struct l2cap_conninfo {
__u16 hci_handle; __u16 hci_handle;
__u8 dev_class[3];
}; };
#define L2CAP_LM 0x03 #define L2CAP_LM 0x03
...@@ -59,20 +61,6 @@ struct l2cap_conninfo { ...@@ -59,20 +61,6 @@ struct l2cap_conninfo {
#define L2CAP_LM_RELIABLE 0x0010 #define L2CAP_LM_RELIABLE 0x0010
#define L2CAP_LM_SECURE 0x0020 #define L2CAP_LM_SECURE 0x0020
#define L2CAP_QOS 0x04
struct l2cap_qos {
__u16 service_type;
__u32 token_rate;
__u32 token_bucket_size;
__u32 peak_bandwidth;
__u32 latency;
__u32 delay_variation;
};
#define L2CAP_SERV_NO_TRAFFIC 0x00
#define L2CAP_SERV_BEST_EFFORT 0x01
#define L2CAP_SERV_GUARANTEED 0x02
/* L2CAP command codes */ /* L2CAP command codes */
#define L2CAP_COMMAND_REJ 0x01 #define L2CAP_COMMAND_REJ 0x01
#define L2CAP_CONN_REQ 0x02 #define L2CAP_CONN_REQ 0x02
...@@ -154,6 +142,7 @@ struct l2cap_conf_opt { ...@@ -154,6 +142,7 @@ struct l2cap_conf_opt {
#define L2CAP_CONF_MTU 0x01 #define L2CAP_CONF_MTU 0x01
#define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_FLUSH_TO 0x02
#define L2CAP_CONF_QOS 0x03 #define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_MAX_SIZE 22 #define L2CAP_CONF_MAX_SIZE 22
...@@ -198,11 +187,11 @@ struct l2cap_conn { ...@@ -198,11 +187,11 @@ struct l2cap_conn {
bdaddr_t *dst; bdaddr_t *dst;
bdaddr_t *src; bdaddr_t *src;
unsigned int mtu; unsigned int mtu;
spinlock_t lock; spinlock_t lock;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
__u32 rx_len; __u32 rx_len;
__u8 rx_ident; __u8 rx_ident;
...@@ -222,7 +211,7 @@ struct l2cap_pinfo { ...@@ -222,7 +211,7 @@ struct l2cap_pinfo {
__u16 imtu; __u16 imtu;
__u16 omtu; __u16 omtu;
__u16 flush_to; __u16 flush_to;
__u32 link_mode; __u32 link_mode;
__u8 conf_state; __u8 conf_state;
......
...@@ -181,6 +181,8 @@ struct rfcomm_dlc { ...@@ -181,6 +181,8 @@ struct rfcomm_dlc {
u8 v24_sig; u8 v24_sig;
u8 mscex; u8 mscex;
u32 link_mode;
uint mtu; uint mtu;
uint cfc; uint cfc;
uint rx_credits; uint rx_credits;
...@@ -216,22 +218,6 @@ struct rfcomm_dlc { ...@@ -216,22 +218,6 @@ struct rfcomm_dlc {
#define RFCOMM_CFC_DISABLED 0 #define RFCOMM_CFC_DISABLED 0
#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS #define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS
extern struct task_struct *rfcomm_thread;
extern unsigned long rfcomm_event;
static inline void rfcomm_schedule(uint event)
{
if (!rfcomm_thread)
return;
//set_bit(event, &rfcomm_event);
set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
extern struct semaphore rfcomm_sem;
#define rfcomm_lock() down(&rfcomm_sem);
#define rfcomm_unlock() up(&rfcomm_sem);
/* ---- RFCOMM DLCs (channels) ---- */ /* ---- RFCOMM DLCs (channels) ---- */
struct rfcomm_dlc *rfcomm_dlc_alloc(int prio); struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
void rfcomm_dlc_free(struct rfcomm_dlc *d); void rfcomm_dlc_free(struct rfcomm_dlc *d);
...@@ -271,11 +257,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ...@@ -271,11 +257,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
} }
/* ---- RFCOMM sessions ---- */ /* ---- RFCOMM sessions ---- */
struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
void rfcomm_session_del(struct rfcomm_session *s);
void rfcomm_session_close(struct rfcomm_session *s, int err);
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst); void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
static inline void rfcomm_session_hold(struct rfcomm_session *s) static inline void rfcomm_session_hold(struct rfcomm_session *s)
...@@ -283,27 +264,36 @@ static inline void rfcomm_session_hold(struct rfcomm_session *s) ...@@ -283,27 +264,36 @@ static inline void rfcomm_session_hold(struct rfcomm_session *s)
atomic_inc(&s->refcnt); atomic_inc(&s->refcnt);
} }
static inline void rfcomm_session_put(struct rfcomm_session *s)
{
if (atomic_dec_and_test(&s->refcnt))
rfcomm_session_del(s);
}
/* ---- RFCOMM chechsum ---- */ /* ---- RFCOMM chechsum ---- */
extern u8 rfcomm_crc_table[]; extern u8 rfcomm_crc_table[];
/* ---- RFCOMM sockets ---- */ /* ---- RFCOMM sockets ---- */
struct sockaddr_rc { struct sockaddr_rc {
sa_family_t rc_family; sa_family_t rc_family;
bdaddr_t rc_bdaddr; bdaddr_t rc_bdaddr;
u8 rc_channel; u8 rc_channel;
}; };
#define RFCOMM_CONNINFO 0x02
struct rfcomm_conninfo {
__u16 hci_handle;
__u8 dev_class[3];
};
#define RFCOMM_LM 0x03
#define RFCOMM_LM_MASTER 0x0001
#define RFCOMM_LM_AUTH 0x0002
#define RFCOMM_LM_ENCRYPT 0x0004
#define RFCOMM_LM_TRUSTED 0x0008
#define RFCOMM_LM_RELIABLE 0x0010
#define RFCOMM_LM_SECURE 0x0020
#define rfcomm_pi(sk) ((struct rfcomm_pinfo *)sk->sk_protinfo) #define rfcomm_pi(sk) ((struct rfcomm_pinfo *)sk->sk_protinfo)
struct rfcomm_pinfo { struct rfcomm_pinfo {
struct rfcomm_dlc *dlc; struct rfcomm_dlc *dlc;
u8 channel; u8 channel;
u32 link_mode;
}; };
int rfcomm_init_sockets(void); int rfcomm_init_sockets(void);
......
...@@ -39,15 +39,16 @@ struct sockaddr_sco { ...@@ -39,15 +39,16 @@ struct sockaddr_sco {
bdaddr_t sco_bdaddr; bdaddr_t sco_bdaddr;
}; };
/* set/get sockopt defines */ /* SCO socket options */
#define SCO_OPTIONS 0x01 #define SCO_OPTIONS 0x01
struct sco_options { struct sco_options {
__u16 mtu; __u16 mtu;
}; };
#define SCO_CONNINFO 0x02 #define SCO_CONNINFO 0x02
struct sco_conninfo { struct sco_conninfo {
__u16 hci_handle; __u16 hci_handle;
__u8 dev_class[3];
}; };
/* ---- SCO connections ---- */ /* ---- SCO connections ---- */
......
...@@ -139,6 +139,19 @@ static int cmtp_msgnum_get(struct cmtp_session *session) ...@@ -139,6 +139,19 @@ static int cmtp_msgnum_get(struct cmtp_session *session)
return session->msgnum; return session->msgnum;
} }
static 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 void cmtp_send_interopmsg(struct cmtp_session *session, static void cmtp_send_interopmsg(struct cmtp_session *session,
__u8 subcmd, __u16 appl, __u16 msgnum, __u8 subcmd, __u16 appl, __u16 msgnum,
...@@ -337,21 +350,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) ...@@ -337,21 +350,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
capi_ctr_handle_message(ctrl, appl, skb); 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) static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{ {
BT_DBG("ctrl %p data %p", ctrl, data); BT_DBG("ctrl %p data %p", ctrl, data);
......
...@@ -120,7 +120,6 @@ int cmtp_attach_device(struct cmtp_session *session); ...@@ -120,7 +120,6 @@ int cmtp_attach_device(struct cmtp_session *session);
void cmtp_detach_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_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) static inline void cmtp_schedule(struct cmtp_session *session)
{ {
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
void hci_acl_connect(struct hci_conn *conn) static void hci_acl_connect(struct hci_conn *conn)
{ {
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
struct inquiry_entry *ie; struct inquiry_entry *ie;
......
...@@ -59,7 +59,7 @@ static void hci_rx_task(unsigned long arg); ...@@ -59,7 +59,7 @@ static void hci_rx_task(unsigned long arg);
static void hci_tx_task(unsigned long arg); static void hci_tx_task(unsigned long arg);
static void hci_notify(struct hci_dev *hdev, int event); static void hci_notify(struct hci_dev *hdev, int event);
rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
/* HCI device list */ /* HCI device list */
LIST_HEAD(hci_dev_list); LIST_HEAD(hci_dev_list);
...@@ -106,7 +106,7 @@ void hci_req_complete(struct hci_dev *hdev, int result) ...@@ -106,7 +106,7 @@ void hci_req_complete(struct hci_dev *hdev, int result)
} }
} }
void hci_req_cancel(struct hci_dev *hdev, int err) static void hci_req_cancel(struct hci_dev *hdev, int err)
{ {
BT_DBG("%s err 0x%2.2x", hdev->name, err); BT_DBG("%s err 0x%2.2x", hdev->name, err);
......
...@@ -447,7 +447,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -447,7 +447,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto done; goto done;
} }
int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int len) static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int len)
{ {
struct hci_ufilter uf = { .opcode = 0 }; struct hci_ufilter uf = { .opcode = 0 };
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -514,7 +514,7 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user ...@@ -514,7 +514,7 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user
return err; return err;
} }
int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{ {
struct hci_ufilter uf; struct hci_ufilter uf;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -567,7 +567,7 @@ int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user ...@@ -567,7 +567,7 @@ int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user
return 0; return 0;
} }
struct proto_ops hci_sock_ops = { static struct proto_ops hci_sock_ops = {
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.release = hci_sock_release, .release = hci_sock_release,
...@@ -647,13 +647,13 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, ...@@ -647,13 +647,13 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
struct net_proto_family hci_sock_family_ops = { static struct net_proto_family hci_sock_family_ops = {
.family = PF_BLUETOOTH, .family = PF_BLUETOOTH,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.create = hci_sock_create, .create = hci_sock_create,
}; };
struct notifier_block hci_sock_nblock = { static struct notifier_block hci_sock_nblock = {
.notifier_call = hci_sock_dev_event .notifier_call = hci_sock_dev_event
}; };
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "1.0" #define VERSION "1.1"
static DECLARE_RWSEM(hidp_session_sem); static DECLARE_RWSEM(hidp_session_sem);
static LIST_HEAD(hidp_session_list); static LIST_HEAD(hidp_session_list);
...@@ -130,7 +130,7 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned i ...@@ -130,7 +130,7 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned i
struct sk_buff *skb; struct sk_buff *skb;
unsigned char newleds; unsigned char newleds;
BT_DBG("session %p hid %p data %p size %d", session, device, data, size); BT_DBG("input %p type %d code %d value %d", dev, type, code, value);
if (type != EV_LED) if (type != EV_LED)
return -1; return -1;
...@@ -151,7 +151,7 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned i ...@@ -151,7 +151,7 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned i
return -ENOMEM; return -ENOMEM;
} }
*skb_put(skb, 1) = 0xa2; *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
*skb_put(skb, 1) = 0x01; *skb_put(skb, 1) = 0x01;
*skb_put(skb, 1) = newleds; *skb_put(skb, 1) = newleds;
...@@ -232,36 +232,171 @@ static inline void hidp_del_timer(struct hidp_session *session) ...@@ -232,36 +232,171 @@ static inline void hidp_del_timer(struct hidp_session *session)
del_timer(&session->timer); del_timer(&session->timer);
} }
static inline void hidp_send_message(struct hidp_session *session, unsigned char hdr) static int __hidp_send_ctrl_message(struct hidp_session *session,
unsigned char hdr, unsigned char *data, int size)
{ {
struct sk_buff *skb; struct sk_buff *skb;
BT_DBG("session %p", session); BT_DBG("session %p data %p size %d", session, data, size);
if (!(skb = alloc_skb(1, GFP_ATOMIC))) { if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for message"); BT_ERR("Can't allocate memory for new frame");
return; return -ENOMEM;
} }
*skb_put(skb, 1) = hdr; *skb_put(skb, 1) = hdr;
if (data && size > 0)
memcpy(skb_put(skb, size), data, size);
skb_queue_tail(&session->ctrl_transmit, skb); skb_queue_tail(&session->ctrl_transmit, skb);
return 0;
}
static int inline hidp_send_ctrl_message(struct hidp_session *session,
unsigned char hdr, unsigned char *data, int size)
{
int err;
err = __hidp_send_ctrl_message(session, hdr, data, size);
hidp_schedule(session); hidp_schedule(session);
return err;
}
static inline void hidp_process_handshake(struct hidp_session *session, unsigned char param)
{
BT_DBG("session %p param 0x%02x", session, param);
switch (param) {
case HIDP_HSHK_SUCCESSFUL:
/* FIXME: Call into SET_ GET_ handlers here */
break;
case HIDP_HSHK_NOT_READY:
case HIDP_HSHK_ERR_INVALID_REPORT_ID:
case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
case HIDP_HSHK_ERR_INVALID_PARAMETER:
/* FIXME: Call into SET_ GET_ handlers here */
break;
case HIDP_HSHK_ERR_UNKNOWN:
break;
case HIDP_HSHK_ERR_FATAL:
/* Device requests a reboot, as this is the only way this error
* can be recovered. */
__hidp_send_ctrl_message(session,
HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
break;
default:
__hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
break;
}
}
static inline void hidp_process_hid_control(struct hidp_session *session, unsigned char param)
{
BT_DBG("session %p param 0x%02x", session, param);
switch (param) {
case HIDP_CTRL_NOP:
break;
case HIDP_CTRL_VIRTUAL_CABLE_UNPLUG:
/* Flush the transmit queues */
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
/* Kill session thread */
atomic_inc(&session->terminate);
break;
case HIDP_CTRL_HARD_RESET:
case HIDP_CTRL_SOFT_RESET:
case HIDP_CTRL_SUSPEND:
case HIDP_CTRL_EXIT_SUSPEND:
/* FIXME: We have to parse these and return no error */
break;
default:
__hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
break;
}
} }
static inline int hidp_recv_frame(struct hidp_session *session, struct sk_buff *skb) static inline void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, unsigned char param)
{ {
__u8 hdr; BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
switch (param) {
case HIDP_DATA_RTYPE_INPUT:
hidp_set_timer(session);
if (session->input)
hidp_input_report(session, skb);
break;
case HIDP_DATA_RTYPE_OTHER:
case HIDP_DATA_RTYPE_OUPUT:
case HIDP_DATA_RTYPE_FEATURE:
break;
default:
__hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
}
}
static inline void hidp_recv_ctrl_frame(struct hidp_session *session, struct sk_buff *skb)
{
unsigned char hdr, type, param;
BT_DBG("session %p skb %p len %d", session, skb, skb->len); BT_DBG("session %p skb %p len %d", session, skb, skb->len);
hdr = skb->data[0]; hdr = skb->data[0];
skb_pull(skb, 1); skb_pull(skb, 1);
if (hdr == 0xa1) { type = hdr & HIDP_HEADER_TRANS_MASK;
hidp_set_timer(session); param = hdr & HIDP_HEADER_PARAM_MASK;
switch (type) {
case HIDP_TRANS_HANDSHAKE:
hidp_process_handshake(session, param);
break;
case HIDP_TRANS_HID_CONTROL:
hidp_process_hid_control(session, param);
break;
case HIDP_TRANS_DATA:
hidp_process_data(session, skb, param);
break;
default:
__hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
break;
}
kfree_skb(skb);
}
static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_buff *skb)
{
unsigned char hdr;
BT_DBG("session %p skb %p len %d", session, skb, skb->len);
hdr = skb->data[0];
skb_pull(skb, 1);
if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
hidp_set_timer(session);
if (session->input) if (session->input)
hidp_input_report(session, skb); hidp_input_report(session, skb);
} else { } else {
...@@ -269,7 +404,6 @@ static inline int hidp_recv_frame(struct hidp_session *session, struct sk_buff * ...@@ -269,7 +404,6 @@ static inline int hidp_recv_frame(struct hidp_session *session, struct sk_buff *
} }
kfree_skb(skb); kfree_skb(skb);
return 0;
} }
static int hidp_send_frame(struct socket *sock, unsigned char *data, int len) static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
...@@ -350,12 +484,12 @@ static int hidp_session(void *arg) ...@@ -350,12 +484,12 @@ static int hidp_session(void *arg)
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
hidp_recv_frame(session, skb); hidp_recv_ctrl_frame(session, skb);
} }
while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
hidp_recv_frame(session, skb); hidp_recv_intr_frame(session, skb);
} }
hidp_process_transmit(session); hidp_process_transmit(session);
...@@ -514,7 +648,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -514,7 +648,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
goto unlink; goto unlink;
if (session->input) { if (session->input) {
hidp_send_message(session, 0x70); hidp_send_ctrl_message(session,
HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
session->leds = 0xff; session->leds = 0xff;
...@@ -554,7 +689,8 @@ int hidp_del_connection(struct hidp_conndel_req *req) ...@@ -554,7 +689,8 @@ int hidp_del_connection(struct hidp_conndel_req *req)
session = __hidp_get_session(&req->bdaddr); session = __hidp_get_session(&req->bdaddr);
if (session) { if (session) {
if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) { if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
hidp_send_message(session, 0x15); hidp_send_ctrl_message(session,
HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
} else { } else {
/* Flush the transmit queues */ /* Flush the transmit queues */
skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->ctrl_transmit);
......
...@@ -26,6 +26,51 @@ ...@@ -26,6 +26,51 @@
#include <linux/types.h> #include <linux/types.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
/* HIDP header masks */
#define HIDP_HEADER_TRANS_MASK 0xf0
#define HIDP_HEADER_PARAM_MASK 0x0f
/* HIDP transaction types */
#define HIDP_TRANS_HANDSHAKE 0x00
#define HIDP_TRANS_HID_CONTROL 0x10
#define HIDP_TRANS_GET_REPORT 0x40
#define HIDP_TRANS_SET_REPORT 0x50
#define HIDP_TRANS_GET_PROTOCOL 0x60
#define HIDP_TRANS_SET_PROTOCOL 0x70
#define HIDP_TRANS_GET_IDLE 0x80
#define HIDP_TRANS_SET_IDLE 0x90
#define HIDP_TRANS_DATA 0xa0
#define HIDP_TRANS_DATC 0xb0
/* HIDP handshake results */
#define HIDP_HSHK_SUCCESSFUL 0x00
#define HIDP_HSHK_NOT_READY 0x01
#define HIDP_HSHK_ERR_INVALID_REPORT_ID 0x02
#define HIDP_HSHK_ERR_UNSUPPORTED_REQUEST 0x03
#define HIDP_HSHK_ERR_INVALID_PARAMETER 0x04
#define HIDP_HSHK_ERR_UNKNOWN 0x0e
#define HIDP_HSHK_ERR_FATAL 0x0f
/* HIDP control operation parameters */
#define HIDP_CTRL_NOP 0x00
#define HIDP_CTRL_HARD_RESET 0x01
#define HIDP_CTRL_SOFT_RESET 0x02
#define HIDP_CTRL_SUSPEND 0x03
#define HIDP_CTRL_EXIT_SUSPEND 0x04
#define HIDP_CTRL_VIRTUAL_CABLE_UNPLUG 0x05
/* HIDP data transaction headers */
#define HIDP_DATA_RTYPE_MASK 0x03
#define HIDP_DATA_RSRVD_MASK 0x0c
#define HIDP_DATA_RTYPE_OTHER 0x00
#define HIDP_DATA_RTYPE_INPUT 0x01
#define HIDP_DATA_RTYPE_OUPUT 0x02
#define HIDP_DATA_RTYPE_FEATURE 0x03
/* HIDP protocol header parameters */
#define HIDP_PROTO_BOOT 0x00
#define HIDP_PROTO_REPORT 0x01
/* HIDP ioctl defines */ /* HIDP ioctl defines */
#define HIDPCONNADD _IOW('H', 200, int) #define HIDPCONNADD _IOW('H', 200, int)
#define HIDPCONNDEL _IOW('H', 201, int) #define HIDPCONNDEL _IOW('H', 201, int)
......
...@@ -57,11 +57,11 @@ ...@@ -57,11 +57,11 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "2.6" #define VERSION "2.7"
static struct proto_ops l2cap_sock_ops; static struct proto_ops l2cap_sock_ops;
struct bt_sock_list l2cap_sk_list = { static struct bt_sock_list l2cap_sk_list = {
.lock = RW_LOCK_UNLOCKED .lock = RW_LOCK_UNLOCKED
}; };
...@@ -798,7 +798,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch ...@@ -798,7 +798,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
switch (optname) { switch (optname) {
case L2CAP_OPTIONS: case L2CAP_OPTIONS:
len = min_t(unsigned int, sizeof(opts), optlen); len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *)&opts, optval, len)) { if (copy_from_user((char *) &opts, optval, len)) {
err = -EFAULT; err = -EFAULT;
break; break;
} }
...@@ -807,7 +807,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch ...@@ -807,7 +807,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
break; break;
case L2CAP_LM: case L2CAP_LM:
if (get_user(opt, (u32 __user *)optval)) { if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT; err = -EFAULT;
break; break;
} }
...@@ -829,7 +829,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -829,7 +829,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct l2cap_options opts; struct l2cap_options opts;
struct l2cap_conninfo cinfo; struct l2cap_conninfo cinfo;
int len, err = 0; int len, err = 0;
BT_DBG("sk %p", sk);
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; return -EFAULT;
...@@ -841,15 +843,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -841,15 +843,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
opts.imtu = l2cap_pi(sk)->imtu; opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu; opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to; opts.flush_to = l2cap_pi(sk)->flush_to;
opts.mode = 0x00;
len = min_t(unsigned int, len, sizeof(opts)); len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *)&opts, len)) if (copy_to_user(optval, (char *) &opts, len))
err = -EFAULT; err = -EFAULT;
break; break;
case L2CAP_LM: case L2CAP_LM:
if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *)optval)) if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *) optval))
err = -EFAULT; err = -EFAULT;
break; break;
...@@ -860,9 +863,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -860,9 +863,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
} }
cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo)); len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *)&cinfo, len)) if (copy_to_user(optval, (char *) &cinfo, len))
err = -EFAULT; err = -EFAULT;
break; break;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/rfcomm.h>
#define VERSION "1.3" #define VERSION "1.4"
#ifndef CONFIG_BT_RFCOMM_DEBUG #ifndef CONFIG_BT_RFCOMM_DEBUG
#undef BT_DBG #undef BT_DBG
...@@ -61,8 +61,12 @@ ...@@ -61,8 +61,12 @@
struct proc_dir_entry *proc_bt_rfcomm; struct proc_dir_entry *proc_bt_rfcomm;
#endif #endif
struct task_struct *rfcomm_thread; static struct task_struct *rfcomm_thread;
DECLARE_MUTEX(rfcomm_sem);
static DECLARE_MUTEX(rfcomm_sem);
#define rfcomm_lock() down(&rfcomm_sem);
#define rfcomm_unlock() up(&rfcomm_sem);
unsigned long rfcomm_event; unsigned long rfcomm_event;
static LIST_HEAD(session_list); static LIST_HEAD(session_list);
...@@ -81,6 +85,10 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr); ...@@ -81,6 +85,10 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
static void rfcomm_process_connect(struct rfcomm_session *s); static void rfcomm_process_connect(struct rfcomm_session *s);
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
static void rfcomm_session_del(struct rfcomm_session *s);
/* ---- RFCOMM frame parsing macros ---- */ /* ---- RFCOMM frame parsing macros ---- */
#define __get_dlci(b) ((b & 0xfc) >> 2) #define __get_dlci(b) ((b & 0xfc) >> 2)
#define __get_channel(b) ((b & 0xf8) >> 3) #define __get_channel(b) ((b & 0xf8) >> 3)
...@@ -111,6 +119,21 @@ static void rfcomm_process_connect(struct rfcomm_session *s); ...@@ -111,6 +119,21 @@ static void rfcomm_process_connect(struct rfcomm_session *s);
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1) #define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
#define __get_rpn_parity(line) (((line) >> 3) & 0x3) #define __get_rpn_parity(line) (((line) >> 3) & 0x3)
static inline void rfcomm_schedule(uint event)
{
if (!rfcomm_thread)
return;
//set_bit(event, &rfcomm_event);
set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
static inline void rfcomm_session_put(struct rfcomm_session *s)
{
if (atomic_dec_and_test(&s->refcnt))
rfcomm_session_del(s);
}
/* ---- RFCOMM FCS computation ---- */ /* ---- RFCOMM FCS computation ---- */
/* CRC on 2 bytes */ /* CRC on 2 bytes */
...@@ -458,7 +481,7 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig) ...@@ -458,7 +481,7 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
} }
/* ---- RFCOMM sessions ---- */ /* ---- RFCOMM sessions ---- */
struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
{ {
struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL); struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s) if (!s)
...@@ -487,7 +510,7 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) ...@@ -487,7 +510,7 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
return s; return s;
} }
void rfcomm_session_del(struct rfcomm_session *s) static void rfcomm_session_del(struct rfcomm_session *s)
{ {
int state = s->state; int state = s->state;
...@@ -505,7 +528,7 @@ void rfcomm_session_del(struct rfcomm_session *s) ...@@ -505,7 +528,7 @@ void rfcomm_session_del(struct rfcomm_session *s)
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
{ {
struct rfcomm_session *s; struct rfcomm_session *s;
struct list_head *p, *n; struct list_head *p, *n;
...@@ -521,7 +544,7 @@ struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) ...@@ -521,7 +544,7 @@ struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
return NULL; return NULL;
} }
void rfcomm_session_close(struct rfcomm_session *s, int err) static void rfcomm_session_close(struct rfcomm_session *s, int err)
{ {
struct rfcomm_dlc *d; struct rfcomm_dlc *d;
struct list_head *p, *n; struct list_head *p, *n;
...@@ -542,7 +565,7 @@ void rfcomm_session_close(struct rfcomm_session *s, int err) ...@@ -542,7 +565,7 @@ void rfcomm_session_close(struct rfcomm_session *s, int err)
rfcomm_session_put(s); rfcomm_session_put(s);
} }
struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err) static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
{ {
struct rfcomm_session *s = NULL; struct rfcomm_session *s = NULL;
struct sockaddr_l2 addr; struct sockaddr_l2 addr;
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG #ifndef CONFIG_BT_RFCOMM_DEBUG
...@@ -261,10 +263,18 @@ static void rfcomm_sock_close(struct sock *sk) ...@@ -261,10 +263,18 @@ static void rfcomm_sock_close(struct sock *sk)
static void rfcomm_sock_init(struct sock *sk, struct sock *parent) static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
{ {
struct rfcomm_pinfo *pi = rfcomm_pi(sk);
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
if (parent) if (parent) {
sk->sk_type = parent->sk_type; sk->sk_type = parent->sk_type;
pi->link_mode = rfcomm_pi(parent)->link_mode;
} else {
pi->link_mode = 0;
}
pi->dlc->link_mode = pi->link_mode;
} }
static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio) static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
...@@ -393,7 +403,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a ...@@ -393,7 +403,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
return err; return err;
} }
int rfcomm_sock_listen(struct socket *sock, int backlog) static int rfcomm_sock_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
...@@ -437,7 +447,7 @@ int rfcomm_sock_listen(struct socket *sock, int backlog) ...@@ -437,7 +447,7 @@ int rfcomm_sock_listen(struct socket *sock, int backlog)
return err; return err;
} }
int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags) static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
struct sock *sk = sock->sk, *nsk; struct sock *sk = sock->sk, *nsk;
...@@ -671,12 +681,22 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c ...@@ -671,12 +681,22 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
u32 opt;
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
lock_sock(sk); lock_sock(sk);
switch (optname) { switch (optname) {
case RFCOMM_LM:
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
rfcomm_pi(sk)->link_mode = opt;
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
...@@ -689,7 +709,9 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c ...@@ -689,7 +709,9 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int len, err = 0; struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
int len, err = 0;
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
...@@ -699,10 +721,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c ...@@ -699,10 +721,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
lock_sock(sk); lock_sock(sk);
switch (optname) { switch (optname) {
case RFCOMM_LM:
if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
err = -EFAULT;
break;
case RFCOMM_CONNINFO:
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
break;
}
l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len))
err = -EFAULT;
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
}; }
release_sock(sk); release_sock(sk);
return err; return err;
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "0.3" #define VERSION "0.4"
static struct proto_ops sco_sock_ops; static struct proto_ops sco_sock_ops;
...@@ -705,6 +705,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char ...@@ -705,6 +705,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
} }
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo)); len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *)&cinfo, len)) if (copy_to_user(optval, (char *)&cinfo, len))
...@@ -1045,7 +1046,7 @@ static void __exit sco_exit(void) ...@@ -1045,7 +1046,7 @@ static void __exit sco_exit(void)
module_init(sco_init); module_init(sco_init);
module_exit(sco_exit); module_exit(sco_exit);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
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