[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