From 7d69230c4381a5abc7286a8dfc893268e14e6ead Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 11:46:49 +0200 Subject: Bluetooth: Correct type for hdev lmp_subver Keep lmp_subver in host byte order. We have following conversion in hci_cc_read_local_version: hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver); Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index db1c5df45224..53e8eb2f0a2e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -155,7 +155,7 @@ struct hci_dev { __u16 hci_rev; __u8 lmp_ver; __u16 manufacturer; - __le16 lmp_subver; + __u16 lmp_subver; __u16 voice_setting; __u8 io_capability; -- cgit v1.2.3 From 9a0066579270584108f1f2f97d98fe989d8117df Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 12:12:12 +0200 Subject: Bluetooth: Correct type for ediv to __le16 Correct type warnings reported by sparse to show that this functions takes ediv argument in __le16 format. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 53e8eb2f0a2e..0eec5dbaee0f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -673,8 +673,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv, - u8 rand[8]); + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index edfd61addcec..af55ea1b6882 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1336,7 +1336,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; -- cgit v1.2.3 From 6935e0f5181644201894f0b7fbe3d8910c18af05 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 9 Mar 2012 15:53:42 +0100 Subject: Bluetooth: Remove redundant hdev->parent field We initialize the "struct device" in hci_alloc_dev() for a long time now so we can access hdev->dev.parent directly. Hence, we can drop the temporary field hdev->parent which is used in no other place than hci_add_sysfs(). SET_HCIDEV_DEV() is never called after registering a device by the drivers so we do not overwrite internal device-state. Furthermore, hdev->dev is initialized to 0 by kzalloc() inside hci_alloc_dev() so the default behavior with dev.parent = NULL is kept. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 2 +- include/net/bluetooth/hci_core.h | 3 +-- net/bluetooth/hci_sysfs.c | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 98a8c05d4f23..e564579a6115 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -388,7 +388,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->close = hci_uart_close; hdev->flush = hci_uart_flush; hdev->send = hci_uart_send_frame; - hdev->parent = hu->tty->dev; + SET_HCIDEV_DEV(hdev, hu->tty->dev); if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0eec5dbaee0f..c80a9684a144 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -263,7 +263,6 @@ struct hci_dev { struct dentry *debugfs; - struct device *parent; struct device dev; struct rfkill *rfkill; @@ -709,7 +708,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn); void hci_conn_add_sysfs(struct hci_conn *conn); void hci_conn_del_sysfs(struct hci_conn *conn); -#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) +#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev)) /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index bc154298979a..60b93d8219ef 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -533,7 +533,6 @@ int hci_add_sysfs(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - dev->parent = hdev->parent; dev_set_name(dev, "%s", hdev->name); err = device_add(dev); -- cgit v1.2.3 From 91c4e9b1ac595f83681c9a9de691e0f30eeafb44 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Mar 2012 19:27:21 -0700 Subject: Bluetooth: Add TX power tag to EIR data The Inquiry Response TX power tag should be added to the Extended Inquiry Data (EIR) as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++++ include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 9 ++++++--- net/bluetooth/mgmt.c | 9 +++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d47e523c9d83..3edb3e759ffe 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -717,6 +717,10 @@ struct hci_rp_read_local_oob_data { } __packed; #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 +struct hci_rp_read_inq_rsp_tx_power { + __u8 status; + __s8 tx_power; +} __packed; #define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66 struct hci_rp_read_flow_control_mode { diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c80a9684a144..ce09bf1592e2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -158,6 +158,7 @@ struct hci_dev { __u16 lmp_subver; __u16 voice_setting; __u8 io_capability; + __s8 inq_tx_power; __u16 pkt_type; __u16 esco_type; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 50ff9a989531..75f01d1b126f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -887,11 +887,14 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, struct sk_buff *skb) { - __u8 status = *((__u8 *) skb->data); + struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (!rp->status) + hdev->inq_tx_power = rp->tx_power; - hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status); + hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status); } static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4a2fb06226fc..02b89e299ff8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -479,6 +479,15 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += (name_len + 2); } + if (hdev->inq_tx_power) { + ptr[0] = 2; + ptr[1] = EIR_TX_POWER; + ptr[2] = (u8) hdev->inq_tx_power; + + eir_len += 3; + ptr += 3; + } + memset(uuid16_list, 0, sizeof(uuid16_list)); /* Group all UUID16 types */ -- cgit v1.2.3 From 2b9be137b70bef9ec7835d83e225d8b35ba9c7ae Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Mar 2012 19:32:12 -0700 Subject: Bluetooth: Handle EIR tags for Device ID The Device ID information can be provided via Extended Inquiry Data as well. If a valid source is present, then include it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 4 ++++ net/bluetooth/mgmt.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ce09bf1592e2..c8e24a9b176c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -159,6 +159,10 @@ struct hci_dev { __u16 voice_setting; __u8 io_capability; __s8 inq_tx_power; + __u16 devid_source; + __u16 devid_vendor; + __u16 devid_product; + __u16 devid_version; __u16 pkt_type; __u16 esco_type; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 02b89e299ff8..1da458d9b5ca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -488,6 +488,19 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += 3; } + if (hdev->devid_source > 0) { + ptr[0] = 9; + ptr[1] = EIR_DEVICE_ID; + + put_unaligned_le16(hdev->devid_source, ptr + 2); + put_unaligned_le16(hdev->devid_vendor, ptr + 4); + put_unaligned_le16(hdev->devid_product, ptr + 6); + put_unaligned_le16(hdev->devid_version, ptr + 8); + + eir_len += 10; + ptr += 10; + } + memset(uuid16_list, 0, sizeof(uuid16_list)); /* Group all UUID16 types */ -- cgit v1.2.3 From cdbaccca733c9dde3faf150150102dade311c91f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Mar 2012 20:00:29 -0700 Subject: Bluetooth: Add management command for setting Device ID The Device ID details need to be programmed into the kernel for every controller at least once. So provide management command for this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 9 +++++++++ net/bluetooth/mgmt.c | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ebfd91fc20f8..23fd0546fccb 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -341,6 +341,15 @@ struct mgmt_cp_unblock_device { } __packed; #define MGMT_UNBLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE +#define MGMT_OP_SET_DEVICE_ID 0x0028 +struct mgmt_cp_set_device_id { + __le16 source; + __le16 vendor; + __le16 product; + __le16 version; +} __packed; +#define MGMT_SET_DEVICE_ID_SIZE 8 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1da458d9b5ca..5e88fda42f1f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -78,6 +78,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_CONFIRM_NAME, MGMT_OP_BLOCK_DEVICE, MGMT_OP_UNBLOCK_DEVICE, + MGMT_OP_SET_DEVICE_ID, }; static const u16 mgmt_events[] = { @@ -2523,6 +2524,30 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, return err; } +static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_set_device_id *cp = data; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + hdev->devid_source = __le16_to_cpu(cp->source); + hdev->devid_vendor = __le16_to_cpu(cp->vendor); + hdev->devid_product = __le16_to_cpu(cp->product); + hdev->devid_version = __le16_to_cpu(cp->version); + + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0); + + update_eir(hdev); + + hci_dev_unlock(hdev); + + return err; +} + static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -2669,6 +2694,7 @@ struct mgmt_handler { { confirm_name, false, MGMT_CONFIRM_NAME_SIZE }, { block_device, false, MGMT_BLOCK_DEVICE_SIZE }, { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE }, + { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE }, }; -- cgit v1.2.3 From 58115373e74c7ee18d0f54f00831649a6471a899 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:06 +0200 Subject: Bluetooth: Correct ediv in SMP ediv is already in little endian order. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/smp.h | 2 +- net/bluetooth/smp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 7b3acdd29134..ca356a734920 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -77,7 +77,7 @@ struct smp_cmd_encrypt_info { #define SMP_CMD_MASTER_IDENT 0x07 struct smp_cmd_master_ident { - __u16 ediv; + __le16 ediv; __u8 rand[8]; } __packed; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index deb119875fd9..6fc7c4708f3e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -956,7 +956,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) HCI_SMP_LTK_SLAVE, 1, authenticated, enc.ltk, smp->enc_key_size, ediv, ident.rand); - ident.ediv = cpu_to_le16(ediv); + ident.ediv = ediv; smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); -- cgit v1.2.3 From 7dbfac1d720d3ea68e00e187bbd2f1147257528b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 15 Mar 2012 16:52:07 -0300 Subject: Bluetooth: Add hci_cancel_le_scan() to hci_core This patch adds to hci_core the hci_cancel_le_scan function which should be used to cancel an ongoing LE scan. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c8e24a9b176c..f7cf928ab6ff 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1078,5 +1078,6 @@ int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, int timeout); +int hci_cancel_le_scan(struct hci_dev *hdev); #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 47a4e9b26b9a..e3920b693f04 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1671,6 +1671,24 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, return 0; } +int hci_cancel_le_scan(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return -EALREADY; + + if (cancel_delayed_work(&hdev->le_scan_disable)) { + struct hci_cp_le_set_scan_enable cp; + + /* Send HCI command to disable LE Scan */ + memset(&cp, 0, sizeof(cp)); + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); + } + + return 0; +} + static void le_scan_disable_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, -- cgit v1.2.3 From 79d6e068bee82e9998b2be78bc0f08f2dec8777a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Mar 2012 00:03:35 -0300 Subject: Bluetooth: Add Periodic Inquiry command complete handler This patch adds a handler function to Periodic Inquiry command complete event. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3edb3e759ffe..9cf088db4861 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -324,6 +324,8 @@ struct hci_cp_inquiry { #define HCI_OP_INQUIRY_CANCEL 0x0402 +#define HCI_OP_PERIODIC_INQ 0x0403 + #define HCI_OP_EXIT_PERIODIC_INQ 0x0404 #define HCI_OP_CREATE_CONN 0x0405 -- cgit v1.2.3 From 21693c15c0c3be1aac16eee19497a545f12b1a37 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Mar 2012 00:03:36 -0300 Subject: Bluetooth: Add HCI_PERIODIC_INQ to dev_flags This patch adds the HCI_PERIODIC_INQ flag to dev_flags. This flag tracks if periodic inquiry is enabled or not. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 9cf088db4861..346f08779792 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -102,6 +102,7 @@ enum { HCI_DISCOVERABLE, HCI_LINK_SECURITY, HCI_PENDING_CLASS, + HCI_PERIODIC_INQ, }; /* HCI ioctl defines */ -- cgit v1.2.3 From 6f74b6f36fc06fafb0c5868563385a59dc22b1b2 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 23 Mar 2012 16:31:50 +0200 Subject: Bluetooth: Comments and style fixes Add comments to timer implementation and style fixes. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9b242c6bf55b..35334a0de070 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -622,21 +622,26 @@ static inline void l2cap_chan_unlock(struct l2cap_chan *chan) } static inline void l2cap_set_timer(struct l2cap_chan *chan, - struct delayed_work *work, long timeout) + struct delayed_work *work, long timeout) { BT_DBG("chan %p state %s timeout %ld", chan, - state_to_string(chan->state), timeout); + state_to_string(chan->state), timeout); + /* If delayed work cancelled do not hold(chan) + since it is already done with previous set_timer */ if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); + schedule_delayed_work(work, timeout); } static inline bool l2cap_clear_timer(struct l2cap_chan *chan, - struct delayed_work *work) + struct delayed_work *work) { bool ret; + /* put(chan) if delayed work cancelled otherwise it + is done in delayed work function */ ret = cancel_delayed_work(work); if (ret) l2cap_chan_put(chan); -- cgit v1.2.3 From d5f7ac38102c12069de247890cfdd357bf845a77 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 23 Mar 2012 16:56:55 -0700 Subject: Bluetooth: Add definitions and struct members for new ERTM state machine Adds some missing values for control field parsing, additional data for the new state machine, and enumerations for states, incoming packet classification, and state machine events. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 35334a0de070..c988df6f63bf 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -139,6 +139,8 @@ struct l2cap_conninfo { #define L2CAP_CTRL_TXSEQ_SHIFT 1 #define L2CAP_CTRL_SUPER_SHIFT 2 +#define L2CAP_CTRL_POLL_SHIFT 4 +#define L2CAP_CTRL_FINAL_SHIFT 7 #define L2CAP_CTRL_REQSEQ_SHIFT 8 #define L2CAP_CTRL_SAR_SHIFT 14 @@ -152,9 +154,11 @@ struct l2cap_conninfo { #define L2CAP_EXT_CTRL_FINAL 0x00000002 #define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */ +#define L2CAP_EXT_CTRL_FINAL_SHIFT 1 #define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2 #define L2CAP_EXT_CTRL_SAR_SHIFT 16 #define L2CAP_EXT_CTRL_SUPER_SHIFT 16 +#define L2CAP_EXT_CTRL_POLL_SHIFT 18 #define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18 /* L2CAP Supervisory Function */ @@ -186,6 +190,8 @@ struct l2cap_hdr { #define L2CAP_FCS_SIZE 2 #define L2CAP_SDULEN_SIZE 2 #define L2CAP_PSMLEN_SIZE 2 +#define L2CAP_ENH_CTRL_SIZE 2 +#define L2CAP_EXT_CTRL_SIZE 4 struct l2cap_cmd_hdr { __u8 code; @@ -446,6 +452,9 @@ struct l2cap_chan { __u16 monitor_timeout; __u16 mps; + __u8 tx_state; + __u8 rx_state; + unsigned long conf_state; unsigned long conn_state; unsigned long flags; @@ -456,9 +465,11 @@ struct l2cap_chan { __u16 buffer_seq; __u16 buffer_seq_srej; __u16 srej_save_reqseq; + __u16 last_acked_seq; __u16 frames_sent; __u16 unacked_frames; __u8 retry_count; + __u16 srej_queue_next; __u8 num_acked; __u16 sdu_len; struct sk_buff *sdu; @@ -600,6 +611,44 @@ enum { FLAG_EFS_ENABLE, }; +enum { + L2CAP_TX_STATE_XMIT, + L2CAP_TX_STATE_WAIT_F, +}; + +enum { + L2CAP_RX_STATE_RECV, + L2CAP_RX_STATE_SREJ_SENT, +}; + +enum { + L2CAP_TXSEQ_EXPECTED, + L2CAP_TXSEQ_EXPECTED_SREJ, + L2CAP_TXSEQ_UNEXPECTED, + L2CAP_TXSEQ_UNEXPECTED_SREJ, + L2CAP_TXSEQ_DUPLICATE, + L2CAP_TXSEQ_DUPLICATE_SREJ, + L2CAP_TXSEQ_INVALID, + L2CAP_TXSEQ_INVALID_IGNORE, +}; + +enum { + L2CAP_EV_DATA_REQUEST, + L2CAP_EV_LOCAL_BUSY_DETECTED, + L2CAP_EV_LOCAL_BUSY_CLEAR, + L2CAP_EV_RECV_REQSEQ_AND_FBIT, + L2CAP_EV_RECV_FBIT, + L2CAP_EV_RETRANS_TO, + L2CAP_EV_MONITOR_TO, + L2CAP_EV_EXPLICIT_POLL, + L2CAP_EV_RECV_IFRAME, + L2CAP_EV_RECV_RR, + L2CAP_EV_RECV_REJ, + L2CAP_EV_RECV_RNR, + L2CAP_EV_RECV_SREJ, + L2CAP_EV_RECV_FRAME, +}; + static inline void l2cap_chan_hold(struct l2cap_chan *c) { atomic_inc(&c->refcnt); -- cgit v1.2.3 From 00e3112c5a90963bb7b56e0648d22fc51ed17d23 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 23 Mar 2012 16:56:56 -0700 Subject: Bluetooth: Add a structure to carry ERTM data in skb control blocks Every field from ERTM control headers is now carried in the control block so it only has to be parsed or generated once, and can be efficiently accessed throughout the ERTM code. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 262ebd1747d4..f2c8bdf08061 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -215,6 +215,18 @@ void bt_accept_unlink(struct sock *sk); struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); /* Skb helpers */ +struct l2cap_ctrl { + unsigned int sframe : 1, + poll : 1, + final : 1, + fcs : 1, + sar : 2, + super : 2; + __u16 reqseq; + __u16 txseq; + __u8 retries; +}; + struct bt_skb_cb { __u8 pkt_type; __u8 incoming; @@ -223,6 +235,7 @@ struct bt_skb_cb { __u8 retries; __u8 sar; __u8 force_active; + struct l2cap_ctrl control; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) -- cgit v1.2.3 From eef1d9b668c51dcae58d8bb41ce0c805f866dbbd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sun, 25 Mar 2012 13:59:16 -0300 Subject: Bluetooth: Remove sk parameter from l2cap_chan_create() Following the separation if core and sock code this change avoid manipulation of sk inside l2cap_chan_create(). Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 6 ++---- net/bluetooth/l2cap_sock.c | 4 +++- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c988df6f63bf..f6f0500bf370 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -906,7 +906,7 @@ int __l2cap_wait_ack(struct sock *sk); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); -struct l2cap_chan *l2cap_chan_create(struct sock *sk); +struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8a3de1149352..a57d96afa245 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -262,7 +262,7 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_put(chan); } -struct l2cap_chan *l2cap_chan_create(struct sock *sk) +struct l2cap_chan *l2cap_chan_create(void) { struct l2cap_chan *chan; @@ -272,8 +272,6 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) mutex_init(&chan->lock); - chan->sk = sk; - write_lock(&chan_list_lock); list_add(&chan->global_l, &chan_list); write_unlock(&chan_list_lock); @@ -284,7 +282,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) atomic_set(&chan->refcnt, 1); - BT_DBG("sk %p chan %p", sk, chan); + BT_DBG("chan %p", chan); return chan; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 29122ed28ea9..53e563f01723 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1048,12 +1048,14 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p sk->sk_protocol = proto; sk->sk_state = BT_OPEN; - chan = l2cap_chan_create(sk); + chan = l2cap_chan_create(); if (!chan) { l2cap_sock_kill(sk); return NULL; } + chan->sk = sk; + l2cap_pi(sk)->chan = chan; return sk; -- cgit v1.2.3 From 0ed09148fa61e01cd27c92933ba275ea8078b34d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 3 Apr 2012 08:46:54 -0300 Subject: Bluetooth: Remove MGMT_ADDR_INVALID macro This patch removes the MGMT_ADDR_INVALID macro. If the address type isn't LE, we consider it is BR/EDR type. Signed-off-by: Andre Guedes Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/mgmt.c | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f7cf928ab6ff..afdea9530d7b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -968,7 +968,6 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); #define MGMT_ADDR_BREDR 0x00 #define MGMT_ADDR_LE_PUBLIC 0x01 #define MGMT_ADDR_LE_RANDOM 0x02 -#define MGMT_ADDR_INVALID 0xff #define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) #define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1ec16721ed7a..5e80c6db6ae7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1640,15 +1640,15 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) switch (addr_type) { case ADDR_LE_DEV_PUBLIC: return MGMT_ADDR_LE_PUBLIC; - case ADDR_LE_DEV_RANDOM: - return MGMT_ADDR_LE_RANDOM; + default: - return MGMT_ADDR_INVALID; + /* Fallback to LE Random address type */ + return MGMT_ADDR_LE_RANDOM; } - case ACL_LINK: - return MGMT_ADDR_BREDR; + default: - return MGMT_ADDR_INVALID; + /* Fallback to BR/EDR type */ + return MGMT_ADDR_BREDR; } } @@ -1690,7 +1690,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, continue; bacpy(&rp->addr[i].bdaddr, &c->dst); rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); - if (rp->addr[i].type == MGMT_ADDR_INVALID) + if (c->type == SCO_LINK || c->type == ESCO_LINK) continue; i++; } -- cgit v1.2.3 From bd4b165312bacbf1e732cbc22c141362cfb5fda3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Mar 2012 16:31:25 +0300 Subject: Bluetooth: Adds set_default function in L2CAP setup Some parameters in L2CAP chan are set to default similar way in socket based channels and A2MP channels. Adds common function which sets all defaults. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 11 +++++++++++ net/bluetooth/l2cap_sock.c | 8 ++------ 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f6f0500bf370..c70e2cf107ff 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -915,5 +915,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); +void l2cap_chan_set_defaults(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a57d96afa245..2eac6184a231 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -296,6 +296,17 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } +void l2cap_chan_set_defaults(struct l2cap_chan *chan) +{ + chan->fcs = L2CAP_FCS_CRC16; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->sec_level = BT_SECURITY_LOW; + + set_bit(FLAG_FORCE_ACTIVE, &chan->flags); +} + static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1d3e9c328a36..ae1d78ee0410 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1006,12 +1006,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { chan->mode = L2CAP_MODE_BASIC; } - chan->max_tx = L2CAP_DEFAULT_MAX_TX; - chan->fcs = L2CAP_FCS_CRC16; - chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; - chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; - chan->sec_level = BT_SECURITY_LOW; - set_bit(FLAG_FORCE_ACTIVE, &chan->flags); + + l2cap_chan_set_defaults(chan); } /* Default config options */ -- cgit v1.2.3 From 9033894722ec595053c92bfa4359b37e7bc91b78 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 6 Apr 2012 20:15:47 -0300 Subject: Bluetooth: Remove err parameter from alloc_skb() Use ERR_PTR maginc instead. Signed-off-by: Gustavo Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 30 +++++++++++++----------------- net/bluetooth/l2cap_sock.c | 12 ++++++++---- 3 files changed, 22 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c70e2cf107ff..a756c2406306 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -519,7 +519,7 @@ struct l2cap_ops { void (*close) (void *data); void (*state_change) (void *data, int state); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, - unsigned long len, int nb, int *err); + unsigned long len, int nb); }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2eac6184a231..03746f565fc4 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1563,7 +1563,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, { struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; - int err, sent = 0; + int sent = 0; if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) return -EFAULT; @@ -1577,11 +1577,10 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, count = min_t(unsigned int, conn->mtu, len); *frag = chan->ops->alloc_skb(chan, count, - msg->msg_flags & MSG_DONTWAIT, - &err); + msg->msg_flags & MSG_DONTWAIT); - if (!*frag) - return err; + if (IS_ERR(*frag)) + return PTR_ERR(*frag); if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; @@ -1610,10 +1609,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; @@ -1645,10 +1643,9 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; @@ -1693,10 +1690,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index ae1d78ee0410..46126cbc9de4 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -927,12 +927,16 @@ static void l2cap_sock_state_change_cb(void *data, int state) } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, - unsigned long len, int nb, - int *err) + unsigned long len, int nb) { - struct sock *sk = chan->sk; + struct sk_buff *skb; + int err; + + skb = bt_skb_send_alloc(chan->sk, len, nb, &err); + if (!skb) + return ERR_PTR(err); - return bt_skb_send_alloc(sk, len, nb, err); + return skb; } static struct l2cap_ops l2cap_chan_ops = { -- cgit v1.2.3 From 3c588192b5e5328cdfc8e299c55477004d397208 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 11 Apr 2012 10:48:42 -0700 Subject: Bluetooth: Add the l2cap_seq_list structure for tracking frames A sequence list is a data structure used to track frames that need to be retransmitted, and frames that have been requested for retransmission by the remote device. It can compactly represent a list of sequence numbers within the ERTM transmit window. Memory for the list is allocated once at connection time, and common operations in ERTM are O(1). Signed-off-by: Mat Martineau Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 12 ++++ net/bluetooth/l2cap_core.c | 150 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 154 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a756c2406306..e33165476e83 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -407,6 +407,16 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ +struct l2cap_seq_list { + __u16 head; + __u16 tail; + __u16 mask; + __u16 *list; +}; + +#define L2CAP_SEQ_LIST_CLEAR 0xFFFF +#define L2CAP_SEQ_LIST_TAIL 0x8000 + struct srej_list { __u16 tx_seq; struct list_head list; @@ -501,6 +511,8 @@ struct l2cap_chan { struct sk_buff *tx_send_head; struct sk_buff_head tx_q; struct sk_buff_head srej_q; + struct l2cap_seq_list srej_list; + struct l2cap_seq_list retrans_list; struct list_head srej_l; struct list_head list; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 03746f565fc4..041ebed9e647 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -232,6 +232,121 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) release_sock(sk); } +/* ---- L2CAP sequence number lists ---- */ + +/* For ERTM, ordered lists of sequence numbers must be tracked for + * SREJ requests that are received and for frames that are to be + * retransmitted. These seq_list functions implement a singly-linked + * list in an array, where membership in the list can also be checked + * in constant time. Items can also be added to the tail of the list + * and removed from the head in constant time, without further memory + * allocs or frees. + */ + +static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) +{ + size_t alloc_size, i; + + /* Allocated size is a power of 2 to map sequence numbers + * (which may be up to 14 bits) in to a smaller array that is + * sized for the negotiated ERTM transmit windows. + */ + alloc_size = roundup_pow_of_two(size); + + seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL); + if (!seq_list->list) + return -ENOMEM; + + seq_list->mask = alloc_size - 1; + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + for (i = 0; i < alloc_size; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + return 0; +} + +static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) +{ + kfree(seq_list->list); +} + +static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, + u16 seq) +{ + /* Constant-time check for list membership */ + return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; +} + +static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { + /* In case someone tries to pop the head of an empty list */ + return L2CAP_SEQ_LIST_CLEAR; + } else if (seq_list->head == seq) { + /* Head can be removed in constant time */ + seq_list->head = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + + if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } + } else { + /* Walk the list to find the sequence number */ + u16 prev = seq_list->head; + while (seq_list->list[prev & mask] != seq) { + prev = seq_list->list[prev & mask]; + if (prev == L2CAP_SEQ_LIST_TAIL) + return L2CAP_SEQ_LIST_CLEAR; + } + + /* Unlink the number from the list and clear it */ + seq_list->list[prev & mask] = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + if (seq_list->tail == seq) + seq_list->tail = prev; + } + return seq; +} + +static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) +{ + /* Remove the head in constant time */ + return l2cap_seq_list_remove(seq_list, seq_list->head); +} + +static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) +{ + if (seq_list->head != L2CAP_SEQ_LIST_CLEAR) { + u16 i; + for (i = 0; i <= seq_list->mask; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } +} + +static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + /* All appends happen in constant time */ + + if (seq_list->list[seq & mask] == L2CAP_SEQ_LIST_CLEAR) { + if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR) + seq_list->head = seq; + else + seq_list->list[seq_list->tail & mask] = seq; + + seq_list->tail = seq; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; + } +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -414,6 +529,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->srej_q); + l2cap_seq_list_free(&chan->srej_list); + l2cap_seq_list_free(&chan->retrans_list); list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_del(&l->list); kfree(l); @@ -2045,8 +2162,10 @@ static void l2cap_ack_timeout(struct work_struct *work) l2cap_chan_put(chan); } -static inline void l2cap_ertm_init(struct l2cap_chan *chan) +static inline int l2cap_ertm_init(struct l2cap_chan *chan) { + int err; + chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; @@ -2060,6 +2179,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); INIT_LIST_HEAD(&chan->srej_l); + err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); + if (err < 0) + return err; + + return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -2853,7 +2977,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u8 rsp[64]; struct l2cap_chan *chan; - int len; + int len, err = 0; dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); @@ -2924,9 +3048,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + err = l2cap_ertm_init(chan); + + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); - l2cap_chan_ready(chan); goto unlock; } @@ -2954,7 +3082,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr unlock: l2cap_chan_unlock(chan); - return 0; + return err; } static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -2963,6 +3091,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 scid, flags, result; struct l2cap_chan *chan; int len = le16_to_cpu(cmd->len) - sizeof(*rsp); + int err = 0; scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); @@ -3054,14 +3183,17 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + err = l2cap_ertm_init(chan); - l2cap_chan_ready(chan); + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); } done: l2cap_chan_unlock(chan); - return 0; + return err; } static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -3805,6 +3937,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) BT_DBG("chan %p, Enter local busy", chan); set_bit(CONN_LOCAL_BUSY, &chan->conn_state); + l2cap_seq_list_clear(&chan->srej_list); __set_ack_timer(chan); } @@ -3897,6 +4030,7 @@ static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) while (tx_seq != chan->expected_tx_seq) { control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); control |= __set_reqseq(chan, chan->expected_tx_seq); + l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq); l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); -- cgit v1.2.3 From 270ca16bc7ff575a5900aec2475fa7f8742f7337 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:19 +0530 Subject: Bluetooth: remove header declared but not defined hci_del_off_timer() doesn't exist anymore. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index afdea9530d7b..ef6e6541aa2a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -698,8 +698,6 @@ struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_adv_entry(struct hci_dev *hdev, struct hci_ev_le_advertising_info *ev); -void hci_del_off_timer(struct hci_dev *hdev); - void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); -- cgit v1.2.3 From e47872209d67a3283f88c39729b5bf11860b7b19 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:20 +0530 Subject: Bluetooth: Remove strtoba header declared but not defined No one is using strtoba() in the bluetooth subsystem. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index f2c8bdf08061..d0e44a4151e6 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -178,7 +178,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) void baswap(bdaddr_t *dst, bdaddr_t *src); char *batostr(bdaddr_t *ba); -bdaddr_t *strtoba(char *str); /* Common socket structures and functions */ -- cgit v1.2.3 From 2bbf2968e5cd72d2dd9e229d85c1617b8aa48f4e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 16 Apr 2012 16:32:03 +0300 Subject: Bluetooth: trivial: Remove empty line Signed-off-by: Andrei Emeltchenko Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e33165476e83..52f7e6a9a237 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -532,7 +532,6 @@ struct l2cap_ops { void (*state_change) (void *data, int state); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, unsigned long len, int nb); - }; struct l2cap_conn { -- cgit v1.2.3 From 591f47f31ba4e89fc0cce2ad90da80945ce8bf94 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:49 -0300 Subject: Bluetooth: Move address type macros to bluetooth.h This patch moves address type macros to bluetooth.h since they will be used by management interface and Bluetooth socket interface. It also replaces the macro prefix MGMT_ADDR_ by BDADDR_. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 5 +++++ include/net/bluetooth/hci_core.h | 16 ++++++---------- net/bluetooth/mgmt.c | 30 +++++++++++++++--------------- 3 files changed, 26 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index d0e44a4151e6..27a6a936487d 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -163,6 +163,11 @@ typedef struct { __u8 b[6]; } __packed bdaddr_t; +/* BD Address type */ +#define BDADDR_BREDR 0x00 +#define BDADDR_LE_PUBLIC 0x01 +#define BDADDR_LE_RANDOM 0x02 + #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ef6e6541aa2a..6777432ca61e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -963,16 +963,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); /* Management interface */ -#define MGMT_ADDR_BREDR 0x00 -#define MGMT_ADDR_LE_PUBLIC 0x01 -#define MGMT_ADDR_LE_RANDOM 0x02 - -#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) -#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ - BIT(MGMT_ADDR_LE_RANDOM)) -#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \ - BIT(MGMT_ADDR_LE_PUBLIC) | \ - BIT(MGMT_ADDR_LE_RANDOM)) +#define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR)) +#define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \ + BIT(BDADDR_LE_RANDOM)) +#define DISCOV_TYPE_INTERLEAVED (BIT(BDADDR_BREDR) | \ + BIT(BDADDR_LE_PUBLIC) | \ + BIT(BDADDR_LE_RANDOM)) int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_index_added(struct hci_dev *hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7d37c88e4bf5..d064ca9fa006 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1524,7 +1524,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); else err = hci_remove_ltk(hdev, &cp->addr.bdaddr); @@ -1536,7 +1536,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, } if (cp->disconnect) { - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else @@ -1596,7 +1596,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); @@ -1631,23 +1631,23 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) case LE_LINK: switch (addr_type) { case ADDR_LE_DEV_PUBLIC: - return MGMT_ADDR_LE_PUBLIC; + return BDADDR_LE_PUBLIC; default: /* Fallback to LE Random address type */ - return MGMT_ADDR_LE_RANDOM; + return BDADDR_LE_RANDOM; } default: /* Fallback to BR/EDR type */ - return MGMT_ADDR_BREDR; + return BDADDR_BREDR; } } static u8 mgmt_to_le(u8 mgmt_type) { switch (mgmt_type) { - case MGMT_ADDR_LE_PUBLIC: + case BDADDR_LE_PUBLIC: return ADDR_LE_DEV_PUBLIC; default: @@ -1914,7 +1914,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, else auth_type = HCI_AT_DEDICATED_BONDING_MITM; - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, auth_type); else @@ -1947,7 +1947,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } /* For LE, just connecting isn't a proof that the pairing finished */ - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn->connect_cfm_cb = pairing_complete_cb; conn->security_cfm_cb = pairing_complete_cb; @@ -2024,7 +2024,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, goto done; } - if (type == MGMT_ADDR_BREDR) + if (type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); @@ -2035,7 +2035,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, goto done; } - if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) { + if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) { /* Continue with pairing via SMP */ err = smp_user_confirm_reply(conn, mgmt_op, passkey); @@ -2967,7 +2967,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persisten ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); - ev.key.addr.type = MGMT_ADDR_BREDR; + ev.key.addr.type = BDADDR_BREDR; ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; @@ -3125,7 +3125,7 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) struct mgmt_ev_pin_code_request ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = MGMT_ADDR_BREDR; + ev.addr.type = BDADDR_BREDR; ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), @@ -3144,7 +3144,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = MGMT_ADDR_BREDR; + rp.addr.type = BDADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, mgmt_status(status), &rp, sizeof(rp)); @@ -3166,7 +3166,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = MGMT_ADDR_BREDR; + rp.addr.type = BDADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, mgmt_status(status), &rp, sizeof(rp)); -- cgit v1.2.3 From 43ef0b8b8d95c7aab7bb3778351e3591502bf355 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:52 -0300 Subject: Bluetooth: Add address type to struct sockaddr_l2 This patch adds the address type info to struct sockaddr_l2 so user-space can inform the remote device address type required to establish LE connections. Soon, instead of looking the advertising cache up to discover the address type, we'll use this address type info to establish LE connections. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 52f7e6a9a237..bb4e3f66b43c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -57,6 +57,7 @@ struct sockaddr_l2 { __le16 l2_psm; bdaddr_t l2_bdaddr; __le16 l2_cid; + __u8 l2_bdaddr_type; }; /* L2CAP socket options */ -- cgit v1.2.3 From 31f7956c6648fbae9c9550e91d1c348d28276309 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:53 -0300 Subject: Bluetooth: Move bdaddr_to_le to hci_core This patch moves the helper function bdaddr_to_le to hci_core, so it can be used in mgmt.c and hci_conn.c. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 12 ++++++++++++ net/bluetooth/mgmt.c | 12 ------------ 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6777432ca61e..7e7fe3f221fb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1073,4 +1073,6 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, int timeout); int hci_cancel_le_scan(struct hci_dev *hdev); +u8 bdaddr_to_le(u8 bdaddr_type); + #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index aa45ea496f87..7bbd5c5767b9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2946,3 +2946,15 @@ int hci_cancel_inquiry(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); } + +u8 bdaddr_to_le(u8 bdaddr_type) +{ + switch (bdaddr_type) { + case BDADDR_LE_PUBLIC: + return ADDR_LE_DEV_PUBLIC; + + default: + /* Fallback to LE Random address type */ + return ADDR_LE_DEV_RANDOM; + } +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 605a35b284fe..4e26c2585817 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1644,18 +1644,6 @@ static u8 link_to_bdaddr(u8 link_type, u8 addr_type) } } -static u8 bdaddr_to_le(u8 bdaddr_type) -{ - switch (bdaddr_type) { - case BDADDR_LE_PUBLIC: - return ADDR_LE_DEV_PUBLIC; - - default: - /* Fallback to LE Random address type */ - return ADDR_LE_DEV_RANDOM; - } -} - static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { -- cgit v1.2.3 From b12f62cfd9f46ac70013ce661640174b489efd39 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:54 -0300 Subject: Bluetooth: Add dst_type parameter to hci_connect This patch adds the dst_type parameter to hci_connect function. Instead of searching the address type in advertising cache, we use the dst_type parameter to establish LE connections. The dst_type is ignored for BR/EDR connection establishment. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 11 +++-------- net/bluetooth/l2cap_core.c | 8 ++++---- net/bluetooth/mgmt.c | 8 ++++---- net/bluetooth/sco.c | 3 ++- 5 files changed, 14 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7e7fe3f221fb..e69a9eed082c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -575,7 +575,7 @@ int hci_chan_del(struct hci_chan *chan); void hci_chan_list_flush(struct hci_conn *conn); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, - __u8 sec_level, __u8 auth_type); + __u8 dst_type, __u8 sec_level, __u8 auth_type); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8f352cd1745a..a3ee1a929a6c 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -513,7 +513,8 @@ EXPORT_SYMBOL(hci_get_route); /* Create SCO, ACL or LE connection. * Device _must_ be locked */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u8 dst_type, __u8 sec_level, __u8 auth_type) { struct hci_conn *acl; struct hci_conn *sco; @@ -522,19 +523,13 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 BT_DBG("%s dst %s", hdev->name, batostr(dst)); if (type == LE_LINK) { - struct adv_entry *entry = NULL; - le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); if (!le) { - entry = hci_find_adv_entry(hdev, dst); - if (!entry) - return ERR_PTR(-EHOSTUNREACH); - le = hci_conn_add(hdev, LE_LINK, dst); if (!le) return ERR_PTR(-ENOMEM); - le->dst_type = entry->bdaddr_type; + le->dst_type = bdaddr_to_le(dst_type); hci_le_connect(le); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 97af2b4f6238..61af06d35335 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1479,11 +1479,11 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, LE_LINK, dst, BDADDR_LE_RANDOM, + chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, ACL_LINK, dst, BDADDR_BREDR, + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4e26c2585817..9038118d37a3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1903,11 +1903,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, auth_type = HCI_AT_DEDICATED_BONDING_MITM; if (cp->addr.type == BDADDR_BREDR) - conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, + cp->addr.type, sec_level, auth_type); else - conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, + cp->addr.type, sec_level, auth_type); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index bf1af0b1497e..cbdd313659a7 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -193,7 +193,8 @@ static int sco_connect(struct sock *sk) else type = SCO_LINK; - hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); + hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW, + HCI_AT_NO_BONDING); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; -- cgit v1.2.3 From 8e9f98921c0718cda76bc53c2b51954657b60fa6 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:55 -0300 Subject: Bluetooth: Use address type info from user-space In order to establish a LE connection we need the address type information. User-space already pass this information to kernel through struct sockaddr_l2. This patch adds the dst_type parameter to l2cap_chan_connect so we are able to pass the address type info from user-space down to hci_conn layer. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 11 ++++++----- net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bb4e3f66b43c..86bb83bc6a4f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -922,7 +922,7 @@ struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, - bdaddr_t *dst); + bdaddr_t *dst, u8 dst_type); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 61af06d35335..4b6d11c199b5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1394,7 +1394,8 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst, u8 dst_type) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; @@ -1404,8 +1405,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d __u8 auth_type; int err; - BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - __le16_to_cpu(chan->psm)); + BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), + dst_type, __le16_to_cpu(chan->psm)); hdev = hci_get_route(dst, src); if (!hdev) @@ -1479,10 +1480,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, BDADDR_LE_RANDOM, + hcon = hci_connect(hdev, LE_LINK, dst, dst_type, chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, BDADDR_BREDR, + hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, chan->sec_level, auth_type); if (IS_ERR(hcon)) { diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 8d8b50a29906..2b5e7e81c3c0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -124,7 +124,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al return -EINVAL; err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), - &la.l2_bdaddr); + &la.l2_bdaddr, la.l2_bdaddr_type); if (err) return err; -- cgit v1.2.3 From 479453d5fe3a5b911b7f56474764988100f9f650 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:56 -0300 Subject: Bluetooth: Remove advertising cache User-space pass the remote device address type to kernel through struct sockaddr_l2 what makes the advertising useless. This patch removes all advertising cache code. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 ----- net/bluetooth/hci_core.c | 74 ---------------------------------------- net/bluetooth/hci_event.c | 7 ---- 3 files changed, 90 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e69a9eed082c..d1e744f3b9be 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -255,9 +255,6 @@ struct hci_dev { struct list_head remote_oob_data; - struct list_head adv_entries; - struct delayed_work adv_work; - struct hci_dev_stats stat; struct sk_buff_head driver_init; @@ -692,12 +689,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, u8 *randomizer); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); -#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */ -int hci_adv_entries_clear(struct hci_dev *hdev); -struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev); - void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7bbd5c5767b9..83d3d3563bcc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1521,75 +1521,6 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_device_unblocked(hdev, bdaddr, type); } -static void hci_clear_adv_cache(struct work_struct *work) -{ - struct hci_dev *hdev = container_of(work, struct hci_dev, - adv_work.work); - - hci_dev_lock(hdev); - - hci_adv_entries_clear(hdev); - - hci_dev_unlock(hdev); -} - -int hci_adv_entries_clear(struct hci_dev *hdev) -{ - struct adv_entry *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) { - list_del(&entry->list); - kfree(entry); - } - - BT_DBG("%s adv cache cleared", hdev->name); - - return 0; -} - -struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr) -{ - struct adv_entry *entry; - - list_for_each_entry(entry, &hdev->adv_entries, list) - if (bacmp(bdaddr, &entry->bdaddr) == 0) - return entry; - - return NULL; -} - -static inline int is_connectable_adv(u8 evt_type) -{ - if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND) - return 1; - - return 0; -} - -int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type)) - return -EINVAL; - - /* Only new entries should be added to adv_entries. So, if - * bdaddr was found, don't add it. */ - if (hci_find_adv_entry(hdev, &ev->bdaddr)) - return 0; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - bacpy(&entry->bdaddr, &ev->bdaddr); - entry->bdaddr_type = ev->bdaddr_type; - - list_add(&entry->list, &hdev->adv_entries); - - BT_DBG("%s adv entry added: address %s type %u", hdev->name, - batostr(&entry->bdaddr), entry->bdaddr_type); - - return 0; -} - static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) { struct le_scan_params *param = (struct le_scan_params *) opt; @@ -1735,7 +1666,6 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); - INIT_LIST_HEAD(&hdev->adv_entries); INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); @@ -1743,7 +1673,6 @@ struct hci_dev *hci_alloc_dev(void) INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->le_scan, le_scan_work); - INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); @@ -1889,8 +1818,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_del_sysfs(hdev); - cancel_delayed_work_sync(&hdev->adv_work); - destroy_workqueue(hdev->workqueue); hci_dev_lock(hdev); @@ -1899,7 +1826,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); - hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 054b1ad74496..ae0a57d21ec4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1100,10 +1100,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, set_bit(HCI_LE_SCAN, &hdev->dev_flags); - cancel_delayed_work_sync(&hdev->adv_work); - hci_dev_lock(hdev); - hci_adv_entries_clear(hdev); hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); break; @@ -1118,8 +1115,6 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); - if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && hdev->discovery.state == DISCOVERY_FINDING) { mgmt_interleaved_discovery(hdev); @@ -3353,8 +3348,6 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; - hci_add_adv_entry(hdev, ev); - rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, NULL, rssi, 0, 1, ev->data, ev->length); -- cgit v1.2.3 From 5a364bd399d23fe6244de8f84c46f249b763c723 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 25 Apr 2012 16:36:12 -0700 Subject: Bluetooth: Improve ERTM sequence number offset calculation Instead of using modular division, the offset can be calculated using only addition and subtraction. The previous calculation did not work as intended and was more difficult to understand, involving unsigned integer underflow and a check for a negative value where one was not possible. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 86bb83bc6a4f..084dec001bf2 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -724,13 +724,10 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan, static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) { - int offset; - - offset = (seq1 - seq2) % (chan->tx_win_max + 1); - if (offset < 0) - offset += (chan->tx_win_max + 1); - - return offset; + if (seq1 >= seq2) + return seq1 - seq2; + else + return chan->tx_win_max + 1 - seq2 + seq1; } static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq) -- cgit v1.2.3 From 3ce3514f5d0f90c7d856e8b0f26c6da393bbeba0 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 25 Apr 2012 16:36:14 -0700 Subject: Bluetooth: Remove duplicate structure members from bt_skb_cb These values are now in the nested l2cap_ctrl struct. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 3 --- net/bluetooth/l2cap_core.c | 38 +++++++++++++++++++------------------- 2 files changed, 19 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 27a6a936487d..2fb268f2895b 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -235,9 +235,6 @@ struct bt_skb_cb { __u8 pkt_type; __u8 incoming; __u16 expect; - __u16 tx_seq; - __u8 retries; - __u8 sar; __u8 force_active; struct l2cap_ctrl control; }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4b6d11c199b5..62ef7c335163 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1620,7 +1620,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) while ((skb = skb_peek(&chan->tx_q)) && chan->unacked_frames) { - if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) + if (bt_cb(skb)->control.txseq == chan->expected_ack_seq) break; skb = skb_dequeue(&chan->tx_q); @@ -1667,21 +1667,21 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) if (!skb) return; - while (bt_cb(skb)->tx_seq != tx_seq) { + while (bt_cb(skb)->control.txseq != tx_seq) { if (skb_queue_is_last(&chan->tx_q, skb)) return; skb = skb_queue_next(&chan->tx_q, skb); } - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1716,15 +1716,15 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1748,11 +1748,11 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) __set_retrans_timer(chan); - bt_cb(skb)->tx_seq = chan->next_tx_seq; + bt_cb(skb)->control.txseq = chan->next_tx_seq; chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - if (bt_cb(skb)->retries == 1) { + if (bt_cb(skb)->control.retries == 1) { chan->unacked_frames++; if (!nsent++) @@ -1978,7 +1978,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE)); - bt_cb(skb)->retries = 0; + bt_cb(skb)->control.retries = 0; return skb; } @@ -3950,19 +3950,19 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, struct sk_buff *next_skb; int tx_seq_offset, next_tx_seq_offset; - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; next_skb = skb_peek(&chan->srej_q); tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); while (next_skb) { - if (bt_cb(next_skb)->tx_seq == tx_seq) + if (bt_cb(next_skb)->control.txseq == tx_seq) return -EINVAL; next_tx_seq_offset = __seq_offset(chan, - bt_cb(next_skb)->tx_seq, chan->buffer_seq); + bt_cb(next_skb)->control.txseq, chan->buffer_seq); if (next_tx_seq_offset > tx_seq_offset) { __skb_queue_before(&chan->srej_q, next_skb, skb); @@ -4134,11 +4134,11 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { int err; - if (bt_cb(skb)->tx_seq != tx_seq) + if (bt_cb(skb)->control.txseq != tx_seq) break; skb = skb_dequeue(&chan->srej_q); - control = __set_ctrl_sar(chan, bt_cb(skb)->sar); + control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); err = l2cap_reassemble_sdu(chan, skb, control); if (err < 0) { @@ -4309,8 +4309,8 @@ expected: chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; __skb_queue_tail(&chan->srej_q, skb); return 0; } -- cgit v1.2.3 From e10b9969f217c948c5523045f44eba4d3a758ff0 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:17 +0530 Subject: Bluetooth: Remove unused hci_le_ltk_reply() In this API, we were using sizeof operator for an array given as function argument, which is invalid. However this API is not used anywhere. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_conn.c | 16 ---------------- 2 files changed, 17 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d1e744f3b9be..e3547ea83619 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1055,7 +1055,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); -void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]); void hci_le_ltk_neg_reply(struct hci_conn *conn); int hci_do_inquiry(struct hci_dev *hdev, u8 length); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a3ee1a929a6c..cae7ec2df7ad 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -223,22 +223,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], } EXPORT_SYMBOL(hci_le_start_enc); -void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_ltk_reply cp; - - BT_DBG("%p", conn); - - memset(&cp, 0, sizeof(cp)); - - cp.handle = cpu_to_le16(conn->handle); - memcpy(cp.ltk, ltk, sizeof(ltk)); - - hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); -} -EXPORT_SYMBOL(hci_le_ltk_reply); - void hci_le_ltk_neg_reply(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; -- cgit v1.2.3 From 2ee8ce35b1e8ba2523fa4c45fa19f9dbe321f008 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Fri, 20 Apr 2012 22:12:31 +0530 Subject: Bluetooth: Remove unused hci_le_ltk_neg_reply() No one is using hci_le_ltk_neg_reply() in bluetooth subsystem. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 2 -- net/bluetooth/hci_conn.c | 14 -------------- 2 files changed, 16 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e3547ea83619..b60d2c844eba 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1055,8 +1055,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); -void hci_le_ltk_neg_reply(struct hci_conn *conn); - int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index cae7ec2df7ad..3f18a6ed9731 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -223,20 +223,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], } EXPORT_SYMBOL(hci_le_start_enc); -void hci_le_ltk_neg_reply(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_ltk_neg_reply cp; - - BT_DBG("%p", conn); - - memset(&cp, 0, sizeof(cp)); - - cp.handle = cpu_to_le16(conn->handle); - - hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp); -} - /* Device _must_ be locked */ void hci_sco_setup(struct hci_conn *conn, __u8 status) { -- cgit v1.2.3 From 9d42820f378e6372f154a3f0c8def5d4bba29191 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 3 May 2012 07:12:31 +0200 Subject: Bluetooth: Enable Low Energy support by default The Bluetooth Low Energy support so far was disabled by default via a module parameter. With this change the module parameter will be removed and Low Energy is enabled by default. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 1 - net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 12 +++--------- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 346f08779792..66a7b579e31c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1438,6 +1438,5 @@ struct hci_inquiry_req { #define IREQ_CACHE_FLUSH 0x0001 extern bool enable_hs; -extern bool enable_le; #endif /* __HCI_H */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ae0a57d21ec4..d81262aff263 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -725,7 +725,7 @@ static void hci_set_le_support(struct hci_dev *hdev) memset(&cp, 0, sizeof(cp)); - if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9038118d37a3..966f6bcfbcb9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,7 +35,6 @@ #include bool enable_hs; -bool enable_le; #define MGMT_VERSION 1 #define MGMT_REVISION 1 @@ -384,10 +383,8 @@ static u32 get_supported_settings(struct hci_dev *hdev) if (enable_hs) settings |= MGMT_SETTING_HS; - if (enable_le) { - if (hdev->features[4] & LMP_LE) - settings |= MGMT_SETTING_LE; - } + if (hdev->features[4] & LMP_LE) + settings |= MGMT_SETTING_LE; return settings; } @@ -1199,7 +1196,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_dev_lock(hdev); - if (!enable_le || !(hdev->features[4] & LMP_LE)) { + if (!(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); goto unlock; @@ -3657,6 +3654,3 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) module_param(enable_hs, bool, 0644); MODULE_PARM_DESC(enable_hs, "Enable High Speed support"); - -module_param(enable_le, bool, 0644); -MODULE_PARM_DESC(enable_le, "Enable Low Energy support"); -- cgit v1.2.3 From 94122bbe9c8c4ad7ba9f02f9a30bfc95672c404e Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 2 May 2012 09:42:02 -0700 Subject: Bluetooth: Refactor L2CAP ERTM and streaming transmit segmentation Use more common code for ERTM and streaming mode segmentation and transmission, and begin using skb control block data for delaying extended or enhanced header generation until just before the packet is transmitted. This code is also better suited for resegmentation, which is needed when L2CAP links are reconfigured after an AMP channel move. Signed-off-by: Mat Martineau Reviewed-by: Ulisses Furquim Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 144 +++++++++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 58 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 084dec001bf2..1c7d1cd5e679 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -44,6 +44,7 @@ #define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF +#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */ #define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100) #define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fcd09fb4b94c..2b30bd767779 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1634,6 +1634,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan) while ((skb = skb_dequeue(&chan->tx_q))) { control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); if (chan->fcs == L2CAP_FCS_CRC16) { @@ -1706,6 +1707,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->state != BT_CONNECTED) return -ENOTCONN; + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return 0; + while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { if (bt_cb(skb)->control.retries == chan->remote_max_tx && @@ -1726,6 +1730,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) control |= __set_reqseq(chan, chan->buffer_seq); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1921,7 +1926,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, - u32 control, u16 sdulen) + u16 sdulen) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; @@ -1956,7 +1961,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); + __put_control(chan, 0, skb_put(skb, __ctrl_size(chan))); if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); @@ -1974,57 +1979,78 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, return skb; } -static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static int l2cap_segment_sdu(struct l2cap_chan *chan, + struct sk_buff_head *seg_queue, + struct msghdr *msg, size_t len) { struct sk_buff *skb; - struct sk_buff_head sar_queue; - u32 control; - size_t size = 0; + u16 sdu_len; + size_t pdu_len; + int err = 0; + u8 sar; - skb_queue_head_init(&sar_queue); - control = __set_ctrl_sar(chan, L2CAP_SAR_START); - skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); + BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); - __skb_queue_tail(&sar_queue, skb); - len -= chan->remote_mps; - size += chan->remote_mps; + /* It is critical that ERTM PDUs fit in a single HCI fragment, + * so fragmented skbs are not used. The HCI layer's handling + * of fragmented skbs is not compatible with ERTM's queueing. + */ - while (len > 0) { - size_t buflen; + /* PDU size is derived from the HCI MTU */ + pdu_len = chan->conn->mtu; - if (len > chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE); - buflen = chan->remote_mps; - } else { - control = __set_ctrl_sar(chan, L2CAP_SAR_END); - buflen = len; - } + pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); + + /* Adjust for largest possible L2CAP overhead. */ + pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE; + + /* Remote device may have requested smaller PDUs */ + pdu_len = min_t(size_t, pdu_len, chan->remote_mps); + + if (len <= pdu_len) { + sar = L2CAP_SAR_UNSEGMENTED; + sdu_len = 0; + pdu_len = len; + } else { + sar = L2CAP_SAR_START; + sdu_len = len; + pdu_len -= L2CAP_SDULEN_SIZE; + } + + while (len > 0) { + skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len); - skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { - skb_queue_purge(&sar_queue); + __skb_queue_purge(seg_queue); return PTR_ERR(skb); } - __skb_queue_tail(&sar_queue, skb); - len -= buflen; - size += buflen; + bt_cb(skb)->control.sar = sar; + __skb_queue_tail(seg_queue, skb); + + len -= pdu_len; + if (sdu_len) { + sdu_len = 0; + pdu_len += L2CAP_SDULEN_SIZE; + } + + if (len <= pdu_len) { + sar = L2CAP_SAR_END; + pdu_len = len; + } else { + sar = L2CAP_SAR_CONTINUE; + } } - skb_queue_splice_tail(&sar_queue, &chan->tx_q); - if (chan->tx_send_head == NULL) - chan->tx_send_head = sar_queue.next; - return size; + return err; } int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { struct sk_buff *skb; - u32 control; int err; + struct sk_buff_head seg_queue; /* Connectionless channel */ if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { @@ -2053,42 +2079,44 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - /* Entire SDU fits into one PDU */ - if (len <= chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED); - skb = l2cap_create_iframe_pdu(chan, msg, len, control, - 0); - if (IS_ERR(skb)) - return PTR_ERR(skb); + /* Check outgoing MTU */ + if (len > chan->omtu) { + err = -EMSGSIZE; + break; + } - __skb_queue_tail(&chan->tx_q, skb); + __skb_queue_head_init(&seg_queue); - if (chan->tx_send_head == NULL) - chan->tx_send_head = skb; + /* Do segmentation before calling in to the state machine, + * since it's possible to block while waiting for memory + * allocation. + */ + err = l2cap_segment_sdu(chan, &seg_queue, msg, len); - } else { - /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(chan, msg, len); - if (err < 0) - return err; + /* The channel could have been closed while segmenting, + * check that it is still connected. + */ + if (chan->state != BT_CONNECTED) { + __skb_queue_purge(&seg_queue); + err = -ENOTCONN; } - if (chan->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(chan); - err = len; + if (err) break; - } - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && - test_bit(CONN_WAIT_F, &chan->conn_state)) { - err = len; - break; - } + skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); + if (chan->mode == L2CAP_MODE_ERTM) + err = l2cap_ertm_send(chan); + else + l2cap_streaming_send(chan); - err = l2cap_ertm_send(chan); if (err >= 0) err = len; + /* If the skbs were not queued for sending, they'll still be in + * seg_queue and need to be purged. + */ + __skb_queue_purge(&seg_queue); break; default: -- cgit v1.2.3 From 536acc085c641ff8ba46c2c0e97b5e137cbc22d6 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Mon, 7 May 2012 11:21:59 +0200 Subject: nl80211: fix typos in comments Signed-off-by: Zefir Kurtisi Signed-off-by: John W. Linville --- include/linux/nl80211.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2540e86d99ab..f296a64d103b 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1994,9 +1994,9 @@ enum nl80211_reg_rule_flags { * enum nl80211_dfs_regions - regulatory DFS regions * * @NL80211_DFS_UNSET: Country has no DFS master region specified - * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC - * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI - * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec + * @NL80211_DFS_FCC: Country follows DFS master rules from FCC + * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI + * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec */ enum nl80211_dfs_regions { NL80211_DFS_UNSET = 0, -- cgit v1.2.3 From 900994332675f84a9fbbb33ff089474614c7f2fe Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:13 +0200 Subject: NFC: Cache the core NFC active target pointer instead of its index The NFC Core now caches the active nfc target pointer, thereby avoiding the need to lookup the target table for each invocation of a driver ops. Consequently, pn533, HCI and NCI now directly receive an nfc_target pointer instead of a target index. Cc: Ilan Elias Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/nfc/pn533.c | 16 +++++----- include/net/nfc/nfc.h | 18 +++++++----- net/nfc/core.c | 81 ++++++++++++++++++++++++++++++++++++++------------- net/nfc/hci/core.c | 36 ++++------------------- net/nfc/nci/core.c | 27 ++++++++--------- 5 files changed, 99 insertions(+), 79 deletions(-) (limited to 'include') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index e6ec16d92e65..766e0bb5ae53 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1194,8 +1194,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) return rc; } -static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, - u32 protocol) +static int pn533_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); int rc; @@ -1243,7 +1243,8 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, return 0; } -static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +static void pn533_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); u8 tg; @@ -1351,7 +1352,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, return 0; } -static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, +static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, u8 comm_mode, u8* gb, size_t gb_len) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); @@ -1552,10 +1553,9 @@ error: return 0; } -static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, - struct sk_buff *skb, - data_exchange_cb_t cb, - void *cb_context) +static int pn533_data_exchange(struct nfc_dev *nfc_dev, + struct nfc_target *target, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533_frame *out_frame, *in_frame; diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 9a2505a5b8de..0fcf4a54776b 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -48,26 +48,28 @@ struct nfc_dev; typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb, int err); +struct nfc_target; + struct nfc_ops { int (*dev_up)(struct nfc_dev *dev); int (*dev_down)(struct nfc_dev *dev); int (*start_poll)(struct nfc_dev *dev, u32 protocols); void (*stop_poll)(struct nfc_dev *dev); - int (*dep_link_up)(struct nfc_dev *dev, int target_idx, u8 comm_mode, - u8 *gb, size_t gb_len); + int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target, + u8 comm_mode, u8 *gb, size_t gb_len); int (*dep_link_down)(struct nfc_dev *dev); - int (*activate_target)(struct nfc_dev *dev, u32 target_idx, + int (*activate_target)(struct nfc_dev *dev, struct nfc_target *target, u32 protocol); - void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); - int (*data_exchange)(struct nfc_dev *dev, u32 target_idx, + void (*deactivate_target)(struct nfc_dev *dev, + struct nfc_target *target); + int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context); - int (*check_presence)(struct nfc_dev *dev, u32 target_idx); + int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target); }; #define NFC_TARGET_IDX_ANY -1 #define NFC_MAX_GT_LEN 48 -#define NFC_TARGET_IDX_NONE 0xffffffff struct nfc_target { u32 idx; @@ -99,7 +101,7 @@ struct nfc_dev { struct device dev; bool dev_up; bool polling; - u32 activated_target_idx; + struct nfc_target *active_target; bool dep_link_up; u32 dep_rf_mode; struct nfc_genl_data genl_data; diff --git a/net/nfc/core.c b/net/nfc/core.c index 3192c3f589ee..7df28ad4727f 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -97,7 +97,7 @@ int nfc_dev_down(struct nfc_dev *dev) goto error; } - if (dev->polling || dev->activated_target_idx != NFC_TARGET_IDX_NONE) { + if (dev->polling || dev->active_target) { rc = -EBUSY; goto error; } @@ -183,11 +183,27 @@ error: return rc; } +static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) +{ + int i; + + if (dev->n_targets == 0) + return NULL; + + for (i = 0; i < dev->n_targets ; i++) { + if (dev->targets[i].idx == target_idx) + return &dev->targets[i]; + } + + return NULL; +} + int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) { int rc = 0; u8 *gb; size_t gb_len; + struct nfc_target *target; pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode); @@ -212,9 +228,15 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) goto error; } - rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len); + target = nfc_find_target(dev, target_index); + if (target == NULL) { + rc = -ENOTCONN; + goto error; + } + + rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len); if (!rc) - dev->activated_target_idx = target_index; + dev->active_target = target; error: device_unlock(&dev->dev); @@ -250,7 +272,7 @@ int nfc_dep_link_down(struct nfc_dev *dev) rc = dev->ops->dep_link_down(dev); if (!rc) { dev->dep_link_up = false; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->active_target = NULL; nfc_llcp_mac_is_down(dev); nfc_genl_dep_link_down_event(dev); } @@ -282,6 +304,7 @@ EXPORT_SYMBOL(nfc_dep_link_is_up); int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) { int rc; + struct nfc_target *target; pr_debug("dev_name=%s target_idx=%u protocol=%u\n", dev_name(&dev->dev), target_idx, protocol); @@ -293,9 +316,20 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) goto error; } - rc = dev->ops->activate_target(dev, target_idx, protocol); + if (dev->active_target) { + rc = -EBUSY; + goto error; + } + + target = nfc_find_target(dev, target_idx); + if (target == NULL) { + rc = -ENOTCONN; + goto error; + } + + rc = dev->ops->activate_target(dev, target, protocol); if (!rc) { - dev->activated_target_idx = target_idx; + dev->active_target = target; if (dev->ops->check_presence) mod_timer(&dev->check_pres_timer, jiffies + @@ -327,11 +361,21 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) goto error; } + if (dev->active_target == NULL) { + rc = -ENOTCONN; + goto error; + } + + if (dev->active_target->idx != target_idx) { + rc = -ENOTCONN; + goto error; + } + if (dev->ops->check_presence) del_timer_sync(&dev->check_pres_timer); - dev->ops->deactivate_target(dev, target_idx); - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->ops->deactivate_target(dev, dev->active_target); + dev->active_target = NULL; error: device_unlock(&dev->dev); @@ -365,13 +409,13 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, goto error; } - if (dev->activated_target_idx == NFC_TARGET_IDX_NONE) { + if (dev->active_target == NULL) { rc = -ENOTCONN; kfree_skb(skb); goto error; } - if (target_idx != dev->activated_target_idx) { + if (dev->active_target->idx != target_idx) { rc = -EADDRNOTAVAIL; kfree_skb(skb); goto error; @@ -380,7 +424,8 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, if (dev->ops->check_presence) del_timer_sync(&dev->check_pres_timer); - rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); + rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb, + cb_context); if (!rc && dev->ops->check_presence) mod_timer(&dev->check_pres_timer, jiffies + @@ -514,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) dev->targets_generation++; dev->n_targets--; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->active_target = NULL; if (dev->n_targets) { memcpy(&dev->targets[i], &dev->targets[i + 1], @@ -556,15 +601,14 @@ static void nfc_check_pres_work(struct work_struct *work) device_lock(&dev->dev); - if (dev->activated_target_idx != NFC_TARGET_IDX_NONE && - timer_pending(&dev->check_pres_timer) == 0) { - rc = dev->ops->check_presence(dev, dev->activated_target_idx); + if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) { + rc = dev->ops->check_presence(dev, dev->active_target); if (!rc) { mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } else { - nfc_target_lost(dev, dev->activated_target_idx); - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + nfc_target_lost(dev, dev->active_target->idx); + dev->active_target = NULL; } } @@ -643,8 +687,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, /* first generation must not be 0 */ dev->targets_generation = 1; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; - if (ops->check_presence) { char name[32]; init_timer(&dev->check_pres_timer); @@ -662,7 +704,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, } } - return dev; } EXPORT_SYMBOL(nfc_allocate_device); diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 86fd00d5a099..545c19f17536 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -520,50 +520,26 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev) } } -static struct nfc_target *hci_find_target(struct nfc_hci_dev *hdev, - u32 target_idx) +static int hci_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) { - int i; - if (hdev->poll_started == false || hdev->targets == NULL) - return NULL; - - for (i = 0; i < hdev->target_count; i++) { - if (hdev->targets[i].idx == target_idx) - return &hdev->targets[i]; - } - - return NULL; -} - -static int hci_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, - u32 protocol) -{ - struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - - if (hci_find_target(hdev, target_idx) == NULL) - return -ENOMEDIUM; - return 0; } -static void hci_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +static void hci_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { } -static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, +static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); int r; - struct nfc_target *target; struct sk_buff *res_skb = NULL; - pr_debug("target_idx=%d\n", target_idx); - - target = hci_find_target(hdev, target_idx); - if (target == NULL) - return -ENOMEDIUM; + pr_debug("target_idx=%d\n", target->idx); switch (target->hci_reader_gate) { case NFC_HCI_RF_READER_A_GATE: diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 8737c2089fdd..d560e6f13072 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -436,16 +436,16 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); } -static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, - __u32 protocol) +static int nci_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, __u32 protocol) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); struct nci_rf_discover_select_param param; - struct nfc_target *target = NULL; + struct nfc_target *nci_target = NULL; int i; int rc = 0; - pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); + pr_debug("target_idx %d, protocol 0x%x\n", target->idx, protocol); if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) && (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { @@ -459,25 +459,25 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, } for (i = 0; i < ndev->n_targets; i++) { - if (ndev->targets[i].idx == target_idx) { - target = &ndev->targets[i]; + if (ndev->targets[i].idx == target->idx) { + nci_target = &ndev->targets[i]; break; } } - if (!target) { + if (!nci_target) { pr_err("unable to find the selected target\n"); return -EINVAL; } - if (!(target->supported_protocols & (1 << protocol))) { + if (!(nci_target->supported_protocols & (1 << protocol))) { pr_err("target does not support the requested protocol 0x%x\n", protocol); return -EINVAL; } if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { - param.rf_discovery_id = target->logical_idx; + param.rf_discovery_id = nci_target->logical_idx; if (protocol == NFC_PROTO_JEWEL) param.rf_protocol = NCI_RF_PROTOCOL_T1T; @@ -501,11 +501,12 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, return rc; } -static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) +static void nci_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); - pr_debug("target_idx %d\n", target_idx); + pr_debug("target_idx %d\n", target->idx); if (!ndev->target_active_prot) { pr_err("unable to deactivate target, no active target\n"); @@ -520,14 +521,14 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) } } -static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx, +static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); int rc; - pr_debug("target_idx %d, len %d\n", target_idx, skb->len); + pr_debug("target_idx %d, len %d\n", target->idx, skb->len); if (!ndev->target_active_prot) { pr_err("unable to exchange data, no active target\n"); -- cgit v1.2.3 From addfabf98daad7b469ad788a622dbeab6aaaa330 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:14 +0200 Subject: NFC: Remove useless HCI private nfc target table Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/hci.h | 2 -- net/nfc/hci/core.c | 7 ------- 2 files changed, 9 deletions(-) (limited to 'include') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index aca65a5a9d0d..95fc0c27578e 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -83,8 +83,6 @@ struct nfc_hci_dev { u8 gate2pipe[NFC_HCI_MAX_GATES]; bool poll_started; - struct nfc_target *targets; - int target_count; u8 sw_romlib; u8 sw_patch; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 545c19f17536..ef5cd5c9e3fb 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -235,13 +235,6 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) targets->hci_reader_gate = gate; r = nfc_targets_found(hdev->ndev, targets, 1); - if (r < 0) - goto exit; - - kfree(hdev->targets); - hdev->targets = targets; - targets = NULL; - hdev->target_count = 1; exit: kfree(targets); -- cgit v1.2.3 From d4ccb132801aeeb2cfd18c4b4b7fa0043ab37f80 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:15 +0200 Subject: NFC: Specify usage for targets found and target lost events It is now specified that nfc_target_found() and nfc_target_lost() core functions must not be called from an atomic context. This allow us to serialize calls and protect the targets table using the nfc device lock instead of a spinlock. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/nfc.h | 1 - net/nfc/core.c | 35 ++++++++++++++++++++++++++--------- net/nfc/netlink.c | 4 ++-- 3 files changed, 28 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 0fcf4a54776b..b7ca4a2a1d72 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -97,7 +97,6 @@ struct nfc_dev { struct nfc_target *targets; int n_targets; int targets_generation; - spinlock_t targets_lock; struct device dev; bool dev_up; bool polling; diff --git a/net/nfc/core.c b/net/nfc/core.c index 7df28ad4727f..9f6ce011d35d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -501,6 +501,9 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); * The device driver must call this function when one or many nfc targets * are found. After calling this function, the device driver must stop * polling for targets. + * IMPORTANT: this function must not be called from an atomic context. + * In addition, it must also not be called from a context that would prevent + * the NFC Core to call other nfc ops entry point concurrently. */ int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, int n_targets) @@ -514,7 +517,7 @@ int nfc_targets_found(struct nfc_dev *dev, for (i = 0; i < n_targets; i++) targets[i].idx = dev->target_next_idx++; - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); dev->targets_generation++; @@ -524,12 +527,12 @@ int nfc_targets_found(struct nfc_dev *dev, if (!dev->targets) { dev->n_targets = 0; - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); return -ENOMEM; } dev->n_targets = n_targets; - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); nfc_genl_targets_found(dev); @@ -537,6 +540,18 @@ int nfc_targets_found(struct nfc_dev *dev, } EXPORT_SYMBOL(nfc_targets_found); +/** + * nfc_target_lost - inform that an activated target went out of field + * + * @dev: The nfc device that had the activated target in field + * @target_idx: the nfc index of the target + * + * The device driver must call this function when the activated target + * goes out of the field. + * IMPORTANT: this function must not be called from an atomic context. + * In addition, it must also not be called from a context that would prevent + * the NFC Core to call other nfc ops entry point concurrently. + */ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) { struct nfc_target *tg; @@ -544,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx); - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); for (i = 0; i < dev->n_targets; i++) { tg = &dev->targets[i]; @@ -553,7 +568,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) } if (i == dev->n_targets) { - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); return -EINVAL; } @@ -569,7 +584,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) dev->targets = NULL; } - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); nfc_genl_target_lost(dev, target_idx); @@ -607,8 +622,10 @@ static void nfc_check_pres_work(struct work_struct *work) mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } else { - nfc_target_lost(dev, dev->active_target->idx); - dev->active_target = NULL; + u32 active_target_idx = dev->active_target->idx; + device_unlock(&dev->dev); + nfc_target_lost(dev, active_target_idx); + return; } } @@ -681,9 +698,9 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, dev->tx_headroom = tx_headroom; dev->tx_tailroom = tx_tailroom; - spin_lock_init(&dev->targets_lock); nfc_genl_data_init(&dev->genl_data); + /* first generation must not be 0 */ dev->targets_generation = 1; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f1829f6ae9c5..77dae74832d3 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -128,7 +128,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, cb->args[1] = (long) dev; } - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); cb->seq = dev->targets_generation; @@ -141,7 +141,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, i++; } - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); cb->args[0] = i; -- cgit v1.2.3 From 1676f75159c8091e865c33b61ad4934dfd3b7821 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:16 +0200 Subject: NFC: Add HCI/SHDLC support to let driver check for tag presence Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/hci.h | 2 ++ include/net/nfc/shdlc.h | 2 ++ net/nfc/hci/core.c | 12 ++++++++++++ net/nfc/hci/shdlc.c | 12 ++++++++++++ 4 files changed, 28 insertions(+) (limited to 'include') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 95fc0c27578e..ae042008571e 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -39,6 +39,8 @@ struct nfc_hci_ops { int (*data_exchange) (struct nfc_hci_dev *hdev, struct nfc_target *target, struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_hci_dev *hdev, + struct nfc_target *target); }; #define NFC_HCI_MAX_CUSTOM_GATES 15 diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h index 1071987d0408..ab06afd462da 100644 --- a/include/net/nfc/shdlc.h +++ b/include/net/nfc/shdlc.h @@ -35,6 +35,8 @@ struct nfc_shdlc_ops { int (*data_exchange) (struct nfc_shdlc *shdlc, struct nfc_target *target, struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_shdlc *shdlc, + struct nfc_target *target); }; enum shdlc_state { diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index ef5cd5c9e3fb..f7e4f5ae4559 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -574,6 +574,17 @@ static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, return 0; } +static int hci_check_presence(struct nfc_dev *nfc_dev, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + + if (hdev->ops->check_presence) + return hdev->ops->check_presence(hdev, target); + + return 0; +} + struct nfc_ops hci_nfc_ops = { .dev_up = hci_dev_up, .dev_down = hci_dev_down, @@ -582,6 +593,7 @@ struct nfc_ops hci_nfc_ops = { .activate_target = hci_activate_target, .deactivate_target = hci_deactivate_target, .data_exchange = hci_data_exchange, + .check_presence = hci_check_presence, }; struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 923bdf7c26d6..5665dc6d893a 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -816,6 +816,17 @@ static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, return -EPERM; } +static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, + struct nfc_target *target) +{ + struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); + + if (shdlc->ops->check_presence) + return shdlc->ops->check_presence(shdlc, target); + + return 0; +} + static struct nfc_hci_ops shdlc_ops = { .open = nfc_shdlc_open, .close = nfc_shdlc_close, @@ -825,6 +836,7 @@ static struct nfc_hci_ops shdlc_ops = { .target_from_gate = nfc_shdlc_target_from_gate, .complete_target_discovered = nfc_shdlc_complete_target_discovered, .data_exchange = nfc_shdlc_data_exchange, + .check_presence = nfc_shdlc_check_presence, }; struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, -- cgit v1.2.3 From bbed0deefbb4bb1ab09e0dbc29e00fda86bb7838 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:29 +0200 Subject: NFC: HCI based pn544 driver This is an NFC driver for NXP pn544. Unlike pn544.c, this one is based on the NFC HCI and SHDLC kernel layers. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/nfc/Kconfig | 13 + drivers/nfc/Makefile | 1 + drivers/nfc/pn544_hci.c | 947 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfc/pn544.h | 7 + 4 files changed, 968 insertions(+) create mode 100644 drivers/nfc/pn544_hci.c (limited to 'include') diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 5af959274d4e..3b20b73ee649 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -17,6 +17,19 @@ config PN544_NFC To compile this driver as a module, choose m here. The module will be called pn544. +config PN544_HCI_NFC + tristate "HCI PN544 NFC driver" + depends on I2C && NFC_SHDLC + select CRC_CCITT + default n + ---help--- + NXP PN544 i2c driver. + This is a driver based on the SHDLC and HCI NFC kernel layers and + will thus not work with NXP libnfc library. + + To compile this driver as a module, choose m here. The module will + be called pn544_hci. + config NFC_PN533 tristate "NXP PN533 USB driver" depends on USB diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index ab99e8572f02..473e44cef612 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_PN544_NFC) += pn544.o +obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c new file mode 100644 index 000000000000..46f4a9f9f5e4 --- /dev/null +++ b/drivers/nfc/pn544_hci.c @@ -0,0 +1,947 @@ +/* + * HCI based Driver for NXP PN544 NFC Chip + * + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define DRIVER_DESC "HCI NFC driver for PN544" + +#define PN544_HCI_DRIVER_NAME "pn544_hci" + +/* Timing restrictions (ms) */ +#define PN544_HCI_RESETVEN_TIME 30 + +static struct i2c_device_id pn544_hci_id_table[] = { + {"pn544", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pn544_hci_id_table); + +#define HCI_MODE 0 +#define FW_MODE 1 + +/* framing in HCI mode */ +#define PN544_HCI_LLC_LEN 1 +#define PN544_HCI_LLC_CRC 2 +#define PN544_HCI_LLC_LEN_CRC (PN544_HCI_LLC_LEN + PN544_HCI_LLC_CRC) +#define PN544_HCI_LLC_MIN_SIZE (1 + PN544_HCI_LLC_LEN_CRC) +#define PN544_HCI_LLC_MAX_PAYLOAD 29 +#define PN544_HCI_LLC_MAX_SIZE (PN544_HCI_LLC_LEN_CRC + 1 + \ + PN544_HCI_LLC_MAX_PAYLOAD) + +enum pn544_state { + PN544_ST_COLD, + PN544_ST_FW_READY, + PN544_ST_READY, +}; + +#define FULL_VERSION_LEN 11 + +/* Proprietary commands */ +#define PN544_WRITE 0x3f + +/* Proprietary gates, events, commands and registers */ + +/* NFC_HCI_RF_READER_A_GATE additional registers and commands */ +#define PN544_RF_READER_A_AUTO_ACTIVATION 0x10 +#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12 +#define PN544_MIFARE_CMD 0x21 + +/* Commands that apply to all RF readers */ +#define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30 +#define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32 + +/* NFC_HCI_ID_MGMT_GATE additional registers */ +#define PN544_ID_MGMT_FULL_VERSION_SW 0x10 + +#define PN544_RF_READER_ISO15693_GATE 0x12 + +#define PN544_RF_READER_F_GATE 0x14 +#define PN544_FELICA_ID 0x04 +#define PN544_FELICA_RAW 0x20 + +#define PN544_RF_READER_JEWEL_GATE 0x15 +#define PN544_JEWEL_RAW_CMD 0x23 + +#define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30 +#define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31 + +#define PN544_SYS_MGMT_GATE 0x90 +#define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02 + +#define PN544_POLLING_LOOP_MGMT_GATE 0x94 +#define PN544_PL_RDPHASES 0x06 +#define PN544_PL_EMULATION 0x07 +#define PN544_PL_NFCT_DEACTIVATED 0x09 + +#define PN544_SWP_MGMT_GATE 0xA0 + +#define PN544_NFC_WI_MGMT_GATE 0xA1 + +static u8 pn544_custom_gates[] = { + PN544_SYS_MGMT_GATE, + PN544_SWP_MGMT_GATE, + PN544_POLLING_LOOP_MGMT_GATE, + PN544_NFC_WI_MGMT_GATE, + PN544_RF_READER_F_GATE, + PN544_RF_READER_JEWEL_GATE, + PN544_RF_READER_ISO15693_GATE, + PN544_RF_READER_NFCIP1_INITIATOR_GATE, + PN544_RF_READER_NFCIP1_TARGET_GATE +}; + +/* Largest headroom needed for outgoing custom commands */ +#define PN544_CMDS_HEADROOM 2 + +struct pn544_hci_info { + struct i2c_client *i2c_dev; + struct nfc_shdlc *shdlc; + + enum pn544_state state; + + struct mutex info_lock; + + unsigned int gpio_en; + unsigned int gpio_irq; + unsigned int gpio_fw; + unsigned int en_polarity; + + int hard_fault; /* + * < 0 if hardware error occured (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static void pn544_hci_platform_init(struct pn544_hci_info *info) +{ + int polarity, retry, ret; + char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 }; + int count = sizeof(rset_cmd); + + pr_info(DRIVER_DESC ": %s\n", __func__); + dev_info(&info->i2c_dev->dev, "Detecting nfc_en polarity\n"); + + /* Disable fw download */ + gpio_set_value(info->gpio_fw, 0); + + for (polarity = 0; polarity < 2; polarity++) { + info->en_polarity = polarity; + retry = 3; + while (retry--) { + /* power off */ + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); + + /* power on */ + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + /* send reset */ + dev_dbg(&info->i2c_dev->dev, "Sending reset cmd\n"); + ret = i2c_master_send(info->i2c_dev, rset_cmd, count); + if (ret == count) { + dev_info(&info->i2c_dev->dev, + "nfc_en polarity : active %s\n", + (polarity == 0 ? "low" : "high")); + goto out; + } + } + } + + dev_err(&info->i2c_dev->dev, + "Could not detect nfc_en polarity, fallback to active high\n"); + +out: + gpio_set_value(info->gpio_en, !info->en_polarity); +} + +static int pn544_hci_enable(struct pn544_hci_info *info, int mode) +{ + pr_info(DRIVER_DESC ": %s\n", __func__); + + gpio_set_value(info->gpio_fw, 0); + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + return 0; +} + +static void pn544_hci_disable(struct pn544_hci_info *info) +{ + pr_info(DRIVER_DESC ": %s\n", __func__); + + gpio_set_value(info->gpio_fw, 0); + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); + + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); +} + +static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + usleep_range(3000, 6000); + + r = i2c_master_send(client, buf, len); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + } + + if (r >= 0 && r != len) + r = -EREMOTEIO; + + return r; +} + +static int check_crc(u8 *buf, int buflen) +{ + u8 len; + u16 crc; + + len = buf[0] + 1; + crc = crc_ccitt(0xffff, buf, len - 2); + crc = ~crc; + + if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) { + pr_err(PN544_HCI_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", + crc, buf[len - 1], buf[len - 2]); + + pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + return 0; +} + +/* + * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees + * that i2c bus will be flushed and that next read will start on a new frame. + * returned skb contains only LLC header and payload. + * returns: + * -EREMOTEIO : i2c read error (fatal) + * -EBADMSG : frame was incorrect and discarded + * -ENOMEM : cannot allocate skb, frame dropped + */ +static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb) +{ + int r; + u8 len; + u8 tmp[PN544_HCI_LLC_MAX_SIZE - 1]; + + r = i2c_master_recv(client, &len, 1); + if (r != 1) { + dev_err(&client->dev, "cannot read len byte\n"); + return -EREMOTEIO; + } + + if ((len < (PN544_HCI_LLC_MIN_SIZE - 1)) || + (len > (PN544_HCI_LLC_MAX_SIZE - 1))) { + dev_err(&client->dev, "invalid len byte\n"); + r = -EBADMSG; + goto flush; + } + + *skb = alloc_skb(1 + len, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto flush; + } + + *skb_put(*skb, 1) = len; + + r = i2c_master_recv(client, skb_put(*skb, len), len); + if (r != len) { + kfree_skb(*skb); + return -EREMOTEIO; + } + + r = check_crc((*skb)->data, (*skb)->len); + if (r != 0) { + kfree_skb(*skb); + r = -EBADMSG; + goto flush; + } + + skb_pull(*skb, 1); + skb_trim(*skb, (*skb)->len - 2); + + usleep_range(3000, 6000); + + return 0; + +flush: + if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) + r = -EREMOTEIO; + + usleep_range(3000, 6000); + + return r; +} + +/* + * Reads an shdlc frame from the chip. This is not as straightforward as it + * seems. There are cases where we could loose the frame start synchronization. + * The frame format is len-data-crc, and corruption can occur anywhere while + * transiting on i2c bus, such that we could read an invalid len. + * In order to recover synchronization with the next frame, we must be sure + * to read the real amount of data without using the len byte. We do this by + * assuming the following: + * - the chip will always present only one single complete frame on the bus + * before triggering the interrupt + * - the chip will not present a new frame until we have completely read + * the previous one (or until we have handled the interrupt). + * The tricky case is when we read a corrupted len that is less than the real + * len. We must detect this here in order to determine that we need to flush + * the bus. This is the reason why we check the crc here. + */ +static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) +{ + struct pn544_hci_info *info = dev_id; + struct i2c_client *client = info->i2c_dev; + struct sk_buff *skb = NULL; + int r; + + BUG_ON(!info); + BUG_ON(irq != info->i2c_dev->irq); + + dev_dbg(&client->dev, "IRQ\n"); + + if (info->hard_fault != 0) + return IRQ_HANDLED; + + r = pn544_hci_i2c_read(client, &skb); + if (r == -EREMOTEIO) { + info->hard_fault = r; + + nfc_shdlc_recv_frame(info->shdlc, NULL); + + return IRQ_HANDLED; + } else if ((r == -ENOMEM) || (r == -EBADMSG)) { + return IRQ_HANDLED; + } + + nfc_shdlc_recv_frame(info->shdlc, skb); + + return IRQ_HANDLED; +} + +static int pn544_hci_open(struct nfc_shdlc *shdlc) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + int r = 0; + + mutex_lock(&info->info_lock); + + if (info->state != PN544_ST_COLD) { + r = -EBUSY; + goto out; + } + + r = pn544_hci_enable(info, HCI_MODE); + +out: + mutex_unlock(&info->info_lock); + return r; +} + +static void pn544_hci_close(struct nfc_shdlc *shdlc) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + + mutex_lock(&info->info_lock); + + if (info->state == PN544_ST_COLD) + goto out; + + pn544_hci_disable(info); + +out: + mutex_unlock(&info->info_lock); +} + +static int pn544_hci_ready(struct nfc_shdlc *shdlc) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct sk_buff *skb; + static struct hw_config { + u8 adr[2]; + u8 value; + } hw_config[] = { + {{0x9f, 0x9a}, 0x00}, + + {{0x98, 0x10}, 0xbc}, + + {{0x9e, 0x71}, 0x00}, + + {{0x98, 0x09}, 0x00}, + + {{0x9e, 0xb4}, 0x00}, + + {{0x9e, 0xd9}, 0xff}, + {{0x9e, 0xda}, 0xff}, + {{0x9e, 0xdb}, 0x23}, + {{0x9e, 0xdc}, 0x21}, + {{0x9e, 0xdd}, 0x22}, + {{0x9e, 0xde}, 0x24}, + + {{0x9c, 0x01}, 0x08}, + + {{0x9e, 0xaa}, 0x01}, + + {{0x9b, 0xd1}, 0x0d}, + {{0x9b, 0xd2}, 0x24}, + {{0x9b, 0xd3}, 0x0a}, + {{0x9b, 0xd4}, 0x22}, + {{0x9b, 0xd5}, 0x08}, + {{0x9b, 0xd6}, 0x1e}, + {{0x9b, 0xdd}, 0x1c}, + + {{0x9b, 0x84}, 0x13}, + {{0x99, 0x81}, 0x7f}, + {{0x99, 0x31}, 0x70}, + + {{0x98, 0x00}, 0x3f}, + + {{0x9f, 0x09}, 0x00}, + + {{0x9f, 0x0a}, 0x05}, + + {{0x9e, 0xd1}, 0xa1}, + {{0x99, 0x23}, 0x00}, + + {{0x9e, 0x74}, 0x80}, + + {{0x9f, 0x28}, 0x10}, + + {{0x9f, 0x35}, 0x14}, + + {{0x9f, 0x36}, 0x60}, + + {{0x9c, 0x31}, 0x00}, + + {{0x9c, 0x32}, 0xc8}, + + {{0x9c, 0x19}, 0x40}, + + {{0x9c, 0x1a}, 0x40}, + + {{0x9c, 0x0c}, 0x00}, + + {{0x9c, 0x0d}, 0x00}, + + {{0x9c, 0x12}, 0x00}, + + {{0x9c, 0x13}, 0x00}, + + {{0x98, 0xa2}, 0x0e}, + + {{0x98, 0x93}, 0x40}, + + {{0x98, 0x7d}, 0x02}, + {{0x98, 0x7e}, 0x00}, + {{0x9f, 0xc8}, 0x01}, + }; + struct hw_config *p = hw_config; + int count = ARRAY_SIZE(hw_config); + struct sk_buff *res_skb; + u8 param[4]; + int r; + + param[0] = 0; + while (count--) { + param[1] = p->adr[0]; + param[2] = p->adr[1]; + param[3] = p->value; + + r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE, + param, 4, &res_skb); + if (r < 0) + return r; + + if (res_skb->len != 1) { + kfree_skb(res_skb); + return -EPROTO; + } + + if (res_skb->data[0] != p->value) { + kfree_skb(res_skb); + return -EIO; + } + + kfree_skb(res_skb); + + p++; + } + + param[0] = NFC_HCI_UICC_HOST_ID; + r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, + NFC_HCI_ADMIN_WHITELIST, param, 1); + if (r < 0) + return r; + + param[0] = 0x3d; + r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE, + PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1); + if (r < 0) + return r; + + param[0] = 0x0; + r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_A_AUTO_ACTIVATION, param, 1); + if (r < 0) + return r; + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (r < 0) + return r; + + param[0] = 0x1; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_NFCT_DEACTIVATED, param, 1); + if (r < 0) + return r; + + param[0] = 0x0; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_RDPHASES, param, 1); + if (r < 0) + return r; + + r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, + PN544_ID_MGMT_FULL_VERSION_SW, &skb); + if (r < 0) + return r; + + if (skb->len != FULL_VERSION_LEN) { + kfree_skb(skb); + return -EINVAL; + } + + print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ", + DUMP_PREFIX_NONE, 16, 1, + skb->data, FULL_VERSION_LEN, false); + + kfree_skb(skb); + + return 0; +} + +static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + struct i2c_client *client = info->i2c_dev; + + if (info->hard_fault != 0) + return info->hard_fault; + + return pn544_hci_i2c_write(client, skb->data, skb->len); +} + +static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + u8 phases = 0; + int r; + u8 duration[2]; + u8 activated; + + pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols); + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (r < 0) + return r; + + duration[0] = 0x18; + duration[1] = 0x6a; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_EMULATION, duration, 2); + if (r < 0) + return r; + + activated = 0; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_NFCT_DEACTIVATED, &activated, 1); + if (r < 0) + return r; + + if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK | + NFC_PROTO_JEWEL_MASK)) + phases |= 1; /* Type A */ + if (protocols & NFC_PROTO_FELICA_MASK) { + phases |= (1 << 2); /* Type F 212 */ + phases |= (1 << 3); /* Type F 424 */ + } + + phases |= (1 << 5); /* NFC active */ + + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_RDPHASES, &phases, 1); + if (r < 0) + return r; + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_READER_REQUESTED, NULL, 0); + if (r < 0) + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + + return r; +} + +static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, + struct nfc_target *target) +{ + switch (gate) { + case PN544_RF_READER_F_GATE: + target->supported_protocols = NFC_PROTO_FELICA_MASK; + break; + case PN544_RF_READER_JEWEL_GATE: + target->supported_protocols = NFC_PROTO_JEWEL_MASK; + target->sens_res = 0x0c00; + break; + default: + return -EPROTO; + } + + return 0; +} + +static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, + u8 gate, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct sk_buff *uid_skb; + int r = 0; + + if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { + if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && + target->nfcid1_len != 10) + return -EPROTO; + + r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_CMD_ACTIVATE_NEXT, + target->nfcid1, target->nfcid1_len, NULL); + } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) { + r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE, + PN544_FELICA_ID, &uid_skb); + if (r < 0) + return r; + + if (uid_skb->len != 8) { + kfree_skb(uid_skb); + return -EPROTO; + } + + r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE, + PN544_RF_READER_CMD_ACTIVATE_NEXT, + uid_skb->data, uid_skb->len, NULL); + kfree_skb(uid_skb); + } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) { + /* + * TODO: maybe other ISO 14443 require some kind of continue + * activation, but for now we've seen only this one below. + */ + if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */ + r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION, + NULL, 0, NULL); + } + + return r; +} + +#define MIFARE_CMD_AUTH_KEY_A 0x60 +#define MIFARE_CMD_AUTH_KEY_B 0x61 +#define MIFARE_CMD_HEADER 2 +#define MIFARE_UID_LEN 4 +#define MIFARE_KEY_LEN 6 +#define MIFARE_CMD_LEN 12 +/* + * Returns: + * <= 0: driver handled the data exchange + * 1: driver doesn't especially handle, please do standard processing + */ +static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, + struct nfc_target *target, + struct sk_buff *skb, + struct sk_buff **res_skb) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + int r; + + pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, + target->hci_reader_gate); + + switch (target->hci_reader_gate) { + case NFC_HCI_RF_READER_A_GATE: + if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { + /* + * It seems that pn544 is inverting key and UID for + * MIFARE authentication commands. + */ + if (skb->len == MIFARE_CMD_LEN && + (skb->data[0] == MIFARE_CMD_AUTH_KEY_A || + skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) { + u8 uid[MIFARE_UID_LEN]; + u8 *data = skb->data + MIFARE_CMD_HEADER; + + memcpy(uid, data + MIFARE_KEY_LEN, + MIFARE_UID_LEN); + memmove(data + MIFARE_UID_LEN, data, + MIFARE_KEY_LEN); + memcpy(data, uid, MIFARE_UID_LEN); + } + + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_MIFARE_CMD, + skb->data, skb->len, res_skb); + } else + return 1; + case PN544_RF_READER_F_GATE: + *skb_push(skb, 1) = 0; + *skb_push(skb, 1) = 0; + + r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_FELICA_RAW, + skb->data, skb->len, res_skb); + if (r == 0) + skb_pull(*res_skb, 1); + return r; + case PN544_RF_READER_JEWEL_GATE: + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_JEWEL_RAW_CMD, + skb->data, skb->len, res_skb); + default: + return 1; + } +} + +static int pn544_hci_check_presence(struct nfc_shdlc *shdlc, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_RF_READER_CMD_PRESENCE_CHECK, + NULL, 0, NULL); +} + +static struct nfc_shdlc_ops pn544_shdlc_ops = { + .open = pn544_hci_open, + .close = pn544_hci_close, + .hci_ready = pn544_hci_ready, + .xmit = pn544_hci_xmit, + .start_poll = pn544_hci_start_poll, + .target_from_gate = pn544_hci_target_from_gate, + .complete_target_discovered = pn544_hci_complete_target_discovered, + .data_exchange = pn544_hci_data_exchange, + .check_presence = pn544_hci_check_presence, +}; + +static int __devinit pn544_hci_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn544_hci_info *info; + struct pn544_nfc_platform_data *pdata; + int r = 0; + u32 protocols; + struct nfc_hci_init_data init_data; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_hci_info.\n"); + r = -ENOMEM; + goto err_info_alloc; + } + + info->i2c_dev = client; + info->state = PN544_ST_COLD; + mutex_init(&info->info_lock); + i2c_set_clientdata(client, info); + + pdata = client->dev.platform_data; + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto err_pdata; + } + + if (pdata->request_resources == NULL) { + dev_err(&client->dev, "request_resources() missing\n"); + r = -EINVAL; + goto err_pdata; + } + + r = pdata->request_resources(client); + if (r) { + dev_err(&client->dev, "Cannot get platform resources\n"); + goto err_pdata; + } + + info->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); + info->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); + info->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); + + pn544_hci_platform_init(info); + + r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, + IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME, + info); + if (r < 0) { + dev_err(&client->dev, "Unable to register IRQ handler\n"); + goto err_rti; + } + + init_data.gate_count = ARRAY_SIZE(pn544_custom_gates); + + memcpy(init_data.gates, pn544_custom_gates, + ARRAY_SIZE(pn544_custom_gates)); + + /* + * TODO: Session id must include the driver name + some bus addr + * persistent info to discriminate 2 identical chips + */ + strcpy(init_data.session_id, "ID544HCI"); + + protocols = NFC_PROTO_JEWEL_MASK | + NFC_PROTO_MIFARE_MASK | + NFC_PROTO_FELICA_MASK | + NFC_PROTO_ISO14443_MASK | + NFC_PROTO_NFC_DEP_MASK; + + info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, + &init_data, protocols, + PN544_CMDS_HEADROOM, 0, + PN544_HCI_LLC_MAX_PAYLOAD, + dev_name(&client->dev)); + if (!info->shdlc) { + dev_err(&client->dev, "Cannot allocate nfc shdlc.\n"); + r = -ENOMEM; + goto err_allocshdlc; + } + + nfc_shdlc_set_clientdata(info->shdlc, info); + + return 0; + +err_allocshdlc: + free_irq(client->irq, info); + +err_rti: + if (pdata->free_resources != NULL) + pdata->free_resources(); + +err_pdata: + kfree(info); + +err_info_alloc: + return r; +} + +static __devexit int pn544_hci_remove(struct i2c_client *client) +{ + struct pn544_hci_info *info = i2c_get_clientdata(client); + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + dev_dbg(&client->dev, "%s\n", __func__); + + nfc_shdlc_free(info->shdlc); + + if (info->state != PN544_ST_COLD) { + if (pdata->disable) + pdata->disable(); + } + + free_irq(client->irq, info); + if (pdata->free_resources) + pdata->free_resources(); + + kfree(info); + + return 0; +} + +static struct i2c_driver pn544_hci_driver = { + .driver = { + .name = PN544_HCI_DRIVER_NAME, + }, + .probe = pn544_hci_probe, + .id_table = pn544_hci_id_table, + .remove = __devexit_p(pn544_hci_remove), +}; + +static int __init pn544_hci_init(void) +{ + int r; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + + r = i2c_add_driver(&pn544_hci_driver); + if (r) { + pr_err(PN544_HCI_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; +} + +static void __exit pn544_hci_exit(void) +{ + i2c_del_driver(&pn544_hci_driver); +} + +module_init(pn544_hci_init); +module_exit(pn544_hci_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h index 7ab8521f2347..9890bbaf4328 100644 --- a/include/linux/nfc/pn544.h +++ b/include/linux/nfc/pn544.h @@ -84,6 +84,12 @@ struct pn544_fw_packet { }; #ifdef __KERNEL__ +enum { + NFC_GPIO_ENABLE, + NFC_GPIO_FW_RESET, + NFC_GPIO_IRQ +}; + /* board config */ struct pn544_nfc_platform_data { int (*request_resources) (struct i2c_client *client); @@ -91,6 +97,7 @@ struct pn544_nfc_platform_data { void (*enable) (int fw); int (*test) (void); void (*disable) (void); + int (*get_gpio)(int type); }; #endif /* __KERNEL__ */ -- cgit v1.2.3 From 03bed29e0501b5757ce62ebdb01829f7bd8d9819 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:31 +0200 Subject: NFC: HCI drivers don't have to keep track of polling state The NFC core code already does that for them. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/hci.h | 2 -- net/nfc/hci/core.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index ae042008571e..4467c9460857 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -84,8 +84,6 @@ struct nfc_hci_dev { u8 gate2pipe[NFC_HCI_MAX_GATES]; - bool poll_started; - u8 sw_romlib; u8 sw_patch; u8 sw_flashlib_major; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 0fdb96f152b1..e1a640d2b588 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -251,11 +251,6 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, switch (event) { case NFC_HCI_EVT_TARGET_DISCOVERED: - if (hdev->poll_started == false) { - r = -EPROTO; - goto exit; - } - if (skb->len < 1) { /* no status data? */ r = -EPROTO; goto exit; @@ -489,28 +484,20 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - int r; if (hdev->ops->start_poll) - r = hdev->ops->start_poll(hdev, protocols); + return hdev->ops->start_poll(hdev, protocols); else - r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, NFC_HCI_EVT_READER_REQUESTED, NULL, 0); - if (r == 0) - hdev->poll_started = true; - - return r; } static void hci_stop_poll(struct nfc_dev *nfc_dev) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - if (hdev->poll_started) { - nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, - NFC_HCI_EVT_END_OPERATION, NULL, 0); - hdev->poll_started = false; - } + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); } static int hci_activate_target(struct nfc_dev *nfc_dev, -- cgit v1.2.3 From 5a20ef3db28faa42dd5dc86ad75d2736bcd3da4c Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:06 +0200 Subject: ssb: remove rev from boardinfo Previously the rev contained the revision read from the pci config space and was used as board_rev in the wireless drivers. This is wrong the board_rev is only fetched from the sprom accordingly to the open source part of the Broadcom SDK and brcmsmac. This patch removes the rev from the boardinfo structure and uses the board_rev attribute from sprom instead. This attribute is filled by PCI, PCMCIA, SDIO and SoC code. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- arch/mips/bcm47xx/setup.c | 2 -- drivers/net/wireless/b43/bus.c | 2 +- drivers/net/wireless/b43/main.c | 4 ++-- drivers/net/wireless/b43legacy/main.c | 2 +- drivers/net/wireless/b43legacy/phy.c | 4 ++-- drivers/net/wireless/b43legacy/radio.c | 10 +++++----- drivers/ssb/pci.c | 1 - include/linux/ssb/ssb.h | 1 - 8 files changed, 11 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 19780aa91708..d9278a82e003 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -115,8 +115,6 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); - if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) - iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); bcm47xx_fill_sprom(&iv->sprom, NULL); diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 424692df239d..8f3c0a889a4e 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -210,7 +210,7 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev) dev->board_vendor = sdev->bus->boardinfo.vendor; dev->board_type = sdev->bus->boardinfo.type; - dev->board_rev = sdev->bus->boardinfo.rev; + dev->board_rev = sdev->bus->sprom.board_rev; dev->chip_id = sdev->bus->chip_id; dev->chip_rev = sdev->bus->chip_rev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 617afc8211b2..5a39b226b2e3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5243,10 +5243,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && - bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) + bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74) bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST; if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && - bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) + bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40) bus->sprom.boardflags_lo |= B43_BFL_PACTRL; if (bus->bustype == SSB_BUSTYPE_PCI) { pdev = bus->host_pci; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1deafaac43e3..cd9c9bc186d9 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3779,7 +3779,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && - bus->boardinfo.rev > 0x40) + bus->sprom.board_rev > 0x40) bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL; } diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 950334197f40..995c7d0c212a 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -408,7 +408,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) if (is_bcm_board_vendor(dev) && (dev->dev->bus->boardinfo.type == 0x0416) && - (dev->dev->bus->boardinfo.rev == 0x0017)) + (dev->dev->bus->sprom.board_rev == 0x0017)) return; b43legacy_ilt_write(dev, 0x5001, 0x0002); @@ -424,7 +424,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) if (is_bcm_board_vendor(dev) && (dev->dev->bus->boardinfo.type == 0x0416) && - (dev->dev->bus->boardinfo.rev == 0x0017)) + (dev->dev->bus->sprom.board_rev == 0x0017)) return; b43legacy_ilt_write(dev, 0x0401, 0x0002); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index fcbafcd603cc..896177690394 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1998,7 +1998,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) if (phy->type == B43legacy_PHYTYPE_G) { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 3; else if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x416) @@ -2008,7 +2008,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) } else { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 7; else att = 6; @@ -2018,7 +2018,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) if (phy->type == B43legacy_PHYTYPE_G) { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 3; else if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == @@ -2052,9 +2052,9 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) } if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421) { - if (dev->dev->bus->boardinfo.rev < 0x43) + if (dev->dev->bus->sprom.board_rev < 0x43) att = 2; - else if (dev->dev->bus->boardinfo.rev < 0x51) + else if (dev->dev->bus->sprom.board_rev < 0x51) att = 3; } if (att == 0xFFFF) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index ed4124469a3a..113208e0ae33 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -784,7 +784,6 @@ static void ssb_pci_get_boardinfo(struct ssb_bus *bus, { bi->vendor = bus->host_pci->subsystem_vendor; bi->type = bus->host_pci->subsystem_device; - bi->rev = bus->host_pci->revision; } int ssb_pci_get_invariants(struct ssb_bus *bus, diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index d27683180025..bc14bd738ade 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -188,7 +188,6 @@ struct ssb_sprom { struct ssb_boardinfo { u16 vendor; u16 type; - u8 rev; }; -- cgit v1.2.3 From 0a2fcaa70ce96be6e663234072984fd2b0ffa36e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:08 +0200 Subject: bcma: add boardinfo struct This struct contains information about the board, the chip is running on. The struct is filled for PCIe devices and SoCs. This information is used by b43 and will be used by brcmsmac soon. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- arch/mips/bcm47xx/setup.c | 2 ++ arch/mips/bcm47xx/sprom.c | 12 ++++++++++++ arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 4 ++++ drivers/bcma/host_pci.c | 3 +++ drivers/net/wireless/b43/bus.c | 4 +--- include/linux/bcma/bcma.h | 7 +++++++ 6 files changed, 29 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 53cdb7244244..9ef46d2a5110 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -190,6 +190,8 @@ static void __init bcm47xx_register_bcma(void) err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) panic("Failed to initialize BCMA bus (err %d)", err); + + bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL); } #endif diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 279991a3583b..a29d20743039 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -630,3 +630,15 @@ void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo, nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0); } #endif + +#ifdef CONFIG_BCM47XX_BCMA +void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, + const char *prefix) +{ + nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0); + if (!boardinfo->vendor) + boardinfo->vendor = SSB_BOARDVENDOR_BCM; + + nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0); +} +#endif diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h index 42887c66ade2..26fdaf40b930 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h @@ -51,5 +51,9 @@ void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix); void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo, const char *prefix); #endif +#ifdef CONFIG_BCM47XX_BCMA +void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, + const char *prefix); +#endif #endif /* __ASM_BCM47XX_H */ diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index e3928d68802b..3a93563b4f7a 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -201,6 +201,9 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev, bus->hosttype = BCMA_HOSTTYPE_PCI; bus->ops = &bcma_host_pci_ops; + bus->boardinfo.vendor = bus->host_pci->subsystem_vendor; + bus->boardinfo.type = bus->host_pci->subsystem_device; + /* Register */ err = bcma_bus_register(bus); if (err) diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 8f3c0a889a4e..565fdbdd6915 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -107,11 +107,9 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core) dev->dma_dev = core->dma_dev; dev->irq = core->irq; - /* dev->board_vendor = core->bus->boardinfo.vendor; dev->board_type = core->bus->boardinfo.type; - dev->board_rev = core->bus->boardinfo.rev; - */ + dev->board_rev = core->bus->sprom.board_rev; dev->chip_id = core->bus->chipinfo.id; dev->chip_rev = core->bus->chipinfo.rev; diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 5af9a075498f..747f2ca6f04e 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -26,6 +26,11 @@ struct bcma_chipinfo { u8 pkg; }; +struct bcma_boardinfo { + u16 vendor; + u16 type; +}; + enum bcma_clkmode { BCMA_CLKMODE_FAST, BCMA_CLKMODE_DYNAMIC, @@ -198,6 +203,8 @@ struct bcma_bus { struct bcma_chipinfo chipinfo; + struct bcma_boardinfo boardinfo; + struct bcma_device *mapped_core; struct list_head cores; u8 nr_cores; -- cgit v1.2.3 From bf7d420b4a3ea06d9638ec7f1b9d7971fa7f4f66 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:10 +0200 Subject: ssb/bcma: fill attribute alpha2 from sprom The attribute country_code and alpha2 are two different attributes in the sprom. country_code contains some code in an 8 bit coding and alpha2 contains two chars with the country code. The attributes where read out wrongly in the past and country_code is only available on sprom version 1. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/sprom.c | 3 ++- drivers/ssb/pci.c | 16 +++++++++++----- include/linux/ssb/ssb_regs.h | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 3e2a6002aae6..1799372131d2 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -243,7 +243,8 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0); SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0); - SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); /* Extract cores power info info */ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 113208e0ae33..82589d447f85 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -360,8 +360,9 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); - SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, - SSB_SPROM1_BINF_CCODE_SHIFT); + if (out->revision == 1) + SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, + SSB_SPROM1_BINF_CCODE_SHIFT); SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, SSB_SPROM1_BINF_ANTA_SHIFT); SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, @@ -387,6 +388,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); if (out->revision >= 2) SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); /* Extract the antenna gain values. */ out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, @@ -456,13 +459,15 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); if (out->revision == 4) { - SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); } else { - SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); @@ -525,7 +530,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } - SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 40b1ef8595ee..d33bd8fec445 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -228,6 +228,7 @@ #define SSB_SPROM1_AGAIN_BG_SHIFT 0 #define SSB_SPROM1_AGAIN_A 0xFF00 /* A-PHY */ #define SSB_SPROM1_AGAIN_A_SHIFT 8 +#define SSB_SPROM1_CCODE 0x0076 /* SPROM Revision 2 (inherits from rev 1) */ #define SSB_SPROM2_BFLHI 0x0038 /* Boardflags (high 16 bits) */ -- cgit v1.2.3 From 673335c8f0c24912d57abf9b8cd10c9d91ff1a40 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:11 +0200 Subject: ssb: fill board_rev attribute from sprom This attribute is now used in b43 driver and should be filled for all sprom versions. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 2 ++ include/linux/ssb/ssb_regs.h | 1 + 2 files changed, 3 insertions(+) (limited to 'include') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 82589d447f85..2cb604d142f4 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -458,6 +458,7 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); + SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); if (out->revision == 4) { SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); @@ -530,6 +531,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } + SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index d33bd8fec445..543795f30f75 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -268,6 +268,7 @@ #define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */ /* SPROM Revision 4 */ +#define SSB_SPROM4_BOARDREV 0x0042 /* Board revision */ #define SSB_SPROM4_BFLLO 0x0044 /* Boardflags (low 16 bits) */ #define SSB_SPROM4_BFLHI 0x0046 /* Board Flags Hi */ #define SSB_SPROM4_BFL2LO 0x0048 /* Board flags 2 (low 16 bits) */ -- cgit v1.2.3 From e2da4bd3ec7842fbef2bc7bffde3e1ad0c15f516 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:13 +0200 Subject: bcma/ssb: parse new attributes from sprom These newly added attributes are used by brcmsmac. Now bcma should parse all attributes used by brcmsmac out of the sprom. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/sprom.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ drivers/ssb/pci.c | 69 +++++++++++++++++++++++++++++++++++++++++++ include/linux/ssb/ssb_regs.h | 59 ++++++++++++++++++++++++++++++++++--- 3 files changed, 194 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 22c99683a180..c7f93359acb0 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -185,6 +185,18 @@ static int bcma_sprom_valid(const u16 *sprom) bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \ sprom[SPOFF(_offset)]) & (_mask)) >> (_shift)) +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) { u16 v, o; @@ -375,6 +387,64 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); + + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); } /* diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 2cb604d142f4..e9d94968f394 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -178,6 +178,18 @@ err_pci: #define SPEX(_outvar, _offset, _mask, _shift) \ SPEX16(_outvar, _offset, _mask, _shift) +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static inline u8 ssb_crc8(u8 crc, u8 data) { @@ -663,6 +675,63 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); sprom_extract_r458(out, in); /* TODO - get remaining rev 8 stuff needed */ diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 543795f30f75..a0525019e1d1 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -391,6 +391,11 @@ #define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ #define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ #define SSB_SPROM8_GPIOB_P3_SHIFT 8 +#define SSB_SPROM8_LEDDC 0x009A +#define SSB_SPROM8_LEDDC_ON 0xFF00 /* oncount */ +#define SSB_SPROM8_LEDDC_ON_SHIFT 8 +#define SSB_SPROM8_LEDDC_OFF 0x00FF /* offcount */ +#define SSB_SPROM8_LEDDC_OFF_SHIFT 0 #define SSB_SPROM8_ANTAVAIL 0x009C /* Antenna available bitfields*/ #define SSB_SPROM8_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */ #define SSB_SPROM8_ANTAVAIL_A_SHIFT 8 @@ -406,6 +411,13 @@ #define SSB_SPROM8_AGAIN2_SHIFT 0 #define SSB_SPROM8_AGAIN3 0xFF00 /* Antenna 3 */ #define SSB_SPROM8_AGAIN3_SHIFT 8 +#define SSB_SPROM8_TXRXC 0x00A2 +#define SSB_SPROM8_TXRXC_TXCHAIN 0x000f +#define SSB_SPROM8_TXRXC_TXCHAIN_SHIFT 0 +#define SSB_SPROM8_TXRXC_RXCHAIN 0x00f0 +#define SSB_SPROM8_TXRXC_RXCHAIN_SHIFT 4 +#define SSB_SPROM8_TXRXC_SWITCH 0xff00 +#define SSB_SPROM8_TXRXC_SWITCH_SHIFT 8 #define SSB_SPROM8_RSSIPARM2G 0x00A4 /* RSSI params for 2GHz */ #define SSB_SPROM8_RSSISMF2G 0x000F #define SSB_SPROM8_RSSISMC2G 0x00F0 @@ -432,6 +444,7 @@ #define SSB_SPROM8_TRI5GH_SHIFT 8 #define SSB_SPROM8_RXPO 0x00AC /* RX power offsets */ #define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */ +#define SSB_SPROM8_RXPO2G_SHIFT 0 #define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */ #define SSB_SPROM8_RXPO5G_SHIFT 8 #define SSB_SPROM8_FEM2G 0x00AE @@ -447,10 +460,38 @@ #define SSB_SROM8_FEM_ANTSWLUT 0xF800 #define SSB_SROM8_FEM_ANTSWLUT_SHIFT 11 #define SSB_SPROM8_THERMAL 0x00B2 -#define SSB_SPROM8_MPWR_RAWTS 0x00B4 -#define SSB_SPROM8_TS_SLP_OPT_CORRX 0x00B6 -#define SSB_SPROM8_FOC_HWIQ_IQSWP 0x00B8 -#define SSB_SPROM8_PHYCAL_TEMPDELTA 0x00BA +#define SSB_SPROM8_THERMAL_OFFSET 0x00ff +#define SSB_SPROM8_THERMAL_OFFSET_SHIFT 0 +#define SSB_SPROM8_THERMAL_TRESH 0xff00 +#define SSB_SPROM8_THERMAL_TRESH_SHIFT 8 +/* Temp sense related entries */ +#define SSB_SPROM8_RAWTS 0x00B4 +#define SSB_SPROM8_RAWTS_RAWTEMP 0x01ff +#define SSB_SPROM8_RAWTS_RAWTEMP_SHIFT 0 +#define SSB_SPROM8_RAWTS_MEASPOWER 0xfe00 +#define SSB_SPROM8_RAWTS_MEASPOWER_SHIFT 9 +#define SSB_SPROM8_OPT_CORRX 0x00B6 +#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE 0x00ff +#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT 0 +#define SSB_SPROM8_OPT_CORRX_TEMPCORRX 0xfc00 +#define SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT 10 +#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION 0x0300 +#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT 8 +/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */ +#define SSB_SPROM8_HWIQ_IQSWP 0x00B8 +#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR 0x000f +#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT 0 +#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP 0x0010 +#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT 4 +#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL 0x0020 +#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT 5 +#define SSB_SPROM8_TEMPDELTA 0x00BA +#define SSB_SPROM8_TEMPDELTA_PHYCAL 0x00ff +#define SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT 0 +#define SSB_SPROM8_TEMPDELTA_PERIOD 0x0f00 +#define SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT 8 +#define SSB_SPROM8_TEMPDELTA_HYSTERESIS 0xf000 +#define SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT 12 /* There are 4 blocks with power info sharing the same layout */ #define SSB_SROM8_PWR_INFO_CORE0 0x00C0 @@ -515,6 +556,16 @@ #define SSB_SPROM8_OFDM5GLPO 0x014A /* 5.2GHz OFDM power offset */ #define SSB_SPROM8_OFDM5GHPO 0x014E /* 5.8GHz OFDM power offset */ +#define SSB_SPROM8_2G_MCSPO 0x0152 +#define SSB_SPROM8_5G_MCSPO 0x0162 +#define SSB_SPROM8_5GL_MCSPO 0x0172 +#define SSB_SPROM8_5GH_MCSPO 0x0182 + +#define SSB_SPROM8_CDDPO 0x0192 +#define SSB_SPROM8_STBCPO 0x0194 +#define SSB_SPROM8_BW40PO 0x0196 +#define SSB_SPROM8_BWDUPPO 0x0198 + /* Values for boardflags_lo read from SPROM */ #define SSB_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ #define SSB_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ -- cgit v1.2.3 From 29f6b3d823885093890b1604d8450e7b57a31281 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:18:50 +0200 Subject: bcma: add bcma_core_pci_extend_L1timer This code is based on code from pcie_extendL1timer() in brcmsmac. This patch is part of the move of pci specific code from brcmsmac to bcma. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/driver_pci.c | 16 ++++++++++++++-- include/linux/bcma/bcma_driver_pci.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 4d38ae179b48..949206674dc8 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -24,14 +24,12 @@ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address) return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA); } -#if 0 static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data) { pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address); pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR); pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data); } -#endif static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy) { @@ -224,3 +222,17 @@ out: return err; } EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); + +void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend) +{ + u32 w; + + w = bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); + if (extend) + w |= BCMA_CORE_PCI_ASPMTIMER_EXTEND; + else + w &= ~BCMA_CORE_PCI_ASPMTIMER_EXTEND; + bcma_pcie_write(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG, w); + bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); +} +EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer); diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 46c71e27d31f..20c9f96d4070 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -133,6 +133,7 @@ struct pci_dev; #define BCMA_CORE_PCI_DLLP_LRREG 0x120 /* Link Replay */ #define BCMA_CORE_PCI_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */ #define BCMA_CORE_PCI_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ +#define BCMA_CORE_PCI_ASPMTIMER_EXTEND 0x01000000 /* > rev7: enable extend ASPM timer */ #define BCMA_CORE_PCI_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */ #define BCMA_CORE_PCI_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */ #define BCMA_CORE_PCI_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */ @@ -207,6 +208,7 @@ struct bcma_drv_pci { extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc); extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, bool enable); +extern void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend); extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); -- cgit v1.2.3 From ec00f3732129e57206e9ef9883d681ad6584f5dd Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:18:51 +0200 Subject: bcma: add bcma_core_pci_fixcfg() This code is based on code from pcicore_fixcfg() in brcmsmac. This patch is part of the move of pci specific code from brcmsmac to bcma. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/driver_pci.c | 19 +++++++++++++++++++ include/linux/bcma/bcma_driver_pci.h | 5 +++++ 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 949206674dc8..472d14fad643 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -168,12 +168,31 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN); } +static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) +{ + struct bcma_device *core = pc->core; + u16 val16, core_index; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); + core_index = (u16)core->core_index; + + val16 = pcicore_read16(pc, regoff); + if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) + != core_index) { + val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | + (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); + pcicore_write16(pc, regoff, val16); + } +} + /************************************************** * Init. **************************************************/ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { + bcma_core_pci_fixcfg(pc); bcma_pcicore_serdes_workaround(pc); } diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 20c9f96d4070..5b0542c336ed 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -87,6 +87,9 @@ struct pci_dev; #define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ #define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ #define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ +#define BCMA_CORE_PCI_SPROM_PI_OFFSET 0 /* first word */ +#define BCMA_CORE_PCI_SPROM_PI_MASK 0xf000 /* bit 15:12 */ +#define BCMA_CORE_PCI_SPROM_PI_SHIFT 12 /* bit 15:12 */ /* SBtoPCIx */ #define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 @@ -202,7 +205,9 @@ struct bcma_drv_pci { }; /* Register access */ +#define pcicore_read16(pc, offset) bcma_read16((pc)->core, offset) #define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset) +#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc); -- cgit v1.2.3 From 2b2715b83c433d22b10bd654e102baea6f5589b0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:18:52 +0200 Subject: bcma: add bcma_core_pci_config_fixup() This code is based on code from pcie_misc_config_fixup() in brcmsmac. This patch is part of the move of pci specific code from brcmsmac to bcma. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/driver_pci.c | 18 ++++++++++++++++++ include/linux/bcma/bcma_driver_pci.h | 4 ++++ 2 files changed, 22 insertions(+) (limited to 'include') diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 472d14fad643..9a96f14c8f47 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -186,6 +186,23 @@ static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) } } +/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc) +{ + u16 val16; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_MISC_CONFIG); + + val16 = pcicore_read16(pc, regoff); + + if (!(val16 & BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST)) { + val16 |= BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST; + pcicore_write16(pc, regoff, val16); + } +} + /************************************************** * Init. **************************************************/ @@ -194,6 +211,7 @@ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { bcma_core_pci_fixcfg(pc); bcma_pcicore_serdes_workaround(pc); + bcma_core_pci_config_fixup(pc); } void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc) diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 5b0542c336ed..41da581e1612 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -90,6 +90,10 @@ struct pci_dev; #define BCMA_CORE_PCI_SPROM_PI_OFFSET 0 /* first word */ #define BCMA_CORE_PCI_SPROM_PI_MASK 0xf000 /* bit 15:12 */ #define BCMA_CORE_PCI_SPROM_PI_SHIFT 12 /* bit 15:12 */ +#define BCMA_CORE_PCI_SPROM_MISC_CONFIG 5 /* word 5 */ +#define BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */ +#define BCMA_CORE_PCI_SPROM_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ +#define BCMA_CORE_PCI_SPROM_CLKREQ_ENB 0x0800 /* bit 11 */ /* SBtoPCIx */ #define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 -- cgit v1.2.3 From ee70108fa2a7688dc67bfedaeb0c8c46a221effb Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Wed, 9 May 2012 08:11:20 +0300 Subject: mac80211: Add IV-room in the skb for TKIP and WEP Add IV-room in skb also for TKIP and WEP. Extend patch: "mac80211: support adding IV-room in the skb for CCMP keys" Signed-off-by: Janusz Dziedzic Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 2 +- net/mac80211/wep.c | 14 +++++++++++--- net/mac80211/wpa.c | 8 +++++++- 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4d6e6c6818d0..60e3766d3739 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -939,7 +939,7 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) * CCMP key if it requires CCMP encryption of management frames (MFP) to * be done in software. * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver - * for a CCMP key if space should be prepared for the IV, but the IV + * if space should be prepared for the IV, but the IV * itself should not be generated. Do not set together with * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. */ diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 7aa31bbfaa3b..e904401684da 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -92,6 +92,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, int keylen, int keyidx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int hdrlen; u8 *newhdr; @@ -104,6 +105,12 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); + + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return newhdr + hdrlen; + ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } @@ -313,14 +320,15 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = info->control.hw_key; - if (!info->control.hw_key) { + if (!hw_key) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } else if (info->control.hw_key->flags & - IEEE80211_KEY_FLAG_GENERATE_IV) { + } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) || + (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key->conf.keylen, tx->key->conf.keyidx)) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 0ae23c60968c..4d05ad9403ae 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -183,7 +183,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) u8 *pos; if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { /* hwaccel - with no need for software-generated IV */ return 0; } @@ -204,6 +205,11 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) memmove(pos, pos + TKIP_IV_LEN, hdrlen); pos += hdrlen; + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return 0; + /* Increase IV for the frame */ spin_lock_irqsave(&key->u.tkip.txlock, flags); key->u.tkip.tx.iv16++; -- cgit v1.2.3 From ac55d2fe0576d272c4a98ed9dfb87b1cca29486e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 09:09:10 +0200 Subject: mac80211: (selectively) add HT details in radiotap Add a flag for the HT format (mixed vs. greenfield) to allow drivers to report that on receive. Not all drivers will do that though, so allow drivers to set which radiotap MCS details they report. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 10 ++++++++++ net/mac80211/main.c | 3 +++ net/mac80211/rx.c | 6 +++--- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 60e3766d3739..1937c7d98304 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -667,6 +667,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_SHORT_GI: Short guard interval was used * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present. * Valid only for data frames (mainly A-MPDU) + * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if + * the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT + * to hw.radiotap_mcs_details to advertise that fact */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -681,6 +684,7 @@ enum mac80211_rx_flags { RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, RX_FLAG_NO_SIGNAL_VAL = 1<<12, + RX_FLAG_HT_GF = 1<<13, }; /** @@ -1288,6 +1292,11 @@ enum ieee80211_hw_flags { * * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX * (if %IEEE80211_HW_QUEUE_CONTROL is set) + * + * @radiotap_mcs_details: lists which MCS information can the HW + * reports, by default it is set to _MCS, _GI and _BW but doesn't + * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only + * adding _BW is supported today. */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -1309,6 +1318,7 @@ struct ieee80211_hw { u8 max_rx_aggregation_subframes; u8 max_tx_aggregation_subframes; u8 offchannel_tx_hw_queue; + u8 radiotap_mcs_details; }; /** diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b70f7f09da61..f5548e953259 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -596,6 +596,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; + local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI | + IEEE80211_RADIOTAP_MCS_HAVE_BW; local->user_power_level = -1; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d5ac02fe37ff..489093b08a4a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -204,14 +204,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->flag & RX_FLAG_HT) { rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); - *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS | - IEEE80211_RADIOTAP_MCS_HAVE_GI | - IEEE80211_RADIOTAP_MCS_HAVE_BW; + *pos++ = local->hw.radiotap_mcs_details; *pos = 0; if (status->flag & RX_FLAG_SHORT_GI) *pos |= IEEE80211_RADIOTAP_MCS_SGI; if (status->flag & RX_FLAG_40MHZ) *pos |= IEEE80211_RADIOTAP_MCS_BW_40; + if (status->flag & RX_FLAG_HT_GF) + *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; pos++; *pos++ = status->rate_idx; } -- cgit v1.2.3 From dbd4fcaf8d664fab4163b1f8682e41ad8bff3444 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 10 May 2012 19:45:51 +0200 Subject: NFC: Export nfc.h to userland The netlink commands and attributes, along with the socket structure definitions need to be exported. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/linux/Kbuild | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3c9b616c834a..f08e3aec1113 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -271,6 +271,7 @@ header-y += netfilter_ipv4.h header-y += netfilter_ipv6.h header-y += netlink.h header-y += netrom.h +header-y += nfc.h header-y += nfs.h header-y += nfs2.h header-y += nfs3.h -- cgit v1.2.3 From 3383b5a69de59eeef2501834c6e0960b7e2bff28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 20:14:43 +0200 Subject: nl80211: prevent additions to old station flags API We don't really want/need to maintain the old station flags API any more, so refuse changes to new (not yet defined) flags from the old flags API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 2 ++ net/wireless/nl80211.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f296a64d103b..a6959f72745e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1594,6 +1594,8 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; +#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER + /** * struct nl80211_sta_flag_update - station flags mask/set * @mask: mask of station flags to set diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b67b1114e25a..f1b0774d098b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2410,10 +2410,16 @@ static int parse_station_flags(struct genl_info *info, return -EINVAL; } - for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) - if (flags[flag]) + for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) { + if (flags[flag]) { params->sta_flags_set |= (1< NL80211_STA_FLAG_MAX_OLD_API) + return -EINVAL; + } + } + return 0; } -- cgit v1.2.3 From 294a20e039a5125b0e88b96e0ee47065ff4e07a5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 21:25:23 +0200 Subject: cfg80211: fix cfg80211_can_beacon_sec_chan prototype It should return bool, not int. The function even does return true/false. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 6 +++--- net/wireless/chan.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index adb2320bccdf..0289d4ce7070 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3365,9 +3365,9 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, * @chan: main channel * @channel_type: HT mode */ -int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); /* * cfg80211_ch_switch_notify - update wdev channel and notify userspace diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 2fcfe0993ca2..884801ac4dd0 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -45,7 +45,7 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, return chan; } -int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { -- cgit v1.2.3 From 9d939d948469b49912a76e789f7d4059eb1f8bc7 Mon Sep 17 00:00:00 2001 From: Vishal Agarwal Date: Thu, 26 Apr 2012 19:19:56 +0530 Subject: Bluetooth: Fix EIR data generation for mgmt_device_found The mgmt_device_found function expects to receive only the significant part of the EIR data so it needs to be removed before calling the function. This patch adds a new eir_get_length() helper function to calculate the length of the significant part. Signed-off-by: Vishal Agarwal Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 17 +++++++++++++++++ net/bluetooth/hci_event.c | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b60d2c844eba..9fc7728f94e4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -926,6 +926,23 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline size_t eir_get_length(u8 *eir, size_t eir_len) +{ + size_t parsed = 0; + + while (parsed < eir_len) { + u8 field_len = eir[0]; + + if (field_len == 0) + return parsed; + + parsed += field_len + 1; + eir += field_len + 1; + } + + return eir_len; +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fac840afd131..9c60e0d8db5f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3001,6 +3001,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct struct inquiry_data data; struct extended_inquiry_info *info = (void *) (skb->data + 1); int num_rsp = *((__u8 *) skb->data); + size_t eir_len; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -3033,9 +3034,10 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct name_known = hci_inquiry_cache_update(hdev, &data, name_known, &ssp); + eir_len = eir_get_length(info->data, sizeof(info->data)); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, !name_known, - ssp, info->data, sizeof(info->data)); + ssp, info->data, eir_len); } hci_dev_unlock(hdev); -- cgit v1.2.3 From a6a5568c03c4805d4d250f6bd9d468eeeb4ea059 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 4 May 2012 14:20:31 -0700 Subject: Bluetooth: Lock the L2CAP channel when sending The ERTM and streaming mode transmit queue must only be accessed while the L2CAP channel lock is held. Locking the channel before calling l2cap_chan_send ensures that multiple threads cannot simultaneously manipulate the queue when sending and receiving concurrently. L2CAP channel locking had previously moved to the l2cap_chan struct instead of the associated socket, so some of the old socket locking can also be removed in this patch. Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 2 -- net/bluetooth/l2cap_sock.c | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index c34a9a6184a1..7981ca48b83a 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -257,12 +257,10 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, { struct sk_buff *skb; - release_sock(sk); if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { skb_reserve(skb, BT_SKB_RESERVE); bt_cb(skb)->incoming = 0; } - lock_sock(sk); if (!skb && *err) return NULL; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b7bc7b981ee2..f6d8e13197d6 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -720,16 +720,13 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - lock_sock(sk); - - if (sk->sk_state != BT_CONNECTED) { - release_sock(sk); + if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - } + l2cap_chan_lock(chan); err = l2cap_chan_send(chan, msg, len, sk->sk_priority); + l2cap_chan_unlock(chan); - release_sock(sk); return err; } @@ -940,7 +937,10 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, struct sk_buff *skb; int err; + l2cap_chan_unlock(chan); skb = bt_skb_send_alloc(chan->sk, len, nb, &err); + l2cap_chan_lock(chan); + if (!skb) return ERR_PTR(err); -- cgit v1.2.3 From c5daa683f2d3315cd766f550ef7d88bfca1671f4 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 16 May 2012 12:17:10 -0300 Subject: Bluetooth: Create flags for bt_sk() defer_setup and suspended are now flags into bt_sk(). Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 8 ++++++-- net/bluetooth/af_bluetooth.c | 8 ++++---- net/bluetooth/l2cap_core.c | 14 ++++++++------ net/bluetooth/l2cap_sock.c | 21 +++++++++++++-------- net/bluetooth/rfcomm/sock.c | 14 ++++++++++---- 5 files changed, 41 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 7981ca48b83a..961669b648fd 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -194,8 +194,12 @@ struct bt_sock { bdaddr_t dst; struct list_head accept_q; struct sock *parent; - u32 defer_setup; - bool suspended; + unsigned long flags; +}; + +enum { + BT_SK_DEFER_SETUP, + BT_SK_SUSPEND, }; struct bt_sock_list { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 6fb68a9743af..46e7f86acfc9 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -210,7 +210,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) } if (sk->sk_state == BT_CONNECTED || !newsock || - bt_sk(parent)->defer_setup) { + test_bit(BT_DEFER_SETUP, &bt_sk(parent)->flags)) { bt_accept_unlink(sk); if (newsock) sock_graft(sk, newsock); @@ -410,8 +410,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent) list_for_each_safe(p, n, &bt_sk(parent)->accept_q) { sk = (struct sock *) list_entry(p, struct bt_sock, accept_q); if (sk->sk_state == BT_CONNECTED || - (bt_sk(parent)->defer_setup && - sk->sk_state == BT_CONNECT2)) + (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) && + sk->sk_state == BT_CONNECT2)) return POLLIN | POLLRDNORM; } @@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa sk->sk_state == BT_CONFIG) return mask; - if (!bt_sk(sk)->suspended && sock_writeable(sk)) + if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 285c5e13c7d5..24f144b72a96 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -71,7 +71,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err); + struct l2cap_chan *chan, int err); /* ---- L2CAP channels ---- */ @@ -586,7 +586,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) struct l2cap_conn_rsp rsp; __u16 result; - if (bt_sk(sk)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) result = L2CAP_CR_SEC_BLOCK; else result = L2CAP_CR_BAD_PSM; @@ -1050,7 +1050,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_chan_check_security(chan)) { lock_sock(sk); - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); @@ -3032,7 +3033,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_chan_check_security(chan)) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHOR_PEND; @@ -4924,7 +4925,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) chan->state == BT_CONFIG)) { struct sock *sk = chan->sk; - bt_sk(sk)->suspended = false; + clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); sk->sk_state_change(sk); l2cap_check_encryption(chan, encrypt); @@ -4946,7 +4947,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) lock_sock(sk); if (!status) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; res = L2CAP_CR_PEND; stat = L2CAP_CS_AUTHOR_PEND; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f52d58e05d02..3bb1611b9d48 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -324,8 +324,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us case L2CAP_CONNINFO: if (sk->sk_state != BT_CONNECTED && - !(sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup)) { + !(sk->sk_state == BT_CONNECT2 && + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) { err = -ENOTCONN; break; } @@ -399,7 +399,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -601,10 +602,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch /* or for ACL link */ } else if ((sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup) || + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || sk->sk_state == BT_CONNECTED) { if (!l2cap_chan_check_security(chan)) - bt_sk(sk)->suspended = true; + set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); else sk->sk_state_change(sk); } else { @@ -623,7 +624,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - bt_sk(sk)->defer_setup = opt; + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); break; case BT_FLUSHABLE: @@ -741,7 +745,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); - if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { + if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { sk->sk_state = BT_CONFIG; pi->chan->state = BT_CONFIG; @@ -984,7 +989,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) struct l2cap_chan *pchan = l2cap_pi(parent)->chan; sk->sk_type = parent->sk_type; - bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; + bt_sk(sk)->flags = bt_sk(parent)->flags; chan->chan_type = pchan->chan_type; chan->imtu = pchan->imtu; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index a55a43e9f70e..e8707debb864 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -260,7 +260,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) if (parent) { sk->sk_type = parent->sk_type; - pi->dlc->defer_setup = bt_sk(parent)->defer_setup; + pi->dlc->defer_setup = test_bit(BT_SK_DEFER_SETUP, + &bt_sk(parent)->flags); pi->sec_level = rfcomm_pi(parent)->sec_level; pi->role_switch = rfcomm_pi(parent)->role_switch; @@ -731,7 +732,11 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c break; } - bt_sk(sk)->defer_setup = opt; + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + break; default: @@ -849,7 +854,8 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c break; } - if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -972,7 +978,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * done: bh_unlock_sock(parent); - if (bt_sk(parent)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) parent->sk_state_change(parent); return result; -- cgit v1.2.3