diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2015-01-28 14:09:56 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-01-28 15:26:25 -0500 |
commit | 385a768c3be1b4235ed57d707581c74b0d0efd63 (patch) | |
tree | 701af9afa74c53b7bca38f8d1a740232a1812b42 /drivers/bluetooth | |
parent | c7741d16a57cbf97eebe53f27e8216b1ff20e20c (diff) |
Bluetooth: btusb: Provide hardware error handler for Intel devices
The Intel Bluetooth controllers can provide an additional exception
info string when a hardware error event occurs. The core will now
call hdev->hw_error to let the driver read out this information.
This change will cause a reset of the hardware to bring it back
into functional state and then read the Intel exception info
string and print it along with the error information.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/btusb.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 70513b8d4d4a..b2753d79edcf 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -2266,6 +2266,46 @@ done: | |||
2266 | return 0; | 2266 | return 0; |
2267 | } | 2267 | } |
2268 | 2268 | ||
2269 | static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code) | ||
2270 | { | ||
2271 | struct sk_buff *skb; | ||
2272 | u8 type = 0x00; | ||
2273 | |||
2274 | BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); | ||
2275 | |||
2276 | skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); | ||
2277 | if (IS_ERR(skb)) { | ||
2278 | BT_ERR("%s: Reset after hardware error failed (%ld)", | ||
2279 | hdev->name, PTR_ERR(skb)); | ||
2280 | return; | ||
2281 | } | ||
2282 | kfree_skb(skb); | ||
2283 | |||
2284 | skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); | ||
2285 | if (IS_ERR(skb)) { | ||
2286 | BT_ERR("%s: Retrieving Intel exception info failed (%ld)", | ||
2287 | hdev->name, PTR_ERR(skb)); | ||
2288 | return; | ||
2289 | } | ||
2290 | |||
2291 | if (skb->len != 13) { | ||
2292 | BT_ERR("%s: Exception info size mismatch", hdev->name); | ||
2293 | kfree_skb(skb); | ||
2294 | return; | ||
2295 | } | ||
2296 | |||
2297 | if (skb->data[0] != 0x00) { | ||
2298 | BT_ERR("%s: Exception info command failure (%02x)", | ||
2299 | hdev->name, skb->data[0]); | ||
2300 | kfree_skb(skb); | ||
2301 | return; | ||
2302 | } | ||
2303 | |||
2304 | BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); | ||
2305 | |||
2306 | kfree_skb(skb); | ||
2307 | } | ||
2308 | |||
2269 | static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) | 2309 | static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
2270 | { | 2310 | { |
2271 | struct sk_buff *skb; | 2311 | struct sk_buff *skb; |
@@ -2649,12 +2689,14 @@ static int btusb_probe(struct usb_interface *intf, | |||
2649 | 2689 | ||
2650 | if (id->driver_info & BTUSB_INTEL) { | 2690 | if (id->driver_info & BTUSB_INTEL) { |
2651 | hdev->setup = btusb_setup_intel; | 2691 | hdev->setup = btusb_setup_intel; |
2692 | hdev->hw_error = btusb_hw_error_intel; | ||
2652 | hdev->set_bdaddr = btusb_set_bdaddr_intel; | 2693 | hdev->set_bdaddr = btusb_set_bdaddr_intel; |
2653 | } | 2694 | } |
2654 | 2695 | ||
2655 | if (id->driver_info & BTUSB_INTEL_NEW) { | 2696 | if (id->driver_info & BTUSB_INTEL_NEW) { |
2656 | hdev->send = btusb_send_frame_intel; | 2697 | hdev->send = btusb_send_frame_intel; |
2657 | hdev->setup = btusb_setup_intel_new; | 2698 | hdev->setup = btusb_setup_intel_new; |
2699 | hdev->hw_error = btusb_hw_error_intel; | ||
2658 | hdev->set_bdaddr = btusb_set_bdaddr_intel; | 2700 | hdev->set_bdaddr = btusb_set_bdaddr_intel; |
2659 | } | 2701 | } |
2660 | 2702 | ||