Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
e563589f71
|
@ -90,6 +90,7 @@ static struct usb_device_id ath3k_table[] = {
|
||||||
{ USB_DEVICE(0x13d3, 0x3393) },
|
{ USB_DEVICE(0x13d3, 0x3393) },
|
||||||
{ USB_DEVICE(0x0489, 0xe04e) },
|
{ USB_DEVICE(0x0489, 0xe04e) },
|
||||||
{ USB_DEVICE(0x0489, 0xe056) },
|
{ USB_DEVICE(0x0489, 0xe056) },
|
||||||
|
{ USB_DEVICE(0x0489, 0xe04d) },
|
||||||
|
|
||||||
/* Atheros AR5BBU12 with sflash firmware */
|
/* Atheros AR5BBU12 with sflash firmware */
|
||||||
{ USB_DEVICE(0x0489, 0xE02C) },
|
{ 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(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0489, 0xe056), .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 */
|
/* Atheros AR5BBU22 with sflash firmware */
|
||||||
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
|
||||||
|
|
|
@ -148,6 +148,7 @@ static struct usb_device_id blacklist_table[] = {
|
||||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0489, 0xe056), .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 */
|
/* Atheros AR5BBU12 with sflash firmware */
|
||||||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
{ 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);
|
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,
|
static int btusb_probe(struct usb_interface *intf,
|
||||||
const struct usb_device_id *id)
|
const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -1028,6 +1045,9 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
hdev->send = btusb_send_frame;
|
hdev->send = btusb_send_frame;
|
||||||
hdev->notify = btusb_notify;
|
hdev->notify = btusb_notify;
|
||||||
|
|
||||||
|
if (id->driver_info & BTUSB_BCM92035)
|
||||||
|
hdev->setup = btusb_setup_bcm92035;
|
||||||
|
|
||||||
/* Interface numbers are hardcoded in the specification */
|
/* Interface numbers are hardcoded in the specification */
|
||||||
data->isoc = usb_ifnum_to_if(data->udev, 1);
|
data->isoc = usb_ifnum_to_if(data->udev, 1);
|
||||||
|
|
||||||
|
@ -1065,17 +1085,6 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
data->isoc = NULL;
|
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) {
|
if (data->isoc) {
|
||||||
err = usb_driver_claim_interface(&btusb_driver,
|
err = usb_driver_claim_interface(&btusb_driver,
|
||||||
data->isoc, data);
|
data->isoc, data);
|
||||||
|
|
|
@ -153,6 +153,9 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||||
|
return -EUNATCH;
|
||||||
|
|
||||||
ret = hci_recv_stream_fragment(hu->hdev, data, count);
|
ret = hci_recv_stream_fragment(hu->hdev, data, count);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
BT_ERR("Frame Reassembly Failed");
|
BT_ERR("Frame Reassembly Failed");
|
||||||
|
|
|
@ -388,7 +388,10 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
|
||||||
|
|
||||||
spin_lock(&hu->rx_lock);
|
spin_lock(&hu->rx_lock);
|
||||||
hu->proto->recv(hu, (void *) data, count);
|
hu->proto->recv(hu, (void *) data, count);
|
||||||
|
|
||||||
|
if (hu->hdev)
|
||||||
hu->hdev->stat.byte_rx += count;
|
hu->hdev->stat.byte_rx += count;
|
||||||
|
|
||||||
spin_unlock(&hu->rx_lock);
|
spin_unlock(&hu->rx_lock);
|
||||||
|
|
||||||
tty_unthrottle(tty);
|
tty_unthrottle(tty);
|
||||||
|
|
|
@ -193,11 +193,11 @@ static inline bool bdaddr_type_is_le(__u8 type)
|
||||||
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
|
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
|
||||||
|
|
||||||
/* Copy, swap, convert BD Address */
|
/* 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));
|
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));
|
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 {
|
struct hci_req_ctrl {
|
||||||
bool start;
|
bool start;
|
||||||
|
u8 event;
|
||||||
hci_req_complete_t complete;
|
hci_req_complete_t complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -984,6 +984,9 @@ struct hci_cp_le_set_adv_data {
|
||||||
|
|
||||||
#define HCI_OP_LE_SET_ADV_ENABLE 0x200a
|
#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
|
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
|
||||||
struct hci_cp_le_set_scan_param {
|
struct hci_cp_le_set_scan_param {
|
||||||
__u8 type;
|
__u8 type;
|
||||||
|
@ -993,8 +996,10 @@ struct hci_cp_le_set_scan_param {
|
||||||
__u8 filter_policy;
|
__u8 filter_policy;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define LE_SCANNING_DISABLED 0x00
|
#define LE_SCAN_DISABLE 0x00
|
||||||
#define LE_SCANNING_ENABLED 0x01
|
#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
|
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
|
||||||
struct hci_cp_le_set_scan_enable {
|
struct hci_cp_le_set_scan_enable {
|
||||||
|
|
|
@ -134,6 +134,8 @@ struct amp_assoc {
|
||||||
__u8 data[HCI_MAX_AMP_ASSOC_SIZE];
|
__u8 data[HCI_MAX_AMP_ASSOC_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HCI_MAX_PAGES 3
|
||||||
|
|
||||||
#define NUM_REASSEMBLY 4
|
#define NUM_REASSEMBLY 4
|
||||||
struct hci_dev {
|
struct hci_dev {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
@ -151,8 +153,8 @@ struct hci_dev {
|
||||||
__u8 dev_class[3];
|
__u8 dev_class[3];
|
||||||
__u8 major_class;
|
__u8 major_class;
|
||||||
__u8 minor_class;
|
__u8 minor_class;
|
||||||
__u8 features[8];
|
__u8 max_page;
|
||||||
__u8 host_features[8];
|
__u8 features[HCI_MAX_PAGES][8];
|
||||||
__u8 le_features[8];
|
__u8 le_features[8];
|
||||||
__u8 le_white_list_size;
|
__u8 le_white_list_size;
|
||||||
__u8 le_states[8];
|
__u8 le_states[8];
|
||||||
|
@ -244,6 +246,7 @@ struct hci_dev {
|
||||||
struct sk_buff_head raw_q;
|
struct sk_buff_head raw_q;
|
||||||
struct sk_buff_head cmd_q;
|
struct sk_buff_head cmd_q;
|
||||||
|
|
||||||
|
struct sk_buff *recv_evt;
|
||||||
struct sk_buff *sent_cmd;
|
struct sk_buff *sent_cmd;
|
||||||
struct sk_buff *reassembly[NUM_REASSEMBLY];
|
struct sk_buff *reassembly[NUM_REASSEMBLY];
|
||||||
|
|
||||||
|
@ -268,8 +271,6 @@ struct hci_dev {
|
||||||
|
|
||||||
struct hci_dev_stats stat;
|
struct hci_dev_stats stat;
|
||||||
|
|
||||||
struct sk_buff_head driver_init;
|
|
||||||
|
|
||||||
atomic_t promisc;
|
atomic_t promisc;
|
||||||
|
|
||||||
struct dentry *debugfs;
|
struct dentry *debugfs;
|
||||||
|
@ -292,6 +293,7 @@ struct hci_dev {
|
||||||
int (*open)(struct hci_dev *hdev);
|
int (*open)(struct hci_dev *hdev);
|
||||||
int (*close)(struct hci_dev *hdev);
|
int (*close)(struct hci_dev *hdev);
|
||||||
int (*flush)(struct hci_dev *hdev);
|
int (*flush)(struct hci_dev *hdev);
|
||||||
|
int (*setup)(struct hci_dev *hdev);
|
||||||
int (*send)(struct sk_buff *skb);
|
int (*send)(struct sk_buff *skb);
|
||||||
void (*notify)(struct hci_dev *hdev, unsigned int evt);
|
void (*notify)(struct hci_dev *hdev, unsigned int evt);
|
||||||
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
|
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
|
||||||
|
@ -313,7 +315,7 @@ struct hci_conn {
|
||||||
bool out;
|
bool out;
|
||||||
__u8 attempt;
|
__u8 attempt;
|
||||||
__u8 dev_class[3];
|
__u8 dev_class[3];
|
||||||
__u8 features[8];
|
__u8 features[HCI_MAX_PAGES][8];
|
||||||
__u16 interval;
|
__u16 interval;
|
||||||
__u16 pkt_type;
|
__u16 pkt_type;
|
||||||
__u16 link_policy;
|
__u16 link_policy;
|
||||||
|
@ -345,7 +347,6 @@ struct hci_conn {
|
||||||
struct timer_list auto_accept_timer;
|
struct timer_list auto_accept_timer;
|
||||||
|
|
||||||
struct device dev;
|
struct device dev;
|
||||||
atomic_t devref;
|
|
||||||
|
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
void *l2cap_data;
|
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);
|
int hci_conn_del(struct hci_conn *conn);
|
||||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||||
void hci_conn_check_pending(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);
|
struct hci_chan *hci_chan_create(struct hci_conn *conn);
|
||||||
void hci_chan_del(struct hci_chan *chan);
|
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_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)
|
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);
|
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));
|
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))
|
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
|
||||||
|
|
||||||
/* ----- LMP capabilities ----- */
|
/* ----- LMP capabilities ----- */
|
||||||
#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
|
#define lmp_encrypt_capable(dev) ((dev)->features[0][0] & LMP_ENCRYPT)
|
||||||
#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
|
#define lmp_rswitch_capable(dev) ((dev)->features[0][0] & LMP_RSWITCH)
|
||||||
#define lmp_hold_capable(dev) ((dev)->features[0] & LMP_HOLD)
|
#define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD)
|
||||||
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
|
#define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF)
|
||||||
#define lmp_park_capable(dev) ((dev)->features[1] & LMP_PARK)
|
#define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK)
|
||||||
#define lmp_inq_rssi_capable(dev) ((dev)->features[3] & LMP_RSSI_INQ)
|
#define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ)
|
||||||
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
|
#define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO)
|
||||||
#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR))
|
#define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR))
|
||||||
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
|
#define lmp_le_capable(dev) ((dev)->features[0][4] & LMP_LE)
|
||||||
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
|
#define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR)
|
||||||
#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC)
|
#define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC)
|
||||||
#define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ)
|
#define lmp_ext_inq_capable(dev) ((dev)->features[0][6] & LMP_EXT_INQ)
|
||||||
#define lmp_le_br_capable(dev) !!((dev)->features[6] & LMP_SIMUL_LE_BR)
|
#define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & LMP_SIMUL_LE_BR))
|
||||||
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
|
#define lmp_ssp_capable(dev) ((dev)->features[0][6] & LMP_SIMPLE_PAIR)
|
||||||
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
|
#define lmp_no_flush_capable(dev) ((dev)->features[0][6] & LMP_NO_FLUSH)
|
||||||
#define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO)
|
#define lmp_lsto_capable(dev) ((dev)->features[0][7] & LMP_LSTO)
|
||||||
#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[7] & LMP_INQ_TX_PWR)
|
#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[0][7] & LMP_INQ_TX_PWR)
|
||||||
#define lmp_ext_feat_capable(dev) ((dev)->features[7] & LMP_EXTFEATURES)
|
#define lmp_ext_feat_capable(dev) ((dev)->features[0][7] & LMP_EXTFEATURES)
|
||||||
|
|
||||||
/* ----- Extended LMP capabilities ----- */
|
/* ----- Extended LMP capabilities ----- */
|
||||||
#define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP)
|
#define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP)
|
||||||
#define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE)
|
#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
|
||||||
#define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR)
|
#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
|
||||||
|
|
||||||
/* returns true if at least one AMP active */
|
/* returns true if at least one AMP active */
|
||||||
static inline bool hci_amp_capable(void)
|
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);
|
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);
|
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(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_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);
|
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);
|
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
|
||||||
|
|
|
@ -583,6 +583,14 @@ struct l2cap_conn {
|
||||||
|
|
||||||
struct list_head chan_l;
|
struct list_head chan_l;
|
||||||
struct mutex chan_lock;
|
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
|
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
|
||||||
|
@ -786,6 +794,7 @@ extern bool disable_ertm;
|
||||||
|
|
||||||
int l2cap_init_sockets(void);
|
int l2cap_init_sockets(void);
|
||||||
void l2cap_cleanup_sockets(void);
|
void l2cap_cleanup_sockets(void);
|
||||||
|
bool l2cap_is_socket(struct socket *sock);
|
||||||
|
|
||||||
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
|
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
|
||||||
int __l2cap_wait_ack(struct sock *sk);
|
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);
|
u8 status);
|
||||||
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
|
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 */
|
#endif /* __L2CAP_H */
|
||||||
|
|
|
@ -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);
|
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)
|
void hci_disconnect(struct hci_conn *conn, __u8 reason)
|
||||||
{
|
{
|
||||||
struct hci_cp_disconnect cp;
|
struct hci_cp_disconnect cp;
|
||||||
|
@ -276,6 +286,8 @@ static void hci_conn_timeout(struct work_struct *work)
|
||||||
hci_acl_create_connection_cancel(conn);
|
hci_acl_create_connection_cancel(conn);
|
||||||
else if (conn->type == LE_LINK)
|
else if (conn->type == LE_LINK)
|
||||||
hci_le_create_connection_cancel(conn);
|
hci_le_create_connection_cancel(conn);
|
||||||
|
} else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
|
||||||
|
hci_reject_sco(conn);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BT_CONFIG:
|
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)
|
if (hdev->notify)
|
||||||
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
|
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
|
||||||
|
|
||||||
atomic_set(&conn->devref, 0);
|
|
||||||
|
|
||||||
hci_conn_init_sysfs(conn);
|
hci_conn_init_sysfs(conn);
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
|
@ -433,7 +443,7 @@ int hci_conn_del(struct hci_conn *conn)
|
||||||
struct hci_conn *acl = conn->link;
|
struct hci_conn *acl = conn->link;
|
||||||
if (acl) {
|
if (acl) {
|
||||||
acl->link = NULL;
|
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);
|
skb_queue_purge(&conn->data_q);
|
||||||
|
|
||||||
hci_conn_put_device(conn);
|
hci_conn_del_sysfs(conn);
|
||||||
|
|
||||||
hci_dev_put(hdev);
|
hci_dev_put(hdev);
|
||||||
|
|
||||||
if (conn->handle == 0)
|
hci_conn_put(conn);
|
||||||
kfree(conn);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -565,7 +574,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
|
||||||
if (!sco) {
|
if (!sco) {
|
||||||
sco = hci_conn_add(hdev, type, dst);
|
sco = hci_conn_add(hdev, type, dst);
|
||||||
if (!sco) {
|
if (!sco) {
|
||||||
hci_conn_put(acl);
|
hci_conn_drop(acl);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,19 +844,6 @@ void hci_conn_check_pending(struct hci_dev *hdev)
|
||||||
hci_dev_unlock(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)
|
int hci_get_conn_list(void __user *arg)
|
||||||
{
|
{
|
||||||
struct hci_conn *c;
|
struct hci_conn *c;
|
||||||
|
@ -980,7 +976,7 @@ void hci_chan_del(struct hci_chan *chan)
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
|
|
||||||
skb_queue_purge(&chan->data_q);
|
skb_queue_purge(&chan->data_q);
|
||||||
kfree(chan);
|
kfree(chan);
|
||||||
|
|
|
@ -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. */
|
/* Execute request and wait for completion. */
|
||||||
static int __hci_req_sync(struct hci_dev *hdev,
|
static int __hci_req_sync(struct hci_dev *hdev,
|
||||||
void (*func)(struct hci_request *req,
|
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)
|
static void hci_init1_req(struct hci_request *req, unsigned long opt)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = req->hdev;
|
struct hci_dev *hdev = req->hdev;
|
||||||
struct hci_request init_req;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
BT_DBG("%s %ld", hdev->name, opt);
|
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 */
|
/* Reset */
|
||||||
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
|
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
|
||||||
hci_reset_req(req, 0);
|
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)
|
static void hci_init3_req(struct hci_request *req, unsigned long opt)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = req->hdev;
|
struct hci_dev *hdev = req->hdev;
|
||||||
|
u8 p;
|
||||||
|
|
||||||
if (hdev->commands[5] & 0x10)
|
if (hdev->commands[5] & 0x10)
|
||||||
hci_setup_link_policy(req);
|
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_set_le_support(req);
|
||||||
hci_update_ad(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)
|
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);
|
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)
|
int hci_inquiry(void __user *arg)
|
||||||
{
|
{
|
||||||
__u8 __user *ptr = arg;
|
__u8 __user *ptr = arg;
|
||||||
|
@ -849,6 +960,13 @@ int hci_inquiry(void __user *arg)
|
||||||
timeo);
|
timeo);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
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
|
/* for unlimited number of responses we will use buffer with
|
||||||
|
@ -999,26 +1117,33 @@ int hci_dev_open(__u16 dev)
|
||||||
goto done;
|
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)) {
|
if (hdev->open(hdev)) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!test_bit(HCI_RAW, &hdev->flags)) {
|
|
||||||
atomic_set(&hdev->cmd_cnt, 1);
|
atomic_set(&hdev->cmd_cnt, 1);
|
||||||
set_bit(HCI_INIT, &hdev->flags);
|
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);
|
ret = __hci_init(hdev);
|
||||||
clear_bit(HCI_INIT, &hdev->flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_bit(HCI_INIT, &hdev->flags);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
hci_dev_hold(hdev);
|
hci_dev_hold(hdev);
|
||||||
set_bit(HCI_UP, &hdev->flags);
|
set_bit(HCI_UP, &hdev->flags);
|
||||||
|
@ -1123,6 +1248,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||||
hdev->sent_cmd = NULL;
|
hdev->sent_cmd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kfree_skb(hdev->recv_evt);
|
||||||
|
hdev->recv_evt = NULL;
|
||||||
|
|
||||||
/* After this point our queues are empty
|
/* After this point our queues are empty
|
||||||
* and no tasks are scheduled. */
|
* and no tasks are scheduled. */
|
||||||
hdev->close(hdev);
|
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;
|
struct hci_cp_le_set_scan_enable cp;
|
||||||
|
|
||||||
memset(&cp, 0, sizeof(cp));
|
memset(&cp, 0, sizeof(cp));
|
||||||
cp.enable = 1;
|
cp.enable = LE_SCAN_ENABLE;
|
||||||
cp.filter_dup = 1;
|
cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
|
||||||
|
|
||||||
hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
|
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;
|
return err;
|
||||||
|
|
||||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
||||||
msecs_to_jiffies(timeout));
|
timeout);
|
||||||
|
|
||||||
return 0;
|
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->discov_off, hci_discov_off);
|
||||||
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
|
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->rx_q);
|
||||||
skb_queue_head_init(&hdev->cmd_q);
|
skb_queue_head_init(&hdev->cmd_q);
|
||||||
skb_queue_head_init(&hdev->raw_q);
|
skb_queue_head_init(&hdev->raw_q);
|
||||||
|
@ -2025,8 +2152,6 @@ EXPORT_SYMBOL(hci_alloc_dev);
|
||||||
/* Free HCI device */
|
/* Free HCI device */
|
||||||
void hci_free_dev(struct hci_dev *hdev)
|
void hci_free_dev(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
skb_queue_purge(&hdev->driver_init);
|
|
||||||
|
|
||||||
/* will free via device release */
|
/* will free via device release */
|
||||||
put_device(&hdev->dev);
|
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 */
|
/* 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 hci_dev *hdev = req->hdev;
|
||||||
struct sk_buff *skb;
|
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))
|
if (skb_queue_empty(&req->cmd_q))
|
||||||
bt_cb(skb)->req.start = true;
|
bt_cb(skb)->req.start = true;
|
||||||
|
|
||||||
|
bt_cb(skb)->req.event = event;
|
||||||
|
|
||||||
skb_queue_tail(&req->cmd_q, skb);
|
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 */
|
/* Get data from the previously sent command */
|
||||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
|
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
|
||||||
{
|
{
|
||||||
|
@ -3309,32 +3442,6 @@ call_complete:
|
||||||
req_complete(hdev, status);
|
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)
|
static void hci_rx_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
|
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
|
||||||
|
|
|
@ -48,13 +48,13 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_bit(HCI_INQUIRY, &hdev->flags);
|
clear_bit(HCI_INQUIRY, &hdev->flags);
|
||||||
|
smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */
|
||||||
|
wake_up_bit(&hdev->flags, HCI_INQUIRY);
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
|
|
||||||
|
|
||||||
hci_conn_check_pending(hdev);
|
hci_conn_check_pending(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,9 +433,9 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
if (sent->mode)
|
if (sent->mode)
|
||||||
hdev->host_features[0] |= LMP_HOST_SSP;
|
hdev->features[1][0] |= LMP_HOST_SSP;
|
||||||
else
|
else
|
||||||
hdev->host_features[0] &= ~LMP_HOST_SSP;
|
hdev->features[1][0] &= ~LMP_HOST_SSP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||||
|
@ -493,18 +493,18 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
|
||||||
/* Adjust default settings according to features
|
/* Adjust default settings according to features
|
||||||
* supported by device. */
|
* supported by device. */
|
||||||
|
|
||||||
if (hdev->features[0] & LMP_3SLOT)
|
if (hdev->features[0][0] & LMP_3SLOT)
|
||||||
hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
|
hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
|
||||||
|
|
||||||
if (hdev->features[0] & LMP_5SLOT)
|
if (hdev->features[0][0] & LMP_5SLOT)
|
||||||
hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
|
hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
|
||||||
|
|
||||||
if (hdev->features[1] & LMP_HV2) {
|
if (hdev->features[0][1] & LMP_HV2) {
|
||||||
hdev->pkt_type |= (HCI_HV2);
|
hdev->pkt_type |= (HCI_HV2);
|
||||||
hdev->esco_type |= (ESCO_HV2);
|
hdev->esco_type |= (ESCO_HV2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdev->features[1] & LMP_HV3) {
|
if (hdev->features[0][1] & LMP_HV3) {
|
||||||
hdev->pkt_type |= (HCI_HV3);
|
hdev->pkt_type |= (HCI_HV3);
|
||||||
hdev->esco_type |= (ESCO_HV3);
|
hdev->esco_type |= (ESCO_HV3);
|
||||||
}
|
}
|
||||||
|
@ -512,26 +512,26 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
|
||||||
if (lmp_esco_capable(hdev))
|
if (lmp_esco_capable(hdev))
|
||||||
hdev->esco_type |= (ESCO_EV3);
|
hdev->esco_type |= (ESCO_EV3);
|
||||||
|
|
||||||
if (hdev->features[4] & LMP_EV4)
|
if (hdev->features[0][4] & LMP_EV4)
|
||||||
hdev->esco_type |= (ESCO_EV4);
|
hdev->esco_type |= (ESCO_EV4);
|
||||||
|
|
||||||
if (hdev->features[4] & LMP_EV5)
|
if (hdev->features[0][4] & LMP_EV5)
|
||||||
hdev->esco_type |= (ESCO_EV5);
|
hdev->esco_type |= (ESCO_EV5);
|
||||||
|
|
||||||
if (hdev->features[5] & LMP_EDR_ESCO_2M)
|
if (hdev->features[0][5] & LMP_EDR_ESCO_2M)
|
||||||
hdev->esco_type |= (ESCO_2EV3);
|
hdev->esco_type |= (ESCO_2EV3);
|
||||||
|
|
||||||
if (hdev->features[5] & LMP_EDR_ESCO_3M)
|
if (hdev->features[0][5] & LMP_EDR_ESCO_3M)
|
||||||
hdev->esco_type |= (ESCO_3EV3);
|
hdev->esco_type |= (ESCO_3EV3);
|
||||||
|
|
||||||
if (hdev->features[5] & LMP_EDR_3S_ESCO)
|
if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
|
||||||
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
|
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
|
||||||
|
|
||||||
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
|
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
|
||||||
hdev->features[0], hdev->features[1],
|
hdev->features[0][0], hdev->features[0][1],
|
||||||
hdev->features[2], hdev->features[3],
|
hdev->features[0][2], hdev->features[0][3],
|
||||||
hdev->features[4], hdev->features[5],
|
hdev->features[0][4], hdev->features[0][5],
|
||||||
hdev->features[6], hdev->features[7]);
|
hdev->features[0][6], hdev->features[0][7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
||||||
|
@ -544,14 +544,10 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
||||||
if (rp->status)
|
if (rp->status)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (rp->page) {
|
hdev->max_page = rp->max_page;
|
||||||
case 0:
|
|
||||||
memcpy(hdev->features, rp->features, 8);
|
if (rp->page < HCI_MAX_PAGES)
|
||||||
break;
|
memcpy(hdev->features[rp->page], rp->features, 8);
|
||||||
case 1:
|
|
||||||
memcpy(hdev->host_features, rp->features, 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
|
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
|
||||||
|
@ -968,7 +964,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (cp->enable) {
|
switch (cp->enable) {
|
||||||
case LE_SCANNING_ENABLED:
|
case LE_SCAN_ENABLE:
|
||||||
if (status) {
|
if (status) {
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
mgmt_start_discovery_failed(hdev, status);
|
mgmt_start_discovery_failed(hdev, status);
|
||||||
|
@ -983,7 +979,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LE_SCANNING_DISABLED:
|
case LE_SCAN_DISABLE:
|
||||||
if (status) {
|
if (status) {
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
mgmt_stop_discovery_failed(hdev, status);
|
mgmt_stop_discovery_failed(hdev, status);
|
||||||
|
@ -1046,14 +1042,14 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
if (sent->le)
|
if (sent->le)
|
||||||
hdev->host_features[0] |= LMP_HOST_LE;
|
hdev->features[1][0] |= LMP_HOST_LE;
|
||||||
else
|
else
|
||||||
hdev->host_features[0] &= ~LMP_HOST_LE;
|
hdev->features[1][0] &= ~LMP_HOST_LE;
|
||||||
|
|
||||||
if (sent->simul)
|
if (sent->simul)
|
||||||
hdev->host_features[0] |= LMP_HOST_LE_BREDR;
|
hdev->features[1][0] |= LMP_HOST_LE_BREDR;
|
||||||
else
|
else
|
||||||
hdev->host_features[0] &= ~LMP_HOST_LE_BREDR;
|
hdev->features[1][0] &= ~LMP_HOST_LE_BREDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
|
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
|
||||||
|
@ -1190,7 +1186,7 @@ static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status)
|
||||||
if (conn) {
|
if (conn) {
|
||||||
if (conn->state == BT_CONFIG) {
|
if (conn->state == BT_CONFIG) {
|
||||||
hci_proto_connect_cfm(conn, status);
|
hci_proto_connect_cfm(conn, status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,7 +1213,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
|
||||||
if (conn) {
|
if (conn) {
|
||||||
if (conn->state == BT_CONFIG) {
|
if (conn->state == BT_CONFIG) {
|
||||||
hci_proto_connect_cfm(conn, status);
|
hci_proto_connect_cfm(conn, status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1379,7 +1375,7 @@ static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
|
||||||
if (conn) {
|
if (conn) {
|
||||||
if (conn->state == BT_CONFIG) {
|
if (conn->state == BT_CONFIG) {
|
||||||
hci_proto_connect_cfm(conn, status);
|
hci_proto_connect_cfm(conn, status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1406,7 +1402,7 @@ static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
|
||||||
if (conn) {
|
if (conn) {
|
||||||
if (conn->state == BT_CONFIG) {
|
if (conn->state == BT_CONFIG) {
|
||||||
hci_proto_connect_cfm(conn, status);
|
hci_proto_connect_cfm(conn, status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1600,13 +1596,14 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||||
|
|
||||||
hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
|
|
||||||
|
|
||||||
hci_conn_check_pending(hdev);
|
hci_conn_check_pending(hdev);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
|
if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */
|
||||||
|
wake_up_bit(&hdev->flags, HCI_INQUIRY);
|
||||||
|
|
||||||
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
|
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1705,7 +1702,6 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
} else
|
} else
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
|
|
||||||
hci_conn_hold_device(conn);
|
|
||||||
hci_conn_add_sysfs(conn);
|
hci_conn_add_sysfs(conn);
|
||||||
|
|
||||||
if (test_bit(HCI_AUTH, &hdev->flags))
|
if (test_bit(HCI_AUTH, &hdev->flags))
|
||||||
|
@ -1752,42 +1748,6 @@ unlock:
|
||||||
hci_conn_check_pending(hdev);
|
hci_conn_check_pending(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hci_conn_accept(struct hci_conn *conn, int mask)
|
|
||||||
{
|
|
||||||
struct hci_dev *hdev = conn->hdev;
|
|
||||||
|
|
||||||
BT_DBG("conn %p", conn);
|
|
||||||
|
|
||||||
conn->state = BT_CONFIG;
|
|
||||||
|
|
||||||
if (!lmp_esco_capable(hdev)) {
|
|
||||||
struct hci_cp_accept_conn_req cp;
|
|
||||||
|
|
||||||
bacpy(&cp.bdaddr, &conn->dst);
|
|
||||||
|
|
||||||
if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
|
|
||||||
cp.role = 0x00; /* Become master */
|
|
||||||
else
|
|
||||||
cp.role = 0x01; /* Remain slave */
|
|
||||||
|
|
||||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
|
|
||||||
} else /* lmp_esco_capable(hdev)) */ {
|
|
||||||
struct hci_cp_accept_sync_conn_req cp;
|
|
||||||
|
|
||||||
bacpy(&cp.bdaddr, &conn->dst);
|
|
||||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
|
||||||
|
|
||||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
|
||||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
|
||||||
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
|
||||||
cp.content_format = cpu_to_le16(hdev->voice_setting);
|
|
||||||
cp.retrans_effort = 0xff;
|
|
||||||
|
|
||||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
|
|
||||||
sizeof(cp), &cp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct hci_ev_conn_request *ev = (void *) skb->data;
|
struct hci_ev_conn_request *ev = (void *) skb->data;
|
||||||
|
@ -1859,7 +1819,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
} else {
|
} else {
|
||||||
conn->state = BT_CONNECT2;
|
conn->state = BT_CONNECT2;
|
||||||
hci_proto_connect_cfm(conn, 0);
|
hci_proto_connect_cfm(conn, 0);
|
||||||
hci_conn_put(conn);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Connection rejected */
|
/* Connection rejected */
|
||||||
|
@ -1966,14 +1925,14 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
} else {
|
} else {
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hci_auth_cfm(conn, ev->status);
|
hci_auth_cfm(conn, ev->status);
|
||||||
|
|
||||||
hci_conn_hold(conn);
|
hci_conn_hold(conn);
|
||||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
|
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
|
||||||
|
@ -2057,7 +2016,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
if (ev->status && conn->state == BT_CONNECTED) {
|
if (ev->status && conn->state == BT_CONNECTED) {
|
||||||
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2066,7 +2025,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
|
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
} else
|
} else
|
||||||
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
|
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
|
||||||
}
|
}
|
||||||
|
@ -2113,7 +2072,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
if (!ev->status)
|
if (!ev->status)
|
||||||
memcpy(conn->features, ev->features, 8);
|
memcpy(conn->features[0], ev->features, 8);
|
||||||
|
|
||||||
if (conn->state != BT_CONFIG)
|
if (conn->state != BT_CONFIG)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
@ -2141,7 +2100,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
|
||||||
if (!hci_outgoing_auth_needed(hdev, conn)) {
|
if (!hci_outgoing_auth_needed(hdev, conn)) {
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -2462,7 +2421,9 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
if (opcode != HCI_OP_NOP)
|
if (opcode != HCI_OP_NOP)
|
||||||
del_timer(&hdev->cmd_timer);
|
del_timer(&hdev->cmd_timer);
|
||||||
|
|
||||||
hci_req_cmd_status(hdev, opcode, ev->status);
|
if (ev->status ||
|
||||||
|
(hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event))
|
||||||
|
hci_req_cmd_complete(hdev, opcode, ev->status);
|
||||||
|
|
||||||
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
|
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
|
||||||
atomic_set(&hdev->cmd_cnt, 1);
|
atomic_set(&hdev->cmd_cnt, 1);
|
||||||
|
@ -2679,7 +2640,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
if (conn->state == BT_CONNECTED) {
|
if (conn->state == BT_CONNECTED) {
|
||||||
hci_conn_hold(conn);
|
hci_conn_hold(conn);
|
||||||
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
|
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
|
if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
|
||||||
|
@ -2782,7 +2743,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
|
if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
|
||||||
conn->key_type = ev->key_type;
|
conn->key_type = ev->key_type;
|
||||||
|
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
|
if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
|
||||||
|
@ -2923,6 +2884,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
|
||||||
if (!conn)
|
if (!conn)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
|
if (ev->page < HCI_MAX_PAGES)
|
||||||
|
memcpy(conn->features[ev->page], ev->features, 8);
|
||||||
|
|
||||||
if (!ev->status && ev->page == 0x01) {
|
if (!ev->status && ev->page == 0x01) {
|
||||||
struct inquiry_entry *ie;
|
struct inquiry_entry *ie;
|
||||||
|
|
||||||
|
@ -2930,8 +2894,19 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
|
||||||
if (ie)
|
if (ie)
|
||||||
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
|
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
|
||||||
|
|
||||||
if (ev->features[0] & LMP_HOST_SSP)
|
if (ev->features[0] & LMP_HOST_SSP) {
|
||||||
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
||||||
|
} else {
|
||||||
|
/* It is mandatory by the Bluetooth specification that
|
||||||
|
* Extended Inquiry Results are only used when Secure
|
||||||
|
* Simple Pairing is enabled, but some devices violate
|
||||||
|
* this.
|
||||||
|
*
|
||||||
|
* To make these devices work, the internal SSP
|
||||||
|
* enabled flag needs to be cleared if the remote host
|
||||||
|
* features do not indicate SSP support */
|
||||||
|
clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->state != BT_CONFIG)
|
if (conn->state != BT_CONFIG)
|
||||||
|
@ -2951,7 +2926,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
|
||||||
if (!hci_outgoing_auth_needed(hdev, conn)) {
|
if (!hci_outgoing_auth_needed(hdev, conn)) {
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -2985,7 +2960,6 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
|
||||||
conn->handle = __le16_to_cpu(ev->handle);
|
conn->handle = __le16_to_cpu(ev->handle);
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
|
|
||||||
hci_conn_hold_device(conn);
|
|
||||||
hci_conn_add_sysfs(conn);
|
hci_conn_add_sysfs(conn);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3084,7 +3058,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
|
||||||
|
|
||||||
if (ev->status && conn->state == BT_CONNECTED) {
|
if (ev->status && conn->state == BT_CONNECTED) {
|
||||||
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3093,13 +3067,13 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
|
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
} else {
|
} else {
|
||||||
hci_auth_cfm(conn, ev->status);
|
hci_auth_cfm(conn, ev->status);
|
||||||
|
|
||||||
hci_conn_hold(conn);
|
hci_conn_hold(conn);
|
||||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -3360,7 +3334,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
|
||||||
mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
|
mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||||
ev->status);
|
ev->status);
|
||||||
|
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
@ -3371,11 +3345,16 @@ static void hci_remote_host_features_evt(struct hci_dev *hdev,
|
||||||
{
|
{
|
||||||
struct hci_ev_remote_host_features *ev = (void *) skb->data;
|
struct hci_ev_remote_host_features *ev = (void *) skb->data;
|
||||||
struct inquiry_entry *ie;
|
struct inquiry_entry *ie;
|
||||||
|
struct hci_conn *conn;
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||||
|
if (conn)
|
||||||
|
memcpy(conn->features[1], ev->features, 8);
|
||||||
|
|
||||||
ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
|
ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
|
||||||
if (ie)
|
if (ie)
|
||||||
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
|
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
|
||||||
|
@ -3448,9 +3427,8 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,
|
||||||
|
|
||||||
hci_conn_hold(hcon);
|
hci_conn_hold(hcon);
|
||||||
hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
|
hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
hci_conn_put(hcon);
|
hci_conn_drop(hcon);
|
||||||
|
|
||||||
hci_conn_hold_device(hcon);
|
|
||||||
hci_conn_add_sysfs(hcon);
|
hci_conn_add_sysfs(hcon);
|
||||||
|
|
||||||
amp_physical_cfm(bredr_hcon, hcon);
|
amp_physical_cfm(bredr_hcon, hcon);
|
||||||
|
@ -3584,7 +3562,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
conn->handle = __le16_to_cpu(ev->handle);
|
conn->handle = __le16_to_cpu(ev->handle);
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
|
|
||||||
hci_conn_hold_device(conn);
|
|
||||||
hci_conn_add_sysfs(conn);
|
hci_conn_add_sysfs(conn);
|
||||||
|
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
|
@ -3698,8 +3675,27 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
struct hci_event_hdr *hdr = (void *) skb->data;
|
struct hci_event_hdr *hdr = (void *) skb->data;
|
||||||
__u8 event = hdr->evt;
|
__u8 event = hdr->evt;
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
/* Received events are (currently) only needed when a request is
|
||||||
|
* ongoing so avoid unnecessary memory allocation.
|
||||||
|
*/
|
||||||
|
if (hdev->req_status == HCI_REQ_PEND) {
|
||||||
|
kfree_skb(hdev->recv_evt);
|
||||||
|
hdev->recv_evt = skb_clone(skb, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
skb_pull(skb, HCI_EVENT_HDR_SIZE);
|
skb_pull(skb, HCI_EVENT_HDR_SIZE);
|
||||||
|
|
||||||
|
if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) {
|
||||||
|
struct hci_command_hdr *hdr = (void *) hdev->sent_cmd->data;
|
||||||
|
u16 opcode = __le16_to_cpu(hdr->opcode);
|
||||||
|
|
||||||
|
hci_req_cmd_complete(hdev, opcode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case HCI_EV_INQUIRY_COMPLETE:
|
case HCI_EV_INQUIRY_COMPLETE:
|
||||||
hci_inquiry_complete_evt(hdev, skb);
|
hci_inquiry_complete_evt(hdev, skb);
|
||||||
|
|
|
@ -48,10 +48,10 @@ static ssize_t show_link_features(struct device *dev,
|
||||||
struct hci_conn *conn = to_hci_conn(dev);
|
struct hci_conn *conn = to_hci_conn(dev);
|
||||||
|
|
||||||
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||||
conn->features[0], conn->features[1],
|
conn->features[0][0], conn->features[0][1],
|
||||||
conn->features[2], conn->features[3],
|
conn->features[0][2], conn->features[0][3],
|
||||||
conn->features[4], conn->features[5],
|
conn->features[0][4], conn->features[0][5],
|
||||||
conn->features[6], conn->features[7]);
|
conn->features[0][6], conn->features[0][7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LINK_ATTR(_name, _mode, _show, _store) \
|
#define LINK_ATTR(_name, _mode, _show, _store) \
|
||||||
|
@ -146,7 +146,6 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
device_del(&conn->dev);
|
device_del(&conn->dev);
|
||||||
put_device(&conn->dev);
|
|
||||||
|
|
||||||
hci_dev_put(hdev);
|
hci_dev_put(hdev);
|
||||||
}
|
}
|
||||||
|
@ -234,10 +233,10 @@ static ssize_t show_features(struct device *dev,
|
||||||
struct hci_dev *hdev = to_hci_dev(dev);
|
struct hci_dev *hdev = to_hci_dev(dev);
|
||||||
|
|
||||||
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||||
hdev->features[0], hdev->features[1],
|
hdev->features[0][0], hdev->features[0][1],
|
||||||
hdev->features[2], hdev->features[3],
|
hdev->features[0][2], hdev->features[0][3],
|
||||||
hdev->features[4], hdev->features[5],
|
hdev->features[0][4], hdev->features[0][5],
|
||||||
hdev->features[6], hdev->features[7]);
|
hdev->features[0][6], hdev->features[0][7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_manufacturer(struct device *dev,
|
static ssize_t show_manufacturer(struct device *dev,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,7 +24,9 @@
|
||||||
#define __HIDP_H
|
#define __HIDP_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/kref.h>
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
|
#include <net/bluetooth/l2cap.h>
|
||||||
|
|
||||||
/* HIDP header masks */
|
/* HIDP header masks */
|
||||||
#define HIDP_HEADER_TRANS_MASK 0xf0
|
#define HIDP_HEADER_TRANS_MASK 0xf0
|
||||||
|
@ -119,43 +121,52 @@ struct hidp_connlist_req {
|
||||||
struct hidp_conninfo __user *ci;
|
struct hidp_conninfo __user *ci;
|
||||||
};
|
};
|
||||||
|
|
||||||
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
|
int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
|
||||||
int hidp_del_connection(struct hidp_conndel_req *req);
|
int hidp_connection_del(struct hidp_conndel_req *req);
|
||||||
int hidp_get_connlist(struct hidp_connlist_req *req);
|
int hidp_get_connlist(struct hidp_connlist_req *req);
|
||||||
int hidp_get_conninfo(struct hidp_conninfo *ci);
|
int hidp_get_conninfo(struct hidp_conninfo *ci);
|
||||||
|
|
||||||
|
enum hidp_session_state {
|
||||||
|
HIDP_SESSION_IDLING,
|
||||||
|
HIDP_SESSION_RUNNING,
|
||||||
|
};
|
||||||
|
|
||||||
/* HIDP session defines */
|
/* HIDP session defines */
|
||||||
struct hidp_session {
|
struct hidp_session {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
struct kref ref;
|
||||||
|
|
||||||
struct hci_conn *conn;
|
/* runtime management */
|
||||||
|
atomic_t state;
|
||||||
struct socket *ctrl_sock;
|
wait_queue_head_t state_queue;
|
||||||
struct socket *intr_sock;
|
|
||||||
|
|
||||||
bdaddr_t bdaddr;
|
|
||||||
|
|
||||||
unsigned long state;
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned long idle_to;
|
|
||||||
|
|
||||||
uint ctrl_mtu;
|
|
||||||
uint intr_mtu;
|
|
||||||
|
|
||||||
atomic_t terminate;
|
atomic_t terminate;
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
unsigned char keys[8];
|
/* connection management */
|
||||||
unsigned char leds;
|
bdaddr_t bdaddr;
|
||||||
|
struct l2cap_conn *conn;
|
||||||
struct input_dev *input;
|
struct l2cap_user user;
|
||||||
|
struct socket *ctrl_sock;
|
||||||
struct hid_device *hid;
|
struct socket *intr_sock;
|
||||||
|
|
||||||
struct timer_list timer;
|
|
||||||
|
|
||||||
struct sk_buff_head ctrl_transmit;
|
struct sk_buff_head ctrl_transmit;
|
||||||
struct sk_buff_head intr_transmit;
|
struct sk_buff_head intr_transmit;
|
||||||
|
uint ctrl_mtu;
|
||||||
|
uint intr_mtu;
|
||||||
|
unsigned long idle_to;
|
||||||
|
|
||||||
|
/* device management */
|
||||||
|
struct input_dev *input;
|
||||||
|
struct hid_device *hid;
|
||||||
|
struct timer_list timer;
|
||||||
|
|
||||||
|
/* Report descriptor */
|
||||||
|
__u8 *rd_data;
|
||||||
|
uint rd_size;
|
||||||
|
|
||||||
|
/* session data */
|
||||||
|
unsigned char keys[8];
|
||||||
|
unsigned char leds;
|
||||||
|
|
||||||
/* Used in hidp_get_raw_report() */
|
/* Used in hidp_get_raw_report() */
|
||||||
int waiting_report_type; /* HIDP_DATA_RTYPE_* */
|
int waiting_report_type; /* HIDP_DATA_RTYPE_* */
|
||||||
|
@ -166,24 +177,8 @@ struct hidp_session {
|
||||||
|
|
||||||
/* Used in hidp_output_raw_report() */
|
/* Used in hidp_output_raw_report() */
|
||||||
int output_report_success; /* boolean */
|
int output_report_success; /* boolean */
|
||||||
|
|
||||||
/* Report descriptor */
|
|
||||||
__u8 *rd_data;
|
|
||||||
uint rd_size;
|
|
||||||
|
|
||||||
wait_queue_head_t startup_queue;
|
|
||||||
int waiting_for_startup;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void hidp_schedule(struct hidp_session *session)
|
|
||||||
{
|
|
||||||
struct sock *ctrl_sk = session->ctrl_sock->sk;
|
|
||||||
struct sock *intr_sk = session->intr_sock->sk;
|
|
||||||
|
|
||||||
wake_up_interruptible(sk_sleep(ctrl_sk));
|
|
||||||
wake_up_interruptible(sk_sleep(intr_sk));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HIDP init defines */
|
/* HIDP init defines */
|
||||||
extern int __init hidp_init_sockets(void);
|
extern int __init hidp_init_sockets(void);
|
||||||
extern void __exit hidp_cleanup_sockets(void);
|
extern void __exit hidp_cleanup_sockets(void);
|
||||||
|
|
|
@ -77,21 +77,12 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csock->sk->sk_state != BT_CONNECTED ||
|
err = hidp_connection_add(&ca, csock, isock);
|
||||||
isock->sk->sk_state != BT_CONNECTED) {
|
if (!err && copy_to_user(argp, &ca, sizeof(ca)))
|
||||||
sockfd_put(csock);
|
|
||||||
sockfd_put(isock);
|
|
||||||
return -EBADFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hidp_add_connection(&ca, csock, isock);
|
|
||||||
if (!err) {
|
|
||||||
if (copy_to_user(argp, &ca, sizeof(ca)))
|
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
} else {
|
|
||||||
sockfd_put(csock);
|
sockfd_put(csock);
|
||||||
sockfd_put(isock);
|
sockfd_put(isock);
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -102,7 +93,7 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
|
||||||
if (copy_from_user(&cd, argp, sizeof(cd)))
|
if (copy_from_user(&cd, argp, sizeof(cd)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
return hidp_del_connection(&cd);
|
return hidp_connection_del(&cd);
|
||||||
|
|
||||||
case HIDPGETCONNLIST:
|
case HIDPGETCONNLIST:
|
||||||
if (copy_from_user(&cl, argp, sizeof(cl)))
|
if (copy_from_user(&cl, argp, sizeof(cl)))
|
||||||
|
@ -296,7 +287,6 @@ int __init hidp_init_sockets(void)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
BT_ERR("Can't register HIDP socket");
|
|
||||||
proto_unregister(&hidp_proto);
|
proto_unregister(&hidp_proto);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -571,7 +571,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
||||||
chan->conn = NULL;
|
chan->conn = NULL;
|
||||||
|
|
||||||
if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
|
if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
|
||||||
hci_conn_put(conn->hcon);
|
hci_conn_drop(conn->hcon);
|
||||||
|
|
||||||
if (mgr && mgr->bredr_chan == chan)
|
if (mgr && mgr->bredr_chan == chan)
|
||||||
mgr->bredr_chan = NULL;
|
mgr->bredr_chan = NULL;
|
||||||
|
@ -1446,6 +1446,89 @@ static void l2cap_info_timeout(struct work_struct *work)
|
||||||
l2cap_conn_start(conn);
|
l2cap_conn_start(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* l2cap_user
|
||||||
|
* External modules can register l2cap_user objects on l2cap_conn. The ->probe
|
||||||
|
* callback is called during registration. The ->remove callback is called
|
||||||
|
* during unregistration.
|
||||||
|
* An l2cap_user object can either be explicitly unregistered or when the
|
||||||
|
* underlying l2cap_conn object is deleted. This guarantees that l2cap->hcon,
|
||||||
|
* l2cap->hchan, .. are valid as long as the remove callback hasn't been called.
|
||||||
|
* External modules must own a reference to the l2cap_conn object if they intend
|
||||||
|
* to call l2cap_unregister_user(). The l2cap_conn object might get destroyed at
|
||||||
|
* any time if they don't.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||||
|
{
|
||||||
|
struct hci_dev *hdev = conn->hcon->hdev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* We need to check whether l2cap_conn is registered. If it is not, we
|
||||||
|
* must not register the l2cap_user. l2cap_conn_del() is unregisters
|
||||||
|
* l2cap_conn objects, but doesn't provide its own locking. Instead, it
|
||||||
|
* relies on the parent hci_conn object to be locked. This itself relies
|
||||||
|
* on the hci_dev object to be locked. So we must lock the hci device
|
||||||
|
* here, too. */
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
if (user->list.next || user->list.prev) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* conn->hchan is NULL after l2cap_conn_del() was called */
|
||||||
|
if (!conn->hchan) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = user->probe(conn, user);
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
list_add(&user->list, &conn->users);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(l2cap_register_user);
|
||||||
|
|
||||||
|
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||||
|
{
|
||||||
|
struct hci_dev *hdev = conn->hcon->hdev;
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
if (!user->list.next || !user->list.prev)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
list_del(&user->list);
|
||||||
|
user->list.next = NULL;
|
||||||
|
user->list.prev = NULL;
|
||||||
|
user->remove(conn, user);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(l2cap_unregister_user);
|
||||||
|
|
||||||
|
static void l2cap_unregister_all_users(struct l2cap_conn *conn)
|
||||||
|
{
|
||||||
|
struct l2cap_user *user;
|
||||||
|
|
||||||
|
while (!list_empty(&conn->users)) {
|
||||||
|
user = list_first_entry(&conn->users, struct l2cap_user, list);
|
||||||
|
list_del(&user->list);
|
||||||
|
user->list.next = NULL;
|
||||||
|
user->list.prev = NULL;
|
||||||
|
user->remove(conn, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
||||||
{
|
{
|
||||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||||
|
@ -1458,6 +1541,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
||||||
|
|
||||||
kfree_skb(conn->rx_skb);
|
kfree_skb(conn->rx_skb);
|
||||||
|
|
||||||
|
l2cap_unregister_all_users(conn);
|
||||||
|
|
||||||
mutex_lock(&conn->chan_lock);
|
mutex_lock(&conn->chan_lock);
|
||||||
|
|
||||||
/* Kill channels */
|
/* Kill channels */
|
||||||
|
@ -1486,7 +1571,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hcon->l2cap_data = NULL;
|
hcon->l2cap_data = NULL;
|
||||||
kfree(conn);
|
conn->hchan = NULL;
|
||||||
|
l2cap_conn_put(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void security_timeout(struct work_struct *work)
|
static void security_timeout(struct work_struct *work)
|
||||||
|
@ -1502,12 +1588,12 @@ static void security_timeout(struct work_struct *work)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
|
||||||
{
|
{
|
||||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||||
struct hci_chan *hchan;
|
struct hci_chan *hchan;
|
||||||
|
|
||||||
if (conn || status)
|
if (conn)
|
||||||
return conn;
|
return conn;
|
||||||
|
|
||||||
hchan = hci_chan_create(hcon);
|
hchan = hci_chan_create(hcon);
|
||||||
|
@ -1520,8 +1606,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kref_init(&conn->ref);
|
||||||
hcon->l2cap_data = conn;
|
hcon->l2cap_data = conn;
|
||||||
conn->hcon = hcon;
|
conn->hcon = hcon;
|
||||||
|
hci_conn_get(conn->hcon);
|
||||||
conn->hchan = hchan;
|
conn->hchan = hchan;
|
||||||
|
|
||||||
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
|
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
|
||||||
|
@ -1547,6 +1635,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
||||||
mutex_init(&conn->chan_lock);
|
mutex_init(&conn->chan_lock);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&conn->chan_l);
|
INIT_LIST_HEAD(&conn->chan_l);
|
||||||
|
INIT_LIST_HEAD(&conn->users);
|
||||||
|
|
||||||
if (hcon->type == LE_LINK)
|
if (hcon->type == LE_LINK)
|
||||||
INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
|
INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
|
||||||
|
@ -1558,6 +1647,26 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void l2cap_conn_free(struct kref *ref)
|
||||||
|
{
|
||||||
|
struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
|
||||||
|
|
||||||
|
hci_conn_put(conn->hcon);
|
||||||
|
kfree(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void l2cap_conn_get(struct l2cap_conn *conn)
|
||||||
|
{
|
||||||
|
kref_get(&conn->ref);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(l2cap_conn_get);
|
||||||
|
|
||||||
|
void l2cap_conn_put(struct l2cap_conn *conn)
|
||||||
|
{
|
||||||
|
kref_put(&conn->ref, l2cap_conn_free);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(l2cap_conn_put);
|
||||||
|
|
||||||
/* ---- Socket interface ---- */
|
/* ---- Socket interface ---- */
|
||||||
|
|
||||||
/* Find socket with psm and source / destination bdaddr.
|
/* Find socket with psm and source / destination bdaddr.
|
||||||
|
@ -1695,9 +1804,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = l2cap_conn_add(hcon, 0);
|
conn = l2cap_conn_add(hcon);
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
hci_conn_put(hcon);
|
hci_conn_drop(hcon);
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1707,7 +1816,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||||
|
|
||||||
if (!list_empty(&conn->chan_l)) {
|
if (!list_empty(&conn->chan_l)) {
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
hci_conn_put(hcon);
|
hci_conn_drop(hcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -6313,7 +6422,7 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||||
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
|
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
conn = l2cap_conn_add(hcon, status);
|
conn = l2cap_conn_add(hcon);
|
||||||
if (conn)
|
if (conn)
|
||||||
l2cap_conn_ready(conn);
|
l2cap_conn_ready(conn);
|
||||||
} else {
|
} else {
|
||||||
|
@ -6482,7 +6591,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
conn = l2cap_conn_add(hcon, 0);
|
conn = l2cap_conn_add(hcon);
|
||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
|
@ -43,6 +43,12 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent);
|
||||||
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
|
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
|
||||||
int proto, gfp_t prio);
|
int proto, gfp_t prio);
|
||||||
|
|
||||||
|
bool l2cap_is_socket(struct socket *sock)
|
||||||
|
{
|
||||||
|
return sock && sock->ops == &l2cap_sock_ops;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(l2cap_is_socket);
|
||||||
|
|
||||||
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
||||||
{
|
{
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
|
|
|
@ -106,11 +106,10 @@ static const u16 mgmt_events[] = {
|
||||||
* These LE scan and inquiry parameters were chosen according to LE General
|
* These LE scan and inquiry parameters were chosen according to LE General
|
||||||
* Discovery Procedure specification.
|
* Discovery Procedure specification.
|
||||||
*/
|
*/
|
||||||
#define LE_SCAN_TYPE 0x01
|
|
||||||
#define LE_SCAN_WIN 0x12
|
#define LE_SCAN_WIN 0x12
|
||||||
#define LE_SCAN_INT 0x12
|
#define LE_SCAN_INT 0x12
|
||||||
#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
|
#define LE_SCAN_TIMEOUT_LE_ONLY msecs_to_jiffies(10240)
|
||||||
#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
|
#define LE_SCAN_TIMEOUT_BREDR_LE msecs_to_jiffies(5120)
|
||||||
|
|
||||||
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
|
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
|
||||||
#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
|
#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
|
||||||
|
@ -2131,7 +2130,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
|
||||||
conn->security_cfm_cb = NULL;
|
conn->security_cfm_cb = NULL;
|
||||||
conn->disconn_cfm_cb = NULL;
|
conn->disconn_cfm_cb = NULL;
|
||||||
|
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
|
|
||||||
mgmt_pending_remove(cmd);
|
mgmt_pending_remove(cmd);
|
||||||
}
|
}
|
||||||
|
@ -2222,7 +2221,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->connect_cfm_cb) {
|
if (conn->connect_cfm_cb) {
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
|
err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
|
||||||
MGMT_STATUS_BUSY, &rp, sizeof(rp));
|
MGMT_STATUS_BUSY, &rp, sizeof(rp));
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
@ -2231,7 +2230,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
|
cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
hci_conn_put(conn);
|
hci_conn_drop(conn);
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2703,7 +2702,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
|
err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
|
||||||
LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
|
LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2715,8 +2714,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
|
err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
|
||||||
LE_SCAN_TIMEOUT_BREDR_LE);
|
LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -83,7 +83,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
|
||||||
if (conn)
|
if (conn)
|
||||||
return conn;
|
return conn;
|
||||||
|
|
||||||
conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
|
conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ static int sco_connect(struct sock *sk)
|
||||||
|
|
||||||
conn = sco_conn_add(hcon);
|
conn = sco_conn_add(hcon);
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
hci_conn_put(hcon);
|
hci_conn_drop(hcon);
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +353,7 @@ static void __sco_sock_close(struct sock *sk)
|
||||||
if (sco_pi(sk)->conn->hcon) {
|
if (sco_pi(sk)->conn->hcon) {
|
||||||
sk->sk_state = BT_DISCONN;
|
sk->sk_state = BT_DISCONN;
|
||||||
sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
|
sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
|
||||||
hci_conn_put(sco_pi(sk)->conn->hcon);
|
hci_conn_drop(sco_pi(sk)->conn->hcon);
|
||||||
sco_pi(sk)->conn->hcon = NULL;
|
sco_pi(sk)->conn->hcon = NULL;
|
||||||
} else
|
} else
|
||||||
sco_chan_del(sk, ECONNRESET);
|
sco_chan_del(sk, ECONNRESET);
|
||||||
|
@ -481,8 +481,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
|
||||||
{
|
{
|
||||||
struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
|
struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
|
|
||||||
BT_DBG("sk %p", sk);
|
BT_DBG("sk %p", sk);
|
||||||
|
|
||||||
|
@ -653,6 +652,42 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sco_conn_defer_accept(struct hci_conn *conn, int mask)
|
||||||
|
{
|
||||||
|
struct hci_dev *hdev = conn->hdev;
|
||||||
|
|
||||||
|
BT_DBG("conn %p", conn);
|
||||||
|
|
||||||
|
conn->state = BT_CONFIG;
|
||||||
|
|
||||||
|
if (!lmp_esco_capable(hdev)) {
|
||||||
|
struct hci_cp_accept_conn_req cp;
|
||||||
|
|
||||||
|
bacpy(&cp.bdaddr, &conn->dst);
|
||||||
|
|
||||||
|
if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
|
||||||
|
cp.role = 0x00; /* Become master */
|
||||||
|
else
|
||||||
|
cp.role = 0x01; /* Remain slave */
|
||||||
|
|
||||||
|
hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
|
||||||
|
} else {
|
||||||
|
struct hci_cp_accept_sync_conn_req cp;
|
||||||
|
|
||||||
|
bacpy(&cp.bdaddr, &conn->dst);
|
||||||
|
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||||
|
|
||||||
|
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||||
|
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||||
|
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
||||||
|
cp.content_format = cpu_to_le16(hdev->voice_setting);
|
||||||
|
cp.retrans_effort = 0xff;
|
||||||
|
|
||||||
|
hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
|
||||||
|
sizeof(cp), &cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
struct msghdr *msg, size_t len, int flags)
|
struct msghdr *msg, size_t len, int flags)
|
||||||
{
|
{
|
||||||
|
@ -663,7 +698,7 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
|
|
||||||
if (sk->sk_state == BT_CONNECT2 &&
|
if (sk->sk_state == BT_CONNECT2 &&
|
||||||
test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
|
test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
|
||||||
hci_conn_accept(pi->conn->hcon, 0);
|
sco_conn_defer_accept(pi->conn->hcon, 0);
|
||||||
sk->sk_state = BT_CONFIG;
|
sk->sk_state = BT_CONFIG;
|
||||||
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
@ -882,7 +917,7 @@ static void sco_chan_del(struct sock *sk, int err)
|
||||||
sco_conn_unlock(conn);
|
sco_conn_unlock(conn);
|
||||||
|
|
||||||
if (conn->hcon)
|
if (conn->hcon)
|
||||||
hci_conn_put(conn->hcon);
|
hci_conn_drop(conn->hcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
sk->sk_state = BT_CLOSED;
|
sk->sk_state = BT_CLOSED;
|
||||||
|
|
|
@ -522,7 +522,7 @@ void smp_chan_destroy(struct l2cap_conn *conn)
|
||||||
kfree(smp);
|
kfree(smp);
|
||||||
conn->smp_chan = NULL;
|
conn->smp_chan = NULL;
|
||||||
conn->hcon->smp_conn = NULL;
|
conn->hcon->smp_conn = NULL;
|
||||||
hci_conn_put(conn->hcon);
|
hci_conn_drop(conn->hcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||||
|
|
Loading…
Reference in New Issue