Skip to content

Commit

Permalink
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/bluetooth/bluetooth-next
  • Loading branch information
John W. Linville committed Jan 30, 2013
2 parents 56e1bd7 + 9b008c0 commit 0f496df
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 120 deletions.
4 changes: 3 additions & 1 deletion include/net/bluetooth/a2mp.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum amp_mgr_state {
READ_LOC_AMP_INFO,
READ_LOC_AMP_ASSOC,
READ_LOC_AMP_ASSOC_FINAL,
WRITE_REMOTE_AMP_ASSOC,
};

struct amp_mgr {
Expand All @@ -33,7 +34,7 @@ struct amp_mgr {
struct kref kref;
__u8 ident;
__u8 handle;
enum amp_mgr_state state;
unsigned long state;
unsigned long flags;

struct list_head amp_ctrls;
Expand Down Expand Up @@ -144,5 +145,6 @@ void a2mp_discover_amp(struct l2cap_chan *chan);
void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status);

#endif /* __A2MP_H */
23 changes: 23 additions & 0 deletions include/net/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,29 @@ typedef struct {
#define BDADDR_LE_PUBLIC 0x01
#define BDADDR_LE_RANDOM 0x02

static inline bool bdaddr_type_is_valid(__u8 type)
{
switch (type) {
case BDADDR_BREDR:
case BDADDR_LE_PUBLIC:
case BDADDR_LE_RANDOM:
return true;
}

return false;
}

static inline bool bdaddr_type_is_le(__u8 type)
{
switch (type) {
case BDADDR_LE_PUBLIC:
case BDADDR_LE_RANDOM:
return true;
}

return false;
}

#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })

Expand Down
18 changes: 18 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,12 @@ struct hci_rp_le_read_buffer_size {
__u8 le_max_pkt;
} __packed;

#define HCI_OP_LE_READ_LOCAL_FEATURES 0x2003
struct hci_rp_le_read_local_features {
__u8 status;
__u8 features[8];
} __packed;

#define HCI_OP_LE_READ_ADV_TX_POWER 0x2007
struct hci_rp_le_read_adv_tx_power {
__u8 status;
Expand Down Expand Up @@ -995,6 +1001,12 @@ struct hci_cp_le_create_conn {

#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e

#define HCI_OP_LE_READ_WHITE_LIST_SIZE 0x200f
struct hci_rp_le_read_white_list_size {
__u8 status;
__u8 size;
} __packed;

#define HCI_OP_LE_CONN_UPDATE 0x2013
struct hci_cp_le_conn_update {
__le16 handle;
Expand Down Expand Up @@ -1033,6 +1045,12 @@ struct hci_rp_le_ltk_neg_reply {
__le16 handle;
} __packed;

#define HCI_OP_LE_READ_SUPPORTED_STATES 0x201c
struct hci_rp_le_read_supported_states {
__u8 status;
__u8 le_states[8];
} __packed;

/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01

Expand Down
4 changes: 4 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ struct hci_dev {
__u8 minor_class;
__u8 features[8];
__u8 host_features[8];
__u8 le_features[8];
__u8 le_white_list_size;
__u8 le_states[8];
__u8 commands[64];
__u8 hci_ver;
__u16 hci_rev;
Expand Down Expand Up @@ -216,6 +219,7 @@ struct hci_dev {
unsigned long le_last_tx;

struct workqueue_struct *workqueue;
struct workqueue_struct *req_workqueue;

struct work_struct power_on;
struct delayed_work power_off;
Expand Down
1 change: 0 additions & 1 deletion include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,6 @@ struct l2cap_chan {
__u16 frames_sent;
__u16 unacked_frames;
__u8 retry_count;
__u16 srej_queue_next;
__u16 sdu_len;
struct sk_buff *sdu;
struct sk_buff *sdu_last_frag;
Expand Down
42 changes: 38 additions & 4 deletions net/bluetooth/a2mp.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
goto done;
}

mgr->state = READ_LOC_AMP_INFO;
set_bit(READ_LOC_AMP_INFO, &mgr->state);
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);

done:
Expand Down Expand Up @@ -499,8 +499,16 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
if (hdev)
hci_dev_put(hdev);

a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
&rsp);
/* Reply error now and success after HCI Write Remote AMP Assoc
command complete with success status
*/
if (rsp.status != A2MP_STATUS_SUCCESS) {
a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident,
sizeof(rsp), &rsp);
} else {
set_bit(WRITE_REMOTE_AMP_ASSOC, &mgr->state);
mgr->ident = hdr->ident;
}

skb_pull(skb, le16_to_cpu(hdr->len));
return 0;
Expand Down Expand Up @@ -840,7 +848,7 @@ struct amp_mgr *amp_mgr_lookup_by_state(u8 state)

mutex_lock(&amp_mgr_list_lock);
list_for_each_entry(mgr, &amp_mgr_list, list) {
if (mgr->state == state) {
if (test_and_clear_bit(state, &mgr->state)) {
amp_mgr_get(mgr);
mutex_unlock(&amp_mgr_list_lock);
return mgr;
Expand Down Expand Up @@ -949,6 +957,32 @@ void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)
kfree(req);
}

void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status)
{
struct amp_mgr *mgr;
struct a2mp_physlink_rsp rsp;
struct hci_conn *hs_hcon;

mgr = amp_mgr_lookup_by_state(WRITE_REMOTE_AMP_ASSOC);
if (!mgr)
return;

hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT);
if (!hs_hcon) {
rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
} else {
rsp.remote_id = hs_hcon->remote_id;
rsp.status = A2MP_STATUS_SUCCESS;
}

BT_DBG("%s mgr %p hs_hcon %p status %u", hdev->name, mgr, hs_hcon,
status);

rsp.local_id = hdev->id;
a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, mgr->ident, sizeof(rsp), &rsp);
amp_mgr_put(mgr);
}

void a2mp_discover_amp(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
Expand Down
25 changes: 10 additions & 15 deletions net/bluetooth/amp.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)

cp.max_len = cpu_to_le16(hdev->amp_assoc_size);

mgr->state = READ_LOC_AMP_ASSOC;
set_bit(READ_LOC_AMP_ASSOC, &mgr->state);
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}

Expand All @@ -250,7 +250,7 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
cp.len_so_far = cpu_to_le16(0);
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);

mgr->state = READ_LOC_AMP_ASSOC_FINAL;
set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);

/* Read Local AMP Assoc final link information data */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
Expand Down Expand Up @@ -317,7 +317,9 @@ void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
if (!hcon)
return;

amp_write_rem_assoc_frag(hdev, hcon);
/* Send A2MP create phylink rsp when all fragments are written */
if (amp_write_rem_assoc_frag(hdev, hcon))
a2mp_send_create_phy_link_rsp(hdev, 0);
}

void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
Expand Down Expand Up @@ -403,26 +405,20 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)

void amp_create_logical_link(struct l2cap_chan *chan)
{
struct hci_conn *hs_hcon = chan->hs_hcon;
struct hci_cp_create_accept_logical_link cp;
struct hci_conn *hcon;
struct hci_dev *hdev;

BT_DBG("chan %p", chan);
BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon, chan->conn->dst);

if (!chan->hs_hcon)
if (!hs_hcon)
return;

hdev = hci_dev_hold(chan->hs_hcon->hdev);
if (!hdev)
return;

BT_DBG("chan %p dst %pMR", chan, chan->conn->dst);

hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst);
if (!hcon)
goto done;

cp.phy_handle = hcon->handle;
cp.phy_handle = hs_hcon->handle;

cp.tx_flow_spec.id = chan->local_id;
cp.tx_flow_spec.stype = chan->local_stype;
Expand All @@ -438,14 +434,13 @@ void amp_create_logical_link(struct l2cap_chan *chan)
cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat);
cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to);

if (hcon->out)
if (hs_hcon->out)
hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp),
&cp);
else
hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp),
&cp);

done:
hci_dev_put(hdev);
}

Expand Down
1 change: 0 additions & 1 deletion net/bluetooth/bnep/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>

#include "bnep.h"

Expand Down
20 changes: 16 additions & 4 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,8 @@ static void hci_power_on(struct work_struct *work)
return;

if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
schedule_delayed_work(&hdev->power_off, HCI_AUTO_OFF_TIMEOUT);
queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
HCI_AUTO_OFF_TIMEOUT);

if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
mgmt_index_added(hdev);
Expand Down Expand Up @@ -1621,8 +1622,8 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
if (err < 0)
return err;

schedule_delayed_work(&hdev->le_scan_disable,
msecs_to_jiffies(timeout));
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
msecs_to_jiffies(timeout));

return 0;
}
Expand Down Expand Up @@ -1799,6 +1800,15 @@ int hci_register_dev(struct hci_dev *hdev)
goto err;
}

hdev->req_workqueue = alloc_workqueue(hdev->name,
WQ_HIGHPRI | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1);
if (!hdev->req_workqueue) {
destroy_workqueue(hdev->workqueue);
error = -ENOMEM;
goto err;
}

error = hci_add_sysfs(hdev);
if (error < 0)
goto err_wqueue;
Expand All @@ -1821,12 +1831,13 @@ int hci_register_dev(struct hci_dev *hdev)
hci_notify(hdev, HCI_DEV_REG);
hci_dev_hold(hdev);

schedule_work(&hdev->power_on);
queue_work(hdev->req_workqueue, &hdev->power_on);

return id;

err_wqueue:
destroy_workqueue(hdev->workqueue);
destroy_workqueue(hdev->req_workqueue);
err:
ida_simple_remove(&hci_index_ida, hdev->id);
write_lock(&hci_dev_list_lock);
Expand Down Expand Up @@ -1880,6 +1891,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_del_sysfs(hdev);

destroy_workqueue(hdev->workqueue);
destroy_workqueue(hdev->req_workqueue);

hci_dev_lock(hdev);
hci_blacklist_clear(hdev);
Expand Down
Loading

0 comments on commit 0f496df

Please sign in to comment.