diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-04-22 14:56:41 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-22 14:56:41 -0400 |
commit | e563589f7187699b0217854467d857f53b29cc50 (patch) | |
tree | c6ff538f85ba5496da39b9d1789db761f58e803a | |
parent | 197bbf0aedfb81ab70247264883c81e7f7d503ba (diff) | |
parent | 76a388beaf92cc75b829d4a0b7d69afaaeaa4b0a (diff) |
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
-rw-r--r-- | drivers/bluetooth/ath3k.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 41 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h4.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 15 | ||||
-rw-r--r-- | include/net/bluetooth/bluetooth.h | 5 | ||||
-rw-r--r-- | include/net/bluetooth/hci.h | 9 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 98 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 15 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 38 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 239 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 184 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 17 | ||||
-rw-r--r-- | net/bluetooth/hidp/core.c | 992 | ||||
-rw-r--r-- | net/bluetooth/hidp/hidp.h | 67 | ||||
-rw-r--r-- | net/bluetooth/hidp/sock.c | 22 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 127 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 6 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 17 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 49 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 2 |
20 files changed, 1213 insertions, 735 deletions
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 6aab00ef4379..11f467c00d0a 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -90,6 +90,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x0489, 0xe04e) }, { USB_DEVICE(0x0489, 0xe056) }, + { USB_DEVICE(0x0489, 0xe04d) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2cc5f774a29c..3d684d20b584 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -148,6 +148,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -926,6 +927,22 @@ static void btusb_waker(struct work_struct *work) usb_autopm_put_interface(data->intf); } +static int btusb_setup_bcm92035(struct hci_dev *hdev) +{ + struct sk_buff *skb; + u8 val = 0x00; + + BT_DBG("%s", hdev->name); + + skb = __hci_cmd_sync(hdev, 0xfc3b, 1, &val, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + BT_ERR("BCM92035 command failed (%ld)", -PTR_ERR(skb)); + else + kfree_skb(skb); + + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1022,11 +1039,14 @@ static int btusb_probe(struct usb_interface *intf, SET_HCIDEV_DEV(hdev, &intf->dev); - hdev->open = btusb_open; - hdev->close = btusb_close; - hdev->flush = btusb_flush; - hdev->send = btusb_send_frame; - hdev->notify = btusb_notify; + hdev->open = btusb_open; + hdev->close = btusb_close; + hdev->flush = btusb_flush; + hdev->send = btusb_send_frame; + hdev->notify = btusb_notify; + + if (id->driver_info & BTUSB_BCM92035) + hdev->setup = btusb_setup_bcm92035; /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); @@ -1065,17 +1085,6 @@ static int btusb_probe(struct usb_interface *intf, data->isoc = NULL; } - if (id->driver_info & BTUSB_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 (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, data->isoc, data); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index c60623f206d4..8ae9f1ea2bb5 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -153,6 +153,9 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) { int ret; + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + ret = hci_recv_stream_fragment(hu->hdev, data, count); if (ret < 0) { BT_ERR("Frame Reassembly Failed"); diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index ed0fade46aed..bc68a440d432 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -260,12 +260,12 @@ static int hci_uart_send_frame(struct sk_buff *skb) /* ------ LDISC part ------ */ /* hci_uart_tty_open - * + * * Called when line discipline changed to HCI_UART. * * Arguments: * tty pointer to tty info structure - * Return Value: + * Return Value: * 0 if success, otherwise error code */ static int hci_uart_tty_open(struct tty_struct *tty) @@ -365,15 +365,15 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) } /* hci_uart_tty_receive() - * + * * Called by tty low level driver when receive data is * available. - * + * * Arguments: tty pointer to tty isntance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes - * + * * Return Value: None */ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) @@ -388,7 +388,10 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f spin_lock(&hu->rx_lock); hu->proto->recv(hu, (void *) data, count); - hu->hdev->stat.byte_rx += count; + + if (hu->hdev) + hu->hdev->stat.byte_rx += count; + spin_unlock(&hu->rx_lock); tty_unthrottle(tty); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index ed6e9552252e..6912ef9a1881 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -193,11 +193,11 @@ static inline bool bdaddr_type_is_le(__u8 type) #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} }) /* Copy, swap, convert BD Address */ -static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) +static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) { return memcmp(ba1, ba2, sizeof(bdaddr_t)); } -static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) +static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) { memcpy(dst, src, sizeof(bdaddr_t)); } @@ -266,6 +266,7 @@ typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status); struct hci_req_ctrl { bool start; + u8 event; hci_req_complete_t complete; }; diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index b3308927a0a1..e0512aaef4b8 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -984,6 +984,9 @@ struct hci_cp_le_set_adv_data { #define HCI_OP_LE_SET_ADV_ENABLE 0x200a +#define LE_SCAN_PASSIVE 0x00 +#define LE_SCAN_ACTIVE 0x01 + #define HCI_OP_LE_SET_SCAN_PARAM 0x200b struct hci_cp_le_set_scan_param { __u8 type; @@ -993,8 +996,10 @@ struct hci_cp_le_set_scan_param { __u8 filter_policy; } __packed; -#define LE_SCANNING_DISABLED 0x00 -#define LE_SCANNING_ENABLED 0x01 +#define LE_SCAN_DISABLE 0x00 +#define LE_SCAN_ENABLE 0x01 +#define LE_SCAN_FILTER_DUP_DISABLE 0x00 +#define LE_SCAN_FILTER_DUP_ENABLE 0x01 #define HCI_OP_LE_SET_SCAN_ENABLE 0x200c struct hci_cp_le_set_scan_enable { diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 358a6983d3bb..80d718a9b31f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -134,6 +134,8 @@ struct amp_assoc { __u8 data[HCI_MAX_AMP_ASSOC_SIZE]; }; +#define HCI_MAX_PAGES 3 + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -151,8 +153,8 @@ struct hci_dev { __u8 dev_class[3]; __u8 major_class; __u8 minor_class; - __u8 features[8]; - __u8 host_features[8]; + __u8 max_page; + __u8 features[HCI_MAX_PAGES][8]; __u8 le_features[8]; __u8 le_white_list_size; __u8 le_states[8]; @@ -244,6 +246,7 @@ struct hci_dev { struct sk_buff_head raw_q; struct sk_buff_head cmd_q; + struct sk_buff *recv_evt; struct sk_buff *sent_cmd; struct sk_buff *reassembly[NUM_REASSEMBLY]; @@ -268,8 +271,6 @@ struct hci_dev { struct hci_dev_stats stat; - struct sk_buff_head driver_init; - atomic_t promisc; struct dentry *debugfs; @@ -292,6 +293,7 @@ struct hci_dev { int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); + int (*setup)(struct hci_dev *hdev); int (*send)(struct sk_buff *skb); void (*notify)(struct hci_dev *hdev, unsigned int evt); int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); @@ -313,7 +315,7 @@ struct hci_conn { bool out; __u8 attempt; __u8 dev_class[3]; - __u8 features[8]; + __u8 features[HCI_MAX_PAGES][8]; __u16 interval; __u16 pkt_type; __u16 link_policy; @@ -345,7 +347,6 @@ struct hci_conn { struct timer_list auto_accept_timer; struct device dev; - atomic_t devref; struct hci_dev *hdev; void *l2cap_data; @@ -584,7 +585,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); int hci_conn_del(struct hci_conn *conn); void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); -void hci_conn_accept(struct hci_conn *conn, int mask); struct hci_chan *hci_chan_create(struct hci_conn *conn); void hci_chan_del(struct hci_chan *chan); @@ -601,8 +601,36 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role); void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); -void hci_conn_hold_device(struct hci_conn *conn); -void hci_conn_put_device(struct hci_conn *conn); +/* + * hci_conn_get() and hci_conn_put() are used to control the life-time of an + * "hci_conn" object. They do not guarantee that the hci_conn object is running, + * working or anything else. They just guarantee that the object is available + * and can be dereferenced. So you can use its locks, local variables and any + * other constant data. + * Before accessing runtime data, you _must_ lock the object and then check that + * it is still running. As soon as you release the locks, the connection might + * get dropped, though. + * + * On the other hand, hci_conn_hold() and hci_conn_drop() are used to control + * how long the underlying connection is held. So every channel that runs on the + * hci_conn object calls this to prevent the connection from disappearing. As + * long as you hold a device, you must also guarantee that you have a valid + * reference to the device via hci_conn_get() (or the initial reference from + * hci_conn_add()). + * The hold()/drop() ref-count is known to drop below 0 sometimes, which doesn't + * break because nobody cares for that. But this means, we cannot use + * _get()/_drop() in it, but require the caller to have a valid ref (FIXME). + */ + +static inline void hci_conn_get(struct hci_conn *conn) +{ + get_device(&conn->dev); +} + +static inline void hci_conn_put(struct hci_conn *conn) +{ + put_device(&conn->dev); +} static inline void hci_conn_hold(struct hci_conn *conn) { @@ -612,7 +640,7 @@ static inline void hci_conn_hold(struct hci_conn *conn) cancel_delayed_work(&conn->disc_work); } -static inline void hci_conn_put(struct hci_conn *conn) +static inline void hci_conn_drop(struct hci_conn *conn) { BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt)); @@ -760,29 +788,29 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev)) /* ----- LMP capabilities ----- */ -#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) -#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) -#define lmp_hold_capable(dev) ((dev)->features[0] & LMP_HOLD) -#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) -#define lmp_park_capable(dev) ((dev)->features[1] & LMP_PARK) -#define lmp_inq_rssi_capable(dev) ((dev)->features[3] & LMP_RSSI_INQ) -#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) -#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR)) -#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) -#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) -#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC) -#define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ) -#define lmp_le_br_capable(dev) !!((dev)->features[6] & LMP_SIMUL_LE_BR) -#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) -#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) -#define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO) -#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[7] & LMP_INQ_TX_PWR) -#define lmp_ext_feat_capable(dev) ((dev)->features[7] & LMP_EXTFEATURES) +#define lmp_encrypt_capable(dev) ((dev)->features[0][0] & LMP_ENCRYPT) +#define lmp_rswitch_capable(dev) ((dev)->features[0][0] & LMP_RSWITCH) +#define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD) +#define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF) +#define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK) +#define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ) +#define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO) +#define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR)) +#define lmp_le_capable(dev) ((dev)->features[0][4] & LMP_LE) +#define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR) +#define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC) +#define lmp_ext_inq_capable(dev) ((dev)->features[0][6] & LMP_EXT_INQ) +#define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & LMP_SIMUL_LE_BR)) +#define lmp_ssp_capable(dev) ((dev)->features[0][6] & LMP_SIMPLE_PAIR) +#define lmp_no_flush_capable(dev) ((dev)->features[0][6] & LMP_NO_FLUSH) +#define lmp_lsto_capable(dev) ((dev)->features[0][7] & LMP_LSTO) +#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[0][7] & LMP_INQ_TX_PWR) +#define lmp_ext_feat_capable(dev) ((dev)->features[0][7] & LMP_EXTFEATURES) /* ----- Extended LMP capabilities ----- */ -#define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP) -#define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE) -#define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR) +#define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP) +#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) +#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) /* returns true if at least one AMP active */ static inline bool hci_amp_capable(void) @@ -1054,8 +1082,14 @@ struct hci_request { void hci_req_init(struct hci_request *req, struct hci_dev *hdev); int hci_req_run(struct hci_request *req, hci_req_complete_t complete); void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param); +void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, void *param, + u8 event); void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); -void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status); + +struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, + void *param, u32 timeout); +struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, + void *param, u8 event, u32 timeout); int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index cdd33021f831..fb94cf13c777 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -583,6 +583,14 @@ struct l2cap_conn { struct list_head chan_l; struct mutex chan_lock; + struct kref ref; + struct list_head users; +}; + +struct l2cap_user { + struct list_head list; + int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user); + void (*remove) (struct l2cap_conn *conn, struct l2cap_user *user); }; #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 @@ -786,6 +794,7 @@ extern bool disable_ertm; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); +bool l2cap_is_socket(struct socket *sock); void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); int __l2cap_wait_ack(struct sock *sk); @@ -812,4 +821,10 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, u8 status); void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); +void l2cap_conn_get(struct l2cap_conn *conn); +void l2cap_conn_put(struct l2cap_conn *conn); + +int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); +void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); + #endif /* __L2CAP_H */ diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b9f90169940b..6c7f36379722 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -117,6 +117,16 @@ static void hci_acl_create_connection_cancel(struct hci_conn *conn) hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp); } +static void hci_reject_sco(struct hci_conn *conn) +{ + struct hci_cp_reject_sync_conn_req cp; + + cp.reason = HCI_ERROR_REMOTE_USER_TERM; + bacpy(&cp.bdaddr, &conn->dst); + + hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp); +} + void hci_disconnect(struct hci_conn *conn, __u8 reason) { struct hci_cp_disconnect cp; @@ -276,6 +286,8 @@ static void hci_conn_timeout(struct work_struct *work) hci_acl_create_connection_cancel(conn); else if (conn->type == LE_LINK) hci_le_create_connection_cancel(conn); + } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) { + hci_reject_sco(conn); } break; case BT_CONFIG: @@ -398,8 +410,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); - atomic_set(&conn->devref, 0); - hci_conn_init_sysfs(conn); return conn; @@ -433,7 +443,7 @@ int hci_conn_del(struct hci_conn *conn) struct hci_conn *acl = conn->link; if (acl) { acl->link = NULL; - hci_conn_put(acl); + hci_conn_drop(acl); } } @@ -448,12 +458,11 @@ int hci_conn_del(struct hci_conn *conn) skb_queue_purge(&conn->data_q); - hci_conn_put_device(conn); + hci_conn_del_sysfs(conn); hci_dev_put(hdev); - if (conn->handle == 0) - kfree(conn); + hci_conn_put(conn); return 0; } @@ -565,7 +574,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, if (!sco) { sco = hci_conn_add(hdev, type, dst); if (!sco) { - hci_conn_put(acl); + hci_conn_drop(acl); return ERR_PTR(-ENOMEM); } } @@ -835,19 +844,6 @@ void hci_conn_check_pending(struct hci_dev *hdev) hci_dev_unlock(hdev); } -void hci_conn_hold_device(struct hci_conn *conn) -{ - atomic_inc(&conn->devref); -} -EXPORT_SYMBOL(hci_conn_hold_device); - -void hci_conn_put_device(struct hci_conn *conn) -{ - if (atomic_dec_and_test(&conn->devref)) - hci_conn_del_sysfs(conn); -} -EXPORT_SYMBOL(hci_conn_put_device); - int hci_get_conn_list(void __user *arg) { struct hci_conn *c; @@ -980,7 +976,7 @@ void hci_chan_del(struct hci_chan *chan) synchronize_rcu(); - hci_conn_put(conn); + hci_conn_drop(conn); skb_queue_purge(&chan->data_q); kfree(chan); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cfcad5423f1c..ce82265f5619 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -79,6 +79,121 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) } } +struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 event) +{ + struct hci_ev_cmd_complete *ev; + struct hci_event_hdr *hdr; + struct sk_buff *skb; + + hci_dev_lock(hdev); + + skb = hdev->recv_evt; + hdev->recv_evt = NULL; + + hci_dev_unlock(hdev); + + if (!skb) + return ERR_PTR(-ENODATA); + + if (skb->len < sizeof(*hdr)) { + BT_ERR("Too short HCI event"); + goto failed; + } + + hdr = (void *) skb->data; + skb_pull(skb, HCI_EVENT_HDR_SIZE); + + if (event) { + if (hdr->evt != event) + goto failed; + return skb; + } + + if (hdr->evt != HCI_EV_CMD_COMPLETE) { + BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt); + goto failed; + } + + if (skb->len < sizeof(*ev)) { + BT_ERR("Too short cmd_complete event"); + goto failed; + } + + ev = (void *) skb->data; + skb_pull(skb, sizeof(*ev)); + + if (opcode == __le16_to_cpu(ev->opcode)) + return skb; + + BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode, + __le16_to_cpu(ev->opcode)); + +failed: + kfree_skb(skb); + return ERR_PTR(-ENODATA); +} + +struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, + void *param, u8 event, u32 timeout) +{ + DECLARE_WAITQUEUE(wait, current); + struct hci_request req; + int err = 0; + + BT_DBG("%s", hdev->name); + + hci_req_init(&req, hdev); + + hci_req_add_ev(&req, opcode, plen, param, event); + + hdev->req_status = HCI_REQ_PEND; + + err = hci_req_run(&req, hci_req_sync_complete); + if (err < 0) + return ERR_PTR(err); + + add_wait_queue(&hdev->req_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + schedule_timeout(timeout); + + remove_wait_queue(&hdev->req_wait_q, &wait); + + if (signal_pending(current)) + return ERR_PTR(-EINTR); + + switch (hdev->req_status) { + case HCI_REQ_DONE: + err = -bt_to_errno(hdev->req_result); + break; + + case HCI_REQ_CANCELED: + err = -hdev->req_result; + break; + + default: + err = -ETIMEDOUT; + break; + } + + hdev->req_status = hdev->req_result = 0; + + BT_DBG("%s end: err %d", hdev->name, err); + + if (err < 0) + return ERR_PTR(err); + + return hci_get_cmd_complete(hdev, opcode, event); +} +EXPORT_SYMBOL(__hci_cmd_sync_ev); + +struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, + void *param, u32 timeout) +{ + return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout); +} +EXPORT_SYMBOL(__hci_cmd_sync); + /* Execute request and wait for completion. */ static int __hci_req_sync(struct hci_dev *hdev, void (*func)(struct hci_request *req, @@ -201,29 +316,9 @@ static void amp_init(struct hci_request *req) static void hci_init1_req(struct hci_request *req, unsigned long opt) { struct hci_dev *hdev = req->hdev; - struct hci_request init_req; - struct sk_buff *skb; BT_DBG("%s %ld", hdev->name, opt); - /* Driver initialization */ - - hci_req_init(&init_req, hdev); - - /* Special commands */ - while ((skb = skb_dequeue(&hdev->driver_init))) { - bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; - skb->dev = (void *) hdev; - - if (skb_queue_empty(&init_req.cmd_q)) - bt_cb(skb)->req.start = true; - - skb_queue_tail(&init_req.cmd_q, skb); - } - skb_queue_purge(&hdev->driver_init); - - hci_req_run(&init_req, NULL); - /* Reset */ if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) hci_reset_req(req, 0); @@ -494,6 +589,7 @@ static void hci_set_le_support(struct hci_request *req) static void hci_init3_req(struct hci_request *req, unsigned long opt) { struct hci_dev *hdev = req->hdev; + u8 p; if (hdev->commands[5] & 0x10) hci_setup_link_policy(req); @@ -502,6 +598,15 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_set_le_support(req); hci_update_ad(req); } + + /* Read features beyond page 1 if available */ + for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) { + struct hci_cp_read_local_ext_features cp; + + cp.page = p; + hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES, + sizeof(cp), &cp); + } } static int __hci_init(struct hci_dev *hdev) @@ -818,6 +923,12 @@ static void hci_inq_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp); } +static int wait_inquiry(void *word) +{ + schedule(); + return signal_pending(current); +} + int hci_inquiry(void __user *arg) { __u8 __user *ptr = arg; @@ -849,6 +960,13 @@ int hci_inquiry(void __user *arg) timeo); if (err < 0) goto done; + + /* Wait until Inquiry procedure finishes (HCI_INQUIRY flag is + * cleared). If it is interrupted by a signal, return -EINTR. + */ + if (wait_on_bit(&hdev->flags, HCI_INQUIRY, wait_inquiry, + TASK_INTERRUPTIBLE)) + return -EINTR; } /* for unlimited number of responses we will use buffer with @@ -999,26 +1117,33 @@ int hci_dev_open(__u16 dev) goto done; } - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) - set_bit(HCI_RAW, &hdev->flags); - - /* Treat all non BR/EDR controllers as raw devices if - enable_hs is not set */ - if (hdev->dev_type != HCI_BREDR && !enable_hs) - set_bit(HCI_RAW, &hdev->flags); - if (hdev->open(hdev)) { ret = -EIO; goto done; } - if (!test_bit(HCI_RAW, &hdev->flags)) { - atomic_set(&hdev->cmd_cnt, 1); - set_bit(HCI_INIT, &hdev->flags); - ret = __hci_init(hdev); - clear_bit(HCI_INIT, &hdev->flags); + atomic_set(&hdev->cmd_cnt, 1); + set_bit(HCI_INIT, &hdev->flags); + + if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) + ret = hdev->setup(hdev); + + if (!ret) { + /* Treat all non BR/EDR controllers as raw devices if + * enable_hs is not set. + */ + if (hdev->dev_type != HCI_BREDR && !enable_hs) + set_bit(HCI_RAW, &hdev->flags); + + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + set_bit(HCI_RAW, &hdev->flags); + + if (!test_bit(HCI_RAW, &hdev->flags)) + ret = __hci_init(hdev); } + clear_bit(HCI_INIT, &hdev->flags); + if (!ret) { hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); @@ -1123,6 +1248,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->sent_cmd = NULL; } + kfree_skb(hdev->recv_evt); + hdev->recv_evt = NULL; + /* After this point our queues are empty * and no tasks are scheduled. */ hdev->close(hdev); @@ -1861,8 +1989,8 @@ static void le_scan_enable_req(struct hci_request *req, unsigned long opt) struct hci_cp_le_set_scan_enable cp; memset(&cp, 0, sizeof(cp)); - cp.enable = 1; - cp.filter_dup = 1; + cp.enable = LE_SCAN_ENABLE; + cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } @@ -1896,7 +2024,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, return err; queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, - msecs_to_jiffies(timeout)); + timeout); return 0; } @@ -2006,7 +2134,6 @@ struct hci_dev *hci_alloc_dev(void) INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); - skb_queue_head_init(&hdev->driver_init); skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); skb_queue_head_init(&hdev->raw_q); @@ -2025,8 +2152,6 @@ EXPORT_SYMBOL(hci_alloc_dev); /* Free HCI device */ void hci_free_dev(struct hci_dev *hdev) { - skb_queue_purge(&hdev->driver_init); - /* will free via device release */ put_device(&hdev->dev); } @@ -2527,7 +2652,8 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) } /* Queue a command to an asynchronous HCI request */ -void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param) +void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, void *param, + u8 event) { struct hci_dev *hdev = req->hdev; struct sk_buff *skb; @@ -2551,9 +2677,16 @@ void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param) if (skb_queue_empty(&req->cmd_q)) bt_cb(skb)->req.start = true; + bt_cb(skb)->req.event = event; + skb_queue_tail(&req->cmd_q, skb); } +void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param) +{ + hci_req_add_ev(req, opcode, plen, param, 0); +} + /* Get data from the previously sent command */ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) { @@ -3309,32 +3442,6 @@ call_complete: req_complete(hdev, status); } -void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status) -{ - hci_req_complete_t req_complete = NULL; - - BT_DBG("opcode 0x%04x status 0x%02x", opcode, status); - - if (status) { - hci_req_cmd_complete(hdev, opcode, status); - return; - } - - /* No need to handle success status if there are more commands */ - if (!hci_req_is_complete(hdev)) - return; - - if (hdev->sent_cmd) - req_complete = bt_cb(hdev->sent_cmd)->req.complete; - - /* If the request doesn't have a complete callback or there - * are other commands/requests in the hdev queue we consider - * this request as completed. - */ - if (!req_complete || !skb_queue_empty(&hdev->cmd_q)) - hci_req_cmd_complete(hdev, opcode, status); -} - static void hci_rx_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 138580745c2c..b93cd2eb5d58 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -48,13 +48,13 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) } clear_bit(HCI_INQUIRY, &hdev->flags); + smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */ + wake_up_bi |