[Vivid][PATCH] UBUNTU: SAUCE: Bluetooth: Support for LED on Marvell modules
Jesse Sung
jesse.sung at canonical.com
Wed Nov 4 12:45:59 UTC 2015
+ Ricardo
2015-11-04 20:27 GMT+08:00 Wen-chien Jesse Sung <jesse.sung at canonical.com>:
> BugLink: https://launchpad.net/bugs/1512999
>
> For Edge Gateway 5000/5100 only.
>
> Add code for controlling bluetooth LED via firmware, and turns
> the LED on and off when the interface is up and down accordingly.
>
> Base on the code found at
> https://chromium.googlesource.com/chromiumos/third_party/kernel/+/8300e2ccad47c5c2f10507661c10d4892211790e%5E%21/#F0
>
> Signed-off-by: Wen-chien Jesse Sung <jesse.sung at canonical.com>
> Tested-by: Gavin Lin <gavin.lin at canonical.com>
> Reviewed-by: Keng-Yu Lin <kengyu at canonical.com>
> ---
> drivers/bluetooth/btusb.c | 91 ++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 86 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 11e9d8f..03055b8 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -24,6 +24,7 @@
> #include <linux/module.h>
> #include <linux/usb.h>
> #include <linux/firmware.h>
> +#include <linux/dmi.h>
>
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> @@ -51,6 +52,8 @@ static struct usb_driver btusb_driver;
> #define BTUSB_MARVELL 0x800
> #define BTUSB_QCA_ROME 0x8000
>
> +#define BTUSB_MARVELL_LED_COMMAND 0xfc77
> +
> static const struct usb_device_id btusb_table[] = {
> /* Generic Bluetooth USB device */
> { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
> @@ -325,6 +328,10 @@ struct btusb_data {
> int isoc_altsetting;
> int suspend_count;
>
> + bool is_edge_gateway;
> + int marvell_cmd_in_progress;
> + wait_queue_head_t marvell_wait_q;
> +
> int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
>
> int (*setup_on_usb)(struct hci_dev *hdev);
> @@ -530,10 +537,31 @@ static void btusb_intr_complete(struct urb *urb)
> if (urb->status == 0) {
> hdev->stat.byte_rx += urb->actual_length;
>
> - if (btusb_recv_intr(data, urb->transfer_buffer,
> - urb->actual_length) < 0) {
> - BT_ERR("%s corrupted event packet", hdev->name);
> - hdev->stat.err_rx++;
> + if (data->is_edge_gateway && data->marvell_cmd_in_progress) {
> + struct hci_ev_cmd_complete *ev;
> + struct hci_event_hdr *hdr;
> + bool consume_ev = false;
> +
> + hdr = urb->transfer_buffer;
> + if (hdr->evt == HCI_EV_CMD_COMPLETE) {
> + ev = (void *)((u8 *)hdr + HCI_EVENT_HDR_SIZE);
> + if (__le16_to_cpu(ev->opcode) == BTUSB_MARVELL_LED_COMMAND) {
> + consume_ev = true;
> + data->marvell_cmd_in_progress = false;
> + wake_up_interruptible(&data->marvell_wait_q);
> + }
> + }
> +
> + if (!consume_ev && btusb_recv_intr(data, urb->transfer_buffer, urb->actual_length) < 0) {
> + BT_ERR("%s corrupted event packet", hdev->name);
> + hdev->stat.err_rx++;
> + }
> + } else {
> + if (btusb_recv_intr(data, urb->transfer_buffer,
> + urb->actual_length) < 0) {
> + BT_ERR("%s corrupted event packet", hdev->name);
> + hdev->stat.err_rx++;
> + }
> }
> } else if (urb->status == -ENOENT) {
> /* Avoid suspend failed when usb_kill_urb */
> @@ -862,6 +890,38 @@ done:
> kfree_skb(skb);
> }
>
> +static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb);
> +
> +static void btusb_marvell_config_led(struct hci_dev *hdev, bool status)
> +{
> + u8 config_led[] = { 0x09, 0x00, 0x01, 0x01 };
> + int len = HCI_COMMAND_HDR_SIZE + sizeof(config_led);
> + struct hci_command_hdr *hdr;
> + struct sk_buff *skb;
> + struct btusb_data *data = hci_get_drvdata(hdev);
> +
> + if ((!data->is_edge_gateway) || data->marvell_cmd_in_progress)
> + return;
> +
> + skb = bt_skb_alloc(len, GFP_ATOMIC);
> + if (!skb)
> + return;
> +
> + hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE);
> + hdr->opcode = cpu_to_le16(BTUSB_MARVELL_LED_COMMAND);
> + hdr->plen = sizeof(config_led);
> +
> + if (status)
> + config_led[1] = 0x01;
> +
> + memcpy(skb_put(skb, sizeof(config_led)), config_led, sizeof(config_led));
> + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
> +
> + data->marvell_cmd_in_progress = true;
> + btusb_send_frame(hdev, skb);
> + wait_event_interruptible_timeout(data->marvell_wait_q, !data->marvell_cmd_in_progress, HZ);
> +}
> +
> static int btusb_open(struct hci_dev *hdev)
> {
> struct btusb_data *data = hci_get_drvdata(hdev);
> @@ -905,6 +965,9 @@ static int btusb_open(struct hci_dev *hdev)
>
> done:
> usb_autopm_put_interface(data->intf);
> +
> + if (data->is_edge_gateway)
> + btusb_marvell_config_led(hdev, true);
> return 0;
>
> failed:
> @@ -928,9 +991,17 @@ static int btusb_close(struct hci_dev *hdev)
>
> BT_DBG("%s", hdev->name);
>
> + if (data->is_edge_gateway && usb_get_intfdata(data->intf))
> + btusb_marvell_config_led(hdev, false);
> +
> if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
> return 0;
>
> + if (data->is_edge_gateway) {
> + data->marvell_cmd_in_progress = false;
> + wake_up_interruptible(&data->marvell_wait_q);
> + }
> +
> cancel_work_sync(&data->work);
> cancel_work_sync(&data->waker);
>
> @@ -2362,8 +2433,13 @@ static int btusb_probe(struct usb_interface *intf,
> hdev->set_bdaddr = btusb_set_bdaddr_intel;
> }
>
> - if (id->driver_info & BTUSB_MARVELL)
> + if (id->driver_info & BTUSB_MARVELL) {
> hdev->set_bdaddr = btusb_set_bdaddr_marvell;
> + if (dmi_match(DMI_PRODUCT_NAME, "Edge Gateway 5000") ||
> + dmi_match(DMI_PRODUCT_NAME, "Edge Gateway 5100"))
> + data->is_edge_gateway = true;
> + init_waitqueue_head(&data->marvell_wait_q);
> + }
>
> if (id->driver_info & BTUSB_INTEL_BOOT)
> set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
> @@ -2495,6 +2571,11 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
> return -EBUSY;
> }
>
> + if (data->is_edge_gateway) {
> + data->marvell_cmd_in_progress = 0;
> + wake_up_interruptible(&data->marvell_wait_q);
> + }
> +
> cancel_work_sync(&data->work);
>
> btusb_stop_traffic(data);
> --
> 2.5.0
>
More information about the kernel-team
mailing list