diff --git a/arch/arm/configs/miniarm-rk3288_defconfig b/arch/arm/configs/miniarm-rk3288_defconfig index e1f19b04c05a..8731909a370f 100644 --- a/arch/arm/configs/miniarm-rk3288_defconfig +++ b/arch/arm/configs/miniarm-rk3288_defconfig @@ -130,7 +130,7 @@ CONFIG_BT_HCIBTUSB=y CONFIG_BT_HCIBTSDIO=y CONFIG_BT_HCIUART=y CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_RTKH5=y +CONFIG_BT_HCIUART_3WIRE=y CONFIG_BT_HCIBFUSB=y CONFIG_BT_HCIVHCI=y CONFIG_BT_MRVL=y diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 718bfa295457..ec6af1595062 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -111,16 +111,6 @@ config BT_HCIUART_ATH3K Say Y here to compile support for HCI UART ATH3K protocol. -config BT_HCIUART_RTKH5 - bool "Realtek H5 protocol support" - depends on BT_HCIUART - help - Realtek H5 is serial protocol for communication - between Realtek Bluetooth device and host. This protocol is required for - Realtek uart h5 bluetooth controller - - Say Y here to compile support for Realtek HCI H5 protocol. - config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUART diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index ae9e31e8b431..07c9cf381e5a 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -33,7 +33,6 @@ hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o -hci_uart-$(CONFIG_BT_HCIUART_RTKH5) += hci_rtk_h5.o rtk_coex.o hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 48a9ed1814a5..a6fce48da0fb 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -24,6 +24,7 @@ */ #include + #include #include #include @@ -31,6 +32,7 @@ #include #include #include + #include #include #include @@ -38,32 +40,18 @@ #include #include #include +#include + #include #include -#include #include "hci_uart.h" -#ifdef BTCOEX -#include "rtk_coex.h" -#endif - -//#define VERSION "1.2" - struct h4_struct { - unsigned long rx_state; - unsigned long rx_count; struct sk_buff *rx_skb; struct sk_buff_head txq; }; -/* H4 receiver States */ -#define H4_W4_PACKET_TYPE 0 -#define H4_W4_EVENT_HDR 1 -#define H4_W4_ACL_HDR 2 -#define H4_W4_SCO_HDR 3 -#define H4_W4_DATA 4 - /* Initialize protocol */ static int h4_open(struct hci_uart *hu) { @@ -71,7 +59,7 @@ static int h4_open(struct hci_uart *hu) BT_DBG("hu %p", hu); - h4 = kzalloc(sizeof(*h4), GFP_ATOMIC); + h4 = kzalloc(sizeof(*h4), GFP_KERNEL); if (!h4) return -ENOMEM; @@ -126,168 +114,27 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) -static inline int h4_check_data_len(struct h4_struct *h4, int len) -#else -static inline int h4_check_data_len(struct hci_dev *hdev, struct h4_struct *h4, int len) -#endif -{ - register int room = skb_tailroom(h4->rx_skb); - - BT_DBG("len %d room %d", len, room); - - if (!len) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - hci_recv_frame(h4->rx_skb); -#else - hci_recv_frame(hdev, h4->rx_skb); -#endif - } else if (len > room) { - BT_ERR("Data length is too large"); - kfree_skb(h4->rx_skb); - } else { - h4->rx_state = H4_W4_DATA; - h4->rx_count = len; - return len; - } - - h4->rx_state = H4_W4_PACKET_TYPE; - h4->rx_skb = NULL; - h4->rx_count = 0; - - return 0; -} +static const struct h4_recv_pkt h4_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, +}; /* Recv data */ -static int h4_recv(struct hci_uart *hu, void *data, int count) +static int h4_recv(struct hci_uart *hu, const void *data, int count) { struct h4_struct *h4 = hu->priv; - register char *ptr; - struct hci_event_hdr *eh; - struct hci_acl_hdr *ah; - struct hci_sco_hdr *sh; - register int len, type, dlen; - BT_DBG("hu %p count %d rx_state %ld rx_count %ld", - hu, count, h4->rx_state, h4->rx_count); + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; - ptr = data; - while (count) { - if (h4->rx_count) { - len = min_t(unsigned int, h4->rx_count, count); - memcpy(skb_put(h4->rx_skb, len), ptr, len); - h4->rx_count -= len; count -= len; ptr += len; - - if (h4->rx_count) - continue; - - switch (h4->rx_state) { - case H4_W4_DATA: - BT_DBG("Complete data"); -#ifdef BTCOEX - if(bt_cb(h4->rx_skb)->pkt_type == HCI_EVENT_PKT) - rtk_btcoex_parse_event( - h4->rx_skb->data, - h4->rx_skb->len); - - if(bt_cb(h4->rx_skb)->pkt_type == HCI_ACLDATA_PKT) - rtk_btcoex_parse_l2cap_data_rx( - h4->rx_skb->data, - h4->rx_skb->len); -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - hci_recv_frame(h4->rx_skb); -#else - hci_recv_frame(hu->hdev, h4->rx_skb); -#endif - - h4->rx_state = H4_W4_PACKET_TYPE; - h4->rx_skb = NULL; - continue; - - case H4_W4_EVENT_HDR: - eh = hci_event_hdr(h4->rx_skb); - - BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - h4_check_data_len(h4, eh->plen); -#else - h4_check_data_len(hu->hdev, h4, eh->plen); -#endif - continue; - - case H4_W4_ACL_HDR: - ah = hci_acl_hdr(h4->rx_skb); - dlen = __le16_to_cpu(ah->dlen); - - BT_DBG("ACL header: dlen %d", dlen); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - h4_check_data_len(h4, dlen); -#else - h4_check_data_len(hu->hdev, h4, dlen); -#endif - continue; - - case H4_W4_SCO_HDR: - sh = hci_sco_hdr(h4->rx_skb); - - BT_DBG("SCO header: dlen %d", sh->dlen); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - h4_check_data_len(h4, sh->dlen); -#else - h4_check_data_len(hu->hdev, h4, sh->dlen); -#endif - continue; - } - } - - /* H4_W4_PACKET_TYPE */ - switch (*ptr) { - case HCI_EVENT_PKT: - BT_DBG("Event packet"); - h4->rx_state = H4_W4_EVENT_HDR; - h4->rx_count = HCI_EVENT_HDR_SIZE; - type = HCI_EVENT_PKT; - break; - - case HCI_ACLDATA_PKT: - BT_DBG("ACL packet"); - h4->rx_state = H4_W4_ACL_HDR; - h4->rx_count = HCI_ACL_HDR_SIZE; - type = HCI_ACLDATA_PKT; - break; - - case HCI_SCODATA_PKT: - BT_DBG("SCO packet"); - h4->rx_state = H4_W4_SCO_HDR; - h4->rx_count = HCI_SCO_HDR_SIZE; - type = HCI_SCODATA_PKT; - break; - - default: - BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); - hu->hdev->stat.err_rx++; - ptr++; count--; - continue; - }; - - ptr++; count--; - - /* Allocate packet */ - h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); - if (!h4->rx_skb) { - BT_ERR("Can't allocate mem for new packet"); - h4->rx_state = H4_W4_PACKET_TYPE; - h4->rx_count = 0; - return -ENOMEM; - } - - h4->rx_skb->dev = (void *) hu->hdev; - bt_cb(h4->rx_skb)->pkt_type = type; + h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count, + h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); + if (IS_ERR(h4->rx_skb)) { + int err = PTR_ERR(h4->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + h4->rx_skb = NULL; + return err; } return count; @@ -299,8 +146,9 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu) return skb_dequeue(&h4->txq); } -static struct hci_uart_proto h4p = { +static const struct hci_uart_proto h4p = { .id = HCI_UART_H4, + .name = "H4", .open = h4_open, .close = h4_close, .recv = h4_recv, @@ -311,17 +159,111 @@ static struct hci_uart_proto h4p = { int __init h4_init(void) { - int err = hci_uart_register_proto(&h4p); - - if (!err) - BT_INFO("HCI H4 protocol initialized"); - else - BT_ERR("HCI H4 protocol registration failed"); - - return err; + return hci_uart_register_proto(&h4p); } int __exit h4_deinit(void) { return hci_uart_unregister_proto(&h4p); } + +struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, + const unsigned char *buffer, int count, + const struct h4_recv_pkt *pkts, int pkts_count) +{ + while (count) { + int i, len; + + if (!skb) { + for (i = 0; i < pkts_count; i++) { + if (buffer[0] != (&pkts[i])->type) + continue; + + skb = bt_skb_alloc((&pkts[i])->maxlen, + GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + bt_cb(skb)->pkt_type = (&pkts[i])->type; + bt_cb(skb)->expect = (&pkts[i])->hlen; + break; + } + + /* Check for invalid packet type */ + if (!skb) + return ERR_PTR(-EILSEQ); + + count -= 1; + buffer += 1; + } + + len = min_t(uint, bt_cb(skb)->expect - skb->len, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + + /* Check for partial packet */ + if (skb->len < bt_cb(skb)->expect) + continue; + + for (i = 0; i < pkts_count; i++) { + if (bt_cb(skb)->pkt_type == (&pkts[i])->type) + break; + } + + if (i >= pkts_count) { + kfree_skb(skb); + return ERR_PTR(-EILSEQ); + } + + if (skb->len == (&pkts[i])->hlen) { + u16 dlen; + + switch ((&pkts[i])->lsize) { + case 0: + /* No variable data length */ + dlen = 0; + break; + case 1: + /* Single octet variable length */ + dlen = skb->data[(&pkts[i])->loff]; + bt_cb(skb)->expect += dlen; + + if (skb_tailroom(skb) < dlen) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + break; + case 2: + /* Double octet variable length */ + dlen = get_unaligned_le16(skb->data + + (&pkts[i])->loff); + bt_cb(skb)->expect += dlen; + + if (skb_tailroom(skb) < dlen) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + break; + default: + /* Unsupported variable length */ + kfree_skb(skb); + return ERR_PTR(-EILSEQ); + } + + if (!dlen) { + /* No more data, complete frame */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + } + } else { + /* Complete frame */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + } + } + + return skb; +} +EXPORT_SYMBOL_GPL(h4_recv_buf); diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index abee2216fdeb..18caf976c137 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -192,7 +192,7 @@ static void h5_peer_reset(struct hci_uart *hu) static int h5_open(struct hci_uart *hu) { struct h5 *h5; - const unsigned char sync[] = { 0x01, 0x7e }; + /* const unsigned char sync[] = { 0x01, 0x7e }; */ BT_DBG("hu %p", hu); @@ -214,11 +214,16 @@ static int h5_open(struct hci_uart *hu) h5->tx_win = H5_TX_WIN_MAX; - set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); + /* set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); */ + + /* Firmware was already download by userspace app rtk_hciattach */ + h5->state = H5_ACTIVE; + hci_uart_init_ready(hu); /* Send initial sync request */ - h5_link_control(hu, sync, sizeof(sync)); - mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); + /* h5_link_control(hu, sync, sizeof(sync)); + * mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); + */ return 0; } @@ -380,6 +385,11 @@ static void h5_complete_rx_pkt(struct hci_uart *hu) static int h5_rx_crc(struct hci_uart *hu, unsigned char c) { + struct h5 *h5 = hu->priv; + + /* TODO: crc check */ + skb_trim(h5->rx_skb, h5->rx_skb->len - 2); + h5_complete_rx_pkt(hu); return 0; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 6b6cbb9315e0..61bb2192a80b 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -24,6 +24,7 @@ */ #include + #include #include #include @@ -31,6 +32,7 @@ #include #include #include + #include #include #include @@ -38,31 +40,20 @@ #include #include #include -#include +#include + #include #include +#include "btintel.h" +#include "btbcm.h" #include "hci_uart.h" -#ifdef BTCOEX -#include "rtk_coex.h" -#endif - -#define VERSION "2.2" - -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0) -#define GET_DRV_DATA(x) hci_get_drvdata(x) -#else -#define GET_DRV_DATA(x) (struct hci_uart *)(x->driver_data) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) -static int reset = 0; -#endif +#define VERSION "2.3" -static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; +static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; -int hci_uart_register_proto(struct hci_uart_proto *p) +int hci_uart_register_proto(const struct hci_uart_proto *p) { if (p->id >= HCI_UART_MAX_PROTO) return -EINVAL; @@ -72,10 +63,12 @@ int hci_uart_register_proto(struct hci_uart_proto *p) hup[p->id] = p; + BT_INFO("HCI UART protocol %s registered", p->name); + return 0; } -int hci_uart_unregister_proto(struct hci_uart_proto *p) +int hci_uart_unregister_proto(const struct hci_uart_proto *p) { if (p->id >= HCI_UART_MAX_PROTO) return -EINVAL; @@ -88,7 +81,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p) return 0; } -static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) +static const struct hci_uart_proto *hci_uart_get_proto(unsigned int id) { if (id >= HCI_UART_MAX_PROTO) return NULL; @@ -130,12 +123,6 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = hu->hdev; - struct sk_buff *skb; -#endif - if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -143,39 +130,11 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) schedule_work(&hu->write_work); -#else - restart: - clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); - - while ((skb = hci_uart_dequeue(hu))) { - int len; - - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - len = tty->ops->write(tty, skb->data, skb->len); - hdev->stat.byte_tx += len; - - skb_pull(skb, len); - if (skb->len) { - hu->tx_skb = skb; - break; - } - - hci_uart_tx_complete(hu, bt_cb(skb)->pkt_type); - kfree_skb(skb); - } - - if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) - goto restart; - - clear_bit(HCI_UART_SENDING, &hu->tx_state); -#endif return 0; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) static void hci_uart_write_work(struct work_struct *work) { struct hci_uart *hu = container_of(work, struct hci_uart, write_work); @@ -187,7 +146,7 @@ static void hci_uart_write_work(struct work_struct *work) * and error value ? */ - restart: +restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); while ((skb = hci_uart_dequeue(hu))) { @@ -211,9 +170,36 @@ static void hci_uart_write_work(struct work_struct *work) goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); - return; } -#endif + +static void hci_uart_init_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); + int err; + + if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return; + + err = hci_register_dev(hu->hdev); + if (err < 0) { + BT_ERR("Can't register HCI device"); + hci_free_dev(hu->hdev); + hu->hdev = NULL; + hu->proto->close(hu); + } + + set_bit(HCI_UART_REGISTERED, &hu->flags); +} + +int hci_uart_init_ready(struct hci_uart *hu) +{ + if (!test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return -EALREADY; + + schedule_work(&hu->init_ready); + + return 0; +} /* ------- Interface to HCI layer ------ */ /* Initialize device */ @@ -222,34 +208,26 @@ static int hci_uart_open(struct hci_dev *hdev) BT_DBG("%s %p", hdev->name, hdev); /* Nothing to do for UART driver */ - - set_bit(HCI_RUNNING, &hdev->flags); - -#ifdef BTCOEX - rtk_btcoex_open(hdev); -#endif - return 0; } /* Reset device */ static int hci_uart_flush(struct hci_dev *hdev) { - struct hci_uart *hu = GET_DRV_DATA(hdev); //(struct hci_uart *) hdev->driver_data; + struct hci_uart *hu = hci_get_drvdata(hdev); struct tty_struct *tty = hu->tty; BT_DBG("hdev %p tty %p", hdev, tty); if (hu->tx_skb) { - kfree_skb(hu->tx_skb); - hu->tx_skb = NULL; + kfree_skb(hu->tx_skb); hu->tx_skb = NULL; } /* Flush any pending characters in the driver and discipline. */ tty_ldisc_flush(tty); tty_driver_flush_buffer(tty); - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hu->proto->flush(hu); return 0; @@ -260,60 +238,17 @@ static int hci_uart_close(struct hci_dev *hdev) { BT_DBG("hdev %p", hdev); - - /* When in kernel 4.4.0 and greater, the HCI_RUNNING bit is - * cleared in hci_dev_do_close(). */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) - return 0; -#else - if (test_bit(HCI_RUNNING, &hdev->flags)) { - BT_ERR("HCI_RUNNING is not cleared before."); - return -1; - } -#endif - hci_uart_flush(hdev); hdev->flush = NULL; - -#ifdef BTCOEX - rtk_btcoex_close(); -#endif - return 0; } /* Send frames from HCI layer */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) -int hci_uart_send_frame(struct sk_buff *skb) -#else -int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) -#endif +static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - struct hci_dev *hdev = (struct hci_dev *)skb->dev; -#endif - struct hci_uart *hu; - - if (!hdev) { - BT_ERR("Frame for unknown device (hdev=NULL)"); - return -ENODEV; - } + struct hci_uart *hu = hci_get_drvdata(hdev); - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return -EBUSY; - - hu = GET_DRV_DATA(hdev); //(struct hci_uart *) hdev->driver_data; - - BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, - skb->len); - -#ifdef BTCOEX - if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) - rtk_btcoex_parse_cmd(skb->data, skb->len); - if (bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT) - rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len); -#endif + BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); hu->proto->enqueue(hu, skb); @@ -322,21 +257,180 @@ int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) -static void hci_uart_destruct(struct hci_dev *hdev) +/* Flow control or un-flow control the device */ +void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) { - if (!hdev) - return; + struct tty_struct *tty = hu->tty; + struct ktermios ktermios; + int status; + unsigned int set = 0; + unsigned int clear = 0; + + if (enable) { + /* Disable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag &= ~CRTSCTS; + status = tty_set_termios(tty, &ktermios); + BT_DBG("Disabling hardware flow control: %s", + status ? "failed" : "success"); + + /* Clear RTS to prevent the device from sending */ + /* Most UARTs need OUT2 to enable interrupts */ + status = tty->driver->ops->tiocmget(tty); + BT_DBG("Current tiocm 0x%x", status); + + set &= ~(TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + BT_DBG("Clearing RTS: %s", status ? "failed" : "success"); + } else { + /* Set RTS to allow the device to send again */ + status = tty->driver->ops->tiocmget(tty); + BT_DBG("Current tiocm 0x%x", status); + + set |= (TIOCM_OUT2 | TIOCM_RTS); + clear = ~set; + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | + TIOCM_OUT2 | TIOCM_LOOP; + status = tty->driver->ops->tiocmset(tty, set, clear); + BT_DBG("Setting RTS: %s", status ? "failed" : "success"); + + /* Re-enable hardware flow control */ + ktermios = tty->termios; + ktermios.c_cflag |= CRTSCTS; + status = tty_set_termios(tty, &ktermios); + BT_DBG("Enabling hardware flow control: %s", + status ? "failed" : "success"); + } +} + +void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, + unsigned int oper_speed) +{ + hu->init_speed = init_speed; + hu->oper_speed = oper_speed; +} + +void hci_uart_init_tty(struct hci_uart *hu) +{ + struct tty_struct *tty = hu->tty; + struct ktermios ktermios; + + /* Bring the UART into a known 8 bits no parity hw fc state */ + ktermios = tty->termios; + ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | + INLCR | IGNCR | ICRNL | IXON); + ktermios.c_oflag &= ~OPOST; + ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ktermios.c_cflag &= ~(CSIZE | PARENB); + ktermios.c_cflag |= CS8; + ktermios.c_cflag |= CRTSCTS; + + /* tty_set_termios() return not checked as it is always 0 */ + tty_set_termios(tty, &ktermios); +} + +void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed) +{ + struct tty_struct *tty = hu->tty; + struct ktermios ktermios; + + ktermios = tty->termios; + ktermios.c_cflag &= ~CBAUD; + tty_termios_encode_baud_rate(&ktermios, speed, speed); + + /* tty_set_termios() return not checked as it is always 0 */ + tty_set_termios(tty, &ktermios); - BT_DBG("%s", hdev->name); - kfree(hdev->driver_data); + BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name, + tty->termios.c_ispeed, tty->termios.c_ospeed); } + +static int hci_uart_setup(struct hci_dev *hdev) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct hci_rp_read_local_version *ver; + struct sk_buff *skb; + unsigned int speed; + int err; + + /* Init speed if any */ + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + else + speed = 0; + + if (speed) + hci_uart_set_baudrate(hu, speed); + + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + else + speed = 0; + + if (hu->proto->set_baudrate && speed) { + err = hu->proto->set_baudrate(hu, speed); + if (!err) + hci_uart_set_baudrate(hu, speed); + } + + if (hu->proto->setup) + return hu->proto->setup(hu); + + if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags)) + return 0; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading local version information failed (%ld)", + hdev->name, PTR_ERR(skb)); + return 0; + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: Event length mismatch for version information", + hdev->name); + goto done; + } + + ver = (struct hci_rp_read_local_version *)skb->data; + + switch (le16_to_cpu(ver->manufacturer)) { +#ifdef CONFIG_BT_HCIUART_INTEL + case 2: + hdev->set_bdaddr = btintel_set_bdaddr; + btintel_check_bdaddr(hdev); + break; +#endif +#ifdef CONFIG_BT_HCIUART_BCM + case 15: + hdev->set_bdaddr = btbcm_set_bdaddr; + btbcm_check_bdaddr(hdev); + break; #endif + } + +done: + kfree_skb(skb); + return 0; +} /* ------ LDISC part ------ */ /* hci_uart_tty_open * - * Called when line discipline changed to HCI_UART. + * Called when line discipline changed to HCI_UART. * * Arguments: * tty pointer to tty info structure @@ -345,21 +439,17 @@ static void hci_uart_destruct(struct hci_dev *hdev) */ static int hci_uart_tty_open(struct tty_struct *tty) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu; BT_DBG("tty %p", tty); - /* FIXME: This btw is bogus, nothing requires the old ldisc to clear - the pointer */ - if (hu) - return -EEXIST; - /* Error if the tty has no write op instead of leaving an exploitable hole */ if (tty->ops->write == NULL) return -EOPNOTSUPP; - if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) { + hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL); + if (!hu) { BT_ERR("Can't allocate control structure"); return -ENFILE; } @@ -368,11 +458,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) hu->tty = tty; tty->receive_room = 65536; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); -#endif - - spin_lock_init(&hu->rx_lock); /* Flush any pending characters in the driver and line discipline. */ @@ -388,47 +475,52 @@ static int hci_uart_tty_open(struct tty_struct *tty) /* hci_uart_tty_close() * - * Called when the line discipline is changed to something - * else, the tty is closed, or the tty detects a hangup. + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. */ static void hci_uart_tty_close(struct tty_struct *tty) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; + struct hci_dev *hdev; BT_DBG("tty %p", tty); /* Detach from the tty */ tty->disc_data = NULL; - if (hu) { - struct hci_dev *hdev = hu->hdev; + if (!hu) + return; + + hdev = hu->hdev; + if (hdev) + hci_uart_close(hdev); - if (hdev) - hci_uart_close(hdev); + cancel_work_sync(&hu->write_work); - if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { - // hu->proto->close(hu); - if (hdev) { + if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) { + if (hdev) { + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); - hci_free_dev(hdev); - } - hu->proto->close(hu); + hci_free_dev(hdev); } - kfree(hu); + hu->proto->close(hu); } + clear_bit(HCI_UART_PROTO_SET, &hu->flags); + + kfree(hu); } /* hci_uart_tty_wakeup() * - * Callback for transmit wakeup. Called when low level - * device driver can accept more send data. + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. * * Arguments: tty pointer to associated tty instance data * Return Value: None */ static void hci_uart_tty_wakeup(struct tty_struct *tty) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; BT_DBG(""); @@ -440,14 +532,14 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) if (tty != hu->tty) return; - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hci_uart_tx_wakeup(hu); } /* hci_uart_tty_receive() * - * Called by tty low level driver when receive data is - * available. + * Called by tty low level driver when receive data is + * available. * * Arguments: tty pointer to tty isntance data * data pointer to received data @@ -456,21 +548,24 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) * * Return Value: None */ -static void hci_uart_tty_receive(struct tty_struct *tty, const u8 * data, +static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; if (!hu || tty != hu->tty) return; - if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) return; - spin_lock(&hu->rx_lock); - hu->proto->recv(hu, (void *)data, count); - hu->hdev->stat.byte_rx += count; - spin_unlock(&hu->rx_lock); + /* It does not need a lock here as it is already protected by a mutex in + * tty caller + */ + hu->proto->recv(hu, data, count); + + if (hu->hdev) + hu->hdev->stat.byte_rx += count; tty_unthrottle(tty); } @@ -479,7 +574,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) { struct hci_dev *hdev; - BT_INFO("hci_uart_register_dev"); + BT_DBG(""); /* Initialize and register HCI device */ hdev = hci_alloc_dev(); @@ -490,68 +585,54 @@ static int hci_uart_register_dev(struct hci_uart *hu) hu->hdev = hdev; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33) hdev->bus = HCI_UART; -#else - hdev->type = HCI_UART; -#endif - -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0) hci_set_drvdata(hdev, hu); -#else - hdev->driver_data = hu; -#endif - hdev->open = hci_uart_open; - hdev->close = hci_uart_close; - hdev->flush = hci_uart_flush; - hdev->send = hci_uart_send_frame; -#if ( (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)) ) - hdev->parent = hu->tty->dev; -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) - hdev->destruct = hci_uart_destruct; - hdev->owner = THIS_MODULE; -#endif + /* Only when vendor specific setup callback is provided, consider + * the manufacturer information valid. This avoids filling in the + * value for Ericsson when nothing is specified. + */ + if (hu->proto->setup) + hdev->manufacturer = hu->proto->manufacturer; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) - if (!reset) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + hdev->open = hci_uart_open; + hdev->close = hci_uart_close; + hdev->flush = hci_uart_flush; + hdev->send = hci_uart_send_frame; + hdev->setup = hci_uart_setup; + 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); -#else - if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) - set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); + if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) + set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); -#endif + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) hdev->dev_type = HCI_AMP; else hdev->dev_type = HCI_BREDR; -#endif + + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return 0; if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); return -ENODEV; } -#ifdef BTCOEX - rtk_btcoex_probe(hdev); -#endif + + set_bit(HCI_UART_REGISTERED, &hu->flags); return 0; } static int hci_uart_set_proto(struct hci_uart *hu, int id) { - struct hci_uart_proto *p; + const struct hci_uart_proto *p; int err; p = hci_uart_get_proto(id); @@ -563,10 +644,11 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) return err; hu->proto = p; + set_bit(HCI_UART_PROTO_READY, &hu->flags); - /* Initialize and register HCI dev */ err = hci_uart_register_dev(hu); if (err) { + clear_bit(HCI_UART_PROTO_READY, &hu->flags); p->close(hu); return err; } @@ -574,6 +656,23 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) return 0; } +static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) +{ + unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | + BIT(HCI_UART_RESET_ON_INIT) | + BIT(HCI_UART_CREATE_AMP) | + BIT(HCI_UART_INIT_PENDING) | + BIT(HCI_UART_EXT_CONFIG) | + BIT(HCI_UART_VND_DETECT); + + if (flags & ~valid_flags) + return -EINVAL; + + hu->hdev_flags = flags; + + return 0; +} + /* hci_uart_tty_ioctl() * * Process IOCTL system call for the tty device. @@ -590,7 +689,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; int err = 0; BT_DBG(""); @@ -617,14 +716,16 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, return -EUNATCH; case HCIUARTGETDEVICE: - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) return hu->hdev->id; return -EUNATCH; case HCIUARTSETFLAGS: if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) return -EBUSY; - hu->hdev_flags = arg; + err = hci_uart_set_flags(hu, arg); + if (err) + return err; break; case HCIUARTGETFLAGS: @@ -633,7 +734,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, default: err = n_tty_ioctl_helper(tty, file, cmd, arg); break; - }; + } return err; } @@ -642,7 +743,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, * We don't provide read/write/poll interface for user space. */ static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user * buf, size_t nr) + unsigned char __user *buf, size_t nr) { return 0; } @@ -654,7 +755,7 @@ static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, } static unsigned int hci_uart_tty_poll(struct tty_struct *tty, - struct file *filp, poll_table * wait) + struct file *filp, poll_table *wait) { return 0; } @@ -669,34 +770,47 @@ static int __init hci_uart_init(void) /* Register the tty discipline */ memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc)); - hci_uart_ldisc.magic = TTY_LDISC_MAGIC; - hci_uart_ldisc.name = "n_hci"; - hci_uart_ldisc.open = hci_uart_tty_open; - hci_uart_ldisc.close = hci_uart_tty_close; - hci_uart_ldisc.read = hci_uart_tty_read; - hci_uart_ldisc.write = hci_uart_tty_write; - hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; - hci_uart_ldisc.poll = hci_uart_tty_poll; - hci_uart_ldisc.receive_buf = hci_uart_tty_receive; - hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; - hci_uart_ldisc.owner = THIS_MODULE; - - if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { + hci_uart_ldisc.magic = TTY_LDISC_MAGIC; + hci_uart_ldisc.name = "n_hci"; + hci_uart_ldisc.open = hci_uart_tty_open; + hci_uart_ldisc.close = hci_uart_tty_close; + hci_uart_ldisc.read = hci_uart_tty_read; + hci_uart_ldisc.write = hci_uart_tty_write; + hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.poll = hci_uart_tty_poll; + hci_uart_ldisc.receive_buf = hci_uart_tty_receive; + hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; + hci_uart_ldisc.owner = THIS_MODULE; + + err = tty_register_ldisc(N_HCI, &hci_uart_ldisc); + if (err) { BT_ERR("HCI line discipline registration failed. (%d)", err); return err; } + #ifdef CONFIG_BT_HCIUART_H4 h4_init(); #endif -// -//Realtek_add_start -//add realtek h5 support -//#ifdef CONFIG_BT_HCIUART_RTKH5 +#ifdef CONFIG_BT_HCIUART_BCSP + bcsp_init(); +#endif +#ifdef CONFIG_BT_HCIUART_LL + ll_init(); +#endif +#ifdef CONFIG_BT_HCIUART_ATH3K + ath_init(); +#endif +#ifdef CONFIG_BT_HCIUART_3WIRE h5_init(); -//#endif - -#ifdef BTCOEX - rtk_btcoex_init(); +#endif +#ifdef CONFIG_BT_HCIUART_INTEL + intel_init(); +#endif +#ifdef CONFIG_BT_HCIUART_BCM + bcm_init(); +#endif +#ifdef CONFIG_BT_HCIUART_QCA + qca_init(); #endif return 0; @@ -709,7 +823,6 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_H4 h4_deinit(); #endif -/* #ifdef CONFIG_BT_HCIUART_BCSP bcsp_deinit(); #endif @@ -719,28 +832,28 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_ATH3K ath_deinit(); #endif -*/ -//#ifdef CONFIG_BT_HCIUART_RTKH5 +#ifdef CONFIG_BT_HCIUART_3WIRE h5_deinit(); -//#endif +#endif +#ifdef CONFIG_BT_HCIUART_INTEL + intel_deinit(); +#endif +#ifdef CONFIG_BT_HCIUART_BCM + bcm_deinit(); +#endif +#ifdef CONFIG_BT_HCIUART_QCA + qca_deinit(); +#endif /* Release tty registration of line discipline */ err = tty_unregister_ldisc(N_HCI); if (err) BT_ERR("Can't unregister HCI line discipline (%d)", err); -#ifdef BTCOEX - rtk_btcoex_exit(); -#endif } module_init(hci_uart_init); module_exit(hci_uart_exit); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) -module_param(reset, bool, 0644); -MODILE_PARAM_DESC(reset, "Send HCI reset command on initialization"); -#endif - MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/hci_rtk_h5.c b/drivers/bluetooth/hci_rtk_h5.c deleted file mode 100644 index 294dc3efed9f..000000000000 --- a/drivers/bluetooth/hci_rtk_h5.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - * - * Bluetooth HCI UART driver - * - * Copyright (C) 2011-2014 wifi_fae - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hci_uart.h" - -#ifdef BTCOEX -#include "rtk_coex.h" -#endif - -//#define VERSION "1.0" - -static int txcrc = 1; -//static int hciextn = 1; - -#define H5_TXWINSIZE 4 -#define H5_ACK_PKT 0x00 -#define H5_LE_PKT 0x0F -#define H5_VDRSPEC_PKT 0x0E - -struct h5_struct { - struct sk_buff_head unack; /* Unack'ed packets queue */ - struct sk_buff_head rel; /* Reliable packets queue */ - struct sk_buff_head unrel; /* Unreliable packets queue */ - - unsigned long rx_count; - struct sk_buff *rx_skb; - u8 rxseq_txack; /* rxseq == txack. */ - u8 rxack; /* Last packet sent by us that the peer ack'ed */ - struct timer_list th5; - - enum { - H5_W4_PKT_DELIMITER, - H5_W4_PKT_START, - H5_W4_HDR, - H5_W4_DATA, - H5_W4_CRC - } rx_state; - - enum { - H5_ESCSTATE_NOESC, - H5_ESCSTATE_ESC - } rx_esc_state; - - u8 use_crc; - u16 message_crc; - u8 txack_req; /* Do we need to send ack's to the peer? */ - - /* Reliable packet sequence number - used to assign seq to each rel pkt. */ - u8 msgq_txseq; -}; - -/* ---- H5 CRC calculation ---- */ - -/* Table for calculating CRC for polynomial 0x1021, LSB processed first, -initial value 0xffff, bits shifted in reverse order. */ - -static const u16 crc_table[] = { - 0x0000, 0x1081, 0x2102, 0x3183, - 0x4204, 0x5285, 0x6306, 0x7387, - 0x8408, 0x9489, 0xa50a, 0xb58b, - 0xc60c, 0xd68d, 0xe70e, 0xf78f -}; - -/* Initialise the crc calculator */ -#define H5_CRC_INIT(x) x = 0xffff - -/* - Update crc with next data byte - - Implementation note - The data byte is treated as two nibbles. The crc is generated - in reverse, i.e., bits are fed into the register from the top. -*/ -static void h5_crc_update(u16 * crc, u8 d) -{ - u16 reg = *crc; - - reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; - reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; - - *crc = reg; -} - -/* ---- H5 core ---- */ - -static void h5_slip_msgdelim(struct sk_buff *skb) -{ - const char pkt_delim = 0xc0; - - memcpy(skb_put(skb, 1), &pkt_delim, 1); -} - -static void h5_slip_one_byte(struct sk_buff *skb, u8 c) -{ - const char esc_c0[2] = { 0xdb, 0xdc }; - const char esc_db[2] = { 0xdb, 0xdd }; - const char esc_11[2] = { 0xdb, 0xde }; - const char esc_13[2] = { 0xdb, 0xdf }; - - switch (c) { - case 0xc0: - memcpy(skb_put(skb, 2), &esc_c0, 2); - break; - case 0xdb: - memcpy(skb_put(skb, 2), &esc_db, 2); - break; - case 0x11: - memcpy(skb_put(skb, 2), &esc_11, 2); - break; - case 0x13: - memcpy(skb_put(skb, 2), &esc_13, 2); - break; - default: - memcpy(skb_put(skb, 1), &c, 1); - } -} - -static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) -{ - struct h5_struct *h5 = hu->priv; - - if (skb->len > 0xFFF) { //Pkt length must be less than 4095 bytes - BT_ERR("Packet too long"); - kfree_skb(skb); - return 0; - } - - switch (bt_cb(skb)->pkt_type) { - case HCI_ACLDATA_PKT: - case HCI_COMMAND_PKT: - skb_queue_tail(&h5->rel, skb); - break; - - case HCI_SCODATA_PKT: - skb_queue_tail(&h5->unrel, skb); - break; - case H5_LE_PKT: - case H5_ACK_PKT: - case H5_VDRSPEC_PKT: - skb_queue_tail(&h5->unrel, skb); /* 3-wire LinkEstablishment */ - break; - - default: - BT_ERR("Unknown packet type"); - kfree_skb(skb); - break; - } - - return 0; -} - -static struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 * data, - int len, int pkt_type) -{ - struct sk_buff *nskb; - u8 hdr[4], chan; - u16 H5_CRC_INIT(h5_txmsg_crc); - int rel, i; - - switch (pkt_type) { - case HCI_ACLDATA_PKT: - chan = 2; /* 3-wire ACL channel */ - rel = 1; /* reliable channel */ - break; - case HCI_COMMAND_PKT: - chan = 1; /* 3-wire cmd channel */ - rel = 1; /* reliable channel */ - break; - case HCI_EVENT_PKT: - chan = 4; /* 3-wire cmd channel */ - rel = 1; /* reliable channel */ - break; - case HCI_SCODATA_PKT: - chan = 3; /* 3-wire SCO channel */ - rel = 0; /* unreliable channel */ - break; - case H5_LE_PKT: - chan = 15; /* 3-wire LinkEstablishment channel */ - rel = 0; /* unreliable channel */ - break; - case H5_ACK_PKT: - chan = 0; /* 3-wire ACK channel */ - rel = 0; /* unreliable channel */ - break; - case H5_VDRSPEC_PKT: - chan = 14; /* 3-wire Vendor Specific channel */ - rel = 0; /* unreliable channel */ - break; - default: - BT_ERR("Unknown packet type"); - return NULL; - } - - /* Max len of packet: (original len +4(h5 hdr) +2(crc))*2 - (because bytes 0xc0 and 0xdb are escaped, worst case is - when the packet is all made of 0xc0 and 0xdb :) ) - + 2 (0xc0 delimiters at start and end). */ - - nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); - if (!nskb) - return NULL; - - bt_cb(nskb)->pkt_type = pkt_type; - - h5_slip_msgdelim(nskb); - - hdr[0] = h5->rxseq_txack << 3; - h5->txack_req = 0; - BT_DBG("We request packet no %u to card", h5->rxseq_txack); - - if (rel) { - hdr[0] |= 0x80 + h5->msgq_txseq; - BT_DBG("Sending packet with seqno %u", h5->msgq_txseq); - h5->msgq_txseq = (h5->msgq_txseq + 1) & 0x07; - } - - if (h5->use_crc) - hdr[0] |= 0x40; - - hdr[1] = ((len << 4) & 0xff) | chan; - hdr[2] = len >> 4; - hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); - - /* Put H5 header */ - for (i = 0; i < 4; i++) { - h5_slip_one_byte(nskb, hdr[i]); - - if (h5->use_crc) - h5_crc_update(&h5_txmsg_crc, hdr[i]); - } - - /* Put payload */ - for (i = 0; i < len; i++) { - h5_slip_one_byte(nskb, data[i]); - - if (h5->use_crc) - h5_crc_update(&h5_txmsg_crc, data[i]); - } - - /* Put CRC */ - if (h5->use_crc) { - h5_txmsg_crc = bitrev16(h5_txmsg_crc); - h5_slip_one_byte(nskb, (u8) ((h5_txmsg_crc >> 8) & 0x00ff)); - h5_slip_one_byte(nskb, (u8) (h5_txmsg_crc & 0x00ff)); - } - - h5_slip_msgdelim(nskb); - return nskb; -} - -/* This is a rewrite of pkt_avail in AH5 */ -static struct sk_buff *h5_dequeue(struct hci_uart *hu) -{ - struct h5_struct *h5 = hu->priv; - unsigned long flags; - struct sk_buff *skb; - - /* First of all, check for unreliable messages in the queue, - since they have priority */ - - if ((skb = skb_dequeue(&h5->unrel)) != NULL) { - struct sk_buff *nskb = - h5_prepare_pkt(h5, skb->data, skb->len, - bt_cb(skb)->pkt_type); - if (nskb) { - kfree_skb(skb); - return nskb; - } else { - skb_queue_head(&h5->unrel, skb); - BT_ERR - ("Could not dequeue pkt because alloc_skb failed"); - } - } - - /* Now, try to send a reliable pkt. We can only send a - reliable packet if the number of packets sent but not yet ack'ed - is < than the winsize */ - - spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); - - if (h5->unack.qlen < H5_TXWINSIZE - && (skb = skb_dequeue(&h5->rel)) != NULL) { - struct sk_buff *nskb = - h5_prepare_pkt(h5, skb->data, skb->len, - bt_cb(skb)->pkt_type); - if (nskb) { - __skb_queue_tail(&h5->unack, skb); - mod_timer(&h5->th5, jiffies + HZ / 4); - spin_unlock_irqrestore(&h5->unack.lock, flags); - return nskb; - } else { - skb_queue_head(&h5->rel, skb); - BT_ERR - ("Could not dequeue pkt because alloc_skb failed"); - } - } - - spin_unlock_irqrestore(&h5->unack.lock, flags); - - /* We could not send a reliable packet, either because there are - none or because there are too many unack'ed pkts. Did we receive - any packets we have not acknowledged yet ? */ - - if (h5->txack_req) { - /* if so, craft an empty ACK pkt and send it on H5 unreliable - channel 0 */ - struct sk_buff *nskb = h5_prepare_pkt(h5, NULL, 0, H5_ACK_PKT); - return nskb; - } - - /* We have nothing to send */ - return NULL; -} - -static int h5_flush(struct hci_uart *hu) -{ - BT_DBG("hu %p", hu); - return 0; -} - -/* Remove ack'ed packets */ -static void h5_pkt_cull(struct h5_struct *h5) -{ - struct sk_buff *skb, *tmp; - unsigned long flags; - int i, pkts_to_be_removed; - u8 seqno; - - spin_lock_irqsave(&h5->unack.lock, flags); - - pkts_to_be_removed = skb_queue_len(&h5->unack); - seqno = h5->msgq_txseq; - - while (pkts_to_be_removed) { - if (h5->rxack == seqno) - break; - pkts_to_be_removed--; - seqno = (seqno - 1) & 0x07; - } - - if (h5->rxack != seqno) - BT_ERR("Peer acked invalid packet"); - - BT_DBG("Removing %u pkts out of %u, up to seqno %u", - pkts_to_be_removed, skb_queue_len(&h5->unack), - (seqno - 1) & 0x07); - - i = 0; - skb_queue_walk_safe(&h5->unack, skb, tmp) { - if (i >= pkts_to_be_removed) - break; - i++; - - __skb_unlink(skb, &h5->unack); - kfree_skb(skb); - } - - if (skb_queue_empty(&h5->unack)) - del_timer(&h5->th5); - - spin_unlock_irqrestore(&h5->unack.lock, flags); - - if (i != pkts_to_be_removed) - BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); -} - -/* Handle H5 link-establishment packets. When we - detect a "sync" packet, symptom that the BT module has reset, - we do nothing :) (yet) */ -#if 0 -static void h5_handle_le_pkt(struct hci_uart *hu) -{ - struct h5_struct *h5 = hu->priv; - u8 conf_pkt[2] = { 0x03, 0xfc }; - u8 conf_rsp_pkt[3] = { 0x04, 0x7b, 0x00 }; - u8 sync_pkt[2] = { 0x01, 0x7e }; - u8 sync_rsp_pkt[2] = { 0x02, 0x7d }; - - u8 wakeup_pkt[2] = { 0x05, 0xfa }; - u8 woken_pkt[2] = { 0x06, 0xf9 }; - u8 sleep_pkt[2] = { 0x07, 0x78 }; - - /* spot "conf" pkts and reply with a "conf rsp" pkt */ - if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_skb->data[4], conf_pkt, 2)) { - struct sk_buff *nskb = alloc_skb(3, GFP_ATOMIC); - - BT_DBG("Found a LE conf pkt"); - if (!nskb) - return; - - conf_rsp_pkt[2] |= txcrc << 0x4; //crc check enable, version no = 0. needed to be as avariable. - memcpy(skb_put(nskb, 3), conf_rsp_pkt, 3); - bt_cb(nskb)->pkt_type = H5_LE_PKT; - - skb_queue_head(&h5->unrel, nskb); - hci_uart_tx_wakeup(hu); - } - /* spot "conf resp" pkts */ - else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_skb->data[4], conf_rsp_pkt, 2)) { - BT_DBG("Found a LE conf resp pkt, device go into active state"); - txcrc = (h5->rx_skb->data[6] >> 0x4) & 0x1; - } - - /* Spot "sync" pkts. If we find one...disaster! */ - else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_skb->data[4], sync_pkt, 2)) { - BT_ERR("Found a LE sync pkt, card has reset"); - //DO Something here - } - /* Spot "sync resp" pkts. If we find one...disaster! */ - else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_skb->data[4], sync_rsp_pkt, 2)) { - BT_ERR - ("Found a LE sync resp pkt, device go into initialized state"); - // DO Something here - } - /* Spot "wakeup" pkts. reply woken message when in active mode */ - else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_skb->data[4], wakeup_pkt, 2)) { - struct sk_buff *nskb = alloc_skb(2, GFP_ATOMIC); - - BT_ERR("Found a LE Wakeup pkt, and reply woken message"); - // DO Something here - - memcpy(skb_put(nskb, 2), woken_pkt, 2); - bt_cb(nskb)->pkt_type = H5_LE_PKT; - - skb_queue_head(&h5->unrel, nskb); - hci_uart_tx_wakeup(hu); - } - /* Spot "woken" pkts. receive woken message from device */ - else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_skb->data[4], woken_pkt, 2)) { - BT_ERR("Found a LE woken pkt from device"); - // DO Something here - } - /* Spot "Sleep" pkts */ - else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 && - !memcmp(&h5->rx_indent: Standard input:620: Error:Unmatched 'else' -skb->data[4], sleep_pkt, 2)) { - BT_ERR("Found a LE Sleep pkt"); - // DO Something here - } -} -#endif - -static inline void h5_unslip_one_byte(struct h5_struct *h5, unsigned char byte) -{ - const u8 c0 = 0xc0, db = 0xdb; - const u8 oof1 = 0x11, oof2 = 0x13; - - switch (h5->rx_esc_state) { - case H5_ESCSTATE_NOESC: - switch (byte) { - case 0xdb: - h5->rx_esc_state = H5_ESCSTATE_ESC; - break; - default: - memcpy(skb_put(h5->rx_skb, 1), &byte, 1); - if ((h5->rx_skb->data[0] & 0x40) != 0 && - h5->rx_state != H5_W4_CRC) - h5_crc_update(&h5->message_crc, byte); - h5->rx_count--; - } - break; - - case H5_ESCSTATE_ESC: - switch (byte) { - case 0xdc: - memcpy(skb_put(h5->rx_skb, 1), &c0, 1); - if ((h5->rx_skb->data[0] & 0x40) != 0 && - h5->rx_state != H5_W4_CRC) - h5_crc_update(&h5->message_crc, 0xc0); - h5->rx_esc_state = H5_ESCSTATE_NOESC; - h5->rx_count--; - break; - - case 0xdd: - memcpy(skb_put(h5->rx_skb, 1), &db, 1); - if ((h5->rx_skb->data[0] & 0x40) != 0 && - h5->rx_state != H5_W4_CRC) - h5_crc_update(&h5->message_crc, 0xdb); - h5->rx_esc_state = H5_ESCSTATE_NOESC; - h5->rx_count--; - break; - - case 0xde: - memcpy(skb_put(h5->rx_skb, 1), &oof1, 1); - if ((h5->rx_skb->data[0] & 0x40) != 0 - && h5->rx_state != H5_W4_CRC) - h5_crc_update(&h5->message_crc, oof1); - h5->rx_esc_state = H5_ESCSTATE_NOESC; - h5->rx_count--; - break; - - case 0xdf: - memcpy(skb_put(h5->rx_skb, 1), &oof2, 1); - if ((h5->rx_skb->data[0] & 0x40) != 0 - && h5->rx_state != H5_W4_CRC) - h5_crc_update(&h5->message_crc, oof2); - h5->rx_esc_state = H5_ESCSTATE_NOESC; - h5->rx_count--; - break; - - default: - BT_ERR("Invalid byte %02x after esc byte", byte); - kfree_skb(h5->rx_skb); - h5->rx_skb = NULL; - h5->rx_state = H5_W4_PKT_DELIMITER; - h5->rx_count = 0; - } - } -} - -static void h5_complete_rx_pkt(struct hci_uart *hu) -{ - struct h5_struct *h5 = hu->priv; - int pass_up; - - if (h5->rx_skb->data[0] & 0x80) { /* reliable pkt */ - BT_DBG("Received seqno %u from card", h5->rxseq_txack); - h5->rxseq_txack++; - h5->rxseq_txack %= 0x8; - h5->txack_req = 1; - - /* If needed, transmit an ack pkt */ - hci_uart_tx_wakeup(hu); - } - - h5->rxack = (h5->rx_skb->data[0] >> 3) & 0x07; - BT_DBG("Request for pkt %u from card", h5->rxack); - - h5_pkt_cull(h5); - - if ((h5->rx_skb->data[1] & 0x0f) == 2 && h5->rx_skb->data[0] & 0x80) { - bt_cb(h5->rx_skb)->pkt_type = HCI_ACLDATA_PKT; - pass_up = 1; - } else if ((h5->rx_skb->data[1] & 0x0f) == 4 && - h5->rx_skb->data[0] & 0x80) { - bt_cb(h5->rx_skb)->pkt_type = HCI_EVENT_PKT; - pass_up = 1; - } else if ((h5->rx_skb->data[1] & 0x0f) == 3) { - bt_cb(h5->rx_skb)->pkt_type = HCI_SCODATA_PKT; - pass_up = 1; - } else if ((h5->rx_skb->data[1] & 0x0f) == 15 && - !(h5->rx_skb->data[0] & 0x80)) { - //h5_handle_le_pkt(hu);//Link Establishment Pkt - pass_up = 0; - } else if ((h5->rx_skb->data[1] & 0x0f) == 1 && - h5->rx_skb->data[0] & 0x80) { - bt_cb(h5->rx_skb)->pkt_type = HCI_COMMAND_PKT; - pass_up = 1; - } else if ((h5->rx_skb->data[1] & 0x0f) == 14) { - bt_cb(h5->rx_skb)->pkt_type = H5_VDRSPEC_PKT; - pass_up = 1; - } else - pass_up = 0; - - if (!pass_up) { - /* struct hci_event_hdr hdr; */ - u8 desc = (h5->rx_skb->data[1] & 0x0f); - - if (desc != H5_ACK_PKT && desc != H5_LE_PKT) { - /* if (hciextn) { - * desc |= 0xc0; - * skb_pull(h5->rx_skb, 4); - * memcpy(skb_push(h5->rx_skb, 1), &desc, 1); - - * hdr.evt = 0xff; - * hdr.plen = h5->rx_skb->len; - * memcpy(skb_push(h5->rx_skb, HCI_EVENT_HDR_SIZE), - * &hdr, HCI_EVENT_HDR_SIZE); - * bt_cb(h5->rx_skb)->pkt_type = HCI_EVENT_PKT; - - * hci_recv_frame(h5->rx_skb); - * } else { */ - BT_ERR("Packet for unknown channel (%u %s)", - h5->rx_skb->data[1] & 0x0f, - h5->rx_skb->data[0] & 0x80 ? - "reliable" : "unreliable"); - kfree_skb(h5->rx_skb); - /* } */ - } else - kfree_skb(h5->rx_skb); - } else { - /* Pull out H5 hdr */ - skb_pull(h5->rx_skb, 4); - -#ifdef BTCOEX - if (bt_cb(h5->rx_skb)->pkt_type == HCI_EVENT_PKT) - rtk_btcoex_parse_event(h5->rx_skb->data, - h5->rx_skb->len); - - if (bt_cb(h5->rx_skb)->pkt_type == HCI_ACLDATA_PKT) - rtk_btcoex_parse_l2cap_data_rx(h5->rx_skb->data, - h5->rx_skb->len); -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - hci_recv_frame(h5->rx_skb); -#else - hci_recv_frame(hu->hdev, h5->rx_skb); -#endif - } - - h5->rx_state = H5_W4_PKT_DELIMITER; - h5->rx_skb = NULL; -} - -static u16 bscp_get_crc(struct h5_struct *h5) { - return get_unaligned_be16(&h5->rx_skb-> - data[h5->rx_skb->len - 2]); -} - -/* Recv data */ -static int h5_recv(struct hci_uart *hu, void *data, int count) -{ - struct h5_struct *h5 = hu->priv; - register unsigned char *ptr; - - BT_DBG("hu %p count %d rx_state %d rx_count %ld", - hu, count, h5->rx_state, h5->rx_count); - - ptr = data; - while (count) { - if (h5->rx_count) { - if (*ptr == 0xc0) { - BT_ERR("Short H5 packet"); - kfree_skb(h5->rx_skb); - h5->rx_state = H5_W4_PKT_START; - h5->rx_count = 0; - } else - h5_unslip_one_byte(h5, *ptr); - - ptr++; - count--; - continue; - } - - switch (h5->rx_state) { - case H5_W4_HDR: - if ((0xff & (u8) ~ - (h5->rx_skb->data[0] + - h5->rx_skb->data[1] + - h5->rx_skb->data[2])) != h5->rx_skb->data[3]) { - BT_ERR("Error in H5 hdr checksum"); - kfree_skb(h5->rx_skb); - h5->rx_state = H5_W4_PKT_DELIMITER; - h5->rx_count = 0; - continue; - } - if (h5->rx_skb->data[0] & 0x80 /* reliable pkt */ - && (h5->rx_skb->data[0] & 0x07) != h5->rxseq_txack) { - BT_ERR - ("Out-of-order packet arrived, got %u expected %u", - h5->rx_skb->data[0] & 0x07, - h5->rxseq_txack); - - h5->txack_req = 1; - hci_uart_tx_wakeup(hu); - kfree_skb(h5->rx_skb); - h5->rx_state = H5_W4_PKT_DELIMITER; - h5->rx_count = 0; - continue; - } - h5->rx_state = H5_W4_DATA; - h5->rx_count = (h5->rx_skb->data[1] >> 4) + (h5->rx_skb->data[2] << 4); /* May be 0 */ - continue; - - case H5_W4_DATA: - if (h5->rx_skb->data[0] & 0x40) { /* pkt with crc */ - h5->rx_state = H5_W4_CRC; - h5->rx_count = 2; - } else - h5_complete_rx_pkt(hu); - continue; - - case H5_W4_CRC: - if (bitrev16(h5->message_crc) != bscp_get_crc(h5)) { - BT_ERR - ("Checksum failed: computed %04x received %04x", - bitrev16(h5->message_crc), - bscp_get_crc(h5)); - - kfree_skb(h5->rx_skb); - h5->rx_state = H5_W4_PKT_DELIMITER; - h5->rx_count = 0; - continue; - } - skb_trim(h5->rx_skb, h5->rx_skb->len - 2); - h5_complete_rx_pkt(hu); - continue; - - case H5_W4_PKT_DELIMITER: - switch (*ptr) { - case 0xc0: - h5->rx_state = H5_W4_PKT_START; - break; - default: - /*BT_ERR("Ignoring byte %02x", *ptr); */ - break; - } - ptr++; - count--; - break; - - case H5_W4_PKT_START: - switch (*ptr) { - case 0xc0: - ptr++; - count--; - break; - - default: - h5->rx_state = H5_W4_HDR; - h5->rx_count = 4; - h5->rx_esc_state = H5_ESCSTATE_NOESC; - H5_CRC_INIT(h5->message_crc); - - /* Do not increment ptr or decrement count - * Allocate packet. Max len of a H5 pkt= - * 0xFFF (payload) +4 (header) +2 (crc) */ - - h5->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC); - if (!h5->rx_skb) { - BT_ERR - ("Can't allocate mem for new packet"); - h5->rx_state = H5_W4_PKT_DELIMITER; - h5->rx_count = 0; - return 0; - } - h5->rx_skb->dev = (void *)hu->hdev; - break; - } - break; - } - } - return count; -} - -/* Arrange to retransmit all messages in the relq. */ -static void h5_timed_event(unsigned long arg) -{ - struct hci_uart *hu = (struct hci_uart *)arg; - struct h5_struct *h5 = hu->priv; - struct sk_buff *skb; - unsigned long flags; - - BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); - - spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); - - while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { - h5->msgq_txseq = (h5->msgq_txseq - 1) & 0x07; - skb_queue_head(&h5->rel, skb); - } - - spin_unlock_irqrestore(&h5->unack.lock, flags); - - hci_uart_tx_wakeup(hu); -} - -static int h5_open(struct hci_uart *hu) -{ - struct h5_struct *h5; - - BT_DBG("hu %p", hu); - - BT_INFO("h5_open"); - h5 = kzalloc(sizeof(*h5), GFP_ATOMIC); - if (!h5) - return -ENOMEM; - - hu->priv = h5; - skb_queue_head_init(&h5->unack); - skb_queue_head_init(&h5->rel); - skb_queue_head_init(&h5->unrel); - - init_timer(&h5->th5); - h5->th5.function = h5_timed_event; - h5->th5.data = (u_long) hu; - - h5->rx_state = H5_W4_PKT_DELIMITER; - - if (txcrc) - h5->use_crc = 1; - - return 0; -} - -static int h5_close(struct hci_uart *hu) -{ - struct h5_struct *h5 = hu->priv; - hu->priv = NULL; - - BT_DBG("hu %p", hu); - BT_INFO("h5_close"); - skb_queue_purge(&h5->unack); - skb_queue_purge(&h5->rel); - skb_queue_purge(&h5->unrel); - del_timer(&h5->th5); - - kfree(h5); - return 0; -} - -static struct hci_uart_proto h5 = { - .id = HCI_UART_3WIRE, - .open = h5_open, - .close = h5_close, - .enqueue = h5_enqueue, - .dequeue = h5_dequeue, - .recv = h5_recv, - .flush = h5_flush -}; - -int h5_init(void) -{ - int err = hci_uart_register_proto(&h5); - - if (!err) - BT_INFO("HCI Realtek H5 protocol initialized"); - else - BT_ERR("HCI Realtek H5 protocol registration failed"); - - return err; -} - -int h5_deinit(void) -{ - return hci_uart_unregister_proto(&h5); -} diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 50ea0065f1c2..a4d52fe70445 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -22,16 +22,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#include -#include -#include #ifndef N_HCI #define N_HCI 15 #endif -#define BTCOEX - /* Ioctls */ #define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTGETPROTO _IOR('U', 201, int) @@ -40,7 +35,7 @@ #define HCIUARTGETFLAGS _IOR('U', 204, int) /* UART protocols */ -#define HCI_UART_MAX_PROTO 6 +#define HCI_UART_MAX_PROTO 9 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 @@ -48,19 +43,31 @@ #define HCI_UART_H4DS 3 #define HCI_UART_LL 4 #define HCI_UART_ATH3K 5 +#define HCI_UART_INTEL 6 +#define HCI_UART_BCM 7 +#define HCI_UART_QCA 8 #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 #define HCI_UART_CREATE_AMP 2 +#define HCI_UART_INIT_PENDING 3 +#define HCI_UART_EXT_CONFIG 4 +#define HCI_UART_VND_DETECT 5 struct hci_uart; struct hci_uart_proto { unsigned int id; + const char *name; + unsigned int manufacturer; + unsigned int init_speed; + unsigned int oper_speed; int (*open)(struct hci_uart *hu); int (*close)(struct hci_uart *hu); int (*flush)(struct hci_uart *hu); - int (*recv)(struct hci_uart *hu, void *data, int len); + int (*setup)(struct hci_uart *hu); + int (*set_baudrate)(struct hci_uart *hu, unsigned int speed); + int (*recv)(struct hci_uart *hu, const void *data, int len); int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); struct sk_buff *(*dequeue)(struct hci_uart *hu); }; @@ -71,38 +78,77 @@ struct hci_uart { unsigned long flags; unsigned long hdev_flags; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + struct work_struct init_ready; struct work_struct write_work; -#endif - struct hci_uart_proto *proto; + const struct hci_uart_proto *proto; void *priv; struct sk_buff *tx_skb; unsigned long tx_state; - spinlock_t rx_lock; + + unsigned int init_speed; + unsigned int oper_speed; }; /* HCI_UART proto flag bits */ #define HCI_UART_PROTO_SET 0 +#define HCI_UART_REGISTERED 1 +#define HCI_UART_PROTO_READY 2 /* TX states */ #define HCI_UART_SENDING 1 #define HCI_UART_TX_WAKEUP 2 -int hci_uart_register_proto(struct hci_uart_proto *p); -int hci_uart_unregister_proto(struct hci_uart_proto *p); +int hci_uart_register_proto(const struct hci_uart_proto *p); +int hci_uart_unregister_proto(const struct hci_uart_proto *p); int hci_uart_tx_wakeup(struct hci_uart *hu); +int hci_uart_init_ready(struct hci_uart *hu); +void hci_uart_init_tty(struct hci_uart *hu); +void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); +void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); +void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, + unsigned int oper_speed); #ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); int h4_deinit(void); -#endif -int h5_init(void); -int h5_deinit(void); +struct h4_recv_pkt { + u8 type; /* Packet type */ + u8 hlen; /* Header length */ + u8 loff; /* Data length offset in header */ + u8 lsize; /* Data length field size */ + u16 maxlen; /* Max overall packet length */ + int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); +}; + +#define H4_RECV_ACL \ + .type = HCI_ACLDATA_PKT, \ + .hlen = HCI_ACL_HDR_SIZE, \ + .loff = 2, \ + .lsize = 2, \ + .maxlen = HCI_MAX_FRAME_SIZE \ + +#define H4_RECV_SCO \ + .type = HCI_SCODATA_PKT, \ + .hlen = HCI_SCO_HDR_SIZE, \ + .loff = 2, \ + .lsize = 1, \ + .maxlen = HCI_MAX_SCO_SIZE + +#define H4_RECV_EVENT \ + .type = HCI_EVENT_PKT, \ + .hlen = HCI_EVENT_HDR_SIZE, \ + .loff = 1, \ + .lsize = 1, \ + .maxlen = HCI_MAX_EVENT_SIZE + +struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, + const unsigned char *buffer, int count, + const struct h4_recv_pkt *pkts, int pkts_count); +#endif -/* #ifdef CONFIG_BT_HCIUART_BCSP int bcsp_init(void); int bcsp_deinit(void); @@ -117,9 +163,23 @@ int ll_deinit(void); int ath_init(void); int ath_deinit(void); #endif -*/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - int hci_uart_send_frame(struct sk_buff *skb); -#else - int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb); + +#ifdef CONFIG_BT_HCIUART_3WIRE +int h5_init(void); +int h5_deinit(void); +#endif + +#ifdef CONFIG_BT_HCIUART_INTEL +int intel_init(void); +int intel_deinit(void); +#endif + +#ifdef CONFIG_BT_HCIUART_BCM +int bcm_init(void); +int bcm_deinit(void); +#endif + +#ifdef CONFIG_BT_HCIUART_QCA +int qca_init(void); +int qca_deinit(void); #endif diff --git a/drivers/bluetooth/rtk_btusb.c b/drivers/bluetooth/rtk_btusb.c deleted file mode 100755 index 631522cc9ad5..000000000000 --- a/drivers/bluetooth/rtk_btusb.c +++ /dev/null @@ -1,3160 +0,0 @@ -/* - * - * Realtek Bluetooth USB driver - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 "rtk_btusb.h" -#define VERSION "2.21" - -#define DBG_FLAG 0 -#if DBG_FLAG -#define RTKBT_DBG(fmt, arg...) printk(KERN_INFO "rtk_btusb: " fmt "\n" , ## arg) -#else -#define RTKBT_DBG(fmt, arg...) -#endif -#define RTKBT_INFO(fmt, arg...) printk(KERN_INFO "rtk_btusb: " fmt "\n" , ## arg) -#define RTKBT_WARN(fmt, arg...) printk(KERN_WARNING "rtk_btusb: " fmt "\n" , ## arg) -#define RTKBT_ERR(fmt, arg...) printk(KERN_ERR "rtk_btusb: " fmt "\n" , ## arg) - -/******************************* -** Reasil patch code -********************************/ -#define CMD_CMP_EVT 0x0e -#define PKT_LEN 300 -#define MSG_TO 1000 -#define PATCH_SEG_MAX 252 -#define DATA_END 0x80 -#define DOWNLOAD_OPCODE 0xfc20 -#define BTOFF_OPCODE 0xfc28 -#define TRUE 1 -#define FALSE 0 -#define CMD_HDR_LEN sizeof(struct hci_command_hdr) -#define EVT_HDR_LEN sizeof(struct hci_event_hdr) -#define CMD_CMP_LEN sizeof(struct hci_ev_cmd_complete) - -enum rtk_endpoit { - CTRL_EP = 0, - INTR_EP = 1, - BULK_EP = 2, - ISOC_EP = 3 -}; - -typedef struct { - uint16_t prod_id; - uint16_t lmp_sub_default; - uint16_t lmp_sub; - uint16_t eversion; - char *mp_patch_name; - char *patch_name; - char *config_name; - uint8_t *fw_cache; - int fw_len; -} patch_info; - -typedef struct { - struct usb_interface *intf; - struct usb_device *udev; - patch_info *patch_entry; - int pipe_in, pipe_out; - uint8_t *send_pkt; - uint8_t *rcv_pkt; - struct hci_command_hdr *cmd_hdr; - struct hci_event_hdr *evt_hdr; - struct hci_ev_cmd_complete *cmd_cmp; - uint8_t *req_para, *rsp_para; - uint8_t *fw_data; - int pkt_len; - int fw_len; -} firmware_info; - -typedef struct { - uint8_t index; - uint8_t data[PATCH_SEG_MAX]; -} __attribute__((packed)) download_cp; - -typedef struct { - uint8_t status; - uint8_t index; -} __attribute__((packed)) download_rp; - -static patch_info fw_patch_table[] = { -/* { pid, lmp_sub_default, lmp_sub, everion, mp_fw_name, fw_name, config_name, fw_cache, fw_len } */ -{ 0x1724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* RTL8723A */ -{ 0x8723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AE */ -{ 0xA723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AE for LI */ -{ 0x0723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AE */ -{ 0x3394, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AE for Azurewave*/ - -{ 0x0724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AU */ -{ 0x8725, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AU */ -{ 0x872A, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AU */ -{ 0x872B, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 }, /* 8723AU */ - -{ 0xb720, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 }, /* RTL8723BU */ -{ 0xb72A, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 }, /* RTL8723BU */ -{ 0xb728, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for LC */ -{ 0xb723, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */ -{ 0xb72B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */ -{ 0xb001, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for HP */ -{ 0xb002, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */ -{ 0xb003, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */ -{ 0xb004, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */ -{ 0xb005, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */ - -{ 0x3410, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for Azurewave */ -{ 0x3416, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for Azurewave */ -{ 0x3459, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for Azurewave */ -{ 0xE085, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for Foxconn */ -{ 0xE08B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for Foxconn */ - -{ 0xA761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 }, /* RTL8761AU only */ -{ 0x818B, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761aw8192eu_fw", "rtl8761aw8192eu_config", NULL, 0 }, /* RTL8761AW + 8192EU */ -{ 0x818C, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761aw8192eu_fw", "rtl8761aw8192eu_config", NULL, 0 }, /* RTL8761AW + 8192EU */ -{ 0x8760, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 }, /* RTL8761AU + 8192EE */ -{ 0xB761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 }, /* RTL8761AU + 8192EE */ -{ 0x8761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 }, /* RTL8761AU + 8192EE for LI */ -{ 0x8A60, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0 }, /* RTL8761AU + 8812AE */ - -{ 0x8821, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AE */ -{ 0x0821, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AE */ -{ 0x0823, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AU */ -{ 0x3414, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AE */ -{ 0x3458, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AE */ -{ 0x3461, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AE */ -{ 0x3462, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 }, /* RTL8821AE */ - -/* NOTE: must append patch entries above the null entry */ -{ 0, 0, 0, 0, NULL, NULL, NULL, NULL, 0 } -}; - -struct btusb_data { - struct hci_dev *hdev; - struct usb_device *udev; - struct usb_interface *intf; - struct usb_interface *isoc; - - spinlock_t lock; - - unsigned long flags; - - struct work_struct work; - struct work_struct waker; - - struct usb_anchor tx_anchor; - struct usb_anchor intr_anchor; - struct usb_anchor bulk_anchor; - struct usb_anchor isoc_anchor; - struct usb_anchor deferred; - int tx_in_flight; - spinlock_t txlock; - - struct usb_endpoint_descriptor *intr_ep; - struct usb_endpoint_descriptor *bulk_tx_ep; - struct usb_endpoint_descriptor *bulk_rx_ep; - struct usb_endpoint_descriptor *isoc_tx_ep; - struct usb_endpoint_descriptor *isoc_rx_ep; - - __u8 cmdreq_type; - - unsigned int sco_num; - int isoc_altsetting; - int suspend_count; -//#ifdef CONFIG_HAS_EARLYSUSPEND -#if 0 - struct early_suspend early_suspend; -#else - struct notifier_block pm_notifier; -#endif - firmware_info *fw_info; -}; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 1) -static bool reset_on_close = 0; -#endif - -static void rtk_free( struct btusb_data *data) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 1) - kfree(data); -#endif - return; -} - -static struct btusb_data *rtk_alloc(struct usb_interface *intf) -{ - struct btusb_data *data; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 1) - data = kzalloc(sizeof(*data), GFP_KERNEL); -#else - data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); -#endif - return data; -} - -static void print_acl(struct sk_buff *skb, int direction) -{ -#if PRINT_ACL_DATA - uint wlength = skb->len; - u16 *handle = (u16 *)(skb->data); - u16 len = *(handle+1); - u8 *acl_data = (u8 *)(skb->data); - - RTK_INFO("%s: direction %d, handle %04x, len %d", - __func__, direction, *handle, len); -#endif -} - -static void print_sco(struct sk_buff *skb, int direction) -{ -#if PRINT_SCO_DATA - uint wlength = skb->len; - u16 *handle = (u16 *)(skb->data); - u8 len = *(u8 *)(handle+1); - u8 *sco_data =(u8 *)(skb->data); - - RTKBT_INFO("%s: direction %d, handle %04x, len %d", - __func__, direction, *handle, len); -#endif -} - -static void print_error_command(struct sk_buff *skb) -{ - uint wlength = skb->len; - uint icount = 0; - u16 *opcode = (u16*)(skb->data); - u8 *cmd_data = (u8*)(skb->data); - u8 len = *(cmd_data+2); - - switch (*opcode) { - case HCI_OP_INQUIRY: - printk("HCI_OP_INQUIRY"); - break; - case HCI_OP_INQUIRY_CANCEL: - printk("HCI_OP_INQUIRY_CANCEL"); - break; - case HCI_OP_EXIT_PERIODIC_INQ: - printk("HCI_OP_EXIT_PERIODIC_INQ"); - break; - case HCI_OP_CREATE_CONN: - printk("HCI_OP_CREATE_CONN"); - break; - case HCI_OP_DISCONNECT: - printk("HCI_OP_DISCONNECT"); - break; - case HCI_OP_CREATE_CONN_CANCEL: - printk("HCI_OP_CREATE_CONN_CANCEL"); - break; - case HCI_OP_ACCEPT_CONN_REQ: - printk("HCI_OP_ACCEPT_CONN_REQ"); - break; - case HCI_OP_REJECT_CONN_REQ: - printk("HCI_OP_REJECT_CONN_REQ"); - break; - case HCI_OP_AUTH_REQUESTED: - printk("HCI_OP_AUTH_REQUESTED"); - break; - case HCI_OP_SET_CONN_ENCRYPT: - printk("HCI_OP_SET_CONN_ENCRYPT"); - break; - case HCI_OP_REMOTE_NAME_REQ: - printk("HCI_OP_REMOTE_NAME_REQ"); - break; - case HCI_OP_READ_REMOTE_FEATURES: - printk("HCI_OP_READ_REMOTE_FEATURES"); - break; - case HCI_OP_SNIFF_MODE: - printk("HCI_OP_SNIFF_MODE"); - break; - case HCI_OP_EXIT_SNIFF_MODE: - printk("HCI_OP_EXIT_SNIFF_MODE"); - break; - case HCI_OP_SWITCH_ROLE: - printk("HCI_OP_SWITCH_ROLE"); - break; - case HCI_OP_SNIFF_SUBRATE: - printk("HCI_OP_SNIFF_SUBRATE"); - break; - case HCI_OP_RESET: - printk("HCI_OP_RESET"); - break; - default: - printk("CMD"); - break; - } - printk(":%04x,len:%d,", *opcode,len); - for (icount = 3; (icount < wlength) && (icount < 24); icount++) - printk("%02x ", *(cmd_data+icount)); - printk("\n"); -} - -static void print_command(struct sk_buff *skb) -{ -#if PRINT_CMD_EVENT - print_error_command(skb); -#endif -} - -#if CONFIG_BLUEDROID -/* Global parameters for bt usb char driver */ -#define BT_CHAR_DEVICE_NAME "rtk_btusb" -struct mutex btchr_mutex; -static struct sk_buff_head btchr_readq; -static wait_queue_head_t btchr_read_wait; -static int bt_char_dev_registered; -static dev_t bt_devid; /* bt char device number */ -static struct cdev bt_char_dev; /* bt character device structure */ -static struct class *bt_char_class; /* device class for usb char driver */ -static int bt_reset = 0; -/* HCI device & lock */ -DEFINE_RWLOCK(hci_dev_lock); -struct hci_dev *ghdev = NULL; - -static void print_event(struct sk_buff *skb) -{ -#if PRINT_CMD_EVENT - uint wlength = skb->len; - uint icount = 0; - u8 *opcode = (u8*)(skb->data); - u8 len = *(opcode+1); - - switch (*opcode) { - case HCI_EV_INQUIRY_COMPLETE: - printk("HCI_EV_INQUIRY_COMPLETE"); - break; - case HCI_EV_INQUIRY_RESULT: - printk("HCI_EV_INQUIRY_RESULT"); - break; - case HCI_EV_CONN_COMPLETE: - printk("HCI_EV_CONN_COMPLETE"); - break; - case HCI_EV_CONN_REQUEST: - printk("HCI_EV_CONN_REQUEST"); - break; - case HCI_EV_DISCONN_COMPLETE: - printk("HCI_EV_DISCONN_COMPLETE"); - break; - case HCI_EV_AUTH_COMPLETE: - printk("HCI_EV_AUTH_COMPLETE"); - break; - case HCI_EV_REMOTE_NAME: - printk("HCI_EV_REMOTE_NAME"); - break; - case HCI_EV_ENCRYPT_CHANGE: - printk("HCI_EV_ENCRYPT_CHANGE"); - break; - case HCI_EV_CHANGE_LINK_KEY_COMPLETE: - printk("HCI_EV_CHANGE_LINK_KEY_COMPLETE"); - break; - case HCI_EV_REMOTE_FEATURES: - printk("HCI_EV_REMOTE_FEATURES"); - break; - case HCI_EV_REMOTE_VERSION: - printk("HCI_EV_REMOTE_VERSION"); - break; - case HCI_EV_QOS_SETUP_COMPLETE: - printk("HCI_EV_QOS_SETUP_COMPLETE"); - break; - case HCI_EV_CMD_COMPLETE: - printk("HCI_EV_CMD_COMPLETE"); - break; - case HCI_EV_CMD_STATUS: - printk("HCI_EV_CMD_STATUS"); - break; - case HCI_EV_ROLE_CHANGE: - printk("HCI_EV_ROLE_CHANGE"); - break; - case HCI_EV_NUM_COMP_PKTS: - printk("HCI_EV_NUM_COMP_PKTS"); - break; - case HCI_EV_MODE_CHANGE: - printk("HCI_EV_MODE_CHANGE"); - break; - case HCI_EV_PIN_CODE_REQ: - printk("HCI_EV_PIN_CODE_REQ"); - break; - case HCI_EV_LINK_KEY_REQ: - printk("HCI_EV_LINK_KEY_REQ"); - break; - case HCI_EV_LINK_KEY_NOTIFY: - printk("HCI_EV_LINK_KEY_NOTIFY"); - break; - case HCI_EV_CLOCK_OFFSET: - printk("HCI_EV_CLOCK_OFFSET"); - break; - case HCI_EV_PKT_TYPE_CHANGE: - printk("HCI_EV_PKT_TYPE_CHANGE"); - break; - case HCI_EV_PSCAN_REP_MODE: - printk("HCI_EV_PSCAN_REP_MODE"); - break; - case HCI_EV_INQUIRY_RESULT_WITH_RSSI: - printk("HCI_EV_INQUIRY_RESULT_WITH_RSSI"); - break; - case HCI_EV_REMOTE_EXT_FEATURES: - printk("HCI_EV_REMOTE_EXT_FEATURES"); - break; - case HCI_EV_SYNC_CONN_COMPLETE: - printk("HCI_EV_SYNC_CONN_COMPLETE"); - break; - case HCI_EV_SYNC_CONN_CHANGED: - printk("HCI_EV_SYNC_CONN_CHANGED"); - break; - case HCI_EV_SNIFF_SUBRATE: - printk("HCI_EV_SNIFF_SUBRATE"); - break; - case HCI_EV_EXTENDED_INQUIRY_RESULT: - printk("HCI_EV_EXTENDED_INQUIRY_RESULT"); - break; - case HCI_EV_IO_CAPA_REQUEST: - printk("HCI_EV_IO_CAPA_REQUEST"); - break; - case HCI_EV_SIMPLE_PAIR_COMPLETE: - printk("HCI_EV_SIMPLE_PAIR_COMPLETE"); - break; - case HCI_EV_REMOTE_HOST_FEATURES: - printk("HCI_EV_REMOTE_HOST_FEATURES"); - break; - default: - printk("event"); - break; - } - printk(":%02x,len:%d,", *opcode,len); - for (icount = 2; (icount < wlength) && (icount < 24); icount++) - printk("%02x ", *(opcode+icount)); - printk("\n"); -#endif -} - -static inline ssize_t usb_put_user(struct sk_buff *skb, - char __user *buf, int count) -{ - char __user *ptr = buf; - int len = min_t(unsigned int, skb->len, count); - - if (copy_to_user(ptr, skb->data, len)) - return -EFAULT; - - return len; -} - -static struct sk_buff *rtk_skb_queue[QUEUE_SIZE]; -static int rtk_skb_queue_front = -1; -static int rtk_skb_queue_rear = -1; - -static void rtk_enqueue(struct sk_buff *skb) -{ - if (rtk_skb_queue_front == (rtk_skb_queue_rear + 1) % QUEUE_SIZE) { - /* - * If queue is full, current solution is to drop - * the following entries. - */ - RTKBT_WARN("%s: Queue is full, entry will be dropped", __func__); - } else { - if (rtk_skb_queue_front == -1) { - rtk_skb_queue_front = 0; - rtk_skb_queue_rear = 0; - } else { - rtk_skb_queue_rear++; - rtk_skb_queue_rear %= QUEUE_SIZE; - } - - rtk_skb_queue[rtk_skb_queue_rear] = skb; - } -} - -static struct sk_buff *rtk_dequeue_try(unsigned int deq_len) -{ - struct sk_buff *skb; - struct sk_buff *skb_copy; - - if (rtk_skb_queue_front == -1) { - RTKBT_WARN("%s: Queue is empty", __func__); - return NULL; - } - - skb = rtk_skb_queue[rtk_skb_queue_front]; - if (deq_len >= skb->len) { - if (rtk_skb_queue_front == rtk_skb_queue_rear) { - rtk_skb_queue_front = -1; - rtk_skb_queue_rear = -1; - } else { - rtk_skb_queue_front++; - rtk_skb_queue_front %= QUEUE_SIZE; - } - /* - * Return skb addr to be dequeued, and the caller - * should free the skb eventually. - */ - return skb; - } else { - skb_copy = pskb_copy(skb, GFP_ATOMIC); - skb_pull(skb, deq_len); - /* Return its copy to be freed */ - return skb_copy; - } -} - -static inline int is_queue_empty(void) -{ - return (rtk_skb_queue_front == -1) ? 1 : 0; -} - -/* - * Realtek - Integrate from hci_core.c - */ - -/* Get HCI device by index. - * Device is held on return. */ -static struct hci_dev *hci_dev_get(int index) -{ - if (index != 0) - return NULL; - - return ghdev; -} - -/* ---- HCI ioctl helpers ---- */ -static int hci_dev_open(__u16 dev) -{ - struct hci_dev *hdev; - int ret = 0; - - RTKBT_DBG("%s: dev %d", __func__, dev); - - hdev = hci_dev_get(dev); - if (!hdev) { - RTKBT_ERR("%s: Failed to get hci dev[Null]", __func__); - return -ENODEV; - } - - if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) { - ret = -ENODEV; - goto done; - } - - if (test_bit(HCI_UP, &hdev->flags)) { - ret = -EALREADY; - goto done; - } - - if (hdev->open(hdev)) { - ret = -EIO; - goto done; - } - - set_bit(HCI_UP, &hdev->flags); -done: - return ret; -} - -static int hci_dev_do_close(struct hci_dev *hdev) -{ - if (hdev->flush) - hdev->flush(hdev); - /* After this point our queues are empty - * and no tasks are scheduled. */ - hdev->close(hdev); - /* Clear flags */ - hdev->flags = 0; - return 0; -} - -static int hci_dev_close(__u16 dev) -{ - struct hci_dev *hdev; - int err; - hdev = hci_dev_get(dev); - if (!hdev) { - RTKBT_ERR("%s: failed to get hci dev[Null]", __func__); - return -ENODEV; - } - - err = hci_dev_do_close(hdev); - - return err; -} - -static struct hci_dev *hci_alloc_dev(void) -{ - struct hci_dev *hdev; - - hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); - if (!hdev) - return NULL; - - return hdev; -} - -/* Free HCI device */ -static void hci_free_dev(struct hci_dev *hdev) -{ - kfree(hdev); -} - -/* Register HCI device */ -static int hci_register_dev(struct hci_dev *hdev) -{ - int i, id; - - RTKBT_DBG("%s: %p name %s bus %d", __func__, hdev, hdev->name, hdev->bus); - /* Do not allow HCI_AMP devices to register at index 0, - * so the index can be used as the AMP controller ID. - */ - id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; - - write_lock(&hci_dev_lock); - - sprintf(hdev->name, "hci%d", id); - hdev->id = id; - hdev->flags = 0; - hdev->dev_flags = 0; - mutex_init(&hdev->lock); - - RTKBT_DBG("%s: id %d, name %s", __func__, hdev->id, hdev->name); - - - for (i = 0; i < NUM_REASSEMBLY; i++) - hdev->reassembly[i] = NULL; - - memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); - atomic_set(&hdev->promisc, 0); - - if (ghdev) { - RTKBT_ERR("%s: Hci device has been registered already", __func__); - return -1; - } else - ghdev = hdev; - - write_unlock(&hci_dev_lock); - - return id; -} - -/* Unregister HCI device */ -static void hci_unregister_dev(struct hci_dev *hdev) -{ - int i; - - RTKBT_DBG("%s: hdev %p name %s bus %d", __func__, hdev, hdev->name, hdev->bus); - set_bit(HCI_UNREGISTER, &hdev->dev_flags); - - write_lock(&hci_dev_lock); - ghdev = NULL; - write_unlock(&hci_dev_lock); - - hci_dev_do_close(hdev); - for (i = 0; i < NUM_REASSEMBLY; i++) - kfree_skb(hdev->reassembly[i]); -} - -static void hci_send_to_stack(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct sk_buff *rtk_skb_copy = NULL; - - RTKBT_DBG("%s", __func__); - - if (!hdev) { - RTKBT_ERR("%s: Frame for unknown HCI device", __func__); - return; - } - - if (!test_bit(HCI_RUNNING, &hdev->flags)) { - RTKBT_ERR("%s: HCI not running", __func__); - return; - } - - rtk_skb_copy = pskb_copy(skb, GFP_ATOMIC); - if (!rtk_skb_copy) { - RTKBT_ERR("%s: Copy skb error", __func__); - return; - } - - memcpy(skb_push(rtk_skb_copy, 1), &bt_cb(skb)->pkt_type, 1); - rtk_enqueue(rtk_skb_copy); - - /* Make sure bt char device existing before wakeup read queue */ - hdev = hci_dev_get(0); - if (hdev) { - RTKBT_DBG("%s: Try to wakeup read queue", __func__); - wake_up_interruptible(&btchr_read_wait); - } - - return; -} - -/* Receive frame from HCI drivers */ -static int hci_recv_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - - if (!hdev || - (!test_bit(HCI_UP, &hdev->flags) && !test_bit(HCI_INIT, &hdev->flags))) { - kfree_skb(skb); - return -ENXIO; - } - - /* Incomming skb */ - bt_cb(skb)->incoming = 1; - - /* Time stamp */ - __net_timestamp(skb); - - if (atomic_read(&hdev->promisc)) { - /* Send copy to the sockets */ - hci_send_to_stack(hdev, skb); - } - kfree_skb(skb); - return 0; -} - -static int hci_reassembly(struct hci_dev *hdev, int type, void *data, - int count, __u8 index) -{ - int len = 0; - int hlen = 0; - int remain = count; - struct sk_buff *skb; - struct bt_skb_cb *scb; - - RTKBT_DBG("%s", __func__); - - if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || - index >= NUM_REASSEMBLY) - return -EILSEQ; - - skb = hdev->reassembly[index]; - - if (!skb) { - switch (type) { - case HCI_ACLDATA_PKT: - len = HCI_MAX_FRAME_SIZE; - hlen = HCI_ACL_HDR_SIZE; - break; - case HCI_EVENT_PKT: - len = HCI_MAX_EVENT_SIZE; - hlen = HCI_EVENT_HDR_SIZE; - break; - case HCI_SCODATA_PKT: - len = HCI_MAX_SCO_SIZE; - hlen = HCI_SCO_HDR_SIZE; - break; - } - - skb = bt_skb_alloc(len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - scb = (void *) skb->cb; - scb->expect = hlen; - scb->pkt_type = type; - - skb->dev = (void *) hdev; - hdev->reassembly[index] = skb; - } - - while (count) { - scb = (void *) skb->cb; - len = min_t(uint, scb->expect, count); - - memcpy(skb_put(skb, len), data, len); - - count -= len; - data += len; - scb->expect -= len; - remain = count; - - switch (type) { - case HCI_EVENT_PKT: - if (skb->len == HCI_EVENT_HDR_SIZE) { - struct hci_event_hdr *h = hci_event_hdr(skb); - scb->expect = h->plen; - - if (skb_tailroom(skb) < scb->expect) { - kfree_skb(skb); - hdev->reassembly[index] = NULL; - return -ENOMEM; - } - } - break; - - case HCI_ACLDATA_PKT: - if (skb->len == HCI_ACL_HDR_SIZE) { - struct hci_acl_hdr *h = hci_acl_hdr(skb); - scb->expect = __le16_to_cpu(h->dlen); - - if (skb_tailroom(skb) < scb->expect) { - kfree_skb(skb); - hdev->reassembly[index] = NULL; - return -ENOMEM; - } - } - break; - - case HCI_SCODATA_PKT: - if (skb->len == HCI_SCO_HDR_SIZE) { - struct hci_sco_hdr *h = hci_sco_hdr(skb); - scb->expect = h->dlen; - - if (skb_tailroom(skb) < scb->expect) { - kfree_skb(skb); - hdev->reassembly[index] = NULL; - return -ENOMEM; - } - } - break; - } - - if (scb->expect == 0) { - /* Complete frame */ - if(HCI_ACLDATA_PKT == type) - print_acl(skb,0); - if(HCI_SCODATA_PKT == type) - print_sco(skb,0); - if(HCI_EVENT_PKT == type) - print_event(skb); - - bt_cb(skb)->pkt_type = type; - hci_recv_frame(skb); - - hdev->reassembly[index] = NULL; - return remain; - } - } - - return remain; -} - -static int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) -{ - int rem = 0; - - if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) - return -EILSEQ; - - while (count) { - rem = hci_reassembly(hdev, type, data, count, type - 1); - if (rem < 0) - return rem; - - data += (count - rem); - count = rem; - } - - return rem; -} - -void hci_hardware_error(void) -{ - struct sk_buff *rtk_skb_copy = NULL; - int len = 3; - uint8_t hardware_err_pkt[3] = {HCI_EVENT_PKT, 0x10, 0x00}; - - rtk_skb_copy = alloc_skb(len, GFP_ATOMIC); - if (!rtk_skb_copy) { - RTKBT_ERR("%s: Failed to allocate mem", __func__); - return; - } - - memcpy(skb_put(rtk_skb_copy, len), hardware_err_pkt, len); - rtk_enqueue(rtk_skb_copy); - - wake_up_interruptible(&btchr_read_wait); -} - -static int btchr_open(struct inode *inode_p, struct file *file_p) -{ - struct btusb_data *data; - struct hci_dev *hdev; - - RTKBT_INFO("%s: BT usb char device is opening", __func__); - /* Not open unless wanna tracing log */ - /* trace_printk("%s: open....\n", __func__); */ - - hdev = hci_dev_get(0); - if (!hdev) { - RTKBT_ERR("%s: Failed to get hci dev[NULL]", __func__); - return -1; - } - data = GET_DRV_DATA(hdev); - - atomic_inc(&hdev->promisc); - /* - * As bt device is not re-opened when hotplugged out, we cannot - * trust on file's private data(may be null) when other file ops - * are invoked. - */ - file_p->private_data = data; - - mutex_lock(&btchr_mutex); - hci_dev_open(0); - mutex_unlock(&btchr_mutex); - - return nonseekable_open(inode_p, file_p); -} - -static int btchr_close(struct inode *inode_p, struct file *file_p) -{ - struct btusb_data *data; - struct hci_dev *hdev; - - RTKBT_INFO("%s: BT usb char device is closing", __func__); - /* Not open unless wanna tracing log */ - /* trace_printk("%s: close....\n", __func__); */ - - data = file_p->private_data; - file_p->private_data = NULL; - -#if CONFIG_BLUEDROID - /* - * If the upper layer closes bt char interfaces, no reset - * action required even bt device hotplugged out. - */ - bt_reset = 0; -#endif - - hdev = hci_dev_get(0); - if (hdev) { - atomic_set(&hdev->promisc, 0); - mutex_lock(&btchr_mutex); - hci_dev_close(0); - mutex_unlock(&btchr_mutex); - } - - return 0; -} - -static ssize_t btchr_read(struct file *file_p, - char __user *buf_p, - size_t count, - loff_t *pos_p) -{ - struct hci_dev *hdev; - struct sk_buff *skb; - ssize_t ret = 0; - - RTKBT_DBG("%s: BT usb char device is reading", __func__); - - while (count) { - hdev = hci_dev_get(0); - if (!hdev) { - /* - * Note: Only when BT device hotplugged out, we wil get - * into such situation. In order to keep the upper layer - * stack alive (blocking the read), we should never return - * EFAULT or break the loop. - */ - RTKBT_ERR("%s: Failed to get hci dev[Null]", __func__); - } - - ret = wait_event_interruptible(btchr_read_wait, !is_queue_empty()); - if (ret < 0) { - RTKBT_ERR("%s: wait event is signaled %d", __func__, ret); - break; - } - - skb = rtk_dequeue_try(count); - if (skb) { - ret = usb_put_user(skb, buf_p, count); - if (ret < 0) - RTKBT_ERR("%s: Failed to put data to user space", __func__); - kfree_skb(skb); - break; - } - } - - return ret; -} - -static ssize_t btchr_write(struct file *file_p, - const char __user *buf_p, - size_t count, - loff_t *pos_p) -{ - struct btusb_data *data = file_p->private_data; - struct hci_dev *hdev; - struct sk_buff *skb; - - RTKBT_DBG("%s: BT usb char device is writing", __func__); - - hdev = hci_dev_get(0); - if (!hdev) { - RTKBT_WARN("%s: Failed to get hci dev[Null]", __func__); - /* - * Note: we bypass the data from the upper layer if bt device - * is hotplugged out. Fortunatelly, H4 or H5 HCI stack does - * NOT check btchr_write's return value. However, returning - * count instead of EFAULT is preferable. - */ - /* return -EFAULT; */ - return count; - } - - /* Never trust on btusb_data, as bt device may be hotplugged out */ - data = GET_DRV_DATA(hdev); - if (!data) { - RTKBT_WARN("%s: Failed to get bt usb driver data[Null]", __func__); - return count; - } - - if (count > HCI_MAX_FRAME_SIZE) - return -EINVAL; - - skb = bt_skb_alloc(count, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - skb_reserve(skb, -1); // Add this line - - if (copy_from_user(skb_put(skb, count), buf_p, count)) { - RTKBT_ERR("%s: Failed to get data from user space", __func__); - kfree_skb(skb); - return -EFAULT; - } - - skb->dev = (void *)hdev; - bt_cb(skb)->pkt_type = *((__u8 *)skb->data); - skb_pull(skb, 1); - data->hdev->send(skb); - - return count; -} - -static unsigned int btchr_poll(struct file *file_p, poll_table *wait) -{ - struct btusb_data *data = file_p->private_data; - struct hci_dev *hdev; - - RTKBT_DBG("%s: BT usb char device is polling", __func__); - - hdev = hci_dev_get(0); - if (!hdev) { - RTKBT_ERR("%s: Failed to get hci dev[Null]", __func__); - mdelay(URB_CANCELING_DELAY_MS); - return POLLOUT | POLLWRNORM; - } - - /* Never trust on btusb_data, as bt device may be hotplugged out */ - data = GET_DRV_DATA(hdev); - if (!data) { - /* - * When bt device is hotplugged out, btusb_data will - * be freed in disconnect. - */ - RTKBT_ERR("%s: Failed to get bt usb driver data[Null]", __func__); - mdelay(URB_CANCELING_DELAY_MS); - return POLLOUT | POLLWRNORM; - } - - if (!is_queue_empty()) - return POLLIN | POLLRDNORM; - - poll_wait(file_p, &btchr_read_wait, wait); - - return POLLOUT | POLLWRNORM; -} - -static struct file_operations bt_chrdev_ops = { - open : btchr_open, - release : btchr_close, - read : btchr_read, - write : btchr_write, - poll : btchr_poll -}; - -static int btchr_init(void) -{ - int res = 0; - struct device *dev; - - RTKBT_INFO("Register usb char device interface for BT driver"); - /* - * btchr mutex is used to sync between - * 1) downloading patch and opening bt char driver - * 2) the file operations of bt char driver - */ - mutex_init(&btchr_mutex); - - skb_queue_head_init(&btchr_readq); - init_waitqueue_head(&btchr_read_wait); - - bt_char_class = class_create(THIS_MODULE, BT_CHAR_DEVICE_NAME); - if (IS_ERR(bt_char_class)) { - RTKBT_ERR("Failed to create bt char class"); - return PTR_ERR(bt_char_class); - } - - res = alloc_chrdev_region(&bt_devid, 0, 1, BT_CHAR_DEVICE_NAME); - if (res < 0) { - RTKBT_ERR("Failed to allocate bt char device"); - goto err_alloc; - } - - dev = device_create(bt_char_class, NULL, bt_devid, NULL, BT_CHAR_DEVICE_NAME); - if (IS_ERR(dev)) { - RTKBT_ERR("Failed to create bt char device"); - res = PTR_ERR(dev); - goto err_create; - } - - cdev_init(&bt_char_dev, &bt_chrdev_ops); - res = cdev_add(&bt_char_dev, bt_devid, 1); - if (res < 0) { - RTKBT_ERR("Failed to add bt char device"); - goto err_add; - } - - return 0; - -err_add: - device_destroy(bt_char_class, bt_devid); -err_create: - unregister_chrdev_region(bt_devid, 1); -err_alloc: - class_destroy(bt_char_class); - return res; -} - -static void btchr_exit(void) -{ - RTKBT_INFO("Unregister usb char device interface for BT driver"); - - device_destroy(bt_char_class, bt_devid); - cdev_del(&bt_char_dev); - unregister_chrdev_region(bt_devid, 1); - class_destroy(bt_char_class); - - return; -} -#endif - -int send_hci_cmd(firmware_info *fw_info) -{ - int ret_val; - - ret_val = usb_control_msg( - fw_info->udev, fw_info->pipe_out, - 0, USB_TYPE_CLASS, 0, 0, - (void *)(fw_info->send_pkt), - fw_info->pkt_len, MSG_TO); - - return ret_val; -} - -int rcv_hci_evt(firmware_info *fw_info) -{ - int ret_len = 0, ret_val = 0; - int i; - - while (1) { - for(i = 0; i < 5; i++) { - ret_val = usb_interrupt_msg( - fw_info->udev, fw_info->pipe_in, - (void *)(fw_info->rcv_pkt), PKT_LEN, - &ret_len, MSG_TO); - if (ret_val >= 0) - break; - } - - if (ret_val < 0) - return ret_val; - - if (CMD_CMP_EVT == fw_info->evt_hdr->evt) { - if (fw_info->cmd_hdr->opcode == fw_info->cmd_cmp->opcode) - return ret_len; - } - } -} - -int set_bt_onoff(firmware_info *fw_info, uint8_t onoff) -{ - patch_info *patch_entry; - int ret_val; - - RTKBT_INFO("%s: %s", __func__, onoff != 0 ? "on" : "off"); - - patch_entry = fw_info->patch_entry; - if (!patch_entry) - return -1; - - fw_info->cmd_hdr->opcode = cpu_to_le16(BTOFF_OPCODE); - fw_info->cmd_hdr->plen = 1; - fw_info->pkt_len = CMD_HDR_LEN + 1; - fw_info->send_pkt[CMD_HDR_LEN] = onoff; - - ret_val = send_hci_cmd(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to send bt %s cmd, errno %d", - __func__, onoff != 0 ? "on" : "off", ret_val); - return ret_val; - } - - ret_val = rcv_hci_evt(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to receive bt %s event, errno %d", - __func__, onoff != 0 ? "on" : "off", ret_val); - return ret_val; - } - - return ret_val; -} - -static patch_info *get_fw_table_entry(struct usb_device* udev) -{ - patch_info *patch_entry = fw_patch_table; - uint16_t pid = le16_to_cpu(udev->descriptor.idProduct); - uint32_t entry_size = sizeof(fw_patch_table) / sizeof(fw_patch_table[0]); - uint32_t i; - - RTKBT_INFO("%s: Product id = 0x%04x, fw table entry size %d", __func__, pid, entry_size); - - for (i = 0; i < entry_size; i++, patch_entry++) { - if (pid == patch_entry->prod_id) - break; - } - - if (i == entry_size) { - RTKBT_ERR("%s: No fw table entry found", __func__); - return NULL; - } - - return patch_entry; -} - -static struct rtk_epatch_entry *get_fw_patch_entry(struct rtk_epatch *epatch_info, uint16_t eco_ver) -{ - int patch_num = epatch_info->number_of_total_patch; - uint8_t *epatch_buf = (uint8_t *)epatch_info; - struct rtk_epatch_entry *p_entry = NULL; - int coex_date; - int coex_ver; - int i; - - for (i = 0; i < patch_num; i++) { - if (*(uint16_t *)(epatch_buf + 14 + 2*i) == eco_ver + 1) { - p_entry = kzalloc(sizeof(*p_entry), GFP_KERNEL); - if (!p_entry) { - RTKBT_ERR("%s: Failed to allocate mem for patch entry", __func__); - return NULL; - } - p_entry->chip_id = eco_ver + 1; - p_entry->patch_length = *(uint16_t*)(epatch_buf + 14 + 2*patch_num + 2*i); - p_entry->start_offset = *(uint32_t*)(epatch_buf + 14 + 4*patch_num + 4*i); - p_entry->coex_version = *(uint32_t*)(epatch_buf + p_entry->start_offset + p_entry->patch_length - 12); - p_entry->svn_version = *(uint32_t*)(epatch_buf + p_entry->start_offset + p_entry->patch_length - 8); - p_entry->fw_version = *(uint32_t*)(epatch_buf + p_entry->start_offset + p_entry->patch_length - 4); - - coex_date = ((p_entry->coex_version >> 16) & 0x7ff) + ((p_entry->coex_version >> 27) * 10000); - coex_ver = p_entry->coex_version & 0xffff; - - RTKBT_INFO("%s: chip id %d, patch length 0x%04x, patch offset 0x%08x, " - "coex version 20%06d-0x%04x, svn version 0x%08x, fw version 0x%08x", - __func__, p_entry->chip_id, p_entry->patch_length, p_entry->start_offset, - coex_date, coex_ver, p_entry->svn_version, p_entry->fw_version); - break; - } - } - - return p_entry; -} - -/* - * check the return value - * 1: need to download fw patch - * 0: no need to download fw patch - * <0: failed to check lmp version - */ -int check_fw_version(firmware_info* fw_info) -{ - struct hci_rp_read_local_version *read_ver_rsp; - patch_info *patch_entry = NULL; - int ret_val = -1; - - fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_OP_READ_LOCAL_VERSION); - fw_info->cmd_hdr->plen = 0; - fw_info->pkt_len = CMD_HDR_LEN; - - ret_val = send_hci_cmd(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to send hci cmd 0x%04x, errno %d", - __func__, fw_info->cmd_hdr->opcode, ret_val); - return ret_val; - } - - ret_val = rcv_hci_evt(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to receive hci event, errno %d", - __func__, ret_val); - return ret_val; - } - - patch_entry = fw_info->patch_entry; - read_ver_rsp = (struct hci_rp_read_local_version *)(fw_info->rsp_para); - - RTKBT_INFO("%s: Controller lmp = 0x%04x, patch lmp = 0x%04x, default patch lmp = 0x%04x", - __func__, read_ver_rsp->lmp_subver, patch_entry->lmp_sub, patch_entry->lmp_sub_default); - - if (read_ver_rsp->lmp_subver == patch_entry->lmp_sub_default) { - RTKBT_INFO("%s: Cold BT controller startup", __func__); - return 1; - } else if (read_ver_rsp->lmp_subver != patch_entry->lmp_sub) { - RTKBT_INFO("%s: Warm BT controller startup with updated lmp", __func__); - return 1; - } else { - RTKBT_INFO("%s: Warm BT controller startup with same lmp", __func__); - return 0; - } -} - -int get_eversion(firmware_info* fw_info) -{ - struct rtk_eversion_evt *ever_evt; - int ret_val; - - if (!fw_info) - return -ENODEV; - - fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_READ_RTK_ROM_VERISION); - fw_info->cmd_hdr->plen = 0; - fw_info->pkt_len = CMD_HDR_LEN; - - ret_val = send_hci_cmd(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to send hci cmd 0x%04x, errno %d", - __func__, fw_info->cmd_hdr->opcode, ret_val); - return ret_val; - } - - ret_val = rcv_hci_evt(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to receive hci event, errno %d", - __func__, ret_val); - return ret_val; - } - - ever_evt = (struct rtk_eversion_evt *)(fw_info->rsp_para); - - RTKBT_INFO("%s: status %d, eversion %d", __func__, ever_evt->status, ever_evt->version); - - if (ever_evt->status) - fw_info->patch_entry->eversion = 0; - else - fw_info->patch_entry->eversion = ever_evt->version; - - return ret_val; -} - -int load_firmware(firmware_info *fw_info, uint8_t **buff) -{ - const struct firmware *fw, *cfg; - struct usb_device *udev; - patch_info *patch_entry; - char *config_name, *fw_name; - int fw_len = 0; - int ret_val; - - int config_len = 0, buf_len = -1; - uint8_t *buf = *buff, *config_file_buf = NULL; - uint8_t *epatch_buf = NULL; - - struct rtk_epatch *epatch_info = NULL; - uint8_t need_download_fw = 1; - struct rtk_extension_entry patch_lmp = {0}; - struct rtk_epatch_entry *p_epatch_entry = NULL; - uint16_t lmp_version; - //uint8_t use_mp_fw = 0; - RTKBT_DBG("%s: start", __func__); - - udev = fw_info->udev; - patch_entry = fw_info->patch_entry; - lmp_version = patch_entry->lmp_sub_default; - config_name = patch_entry->config_name; - fw_name = patch_entry->patch_name; - - RTKBT_INFO("%s: Default lmp version = 0x%04x, config file name[%s], " - "fw file name[%s]", __func__, lmp_version,config_name, fw_name); - -/* ret_val = request_firmware(&cfg, "mp_test", &udev->dev); - if (ret_val > 0) - config_file_buf = kzalloc(cfg->size, GFP_KERNEL); - if (config_file_buf) { - memcpy(config_file_buf, cfg->data, cfg->size); - use_mp_fw = *config_file_buf; - if (1 == use_mp_fw){ - fw_name = patch_entry->mp_patch_name; - RTKBT_WARN("%s: use_mp_fw = %04d, fw file name[%s]", __func__, use_mp_fw, fw_name); - } - kfree(config_file_buf); - release_firmware(cfg); - } -*/ - ret_val = request_firmware(&cfg, config_name, &udev->dev); - if (ret_val < 0) - config_len = 0; - else { - config_file_buf = kzalloc(cfg->size, GFP_KERNEL); - if (!config_file_buf) - return -ENOMEM; - memcpy(config_file_buf, cfg->data, cfg->size); - config_len = cfg->size; - release_firmware(cfg); - } - - ret_val = request_firmware(&fw, fw_name, &udev->dev); - if (ret_val < 0) - goto fw_fail; - else { - epatch_buf = kzalloc(fw->size, GFP_KERNEL); - if (!epatch_buf) { - release_firmware(fw); - goto fw_fail; - } - memcpy(epatch_buf, fw->data, fw->size); - fw_len = fw->size; - buf_len = fw_len + config_len; - release_firmware(fw); - } - - if (lmp_version == ROM_LMP_8723a) { - RTKBT_DBG("%s: 8723a -> use old style patch", __func__); - if (!memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8)) { - RTKBT_ERR("%s: 8723a check signature error", __func__); - need_download_fw = 0; - } else { - if (!(buf = kzalloc(buf_len, GFP_KERNEL))) { - RTKBT_ERR("%s: Failed to allocate mem for fw&config", __func__); - buf_len = -1; - } else { - RTKBT_DBG("%s: 8723a -> fw copy directly", __func__); - memcpy(buf, epatch_buf, buf_len); - patch_entry->lmp_sub = *(uint16_t *)(buf + buf_len - config_len - 4); - RTKBT_DBG("%s: Config lmp version = 0x%04x", __func__, - patch_entry->lmp_sub); - kfree(epatch_buf); - epatch_buf = NULL; - if (config_len) - memcpy(buf + buf_len - config_len, config_file_buf, config_len); - } - } - } else { - RTKBT_DBG("%s: Not 8723a -> use new style patch", __func__); - ret_val = get_eversion(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to get eversion, errno %d", __func__, ret_val); - goto fw_fail; - } - RTKBT_DBG("%s: Get eversion =%d", __func__, patch_entry->eversion); - if (memcmp(epatch_buf + buf_len - config_len - 4 , EXTENSION_SECTION_SIGNATURE, 4)) { - RTKBT_ERR("%s: Failed to check extension section signature", __func__); - need_download_fw = 0; - } else { - uint8_t *temp; - temp = epatch_buf+buf_len-config_len - 5; - do { - if (*temp == 0x00) { - patch_lmp.opcode = *temp; - patch_lmp.length = *(temp-1); - if ((patch_lmp.data = kzalloc(patch_lmp.length, GFP_KERNEL))) { - int k; - for (k = 0; k < patch_lmp.length; k++) { - *(patch_lmp.data+k) = *(temp-2-k); - RTKBT_DBG("data = 0x%x", *(patch_lmp.data+k)); - } - } - RTKBT_DBG("%s: opcode = 0x%x, length = 0x%x, data = 0x%x", __func__, - patch_lmp.opcode, patch_lmp.length, *(patch_lmp.data)); - break; - } - temp -= *(temp-1) + 2; - } while (*temp != 0xFF); - - if (lmp_version != project_id[*(patch_lmp.data)]) { - RTKBT_ERR("%s: Default lmp_version 0x%04x, project_id 0x%04x " - "-> not match", __func__, lmp_version, project_id[*(patch_lmp.data)]); - if (patch_lmp.data) - kfree(patch_lmp.data); - need_download_fw = 0; - } else { - RTKBT_INFO("%s: Default lmp_version 0x%04x, project_id 0x%04x " - "-> match", __func__, lmp_version, project_id[*(patch_lmp.data)]); - if (patch_lmp.data) - kfree(patch_lmp.data); - if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8)) { - RTKBT_ERR("%s: Check signature error", __func__); - need_download_fw = 0; - } else { - epatch_info = (struct rtk_epatch*)epatch_buf; - patch_entry->lmp_sub = (uint16_t)epatch_info->fw_version; - - RTKBT_DBG("%s: lmp version 0x%04x, fw_version 0x%x, " - "number_of_total_patch %d", __func__, - patch_entry->lmp_sub, epatch_info->fw_version, - epatch_info->number_of_total_patch); - - /* Get right epatch entry */ - p_epatch_entry = get_fw_patch_entry(epatch_info, patch_entry->eversion); - if (p_epatch_entry == NULL) { - RTKBT_WARN("%s: Failed to get fw patch entry", __func__); - ret_val = -1; - goto fw_fail ; - } - - buf_len = p_epatch_entry->patch_length + config_len; - RTKBT_DBG("buf_len = 0x%x", buf_len); - - if (!(buf = kzalloc(buf_len, GFP_KERNEL))) { - RTKBT_ERR("%s: Can't alloc memory for fw&config", __func__); - buf_len = -1; - } else { - memcpy(buf, &epatch_buf[p_epatch_entry->start_offset], p_epatch_entry->patch_length); - memcpy(&buf[p_epatch_entry->patch_length-4], &epatch_info->fw_version, 4); - kfree(p_epatch_entry); - } - kfree(epatch_buf); - epatch_buf = NULL; - - if (config_len) - memcpy(&buf[buf_len - config_len], config_file_buf, config_len); - } - } - } - } - - if (config_file_buf) - kfree(config_file_buf); - - RTKBT_INFO("%s: fw%s exists, config file%s exists", __func__, - (buf_len > 0) ? "" : " not", (config_len > 0) ? "":" not"); - - if (buf && buf_len > 0 && need_download_fw) - *buff = buf; - - RTKBT_DBG("%s: done", __func__); - - return buf_len; - -fw_fail: - if (config_file_buf) - kfree(config_file_buf); - return ret_val; -} - -int get_firmware(firmware_info *fw_info, int cached) -{ - patch_info *patch_entry = fw_info->patch_entry; - - RTKBT_INFO("%s: start, cached %d,patch_entry->fw_len= %d", __func__, cached,patch_entry->fw_len); - - if (cached > 0) { - if (patch_entry->fw_len > 0) { - fw_info->fw_data = kzalloc(patch_entry->fw_len, GFP_KERNEL); - if (!fw_info->fw_data) - return -ENOMEM; - memcpy(fw_info->fw_data, patch_entry->fw_cache, patch_entry->fw_len); - fw_info->fw_len = patch_entry->fw_len; - } else { - fw_info->fw_len = load_firmware(fw_info, &fw_info->fw_data); - if (fw_info->fw_len <= 0) - return -1; - } - } else { - fw_info->fw_len = load_firmware(fw_info, &fw_info->fw_data); - if (fw_info->fw_len <= 0) - return -1; - } - - return 0; -} - -/* - * Open the log message only if in debugging, - * or it will decelerate download procedure. - */ -int download_data(firmware_info *fw_info) -{ - download_cp *cmd_para; - download_rp *evt_para; - uint8_t *pcur; - int pkt_len, frag_num, frag_len; - int i, ret_val; - int ncmd = 1, step = 1; - - RTKBT_DBG("%s: start", __func__); - - cmd_para = (download_cp *)fw_info->req_para; - evt_para = (download_rp *)fw_info->rsp_para; - pcur = fw_info->fw_data; - pkt_len = CMD_HDR_LEN + sizeof(download_cp); - frag_num = fw_info->fw_len / PATCH_SEG_MAX + 1; - frag_len = PATCH_SEG_MAX; - - for (i = 0; i < frag_num; i++) { - cmd_para->index = i; - if (i == (frag_num - 1)) { - cmd_para->index |= DATA_END; - frag_len = fw_info->fw_len % PATCH_SEG_MAX; - pkt_len -= (PATCH_SEG_MAX - frag_len); - } - fw_info->cmd_hdr->opcode = cpu_to_le16(DOWNLOAD_OPCODE); - fw_info->cmd_hdr->plen = sizeof(uint8_t) + frag_len; - fw_info->pkt_len = pkt_len; - memcpy(cmd_para->data, pcur, frag_len); - - if (step > 0) { - ret_val = send_hci_cmd(fw_info); - if (ret_val < 0) { - RTKBT_DBG("%s: Failed to send frag num %d", __func__, cmd_para->index); - return ret_val; - } else - RTKBT_DBG("%s: Send frag num %d", __func__, cmd_para->index); - - if (--step > 0 && i < frag_num - 1) { - RTKBT_DBG("%s: Continue to send frag num %d", __func__, cmd_para->index + 1); - pcur += PATCH_SEG_MAX; - continue; - } - } - - while (ncmd > 0) { - ret_val = rcv_hci_evt(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: rcv_hci_evt err %d", __func__, ret_val); - return ret_val; - } else { - RTKBT_DBG("%s: Receive acked frag num %d", __func__, evt_para->index); - ncmd--; - } - - if (0 != evt_para->status) { - RTKBT_ERR("%s: Receive acked frag num %d, err status %d", - __func__, ret_val, evt_para->status); - return -1; - } - - if ((evt_para->index & DATA_END) || (evt_para->index == frag_num - 1)) { - RTKBT_DBG("%s: Receive last acked index %d", __func__, evt_para->index); - goto end; - } - } - - ncmd = step = fw_info->cmd_cmp->ncmd; - pcur += PATCH_SEG_MAX; - RTKBT_DBG("%s: HCI command packet num %d", __func__, ncmd); - } - - /* - * It is tricky that Host cannot receive DATA_END index from BT - * controller, at least for 8723au. We are doomed if failed. - */ -#if 0 - /* Continue to receive the responsed events until last index occurs */ - if (i == frag_num) { - RTKBT_DBG("%s: total frag count %d", __func__, frag_num); - while (!(evt_para->index & DATA_END)) { - ret_val = rcv_hci_evt(fw_info); - if (ret_val < 0) { - RTKBT_ERR("%s: rcv_hci_evt err %d", __func__, ret_val); - return ret_val; - } - if (0 != evt_para->status) - return -1; - RTKBT_DBG("%s: continue to receive acked frag num %d", __func__, evt_para->index); - } - } -#endif -end: - RTKBT_INFO("%s: done, sent %d frag pkts, received %d frag events", - __func__, cmd_para->index, evt_para->index); - return fw_info->fw_len; -} - -int download_patch(firmware_info *fw_info, int cached) -{ - int ret_val = 0; - - RTKBT_DBG("%s: Download fw patch start, cached %d", __func__, cached); - - if (!fw_info || !fw_info->patch_entry) { - RTKBT_ERR("%s: No patch entry exists(fw_info %p)", __func__, fw_info); - ret_val = -1; - goto end; - } - - /* - * step1: get local firmware if existed - * step2: check firmware version - * step3: download firmware if updated - */ - ret_val = get_firmware(fw_info, cached); - if (ret_val < 0) { - RTKBT_ERR("%s: Failed to get firmware", __func__); - goto end; - } - - ret_val = check_fw_version(fw_info); - if (ret_val > 0) { - ret_val = download_data(fw_info); - if (ret_val > 0) - RTKBT_DBG("%s: Download fw patch done, fw len %d", __func__, ret_val); - } - /* Free fw data after download finished */ - kfree(fw_info->fw_data); - fw_info->fw_data = NULL; - -end: - return ret_val; -} - -firmware_info *firmware_info_init(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - firmware_info *fw_info; - - RTKBT_DBG("%s: start", __func__); - - fw_info = kzalloc(sizeof(*fw_info), GFP_KERNEL); - if (!fw_info) - return NULL; - - fw_info->send_pkt = kzalloc(PKT_LEN, GFP_KERNEL); - if (!fw_info->send_pkt) { - kfree(fw_info); - return NULL; - } - - fw_info->rcv_pkt = kzalloc(PKT_LEN, GFP_KERNEL); - if (!fw_info->rcv_pkt) { - kfree(fw_info->send_pkt); - kfree(fw_info); - return NULL; - } - - fw_info->patch_entry = get_fw_table_entry(udev); - if (!fw_info->patch_entry) { - kfree(fw_info->rcv_pkt); - kfree(fw_info->send_pkt); - kfree(fw_info); - return NULL; - } - - fw_info->intf = intf; - fw_info->udev = udev; - fw_info->pipe_in = usb_rcvintpipe(fw_info->udev, INTR_EP); - fw_info->pipe_out = usb_sndctrlpipe(fw_info->udev, CTRL_EP); - fw_info->cmd_hdr = (struct hci_command_hdr *)(fw_info->send_pkt); - fw_info->evt_hdr = (struct hci_event_hdr *)(fw_info->rcv_pkt); - fw_info->cmd_cmp = (struct hci_ev_cmd_complete *)(fw_info->rcv_pkt + EVT_HDR_LEN); - fw_info->req_para = fw_info->send_pkt + CMD_HDR_LEN; - fw_info->rsp_para = fw_info->rcv_pkt + EVT_HDR_LEN + CMD_CMP_LEN; - -#if BTUSB_RPM - RTKBT_INFO("%s: Auto suspend is enabled", __func__); - usb_enable_autosuspend(udev); - pm_runtime_set_autosuspend_delay(&(udev->dev), 2000); -#else - RTKBT_INFO("%s: Auto suspend is disabled", __func__); - usb_disable_autosuspend(udev); -#endif - -#if BTUSB_WAKEUP_HOST - device_wakeup_enable(&udev->dev); -#endif - - return fw_info; -} - -void firmware_info_destroy(struct usb_interface *intf) -{ - firmware_info *fw_info; - struct usb_device *udev; - struct btusb_data *data; - - udev = interface_to_usbdev(intf); - data = usb_get_intfdata(intf); - - fw_info = data->fw_info; - if (!fw_info) - return; - -#if BTUSB_RPM - usb_disable_autosuspend(udev); -#endif - - /* - * In order to reclaim fw data mem, we free fw_data immediately - * after download patch finished instead of here. - */ - kfree(fw_info->rcv_pkt); - kfree(fw_info->send_pkt); - kfree(fw_info); -} - -static struct usb_driver btusb_driver; - -static struct usb_device_id btusb_table[] = { - { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0bda, - .bInterfaceClass = 0xe0, - .bInterfaceSubClass = 0x01, - .bInterfaceProtocol = 0x01 }, - - { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x13d3, - .bInterfaceClass = 0xe0, - .bInterfaceSubClass = 0x01, - .bInterfaceProtocol = 0x01 }, - - { } -}; - -MODULE_DEVICE_TABLE(usb, btusb_table); - -static int inc_tx(struct btusb_data *data) -{ - unsigned long flags; - int rv; - - spin_lock_irqsave(&data->txlock, flags); - rv = test_bit(BTUSB_SUSPENDING, &data->flags); - if (!rv) - data->tx_in_flight++; - spin_unlock_irqrestore(&data->txlock, flags); - - return rv; -} - -void check_sco_event(struct urb *urb) -{ - u8* opcode = (u8*)(urb->transfer_buffer); - u8 status; - static uint16_t sco_handle = 0; - uint16_t handle; - struct hci_dev *hdev = urb->context; - struct btusb_data *data = GET_DRV_DATA(hdev); - - switch (*opcode) { - case HCI_EV_SYNC_CONN_COMPLETE: - RTKBT_INFO("%s: HCI_EV_SYNC_CONN_COMPLETE(0x%02x)", __func__, *opcode); - status = *(opcode + 2); - sco_handle = *(opcode + 3) | *(opcode + 4) << 8; - if (status == 0) { - hdev->conn_hash.sco_num++; - schedule_work(&data->work); - } - break; - case HCI_EV_DISCONN_COMPLETE: - RTKBT_INFO("%s: HCI_EV_DISCONN_COMPLETE(0x%02x)", __func__, *opcode); - status = *(opcode + 2); - handle = *(opcode + 3) | *(opcode + 4) << 8; - if (status == 0 && sco_handle == handle) { - hdev->conn_hash.sco_num--; - schedule_work(&data->work); - } - break; - default: - RTKBT_DBG("%s: event 0x%02x", __func__, *opcode); - break; - } -} - -static void btusb_intr_complete(struct urb *urb) -{ - struct hci_dev *hdev = urb->context; - struct btusb_data *data = GET_DRV_DATA(hdev); - int err; - - RTKBT_DBG("%s: urb %p status %d count %d ", __func__, - urb, urb->status, urb->actual_length); - - check_sco_event(urb); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - - - if (urb->status == 0) { - hdev->stat.byte_rx += urb->actual_length; - - if (hci_recv_fragment(hdev, HCI_EVENT_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { - RTKBT_ERR("%s: Corrupted event packet", __func__); - hdev->stat.err_rx++; - } - } - /* Avoid suspend failed when usb_kill_urb */ - else if(urb->status == -ENOENT) { - return; - } - - - if (!test_bit(BTUSB_INTR_RUNNING, &data->flags)) - return; - - usb_mark_last_busy(data->udev); - usb_anchor_urb(urb, &data->intr_anchor); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - /* EPERM: urb is being killed; - * ENODEV: device got disconnected */ - if (err != -EPERM && err != -ENODEV) - RTKBT_ERR("%s: Failed to re-submit urb %p, err %d", - __func__, urb, err); - usb_unanchor_urb(urb); - } -} - -static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - struct urb *urb; - unsigned char *buf; - unsigned int pipe; - int err, size; - - if (!data->intr_ep) - return -ENODEV; - - urb = usb_alloc_urb(0, mem_flags); - if (!urb) - return -ENOMEM; - - size = le16_to_cpu(data->intr_ep->wMaxPacketSize); - - buf = kmalloc(size, mem_flags); - if (!buf) { - usb_free_urb(urb); - return -ENOMEM; - } - - RTKBT_DBG("%s: mMaxPacketSize %d, bEndpointAddress 0x%02x", - __func__, size, data->intr_ep->bEndpointAddress); - - pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress); - - usb_fill_int_urb(urb, data->udev, pipe, buf, size, - btusb_intr_complete, hdev, - data->intr_ep->bInterval); - - urb->transfer_flags |= URB_FREE_BUFFER; - - usb_anchor_urb(urb, &data->intr_anchor); - - err = usb_submit_urb(urb, mem_flags); - if (err < 0) { - RTKBT_ERR("%s: Failed to submit urb %p, err %d", - __func__, urb, err); - usb_unanchor_urb(urb); - } - - usb_free_urb(urb); - - return err; -} - -static void btusb_bulk_complete(struct urb *urb) -{ - struct hci_dev *hdev = urb->context; - struct btusb_data *data = GET_DRV_DATA(hdev); - int err; - - RTKBT_DBG("%s: urb %p status %d count %d", - __func__, urb, urb->status, urb->actual_length); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - - if (urb->status == 0) { - hdev->stat.byte_rx += urb->actual_length; - - if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { - RTKBT_ERR("%s: Corrupted ACL packet", __func__); - hdev->stat.err_rx++; - } - } - /* Avoid suspend failed when usb_kill_urb */ - else if(urb->status == -ENOENT) { - return; - } - - - if (!test_bit(BTUSB_BULK_RUNNING, &data->flags)) - return; - - usb_anchor_urb(urb, &data->bulk_anchor); - usb_mark_last_busy(data->udev); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - /* -EPERM: urb is being killed; - * -ENODEV: device got disconnected */ - if (err != -EPERM && err != -ENODEV) - RTKBT_ERR("btusb_bulk_complete %s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); - usb_unanchor_urb(urb); - } -} - -static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - struct urb *urb; - unsigned char *buf; - unsigned int pipe; - int err, size = HCI_MAX_FRAME_SIZE; - - RTKBT_DBG("%s: hdev name %s", __func__, hdev->name); - - if (!data->bulk_rx_ep) - return -ENODEV; - - urb = usb_alloc_urb(0, mem_flags); - if (!urb) - return -ENOMEM; - - buf = kmalloc(size, mem_flags); - if (!buf) { - usb_free_urb(urb); - return -ENOMEM; - } - - pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress); - - usb_fill_bulk_urb(urb, data->udev, pipe, - buf, size, btusb_bulk_complete, hdev); - - urb->transfer_flags |= URB_FREE_BUFFER; - - usb_mark_last_busy(data->udev); - usb_anchor_urb(urb, &data->bulk_anchor); - - err = usb_submit_urb(urb, mem_flags); - if (err < 0) { - RTKBT_ERR("%s: Failed to submit urb %p, err %d", __func__, urb, err); - usb_unanchor_urb(urb); - } - - usb_free_urb(urb); - - return err; -} - -static void btusb_isoc_complete(struct urb *urb) -{ - struct hci_dev *hdev = urb->context; - struct btusb_data *data = GET_DRV_DATA(hdev); - int i, err; - - - RTKBT_DBG("%s: urb %p status %d count %d", - __func__, urb, urb->status, urb->actual_length); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - - if (urb->status == 0) { - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int offset = urb->iso_frame_desc[i].offset; - unsigned int length = urb->iso_frame_desc[i].actual_length; - - if (urb->iso_frame_desc[i].status) - continue; - - hdev->stat.byte_rx += length; - - if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, - urb->transfer_buffer + offset, - length) < 0) { - RTKBT_ERR("%s: Corrupted SCO packet", __func__); - hdev->stat.err_rx++; - } - } - } - /* Avoid suspend failed when usb_kill_urb */ - else if(urb->status == -ENOENT) { - return; - } - - - if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags)) - return; - - usb_anchor_urb(urb, &data->isoc_anchor); - i = 0; -retry: - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - /* -EPERM: urb is being killed; - * -ENODEV: device got disconnected */ - if (err != -EPERM && err != -ENODEV) - RTKBT_ERR("%s: Failed to re-sumbit urb %p, retry %d, err %d", - __func__, urb, i, err); - if (i < 10) { - i++; - mdelay(1); - goto retry; - } - - usb_unanchor_urb(urb); - } -} - -static inline void fill_isoc_descriptor(struct urb *urb, int len, int mtu) -{ - int i, offset = 0; - - RTKBT_DBG("%s: len %d mtu %d", __func__, len, mtu); - - for (i = 0; i < BTUSB_MAX_ISOC_FRAMES && len >= mtu; - i++, offset += mtu, len -= mtu) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = mtu; - } - - if (len && i < BTUSB_MAX_ISOC_FRAMES) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = len; - i++; - } - - urb->number_of_packets = i; -} - -static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - struct urb *urb; - unsigned char *buf; - unsigned int pipe; - int err, size; - - if (!data->isoc_rx_ep) - return -ENODEV; - - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags); - if (!urb) - return -ENOMEM; - - size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * - BTUSB_MAX_ISOC_FRAMES; - - buf = kmalloc(size, mem_flags); - if (!buf) { - usb_free_urb(urb); - return -ENOMEM; - } - - pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); - - urb->dev = data->udev; - urb->pipe = pipe; - urb->context = hdev; - urb->complete = btusb_isoc_complete; - urb->interval = data->isoc_rx_ep->bInterval; - - urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; - urb->transfer_buffer = buf; - urb->transfer_buffer_length = size; - - fill_isoc_descriptor(urb, size, - le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); - - usb_anchor_urb(urb, &data->isoc_anchor); - - err = usb_submit_urb(urb, mem_flags); - if (err < 0) { - RTKBT_ERR("%s: Failed to submit urb %p, err %d", __func__, urb, err); - usb_unanchor_urb(urb); - } - - usb_free_urb(urb); - - return err; -} - -static void btusb_tx_complete(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct btusb_data *data = GET_DRV_DATA(hdev); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - goto done; - - if (!urb->status) - hdev->stat.byte_tx += urb->transfer_buffer_length; - else - hdev->stat.err_tx++; - -done: - spin_lock(&data->txlock); - data->tx_in_flight--; - spin_unlock(&data->txlock); - - kfree(urb->setup_packet); - - kfree_skb(skb); -} - -static void btusb_isoc_tx_complete(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - - RTKBT_DBG("%s: urb %p status %d count %d", - __func__, urb, urb->status, urb->actual_length); - - if (skb && hdev) { - if (!test_bit(HCI_RUNNING, &hdev->flags)) - goto done; - - if (!urb->status) - hdev->stat.byte_tx += urb->transfer_buffer_length; - else - hdev->stat.err_tx++; - } else - RTKBT_ERR("%s: skb 0x%p hdev 0x%p", __func__, skb, hdev); - -done: - kfree(urb->setup_packet); - - kfree_skb(skb); -} - -static int btusb_open(struct hci_dev *hdev) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - int err = 0; - - RTKBT_INFO("%s: Start, PM usage count %d", __func__, - atomic_read(&(data->intf->pm_usage_cnt))); - - err = usb_autopm_get_interface(data->intf); - if (err < 0) - return err; - - data->intf->needs_remote_wakeup = 1; - - err = download_patch(data->fw_info, 1); - if (err < 0) goto failed; - - if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) - goto done; - - if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) - goto done; - - err = btusb_submit_intr_urb(hdev, GFP_KERNEL); - if (err < 0) - goto failed; - - err = btusb_submit_bulk_urb(hdev, GFP_KERNEL); - if (err < 0) { - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->intr_anchor); - goto failed; - } - - set_bit(BTUSB_BULK_RUNNING, &data->flags); - btusb_submit_bulk_urb(hdev, GFP_KERNEL); - -done: - usb_autopm_put_interface(data->intf); - RTKBT_INFO("%s: End, PM usage count %d", __func__, - atomic_read(&(data->intf->pm_usage_cnt))); - return 0; - -failed: - clear_bit(BTUSB_INTR_RUNNING, &data->flags); - clear_bit(HCI_RUNNING, &hdev->flags); - usb_autopm_put_interface(data->intf); - RTKBT_ERR("%s: Failed, PM usage count %d", __func__, - atomic_read(&(data->intf->pm_usage_cnt))); - return err; -} - -static void btusb_stop_traffic(struct btusb_data *data) -{ - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->intr_anchor); - usb_kill_anchored_urbs(&data->bulk_anchor); - usb_kill_anchored_urbs(&data->isoc_anchor); -} - -static int btusb_close(struct hci_dev *hdev) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - int i, err; - - RTKBT_INFO("%s: hci running %lu", __func__, hdev->flags & HCI_RUNNING); - - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) - return 0; - - for (i = 0; i < NUM_REASSEMBLY; i++) { - if (hdev->reassembly[i]) { - RTKBT_DBG("%s: free ressembly[%d]", __func__, i); - kfree_skb(hdev->reassembly[i]); - hdev->reassembly[i] = NULL; - } - } - - cancel_work_sync(&data->work); - cancel_work_sync(&data->waker); - - clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - clear_bit(BTUSB_INTR_RUNNING, &data->flags); - - btusb_stop_traffic(data); - err = usb_autopm_get_interface(data->intf); - if (err < 0) - goto failed; - - data->intf->needs_remote_wakeup = 0; - usb_autopm_put_interface(data->intf); - -failed: - mdelay(URB_CANCELING_DELAY_MS); - usb_scuttle_anchored_urbs(&data->deferred); - return 0; -} - -static int btusb_flush(struct hci_dev *hdev) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - - RTKBT_DBG("%s", __func__); - - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->tx_anchor); - - return 0; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) -static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) -{ -#else -static int btusb_send_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; -#endif - struct btusb_data *data = GET_DRV_DATA(hdev); - struct usb_ctrlrequest *dr; - struct urb *urb; - unsigned int pipe; - int err; - int retries = 0; - - RTKBT_DBG("%s: hdev %p, btusb data %p, pkt type %d", - __func__, hdev, data, bt_cb(skb)->pkt_type); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return -EBUSY; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) - skb->dev = (void *)hdev; -#endif - - switch (bt_cb(skb)->pkt_type) { - case HCI_COMMAND_PKT: - print_command(skb); - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - dr = kmalloc(sizeof(*dr), GFP_ATOMIC); - if (!dr) { - usb_free_urb(urb); - return -ENOMEM; - } - - dr->bRequestType = data->cmdreq_type; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = __cpu_to_le16(skb->len); - - pipe = usb_sndctrlpipe(data->udev, 0x00); - - usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, - skb->data, skb->len, btusb_tx_complete, skb); - - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - print_acl(skb, 1); - if (!data->bulk_tx_ep) - return -ENODEV; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - pipe = usb_sndbulkpipe(data->udev, - data->bulk_tx_ep->bEndpointAddress); - - usb_fill_bulk_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_tx_complete, skb); - - hdev->stat.acl_tx++; - break; - - case HCI_SCODATA_PKT: - print_sco(skb, 1); - if (!data->isoc_tx_ep || SCO_NUM < 1) { - kfree(skb); - return -ENODEV; - } - - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!urb) { - RTKBT_ERR("%s: Failed to allocate mem for sco pkts", __func__); - kfree(skb); - return -ENOMEM; - } - - pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); - - usb_fill_int_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_isoc_tx_complete, - skb, data->isoc_tx_ep->bInterval); - - urb->transfer_flags = URB_ISO_ASAP; - - fill_isoc_descriptor(urb, skb->len, - le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); - - hdev->stat.sco_tx++; - goto skip_waking; - - default: - return -EILSEQ; - } - - err = inc_tx(data); - if (err) { - usb_anchor_urb(urb, &data->deferred); - schedule_work(&data->waker); - err = 0; - goto done; - } - -skip_waking: - usb_anchor_urb(urb, &data->tx_anchor); -retry: - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - RTKBT_ERR("%s: Failed to submit urb %p, pkt type %d, err %d, retries %d", - __func__, urb, bt_cb(skb)->pkt_type, err, retries); - if ((bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) && (retries < 10)) { - mdelay(1); - - if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) - print_error_command(skb); - retries++; - goto retry; - } - kfree(urb->setup_packet); - usb_unanchor_urb(urb); - } else - usb_mark_last_busy(data->udev); - usb_free_urb(urb); - -done: - return err; -} - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) -static void btusb_destruct(struct hci_dev *hdev) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - - RTKBT_DBG("%s: name %s", __func__, hdev->name); - - kfree(data); -} -#endif - -static void btusb_notify(struct hci_dev *hdev, unsigned int evt) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - - RTKBT_DBG("%s: name %s, evt %d", __func__, hdev->name, evt); - - if (SCO_NUM != data->sco_num) { - data->sco_num = SCO_NUM; - schedule_work(&data->work); - } -} - -static inline int set_isoc_interface(struct hci_dev *hdev, int altsetting) -{ - struct btusb_data *data = GET_DRV_DATA(hdev); - struct usb_interface *intf = data->isoc; - struct usb_endpoint_descriptor *ep_desc; - int i, err; - - if (!data->isoc) - return -ENODEV; - - err = usb_set_interface(data->udev, 1, altsetting); - if (err < 0) { - RTKBT_ERR("%s: Failed to set interface, altsetting %d, err %d", - __func__, altsetting, err); - return err; - } - - data->isoc_altsetting = altsetting; - - data->isoc_tx_ep = NULL; - data->isoc_rx_ep = NULL; - - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { - ep_desc = &intf->cur_altsetting->endpoint[i].desc; - - if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) { - data->isoc_tx_ep = ep_desc; - continue; - } - - if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) { - data->isoc_rx_ep = ep_desc; - continue; - } - } - - if (!data->isoc_tx_ep || !data->isoc_rx_ep) { - RTKBT_ERR("%s: Invalid SCO descriptors", __func__); - return -ENODEV; - } - - return 0; -} - -static void btusb_work(struct work_struct *work) -{ - struct btusb_data *data = container_of(work, struct btusb_data, work); - struct hci_dev *hdev = data->hdev; - int err; - int new_alts; - if (data->sco_num > 0) { - if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) { - err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf); - if (err < 0) { - clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->isoc_anchor); - return; - } - - set_bit(BTUSB_DID_ISO_RESUME, &data->flags); - } -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1) - if (hdev->voice_setting & 0x0020) { - static const int alts[3] = { 2, 4, 5 }; - new_alts = alts[data->sco_num - 1]; - } else{ - new_alts = data->sco_num; - } - if (data->isoc_altsetting != new_alts) { -#else - if (data->isoc_altsetting != 2) { - new_alts = 2; -#endif - - clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->isoc_anchor); - - if (set_isoc_interface(hdev, new_alts) < 0) - return; - } - - if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { - if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0) - clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - else - btusb_submit_isoc_urb(hdev, GFP_KERNEL); - } - } else { - clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->isoc_anchor); - - set_isoc_interface(hdev, 0); - if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags)) - usb_autopm_put_interface(data->isoc ? data->isoc : data->intf); - } -} - -static void btusb_waker(struct work_struct *work) -{ - struct btusb_data *data = container_of(work, struct btusb_data, waker); - int err; - - RTKBT_DBG("%s: PM usage count %d", __func__, - atomic_read(&data->intf->pm_usage_cnt)); - - err = usb_autopm_get_interface(data->intf); - if (err < 0) - return; - - usb_autopm_put_interface(data->intf); -} - - -//#ifdef CONFIG_HAS_EARLYSUSPEND -#if 0 -static void btusb_early_suspend(struct early_suspend *h) -{ - struct btusb_data *data; - firmware_info *fw_info; - patch_info *patch_entry; - - RTKBT_INFO("%s", __func__); - - data = container_of(h, struct btusb_data, early_suspend); - fw_info = data->fw_info; - patch_entry = fw_info->patch_entry; - - patch_entry->fw_len = load_firmware(fw_info, &patch_entry->fw_cache); - if (patch_entry->fw_len <= 0) { - /* We may encount failure in loading firmware, just give a warning */ - RTKBT_WARN("%s: Failed to load firmware", __func__); - } -} - -static void btusb_late_resume(struct early_suspend *h) -{ - struct btusb_data *data; - firmware_info *fw_info; - patch_info *patch_entry; - - RTKBT_INFO("%s", __func__); - - data = container_of(h, struct btusb_data, early_suspend); - fw_info = data->fw_info; - patch_entry = fw_info->patch_entry; - - /* Reclaim fw buffer when bt usb resumed */ - if (patch_entry->fw_len > 0) { - kfree(patch_entry->fw_cache); - patch_entry->fw_cache = NULL; - patch_entry->fw_len = 0; - } -} -#else -int bt_pm_notify(struct notifier_block *notifier, ulong pm_event, void *unused) -{ - struct btusb_data *data; - firmware_info *fw_info; - patch_info *patch_entry; - struct usb_device *udev; - - RTKBT_INFO("%s: pm event %ld", __func__, pm_event); - - data = container_of(notifier, struct btusb_data, pm_notifier); - fw_info = data->fw_info; - patch_entry = fw_info->patch_entry; - udev = fw_info->udev; - - switch (pm_event) { - case PM_SUSPEND_PREPARE: - case PM_HIBERNATION_PREPARE: -#if 0 - patch_entry->fw_len = load_firmware(fw_info, &patch_entry->fw_cache); - if (patch_entry->fw_len <= 0) { - /* We may encount failure in loading firmware, just give a warning */ - RTKBT_WARN("%s: Failed to load firmware", __func__); - } -#endif - if (!device_may_wakeup(&udev->dev)) { -#if (CONFIG_RESET_RESUME || CONFIG_BLUEDROID) - RTKBT_INFO("%s:remote wakeup not supported, reset resume supported", __func__); -#else -/*this will force usb driver to disconnect/probe*/ - fw_info->intf->needs_binding = 1; - RTKBT_INFO("%s:remote wakeup not supported, binding needed", __func__); -#endif - } - break; - - case PM_POST_SUSPEND: - case PM_POST_HIBERNATION: - case PM_POST_RESTORE: -#if 0 - /* Reclaim fw buffer when bt usb resumed */ - if (patch_entry->fw_len > 0) { - kfree(patch_entry->fw_cache); - patch_entry->fw_cache = NULL; - patch_entry->fw_len = 0; - } -#endif - -#if BTUSB_RPM - usb_disable_autosuspend(udev); - usb_enable_autosuspend(udev); - pm_runtime_set_autosuspend_delay(&(udev->dev), 2000); -#endif - break; - - default: - break; - } - - return NOTIFY_DONE; -} -#endif - -static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_endpoint_descriptor *ep_desc; - struct btusb_data *data; - struct hci_dev *hdev; - firmware_info *fw_info; - int i, err=0; - - RTKBT_INFO("%s: usb_interface %p, bInterfaceNumber %d, idVendor 0x%04x, " - "idProduct 0x%04x", __func__, intf, - intf->cur_altsetting->desc.bInterfaceNumber, - id->idVendor, id->idProduct); - - /* interface numbers are hardcoded in the spec */ - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return -ENODEV; - - RTKBT_DBG("%s: can wakeup = %x, may wakeup = %x", __func__, - device_can_wakeup(&udev->dev), device_may_wakeup(&udev->dev)); - - data = rtk_alloc(intf); - if (!data) - return -ENOMEM; - - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { - ep_desc = &intf->cur_altsetting->endpoint[i].desc; - - if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) { - data->intr_ep = ep_desc; - continue; - } - - if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) { - data->bulk_tx_ep = ep_desc; - continue; - } - - if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) { - data->bulk_rx_ep = ep_desc; - continue; - } - } - - if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { - rtk_free(data); - return -ENODEV; - } - - data->cmdreq_type = USB_TYPE_CLASS; - - data->udev = udev; - data->intf = intf; - - spin_lock_init(&data->lock); - - INIT_WORK(&data->work, btusb_work); - INIT_WORK(&data->waker, btusb_waker); - spin_lock_init(&data->txlock); - - init_usb_anchor(&data->tx_anchor); - init_usb_anchor(&data->intr_anchor); - init_usb_anchor(&data->bulk_anchor); - init_usb_anchor(&data->isoc_anchor); - init_usb_anchor(&data->deferred); - - fw_info = firmware_info_init(intf); - if (fw_info) - data->fw_info = fw_info; - else { - RTKBT_WARN("%s: Failed to initialize fw info", __func__); - /* Skip download patch */ - goto end; - } - - RTKBT_INFO("%s: download begining...", __func__); - -#if CONFIG_BLUEDROID - mutex_lock(&btchr_mutex); -#endif - -#if 0 - err = download_patch(fw_info, 0); - /* If download failed, we just throw out a warning */ - if (err < 0) - RTKBT_WARN("%s: Failed to download fw patch", __func__); -#endif - -#if CONFIG_BLUEDROID - mutex_unlock(&btchr_mutex); -#endif - - RTKBT_INFO("%s: download ending...", __func__); - - hdev = hci_alloc_dev(); - if (!hdev) { - rtk_free(data); - data = NULL; - return -ENOMEM; - } - - HDEV_BUS = HCI_USB; - - data->hdev = hdev; - - SET_HCIDEV_DEV(hdev, &intf->dev); - - hdev->open = btusb_open; - hdev->close = btusb_close; - hdev->flush = btusb_flush; - hdev->send = btusb_send_frame; - hdev->notify = btusb_notify; - -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0) - hci_set_drvdata(hdev, data); -#else - hdev->driver_data = data; - hdev->destruct = btusb_destruct; - hdev->owner = THIS_MODULE; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 1) - if (!reset_on_close){ - /* set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); */ - RTKBT_DBG("%s: Set HCI_QUIRK_RESET_ON_CLOSE", __func__); - } -#endif - - /* Interface numbers are hardcoded in the specification */ - data->isoc = usb_ifnum_to_if(data->udev, 1); - if (data->isoc) { - err = usb_driver_claim_interface(&btusb_driver, - data->isoc, data); - if (err < 0) { - hci_free_dev(hdev); - hdev = NULL; - rtk_free(data); - data = NULL; - return err; - } - } - - err = hci_register_dev(hdev); - if (err < 0) { - hci_free_dev(hdev); - hdev = NULL; - rtk_free(data); - data = NULL; - return err; - } - - usb_set_intfdata(intf, data); - -//#ifdef CONFIG_HAS_EARLYSUSPEND -#if 0 - data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; - data->early_suspend.suspend = btusb_early_suspend; - data->early_suspend.resume = btusb_late_resume; - register_early_suspend(&data->early_suspend); -#else - data->pm_notifier.notifier_call = bt_pm_notify; - register_pm_notifier(&data->pm_notifier); -#endif - -#if CONFIG_BLUEDROID - RTKBT_INFO("%s: Check bt reset flag %d", __func__, bt_reset); - /* Report hci hardware error after everthing is ready, - * especially hci register is completed. Or, btchr_poll - * will get null hci dev when hotplug in. - */ - if (bt_reset == 1) { - hci_hardware_error(); - bt_reset = 0; - } else - bt_reset = 0; /* Clear and reset it anyway */ -#endif - -end: - return 0; -} - -static void btusb_disconnect(struct usb_interface *intf) -{ - struct btusb_data *data = usb_get_intfdata(intf); - struct hci_dev *hdev = NULL; - - RTKBT_INFO("%s: usb_interface %p, bInterfaceNumber %d", - __func__, intf, intf->cur_altsetting->desc.bInterfaceNumber); - - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return; - - if (data) - hdev = data->hdev; - else { - RTKBT_WARN("%s: Failed to get bt usb data[Null]", __func__); - return; - } - -//#ifdef CONFIG_HAS_EARLYSUSPEND -#if 0 - unregister_early_suspend(&data->early_suspend); -#else - unregister_pm_notifier(&data->pm_notifier); -#endif - - firmware_info_destroy(intf); - -#if CONFIG_BLUEDROID - if (test_bit(HCI_RUNNING, &hdev->flags)) { - RTKBT_INFO("%s: Set BT reset flag", __func__); - bt_reset = 1; - } -#endif - - usb_set_intfdata(data->intf, NULL); - - if (data->isoc) - usb_set_intfdata(data->isoc, NULL); - - hci_unregister_dev(hdev); - - if (intf == data->isoc) - usb_driver_release_interface(&btusb_driver, data->intf); - else if (data->isoc) - usb_driver_release_interface(&btusb_driver, data->isoc); - -#if !CONFIG_BLUEDROID -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) - __hci_dev_put(hdev); -#endif -#endif - - hci_free_dev(hdev); - rtk_free(data); - data = NULL; -} - -#ifdef CONFIG_PM -static int btusb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct btusb_data *data = usb_get_intfdata(intf); - firmware_info *fw_info = data->fw_info; - - RTKBT_INFO("%s: event 0x%x, suspend count %d", __func__, - message.event, data->suspend_count); - - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return 0; - - if (!test_bit(HCI_RUNNING, &data->hdev->flags)) - set_bt_onoff(fw_info, 1); - - if (data->suspend_count++) - return 0; - - spin_lock_irq(&data->txlock); - if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) { - set_bit(BTUSB_SUSPENDING, &data->flags); - spin_unlock_irq(&data->txlock); - } else { - spin_unlock_irq(&data->txlock); - data->suspend_count--; - RTKBT_ERR("%s: Failed to enter suspend", __func__); - return -EBUSY; - } - - cancel_work_sync(&data->work); - - btusb_stop_traffic(data); - mdelay(URB_CANCELING_DELAY_MS); - usb_kill_anchored_urbs(&data->tx_anchor); - - return 0; -} - -static void play_deferred(struct btusb_data *data) -{ - struct urb *urb; - int err; - - while ((urb = usb_get_from_anchor(&data->deferred))) { - usb_anchor_urb(urb, &data->tx_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - RTKBT_ERR("%s: Failed to submit urb %p, err %d", - __func__, urb, err); - kfree(urb->setup_packet); - usb_unanchor_urb(urb); - } else { - usb_mark_last_busy(data->udev); - } - usb_free_urb(urb); - - data->tx_in_flight++; - } - mdelay(URB_CANCELING_DELAY_MS); - usb_scuttle_anchored_urbs(&data->deferred); -} - -static int btusb_resume(struct usb_interface *intf) -{ - struct btusb_data *data = usb_get_intfdata(intf); - struct hci_dev *hdev = data->hdev; - //firmware_info *fw_info = data->fw_info; - int err = 0; - - RTKBT_INFO("%s: Suspend count %d", __func__, data->suspend_count); - - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return 0; - -#if 0 - if (!test_bit(HCI_RUNNING, &hdev->flags)) { - RTKBT_INFO("%s: Bt is off, download patch before bt is on", __func__); - download_patch(fw_info, 1); - } -#endif - - if (--data->suspend_count) - return 0; - - if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) { - err = btusb_submit_intr_urb(hdev, GFP_NOIO); - if (err < 0) { - clear_bit(BTUSB_INTR_RUNNING, &data->flags); - goto failed; - } - } - - if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) { - err = btusb_submit_bulk_urb(hdev, GFP_NOIO); - if (err < 0) { - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - goto failed; - } - - btusb_submit_bulk_urb(hdev, GFP_NOIO); - } - - if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) { - if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0) - clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - else - btusb_submit_isoc_urb(hdev, GFP_NOIO); - } - - spin_lock_irq(&data->txlock); - play_deferred(data); - clear_bit(BTUSB_SUSPENDING, &data->flags); - spin_unlock_irq(&data->txlock); - schedule_work(&data->work); - - return 0; - -failed: - mdelay(URB_CANCELING_DELAY_MS); - usb_scuttle_anchored_urbs(&data->deferred); - spin_lock_irq(&data->txlock); - clear_bit(BTUSB_SUSPENDING, &data->flags); - spin_unlock_irq(&data->txlock); - - return err; -} -#endif - -static struct usb_driver btusb_driver = { - .name = "rtk_btusb", - .probe = btusb_probe, - .disconnect = btusb_disconnect, -#ifdef CONFIG_PM - .suspend = btusb_suspend, - .resume = btusb_resume, -#endif -#if CONFIG_RESET_RESUME - .reset_resume = btusb_resume, -#endif - .id_table = btusb_table, - .supports_autosuspend = 1, -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1) - .disable_hub_initiated_lpm = 1, -#endif -}; - -static int __init btusb_init(void) -{ - int err; - - RTKBT_INFO("Realtek Bluetooth USB driver module init, version %s", VERSION); -#if CONFIG_BLUEDROID - err = btchr_init(); - if (err < 0) { - /* usb register will go on, even bt char register failed */ - RTKBT_ERR("Failed to register usb char device interfaces"); - } else - bt_char_dev_registered = 1; -#endif - err = usb_register(&btusb_driver); - if (err < 0) - RTKBT_ERR("Failed to register RTK bluetooth USB driver"); - return err; -} - -static void __exit btusb_exit(void) -{ - RTKBT_INFO("Realtek Bluetooth USB driver module exit"); -#if CONFIG_BLUEDROID - if (bt_char_dev_registered > 0) - btchr_exit(); -#endif - usb_deregister(&btusb_driver); -} - -module_init(btusb_init); -module_exit(btusb_exit); - -MODULE_AUTHOR("Realtek Corporation"); -MODULE_DESCRIPTION("Realtek Bluetooth USB driver version"); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/rtk_btusb.h b/drivers/bluetooth/rtk_btusb.h deleted file mode 100755 index 4dc390f8d36d..000000000000 --- a/drivers/bluetooth/rtk_btusb.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * - * Realtek Bluetooth USB driver - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 -#include -#include -#include - -#define CONFIG_BLUEDROID 1 /* bleuz 0, bluedroid 1 */ - -/* Some Android system may use standard Linux kernel, while - * standard Linux may also implement early suspend feature. - * So exclude earysuspend.h from CONFIG_BLUEDROID. - */ -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif - -#if CONFIG_BLUEDROID -#else -#include -#include -#include -#endif - - -/*********************************** -** Realtek - For rtk_btusb driver ** -***********************************/ -#define URB_CANCELING_DELAY_MS 10 -/* when OS suspended, module is still powered,usb is not powered, - * this may set to 1, and must comply with special patch code. - */ -#define CONFIG_RESET_RESUME 0 -#define PRINT_CMD_EVENT 0 -#define PRINT_ACL_DATA 0 -#define PRINT_SCO_DATA 0 - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33) -#define HDEV_BUS hdev->bus -#define USB_RPM 1 -#else -#define HDEV_BUS hdev->type -#define USB_RPM 0 -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) -#define NUM_REASSEMBLY 3 -#endif - -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0) -#define GET_DRV_DATA(x) hci_get_drvdata(x) -#else -#define GET_DRV_DATA(x) x->driver_data -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) -#define SCO_NUM hdev->conn_hash.sco_num -#else -#define SCO_NUM hci_conn_num(hdev, SCO_LINK) -#endif - -#define BTUSB_RPM (0 * USB_RPM) /* 1 SS enable; 0 SS disable */ -#define BTUSB_WAKEUP_HOST 0 /* 1 enable; 0 disable */ -#define BTUSB_MAX_ISOC_FRAMES 10 -#define BTUSB_INTR_RUNNING 0 -#define BTUSB_BULK_RUNNING 1 -#define BTUSB_ISOC_RUNNING 2 -#define BTUSB_SUSPENDING 3 -#define BTUSB_DID_ISO_RESUME 4 - -#define HCI_CMD_READ_BD_ADDR 0x1009 -#define HCI_VENDOR_CHANGE_BDRATE 0xfc17 -#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d -#define HCI_VENDOR_READ_LMP_VERISION 0x1001 - -#define ROM_LMP_8723a 0x1200 -#define ROM_LMP_8723b 0x8723 -#define ROM_LMP_8821a 0X8821 -#define ROM_LMP_8761a 0X8761 - -/* signature: Realtek */ -const uint8_t RTK_EPATCH_SIGNATURE[8] = {0x52,0x65,0x61,0x6C,0x74,0x65,0x63,0x68}; -/* Extension Section IGNATURE:0x77FD0451 */ -const uint8_t EXTENSION_SECTION_SIGNATURE[4] = {0x51,0x04,0xFD,0x77}; - -uint16_t project_id[] = { - ROM_LMP_8723a, - ROM_LMP_8723b, - ROM_LMP_8821a, - ROM_LMP_8761a -}; -struct rtk_eversion_evt { - uint8_t status; - uint8_t version; -} __attribute__ ((packed)); - -struct rtk_epatch_entry { - uint16_t chip_id; - uint16_t patch_length; - uint32_t start_offset; - uint32_t coex_version; - uint32_t svn_version; - uint32_t fw_version; -} __attribute__ ((packed)); - -struct rtk_epatch { - uint8_t signature[8]; - uint32_t fw_version; - uint16_t number_of_total_patch; - struct rtk_epatch_entry entry[0]; -} __attribute__ ((packed)); - -struct rtk_extension_entry { - uint8_t opcode; - uint8_t length; - uint8_t *data; -} __attribute__ ((packed)); -/* Realtek - For rtk_btusb driver end */ - -#if CONFIG_BLUEDROID -#define QUEUE_SIZE 500 - -/*************************************** -** Realtek - Integrate from bluetooth.h ** -*****************************************/ -/* Reserv for core and drivers use */ -#define BT_SKB_RESERVE 8 - -/* BD Address */ -typedef struct { - __u8 b[6]; -} __packed bdaddr_t; - -/* Skb helpers */ -struct bt_skb_cb { - __u8 pkt_type; - __u8 incoming; - __u16 expect; - __u16 tx_seq; - __u8 retries; - __u8 sar; - __u8 force_active; -}; - -#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) - -static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how) -{ - struct sk_buff *skb; - - if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) { - skb_reserve(skb, BT_SKB_RESERVE); - bt_cb(skb)->incoming = 0; - } - return skb; -} -/* Realtek - Integrate from bluetooth.h end */ - -/*********************************** -** Realtek - Integrate from hci.h ** -***********************************/ -#define HCI_MAX_ACL_SIZE 1024 -#define HCI_MAX_SCO_SIZE 255 -#define HCI_MAX_EVENT_SIZE 260 -#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) - -/* HCI bus types */ -#define HCI_VIRTUAL 0 -#define HCI_USB 1 -#define HCI_PCCARD 2 -#define HCI_UART 3 -#define HCI_RS232 4 -#define HCI_PCI 5 -#define HCI_SDIO 6 - -/* HCI controller types */ -#define HCI_BREDR 0x00 -#define HCI_AMP 0x01 - -/* HCI device flags */ -enum { - HCI_UP, - HCI_INIT, - HCI_RUNNING, - - HCI_PSCAN, - HCI_ISCAN, - HCI_AUTH, - HCI_ENCRYPT, - HCI_INQUIRY, - - HCI_RAW, - - HCI_RESET, -}; - -/* - * BR/EDR and/or LE controller flags: the flags defined here should represent - * states from the controller. - */ -enum { - HCI_SETUP, - HCI_AUTO_OFF, - HCI_MGMT, - HCI_PAIRABLE, - HCI_SERVICE_CACHE, - HCI_LINK_KEYS, - HCI_DEBUG_KEYS, - HCI_UNREGISTER, - - HCI_LE_SCAN, - HCI_SSP_ENABLED, - HCI_HS_ENABLED, - HCI_LE_ENABLED, - HCI_CONNECTABLE, - HCI_DISCOVERABLE, - HCI_LINK_SECURITY, - HCI_PENDING_CLASS, -}; - -/* HCI data types */ -#define HCI_COMMAND_PKT 0x01 -#define HCI_ACLDATA_PKT 0x02 -#define HCI_SCODATA_PKT 0x03 -#define HCI_EVENT_PKT 0x04 -#define HCI_VENDOR_PKT 0xff - -#define HCI_MAX_NAME_LENGTH 248 -#define HCI_MAX_EIR_LENGTH 240 - -#define HCI_OP_READ_LOCAL_VERSION 0x1001 -struct hci_rp_read_local_version { - __u8 status; - __u8 hci_ver; - __le16 hci_rev; - __u8 lmp_ver; - __le16 manufacturer; - __le16 lmp_subver; -} __packed; - -#define HCI_EV_CMD_COMPLETE 0x0e -struct hci_ev_cmd_complete { - __u8 ncmd; - __le16 opcode; -} __packed; - -/* ---- HCI Packet structures ---- */ -#define HCI_COMMAND_HDR_SIZE 3 -#define HCI_EVENT_HDR_SIZE 2 -#define HCI_ACL_HDR_SIZE 4 -#define HCI_SCO_HDR_SIZE 3 - -struct hci_command_hdr { - __le16 opcode; /* OCF & OGF */ - __u8 plen; -} __packed; - -struct hci_event_hdr { - __u8 evt; - __u8 plen; -} __packed; - -struct hci_acl_hdr { - __le16 handle; /* Handle & Flags(PB, BC) */ - __le16 dlen; -} __packed; - -struct hci_sco_hdr { - __le16 handle; - __u8 dlen; -} __packed; - -static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) -{ - return (struct hci_event_hdr *) skb->data; -} - -static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb) -{ - return (struct hci_acl_hdr *) skb->data; -} - -static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) -{ - return (struct hci_sco_hdr *) skb->data; -} - -/* ---- HCI Ioctl requests structures ---- */ -struct hci_dev_stats { - __u32 err_rx; - __u32 err_tx; - __u32 cmd_tx; - __u32 evt_rx; - __u32 acl_tx; - __u32 acl_rx; - __u32 sco_tx; - __u32 sco_rx; - __u32 byte_rx; - __u32 byte_tx; -}; -/* Realtek - Integrate from hci.h end */ - -/***************************************** -** Realtek - Integrate from hci_core.h ** -*****************************************/ -struct hci_conn_hash { - struct list_head list; - unsigned int acl_num; - unsigned int sco_num; - unsigned int le_num; -}; - -#define HCI_MAX_SHORT_NAME_LENGTH 10 - -#define NUM_REASSEMBLY 4 -struct hci_dev { - struct mutex lock; - - char name[8]; - unsigned long flags; - __u16 id; - __u8 bus; - __u8 dev_type; - - struct sk_buff *reassembly[NUM_REASSEMBLY]; - - struct hci_conn_hash conn_hash; - - struct hci_dev_stats stat; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) - atomic_t refcnt; - struct module *owner; - void *driver_data; -#endif - - atomic_t promisc; - - struct device *parent; - struct device dev; - - unsigned long dev_flags; - - int (*open)(struct hci_dev *hdev); - int (*close)(struct hci_dev *hdev); - int (*flush)(struct hci_dev *hdev); - int (*send)(struct sk_buff *skb); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) - void (*destruct)(struct hci_dev *hdev); -#endif -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1) - __u16 voice_setting; -#endif - void (*notify)(struct hci_dev *hdev, unsigned int evt); - int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); -}; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) -static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) -{ - atomic_inc(&d->refcnt); - return d; -} - -static inline void __hci_dev_put(struct hci_dev *d) -{ - if (atomic_dec_and_test(&d->refcnt)) - d->destruct(d); -} -#endif - -static inline void *hci_get_drvdata(struct hci_dev *hdev) -{ - return dev_get_drvdata(&hdev->dev); -} - -static inline int hci_set_drvdata(struct hci_dev *hdev, void *data) -{ - return dev_set_drvdata(&hdev->dev, data); -} - -#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) -/* Realtek - Integrate from hci_core.h end */ - -/* ----- HCI Commands ---- */ -#define HCI_OP_INQUIRY 0x0401 -#define HCI_OP_INQUIRY_CANCEL 0x0402 -#define HCI_OP_EXIT_PERIODIC_INQ 0x0404 -#define HCI_OP_CREATE_CONN 0x0405 -#define HCI_OP_DISCONNECT 0x0406 -#define HCI_OP_ADD_SCO 0x0407 -#define HCI_OP_CREATE_CONN_CANCEL 0x0408 -#define HCI_OP_ACCEPT_CONN_REQ 0x0409 -#define HCI_OP_REJECT_CONN_REQ 0x040a -#define HCI_OP_LINK_KEY_REPLY 0x040b -#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c -#define HCI_OP_PIN_CODE_REPLY 0x040d -#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e -#define HCI_OP_CHANGE_CONN_PTYPE 0x040f -#define HCI_OP_AUTH_REQUESTED 0x0411 -#define HCI_OP_SET_CONN_ENCRYPT 0x0413 -#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 -#define HCI_OP_REMOTE_NAME_REQ 0x0419 -#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a -#define HCI_OP_READ_REMOTE_FEATURES 0x041b -#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c -#define HCI_OP_READ_REMOTE_VERSION 0x041d -#define HCI_OP_SETUP_SYNC_CONN 0x0428 -#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 -#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a -#define HCI_OP_SNIFF_MODE 0x0803 -#define HCI_OP_EXIT_SNIFF_MODE 0x0804 -#define HCI_OP_ROLE_DISCOVERY 0x0809 -#define HCI_OP_SWITCH_ROLE 0x080b -#define HCI_OP_READ_LINK_POLICY 0x080c -#define HCI_OP_WRITE_LINK_POLICY 0x080d -#define HCI_OP_READ_DEF_LINK_POLICY 0x080e -#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f -#define HCI_OP_SNIFF_SUBRATE 0x0811 -#define HCI_OP_SET_EVENT_MASK 0x0c01 -#define HCI_OP_RESET 0x0c03 -#define HCI_OP_SET_EVENT_FLT 0x0c05 - -/* ----- HCI events---- */ -#define HCI_OP_DISCONNECT 0x0406 -#define HCI_EV_INQUIRY_COMPLETE 0x01 -#define HCI_EV_INQUIRY_RESULT 0x02 -#define HCI_EV_CONN_COMPLETE 0x03 -#define HCI_EV_CONN_REQUEST 0x04 -#define HCI_EV_DISCONN_COMPLETE 0x05 -#define HCI_EV_AUTH_COMPLETE 0x06 -#define HCI_EV_REMOTE_NAME 0x07 -#define HCI_EV_ENCRYPT_CHANGE 0x08 -#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 - -#define HCI_EV_REMOTE_FEATURES 0x0b -#define HCI_EV_REMOTE_VERSION 0x0c -#define HCI_EV_QOS_SETUP_COMPLETE 0x0d -#define HCI_EV_CMD_COMPLETE 0x0e -#define HCI_EV_CMD_STATUS 0x0f - -#define HCI_EV_ROLE_CHANGE 0x12 -#define HCI_EV_NUM_COMP_PKTS 0x13 -#define HCI_EV_MODE_CHANGE 0x14 -#define HCI_EV_PIN_CODE_REQ 0x16 -#define HCI_EV_LINK_KEY_REQ 0x17 -#define HCI_EV_LINK_KEY_NOTIFY 0x18 -#define HCI_EV_CLOCK_OFFSET 0x1c -#define HCI_EV_PKT_TYPE_CHANGE 0x1d -#define HCI_EV_PSCAN_REP_MODE 0x20 - -#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 -#define HCI_EV_REMOTE_EXT_FEATURES 0x23 -#define HCI_EV_SYNC_CONN_COMPLETE 0x2c -#define HCI_EV_SYNC_CONN_CHANGED 0x2d -#define HCI_EV_SNIFF_SUBRATE 0x2e -#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f -#define HCI_EV_IO_CAPA_REQUEST 0x31 -#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 -#define HCI_EV_REMOTE_HOST_FEATURES 0x3d - -#endif /* CONFIG_BLUEDROID */ diff --git a/drivers/bluetooth/rtk_coex.c b/drivers/bluetooth/rtk_coex.c deleted file mode 100644 index 5911bcaf8c13..000000000000 --- a/drivers/bluetooth/rtk_coex.c +++ /dev/null @@ -1,2559 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rtk_coex.h" - -#if BTRTL_HCI_IF == BTRTL_HCIUSB -#include -#include "rtk_bt.h" -#undef RTKBT_DBG -#undef RTKBT_INFO -#undef RTKBT_WARN -#undef RTKBT_ERR - -#elif BTRTL_HCI_IF == BTRTL_HCIUART -/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */ -#define HCI_VERSION_CODE LINUX_VERSION_CODE - -#else -#error "Please set type of HCI interface" -#endif - -#define RTK_VERSION "1.2" - -#define RTKBT_DBG(fmt, arg...) printk(KERN_INFO "rtk_btcoex: " fmt "\n" , ## arg) -#define RTKBT_INFO(fmt, arg...) printk(KERN_INFO "rtk_btcoex: " fmt "\n" , ## arg) -#define RTKBT_WARN(fmt, arg...) printk(KERN_WARNING "rtk_btcoex: " fmt "\n", ## arg) -#define RTKBT_ERR(fmt, arg...) printk(KERN_WARNING "rtk_btcoex: " fmt "\n", ## arg) - -static struct rtl_coex_struct btrtl_coex; - -#define is_profile_connected(profile) ((btrtl_coex.profile_bitmap & BIT(profile)) > 0) -#define is_profile_busy(profile) ((btrtl_coex.profile_status & BIT(profile)) > 0) - -static void rtk_handle_event_from_wifi(uint8_t * msg); -static void count_a2dp_packet_timeout(unsigned long data); -static void count_pan_packet_timeout(unsigned long data); -static void count_hogp_packet_timeout(unsigned long data); - -static int rtl_alloc_buff(struct rtl_coex_struct *coex) -{ - struct rtl_hci_ev *ev; - struct rtl_l2_buff *l2; - int i; - int order; - unsigned long addr; - unsigned long addr2; - int ev_size; - int l2_size; - int n; - - spin_lock_init(&coex->buff_lock); - - INIT_LIST_HEAD(&coex->ev_used_list); - INIT_LIST_HEAD(&coex->ev_free_list); - - INIT_LIST_HEAD(&coex->l2_used_list); - INIT_LIST_HEAD(&coex->l2_free_list); - - n = NUM_RTL_HCI_EV * sizeof(struct rtl_hci_ev); - ev_size = ALIGN(n, sizeof(unsigned long)); - - n = L2_MAX_PKTS * sizeof(struct rtl_l2_buff); - l2_size = ALIGN(n, sizeof(unsigned long)); - - RTKBT_DBG("alloc buffers %d, %d for ev and l2", ev_size, l2_size); - - order = get_order(ev_size + l2_size); - addr = __get_free_pages(GFP_KERNEL, order); - if (!addr) { - RTKBT_ERR("failed to alloc buffers for ev and l2."); - return -ENOMEM; - } - memset((void *)addr, 0, ev_size + l2_size); - - coex->pages_addr = addr; - coex->buff_size = ev_size + l2_size; - - ev = (struct rtl_hci_ev *)addr; - for (i = 0; i < NUM_RTL_HCI_EV; i++) { - list_add_tail(&ev->list, &coex->ev_free_list); - ev++; - } - - addr2 = addr + ev_size; - l2 = (struct rtl_l2_buff *)addr2; - for (i = 0; i < L2_MAX_PKTS; i++) { - list_add_tail(&l2->list, &coex->l2_free_list); - l2++; - } - - return 0; -} - -static void rtl_free_buff(struct rtl_coex_struct *coex) -{ - struct rtl_hci_ev *ev; - struct rtl_l2_buff *l2; - unsigned long flags; - - spin_lock_irqsave(&coex->buff_lock, flags); - - while (!list_empty(&coex->ev_used_list)) { - ev = list_entry(coex->ev_used_list.next, struct rtl_hci_ev, - list); - list_del(&ev->list); - } - - while (!list_empty(&coex->ev_free_list)) { - ev = list_entry(coex->ev_free_list.next, struct rtl_hci_ev, - list); - list_del(&ev->list); - } - - while (!list_empty(&coex->l2_used_list)) { - l2 = list_entry(coex->l2_used_list.next, struct rtl_l2_buff, - list); - list_del(&l2->list); - } - - while (!list_empty(&coex->l2_free_list)) { - l2 = list_entry(coex->l2_free_list.next, struct rtl_l2_buff, - list); - list_del(&l2->list); - } - - spin_unlock_irqrestore(&coex->buff_lock, flags); - - if (coex->buff_size > 0) { - free_pages(coex->pages_addr, get_order(coex->buff_size)); - coex->pages_addr = 0; - coex->buff_size = 0; - } -} - -static struct rtl_hci_ev *rtl_ev_node_get(struct rtl_coex_struct *coex) -{ - struct rtl_hci_ev *ev; - unsigned long flags; - - if (!coex->buff_size) - return NULL; - - spin_lock_irqsave(&coex->buff_lock, flags); - if (!list_empty(&coex->ev_free_list)) { - ev = list_entry(coex->ev_free_list.next, struct rtl_hci_ev, - list); - list_del(&ev->list); - } else - ev = NULL; - spin_unlock_irqrestore(&coex->buff_lock, flags); - return ev; -} - -static int rtl_ev_node_to_used(struct rtl_coex_struct *coex, - struct rtl_hci_ev *ev) -{ - unsigned long flags; - - spin_lock_irqsave(&coex->buff_lock, flags); - list_add_tail(&ev->list, &coex->ev_used_list); - spin_unlock_irqrestore(&coex->buff_lock, flags); - - return 0; -} - -static struct rtl_l2_buff *rtl_l2_node_get(struct rtl_coex_struct *coex) -{ - struct rtl_l2_buff *l2; - unsigned long flags; - - if (!coex->buff_size) - return NULL; - - spin_lock_irqsave(&coex->buff_lock, flags); - - if(!list_empty(&coex->l2_free_list)) { - l2 = list_entry(coex->l2_free_list.next, struct rtl_l2_buff, - list); - list_del(&l2->list); - } else - l2 = NULL; - - spin_unlock_irqrestore(&coex->buff_lock, flags); - return l2; -} - -static int rtl_l2_node_to_used(struct rtl_coex_struct *coex, - struct rtl_l2_buff *l2) -{ - unsigned long flags; - - spin_lock_irqsave(&coex->buff_lock, flags); - list_add_tail(&l2->list, &coex->l2_used_list); - spin_unlock_irqrestore(&coex->buff_lock, flags); - - return 0; -} - -static int8_t psm_to_profile_index(uint16_t psm) -{ - switch (psm) { - case PSM_AVCTP: - case PSM_SDP: - return -1; //ignore - - case PSM_HID: - case PSM_HID_INT: - return profile_hid; - - case PSM_AVDTP: - return profile_a2dp; - - case PSM_PAN: - case PSM_OPP: - case PSM_FTP: - case PSM_BIP: - case PSM_RFCOMM: - return profile_pan; - - default: - return profile_pan; - } -} - -static rtk_conn_prof *find_connection_by_handle(struct rtl_coex_struct * coex, - uint16_t handle) -{ - struct list_head *head = &coex->conn_hash; - struct list_head *iter = NULL, *temp = NULL; - rtk_conn_prof *desc = NULL; - - list_for_each_safe(iter, temp, head) { - desc = list_entry(iter, rtk_conn_prof, list); - if ((handle & 0xEFF) == desc->handle) { - return desc; - } - } - return NULL; -} - -static rtk_conn_prof *allocate_connection_by_handle(uint16_t handle) -{ - rtk_conn_prof *phci_conn = NULL; - phci_conn = kmalloc(sizeof(rtk_conn_prof), GFP_ATOMIC); - if (phci_conn) - phci_conn->handle = handle; - - return phci_conn; -} - -static void init_connection_hash(struct rtl_coex_struct * coex) -{ - struct list_head *head = &coex->conn_hash; - INIT_LIST_HEAD(head); -} - -static void add_connection_to_hash(struct rtl_coex_struct * coex, - rtk_conn_prof * desc) -{ - struct list_head *head = &coex->conn_hash; - list_add_tail(&desc->list, head); -} - -static void delete_connection_from_hash(rtk_conn_prof * desc) -{ - if (desc) { - list_del(&desc->list); - kfree(desc); - } -} - -static void flush_connection_hash(struct rtl_coex_struct * coex) -{ - struct list_head *head = &coex->conn_hash; - struct list_head *iter = NULL, *temp = NULL; - rtk_conn_prof *desc = NULL; - - list_for_each_safe(iter, temp, head) { - desc = list_entry(iter, rtk_conn_prof, list); - if (desc) { - list_del(&desc->list); - kfree(desc); - } - } - //INIT_LIST_HEAD(head); -} - -static void init_profile_hash(struct rtl_coex_struct * coex) -{ - struct list_head *head = &coex->profile_list; - INIT_LIST_HEAD(head); -} - -static uint8_t list_allocate_add(uint16_t handle, uint16_t psm, - int8_t profile_index, uint16_t dcid, - uint16_t scid) -{ - rtk_prof_info *pprof_info = NULL; - - if (profile_index < 0) { - RTKBT_ERR("PSM(0x%x) do not need parse", psm); - return FALSE; - } - - pprof_info = kmalloc(sizeof(rtk_prof_info), GFP_ATOMIC); - - if (NULL == pprof_info) { - RTKBT_ERR("list_allocate_add: allocate error"); - return FALSE; - } - - pprof_info->handle = handle; - pprof_info->psm = psm; - pprof_info->scid = scid; - pprof_info->dcid = dcid; - pprof_info->profile_index = profile_index; - list_add_tail(&(pprof_info->list), &(btrtl_coex.profile_list)); - - return TRUE; -} - -static void delete_profile_from_hash(rtk_prof_info * desc) -{ - RTKBT_DBG("Delete profile: hndl 0x%04x, psm 0x%04x, dcid 0x%04x, " - "scid 0x%04x", desc->handle, desc->psm, desc->dcid, - desc->scid); - if (desc) { - list_del(&desc->list); - kfree(desc); - desc = NULL; - } -} - -static void flush_profile_hash(struct rtl_coex_struct * coex) -{ - struct list_head *head = &coex->profile_list; - struct list_head *iter = NULL, *temp = NULL; - rtk_prof_info *desc = NULL; - - spin_lock(&btrtl_coex.spin_lock_profile); - list_for_each_safe(iter, temp, head) { - desc = list_entry(iter, rtk_prof_info, list); - delete_profile_from_hash(desc); - } - //INIT_LIST_HEAD(head); - spin_unlock(&btrtl_coex.spin_lock_profile); -} - -static rtk_prof_info *find_profile_by_handle_scid(struct rtl_coex_struct * - coex, uint16_t handle, - uint16_t scid) -{ - struct list_head *head = &coex->profile_list; - struct list_head *iter = NULL, *temp = NULL; - rtk_prof_info *desc = NULL; - - list_for_each_safe(iter, temp, head) { - desc = list_entry(iter, rtk_prof_info, list); - if (((handle & 0xFFF) == desc->handle) && (scid == desc->scid)) { - return desc; - } - } - return NULL; -} - -static rtk_prof_info *find_profile_by_handle_dcid(struct rtl_coex_struct * - coex, uint16_t handle, - uint16_t dcid) -{ - struct list_head *head = &coex->profile_list; - struct list_head *iter = NULL, *temp = NULL; - rtk_prof_info *desc = NULL; - - list_for_each_safe(iter, temp, head) { - desc = list_entry(iter, rtk_prof_info, list); - if (((handle & 0xFFF) == desc->handle) && (dcid == desc->dcid)) { - return desc; - } - } - return NULL; -} - -static rtk_prof_info *find_profile_by_handle_dcid_scid(struct rtl_coex_struct - * coex, uint16_t handle, - uint16_t dcid, - uint16_t scid) -{ - struct list_head *head = &coex->profile_list; - struct list_head *iter = NULL, *temp = NULL; - rtk_prof_info *desc = NULL; - - list_for_each_safe(iter, temp, head) { - desc = list_entry(iter, rtk_prof_info, list); - if (((handle & 0xFFF) == desc->handle) && (dcid == desc->dcid) - && (scid == desc->scid)) { - return desc; - } - } - return NULL; -} - -static void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, - uint8_t * parameter) -{ - int len = HCI_CMD_PREAMBLE_SIZE + parameter_len; - uint8_t *p; - struct sk_buff *skb; - struct hci_dev *hdev = btrtl_coex.hdev; - - skb = bt_skb_alloc(len, GFP_ATOMIC); - if (!skb) { - RTKBT_DBG("there is no room for cmd 0x%x", opcode); - return; - } - - p = (uint8_t *) skb_put(skb, HCI_CMD_PREAMBLE_SIZE); - UINT16_TO_STREAM(p, opcode); - *p++ = parameter_len; - - if (parameter_len) - memcpy(skb_put(skb, parameter_len), parameter, parameter_len); - - bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; - -#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) -#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0) - bt_cb(skb)->opcode = opcode; -#else - bt_cb(skb)->hci.opcode = opcode; -#endif -#endif - - /* Stand-alone HCI commands must be flagged as - * single-command requests. - */ -#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) -#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0) - bt_cb(skb)->req.start = true; -#else - bt_cb(skb)->hci.req_start = true; -#endif -#endif - RTKBT_DBG("%s: opcode 0x%x", __func__, opcode); - - /* It is harmless if set skb->dev twice. The dev will be used in - * btusb_send_frame() after or equal to kernel/hci 3.13.0, - * the hdev will not come from skb->dev. */ -#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0) - skb->dev = (void *)btrtl_coex.hdev; -#endif - /* Put the skb to the global hdev->cmd_q */ - skb_queue_tail(&hdev->cmd_q, skb); - -#if HCI_VERSION_CODE < KERNEL_VERSION(3, 3, 0) - tasklet_schedule(&hdev->cmd_task); -#else - queue_work(hdev->workqueue, &hdev->cmd_work); -#endif - - return; -} - -static void rtk_notify_profileinfo_to_fw(void) -{ - struct list_head *head = NULL; - struct list_head *iter = NULL; - struct list_head *temp = NULL; - rtk_conn_prof *hci_conn = NULL; - uint8_t handle_number = 0; - uint32_t buffer_size = 0; - uint8_t *p_buf = NULL; - uint8_t *p = NULL; - - head = &btrtl_coex.conn_hash; - list_for_each_safe(iter, temp, head) { - hci_conn = list_entry(iter, rtk_conn_prof, list); - if (hci_conn && hci_conn->profile_bitmap) - handle_number++; - } - - buffer_size = 1 + handle_number * 3 + 1; - - p_buf = kmalloc(buffer_size, GFP_ATOMIC); - - if (NULL == p_buf) { - RTKBT_ERR("%s: alloc error", __func__); - return; - } - p = p_buf; - - RTKBT_DBG("%s: BufferSize %u", __func__, buffer_size); - *p++ = handle_number; - RTKBT_DBG("%s: NumberOfHandles %u", __func__, handle_number); - head = &btrtl_coex.conn_hash; - list_for_each(iter, head) { - hci_conn = list_entry(iter, rtk_conn_prof, list); - if (hci_conn && hci_conn->profile_bitmap) { - UINT16_TO_STREAM(p, hci_conn->handle); - RTKBT_DBG("%s: handle 0x%04x", __func__, - hci_conn->handle); - *p++ = hci_conn->profile_bitmap; - RTKBT_DBG("%s: profile_bitmap 0x%02x", __func__, - hci_conn->profile_bitmap); - handle_number--; - } - if (0 == handle_number) - break; - } - - *p++ = btrtl_coex.profile_status; - RTKBT_DBG("%s: profile_status 0x%02x", __func__, - btrtl_coex.profile_status); - - rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size, - p_buf); - - kfree(p_buf); - return; -} - -static void rtk_check_setup_timer(int8_t profile_index) -{ - if (profile_index == profile_a2dp) { - btrtl_coex.a2dp_packet_count = 0; - setup_timer(&(btrtl_coex.a2dp_count_timer), - count_a2dp_packet_timeout, 0); - btrtl_coex.a2dp_count_timer.expires = - jiffies + msecs_to_jiffies(1000); - add_timer(&(btrtl_coex.a2dp_count_timer)); - } - - if (profile_index == profile_pan) { - btrtl_coex.pan_packet_count = 0; - setup_timer(&(btrtl_coex.pan_count_timer), - count_pan_packet_timeout, 0); - btrtl_coex.pan_count_timer.expires = - jiffies + msecs_to_jiffies(1000); - add_timer(&(btrtl_coex.pan_count_timer)); - } - - /* hogp & voice share one timer now */ - if ((profile_index == profile_hogp) || (profile_index == profile_voice)) { - if ((0 == btrtl_coex.profile_refcount[profile_hogp]) - && (0 == btrtl_coex.profile_refcount[profile_voice])) { - btrtl_coex.hogp_packet_count = 0; - btrtl_coex.voice_packet_count = 0; - setup_timer(&(btrtl_coex.hogp_count_timer), - count_hogp_packet_timeout, 0); - btrtl_coex.hogp_count_timer.expires = - jiffies + msecs_to_jiffies(1000); - add_timer(&(btrtl_coex.hogp_count_timer)); - } - } -} - -static void rtk_check_del_timer(int8_t profile_index) -{ - if (profile_a2dp == profile_index) { - btrtl_coex.a2dp_packet_count = 0; - del_timer(&(btrtl_coex.a2dp_count_timer)); - } - if (profile_pan == profile_index) { - btrtl_coex.pan_packet_count = 0; - del_timer(&(btrtl_coex.pan_count_timer)); - } - if (profile_hogp == profile_index) { - btrtl_coex.hogp_packet_count = 0; - if (btrtl_coex.profile_refcount[profile_voice] == 0) { - del_timer(&(btrtl_coex.hogp_count_timer)); - } - } - if (profile_voice == profile_index) { - btrtl_coex.voice_packet_count = 0; - if (btrtl_coex.profile_refcount[profile_hogp] == 0) { - del_timer(&(btrtl_coex.hogp_count_timer)); - } - } -} - -static void update_profile_state(uint8_t profile_index, uint8_t is_busy) -{ - uint8_t need_update = FALSE; - - if ((btrtl_coex.profile_bitmap & BIT(profile_index)) == 0) { - RTKBT_ERR("%s: : ERROR!!! profile(Index: %x) does not exist", - __func__, profile_index); - return; - } - - if (is_busy) { - if ((btrtl_coex.profile_status & BIT(profile_index)) == 0) { - need_update = TRUE; - btrtl_coex.profile_status |= BIT(profile_index); - } - } else { - if ((btrtl_coex.profile_status & BIT(profile_index)) > 0) { - need_update = TRUE; - btrtl_coex.profile_status &= ~(BIT(profile_index)); - } - } - - if (need_update) { - RTKBT_DBG("%s: btrtl_coex.profie_bitmap = %x", - __func__, btrtl_coex.profile_bitmap); - RTKBT_DBG("%s: btrtl_coex.profile_status = %x", - __func__, btrtl_coex.profile_status); - rtk_notify_profileinfo_to_fw(); - } -} - -static void update_profile_connection(rtk_conn_prof * phci_conn, - int8_t profile_index, uint8_t is_add) -{ - uint8_t need_update = FALSE; - uint8_t kk; - - RTKBT_DBG("%s: is_add %d, profile_index %x", __func__, - is_add, profile_index); - if (profile_index < 0) - return; - - if (is_add) { - if (btrtl_coex.profile_refcount[profile_index] == 0) { - need_update = TRUE; - btrtl_coex.profile_bitmap |= BIT(profile_index); - - /* SCO is always busy */ - if (profile_index == profile_sco) - btrtl_coex.profile_status |= - BIT(profile_index); - - rtk_check_setup_timer(profile_index); - } - btrtl_coex.profile_refcount[profile_index]++; - - if (0 == phci_conn->profile_refcount[profile_index]) { - need_update = TRUE; - phci_conn->profile_bitmap |= BIT(profile_index); - } - phci_conn->profile_refcount[profile_index]++; - } else { - btrtl_coex.profile_refcount[profile_index]--; - RTKBT_DBG("%s: btrtl_coex.profile_refcount[%x] = %x", - __func__, profile_index, - btrtl_coex.profile_refcount[profile_index]); - if (btrtl_coex.profile_refcount[profile_index] == 0) { - need_update = TRUE; - btrtl_coex.profile_bitmap &= ~(BIT(profile_index)); - - /* if profile does not exist, status is meaningless */ - btrtl_coex.profile_status &= ~(BIT(profile_index)); - rtk_check_del_timer(profile_index); - } - - phci_conn->profile_refcount[profile_index]--; - if (0 == phci_conn->profile_refcount[profile_index]) { - need_update = TRUE; - phci_conn->profile_bitmap &= ~(BIT(profile_index)); - - /* clear profile_hid_interval if need */ - if ((profile_hid == profile_index) - && (phci_conn-> - profile_bitmap & (BIT(profile_hid_interval)))) { - phci_conn->profile_bitmap &= - ~(BIT(profile_hid_interval)); - btrtl_coex. - profile_refcount[profile_hid_interval]--; - } - } - } - - RTKBT_DBG("%s: btrtl_coex.profile_bitmap 0x%02x", __func__, - btrtl_coex.profile_bitmap); - for (kk = 0; kk < 8; kk++) - RTKBT_DBG("%s: btrtl_coex.profile_refcount[%d] = %d", - __func__, kk, - btrtl_coex.profile_refcount[kk]); - - if (need_update) - rtk_notify_profileinfo_to_fw(); -} - -static void update_hid_active_state(uint16_t handle, uint16_t interval) -{ - uint8_t need_update = 0; - rtk_conn_prof *phci_conn = - find_connection_by_handle(&btrtl_coex, handle); - - if (phci_conn == NULL) - return; - - RTKBT_DBG("%s: handle 0x%04x, interval %u", __func__, handle, interval); - if (((phci_conn->profile_bitmap) & (BIT(profile_hid))) == 0) { - RTKBT_DBG("HID not connected, nothing to be down"); - return; - } - - if (interval < 60) { - if ((phci_conn->profile_bitmap & (BIT(profile_hid_interval))) == - 0) { - need_update = 1; - phci_conn->profile_bitmap |= BIT(profile_hid_interval); - - btrtl_coex.profile_refcount[profile_hid_interval]++; - if (btrtl_coex. - profile_refcount[profile_hid_interval] == 1) - btrtl_coex.profile_status |= - BIT(profile_hid); - } - } else { - if ((phci_conn->profile_bitmap & (BIT(profile_hid_interval)))) { - need_update = 1; - phci_conn->profile_bitmap &= - ~(BIT(profile_hid_interval)); - - btrtl_coex.profile_refcount[profile_hid_interval]--; - if (btrtl_coex. - profile_refcount[profile_hid_interval] == 0) - btrtl_coex.profile_status &= - ~(BIT(profile_hid)); - } - } - - if (need_update) - rtk_notify_profileinfo_to_fw(); -} - -static uint8_t handle_l2cap_con_req(uint16_t handle, uint16_t psm, - uint16_t scid, uint8_t direction) -{ - uint8_t status = FALSE; - rtk_prof_info *prof_info = NULL; - int8_t profile_index = psm_to_profile_index(psm); - - if (profile_index < 0) { - RTKBT_DBG("PSM(0x%04x) do not need parse", psm); - return status; - } - - spin_lock(&btrtl_coex.spin_lock_profile); - if (direction) //1: out - prof_info = - find_profile_by_handle_scid(&btrtl_coex, handle, scid); - else // 0:in - prof_info = - find_profile_by_handle_dcid(&btrtl_coex, handle, scid); - - if (prof_info) { - RTKBT_DBG("%s: this profile is already exist!", __func__); - spin_unlock(&btrtl_coex.spin_lock_profile); - return status; - } - - if (direction) //1: out - status = list_allocate_add(handle, psm, profile_index, 0, scid); - else // 0:in - status = list_allocate_add(handle, psm, profile_index, scid, 0); - - spin_unlock(&btrtl_coex.spin_lock_profile); - - if (!status) - RTKBT_ERR("%s: list_allocate_add failed!", __func__); - - return status; -} - -static uint8_t handle_l2cap_con_rsp(uint16_t handle, uint16_t dcid, - uint16_t scid, uint8_t direction, - uint8_t result) -{ - rtk_prof_info *prof_info = NULL; - rtk_conn_prof *phci_conn = NULL; - - spin_lock(&btrtl_coex.spin_lock_profile); - if (!direction) //0, in - prof_info = - find_profile_by_handle_scid(&btrtl_coex, handle, scid); - else //1, out - prof_info = - find_profile_by_handle_dcid(&btrtl_coex, handle, scid); - - if (!prof_info) { - //RTKBT_DBG("handle_l2cap_con_rsp: prof_info Not Find!!"); - spin_unlock(&btrtl_coex.spin_lock_profile); - return FALSE; - } - - if (!result) { //success - RTKBT_DBG("l2cap connection success, update connection"); - if (!direction) //0, in - prof_info->dcid = dcid; - else //1, out - prof_info->scid = dcid; - - phci_conn = find_connection_by_handle(&btrtl_coex, handle); - if (phci_conn) - update_profile_connection(phci_conn, - prof_info->profile_index, - TRUE); - } - - spin_unlock(&btrtl_coex.spin_lock_profile); - return TRUE; -} - -static uint8_t handle_l2cap_discon_req(uint16_t handle, uint16_t dcid, - uint16_t scid, uint8_t direction) -{ - rtk_prof_info *prof_info = NULL; - rtk_conn_prof *phci_conn = NULL; - RTKBT_DBG("%s: handle 0x%04x, dcid 0x%04x, scid 0x%04x, dir %u", - __func__, handle, dcid, scid, direction); - - spin_lock(&btrtl_coex.spin_lock_profile); - if (!direction) //0: in - prof_info = - find_profile_by_handle_dcid_scid(&btrtl_coex, handle, - scid, dcid); - else //1: out - prof_info = - find_profile_by_handle_dcid_scid(&btrtl_coex, handle, - dcid, scid); - - if (!prof_info) { - //LogMsg("handle_l2cap_discon_req: prof_info Not Find!"); - spin_unlock(&btrtl_coex.spin_lock_profile); - return 0; - } - - phci_conn = find_connection_by_handle(&btrtl_coex, handle); - if (!phci_conn) { - spin_unlock(&btrtl_coex.spin_lock_profile); - return 0; - } - - update_profile_connection(phci_conn, prof_info->profile_index, FALSE); - delete_profile_from_hash(prof_info); - spin_unlock(&btrtl_coex.spin_lock_profile); - - return 1; -} - -static void packets_count(uint16_t handle, uint16_t scid, uint16_t length, - uint8_t direction, u8 *user_data) -{ - rtk_prof_info *prof_info = NULL; - - rtk_conn_prof *hci_conn = - find_connection_by_handle(&btrtl_coex, handle); - if (NULL == hci_conn) - return; - - if (0 == hci_conn->type) { - if (!direction) //0: in - prof_info = - find_profile_by_handle_scid(&btrtl_coex, handle, - scid); - else //1: out - prof_info = - find_profile_by_handle_dcid(&btrtl_coex, handle, - scid); - - if (!prof_info) { - //RTKBT_DBG("packets_count: prof_info Not Find!"); - return; - } - - if ((prof_info->profile_index == profile_a2dp) && (length > 100)) { //avdtp media data - if (!is_profile_busy(profile_a2dp)) { - struct sbc_frame_hdr *sbc_header; - struct rtp_header *rtph; - u8 bitpool; - update_profile_state(profile_a2dp, TRUE); - rtph = (struct rtp_header *)user_data; - - RTKBT_DBG("cc %u", rtph->cc); - /* move forward */ - user_data += sizeof(struct rtp_header) + - rtph->cc * 4 + 1; - - /* point to the sbc frame header */ - sbc_header = (struct sbc_frame_hdr *)user_data; - bitpool = sbc_header->bitpool; - - RTKBT_DBG("bitpool %u", bitpool); - - rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_BITPOOL, - 1, &bitpool); - } - btrtl_coex.a2dp_packet_count++; - } - - if (prof_info->profile_index == profile_pan) - btrtl_coex.pan_packet_count++; - } -} - -static void count_a2dp_packet_timeout(unsigned long data) -{ - RTKBT_DBG("%s: a2dp_packet_count %d", __func__, - btrtl_coex.a2dp_packet_count); - if (btrtl_coex.a2dp_packet_count == 0) { - if (is_profile_busy(profile_a2dp)) { - RTKBT_DBG("%s: a2dp busy->idle!", __func__); - update_profile_state(profile_a2dp, FALSE); - } - } - btrtl_coex.a2dp_packet_count = 0; - mod_timer(&(btrtl_coex.a2dp_count_timer), - jiffies + msecs_to_jiffies(1000)); -} - -static void count_pan_packet_timeout(unsigned long data) -{ - RTKBT_DBG("%s: pan_packet_count %d", __func__, - btrtl_coex.pan_packet_count); - if (btrtl_coex.pan_packet_count < PAN_PACKET_COUNT) { - if (is_profile_busy(profile_pan)) { - RTKBT_DBG("%s: pan busy->idle!", __func__); - update_profile_state(profile_pan, FALSE); - } - } else { - if (!is_profile_busy(profile_pan)) { - RTKBT_DBG("timeout_handler: pan idle->busy!"); - update_profile_state(profile_pan, TRUE); - } - } - btrtl_coex.pan_packet_count = 0; - mod_timer(&(btrtl_coex.pan_count_timer), - jiffies + msecs_to_jiffies(1000)); -} - -static void count_hogp_packet_timeout(unsigned long data) -{ - RTKBT_DBG("%s: hogp_packet_count %d", __func__, - btrtl_coex.hogp_packet_count); - if (btrtl_coex.hogp_packet_count == 0) { - if (is_profile_busy(profile_hogp)) { - RTKBT_DBG("%s: hogp busy->idle!", __func__); - update_profile_state(profile_hogp, FALSE); - } - } - btrtl_coex.hogp_packet_count = 0; - - RTKBT_DBG("%s: voice_packet_count %d", __func__, - btrtl_coex.voice_packet_count); - if (btrtl_coex.voice_packet_count == 0) { - if (is_profile_busy(profile_voice)) { - RTKBT_DBG("%s: voice busy->idle!", __func__); - update_profile_state(profile_voice, FALSE); - } - } - btrtl_coex.voice_packet_count = 0; - mod_timer(&(btrtl_coex.hogp_count_timer), - jiffies + msecs_to_jiffies(1000)); -} - -static int udpsocket_send(char *tx_msg, int msg_size) -{ - u8 error = 0; - struct msghdr udpmsg; - mm_segment_t oldfs; - struct iovec iov; - - RTKBT_DBG("send msg %s with len:%d", tx_msg, msg_size); - - if (btrtl_coex.sock_open) { - iov.iov_base = (void *)tx_msg; - iov.iov_len = msg_size; - udpmsg.msg_name = &btrtl_coex.wifi_addr; - udpmsg.msg_namelen = sizeof(struct sockaddr_in); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) - udpmsg.msg_iov = &iov; - udpmsg.msg_iovlen = 1; -#else - iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size); -#endif - udpmsg.msg_control = NULL; - udpmsg.msg_controllen = 0; - udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; - oldfs = get_fs(); - set_fs(KERNEL_DS); -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) - error = sock_sendmsg(btrtl_coex.udpsock, &udpmsg, msg_size); -#else - error = sock_sendmsg(btrtl_coex.udpsock, &udpmsg); -#endif - set_fs(oldfs); - - if (error < 0) - RTKBT_DBG("Error when sendimg msg, error:%d", error); - } - - return error; -} - -static void udpsocket_recv_data(void) -{ - u8 recv_data[512]; - u32 len = 0; - u16 recv_length; - struct sk_buff *skb; - - RTKBT_DBG("-"); - - spin_lock(&btrtl_coex.spin_lock_sock); - len = skb_queue_len(&btrtl_coex.sk->sk_receive_queue); - - while (len > 0) { - skb = skb_dequeue(&btrtl_coex.sk->sk_receive_queue); - - /*important: cut the udp header from skb->data! header length is 8 byte */ - recv_length = skb->len - 8; - memset(recv_data, 0, sizeof(recv_data)); - memcpy(recv_data, skb->data + 8, recv_length); - //RTKBT_DBG("received data: %s :with len %u", recv_data, recv_length); - - rtk_handle_event_from_wifi(recv_data); - - len--; - kfree_skb(skb); - } - - spin_unlock(&btrtl_coex.spin_lock_sock); -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) -static void udpsocket_recv(struct sock *sk, int bytes) -#else -static void udpsocket_recv(struct sock *sk) -#endif -{ - spin_lock(&btrtl_coex.spin_lock_sock); - btrtl_coex.sk = sk; - spin_unlock(&btrtl_coex.spin_lock_sock); - queue_delayed_work(btrtl_coex.sock_wq, &btrtl_coex.sock_work, 0); -} - -static void create_udpsocket(void) -{ - int err; - RTKBT_DBG("%s: connect_port: %d", __func__, CONNECT_PORT); - btrtl_coex.sock_open = 0; - - err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, - &btrtl_coex.udpsock); - if (err < 0) { - RTKBT_ERR("%s: sock create error, err = %d", __func__, err); - return; - } - - memset(&btrtl_coex.addr, 0, sizeof(struct sockaddr_in)); - btrtl_coex.addr.sin_family = AF_INET; - btrtl_coex.addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - btrtl_coex.addr.sin_port = htons(CONNECT_PORT); - - memset(&btrtl_coex.wifi_addr, 0, sizeof(struct sockaddr_in)); - btrtl_coex.wifi_addr.sin_family = AF_INET; - btrtl_coex.wifi_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - btrtl_coex.wifi_addr.sin_port = htons(CONNECT_PORT_WIFI); - - err = - btrtl_coex.udpsock->ops->bind(btrtl_coex.udpsock, - (struct sockaddr *)&btrtl_coex. - addr, sizeof(struct sockaddr)); - if (err < 0) { - sock_release(btrtl_coex.udpsock); - RTKBT_ERR("%s: sock bind error, err = %d",__func__, err); - return; - } - - btrtl_coex.sock_open = 1; - btrtl_coex.udpsock->sk->sk_data_ready = udpsocket_recv; -} - -static void rtk_notify_extension_version_to_wifi(void) -{ - uint8_t para_length = 2; - char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = p_buf; - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_HCI_EXTENSION_VERSION_NOTIFY); - *p++ = para_length; - UINT16_TO_STREAM(p, HCI_EXTENSION_VERSION); - RTKBT_DBG("extension version is 0x%x", HCI_EXTENSION_VERSION); - if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -static void rtk_notify_btpatch_version_to_wifi(void) -{ - uint8_t para_length = 4; - char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = p_buf; - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_HCI_BT_PATCH_VER_NOTIFY); - *p++ = para_length; - UINT16_TO_STREAM(p, btrtl_coex.hci_reversion); - UINT16_TO_STREAM(p, btrtl_coex.lmp_subversion); - RTKBT_DBG("btpatch ver: len %u, hci_rev 0x%04x, lmp_subver 0x%04x", - para_length, btrtl_coex.hci_reversion, - btrtl_coex.lmp_subversion); - - if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -static void rtk_notify_afhmap_to_wifi(void) -{ - uint8_t para_length = 13; - char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = p_buf; - uint8_t kk = 0; - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_HCI_BT_AFH_MAP_NOTIFY); - *p++ = para_length; - *p++ = btrtl_coex.piconet_id; - *p++ = btrtl_coex.mode; - *p++ = 10; - memcpy(p, btrtl_coex.afh_map, 10); - - RTKBT_DBG("afhmap, piconet_id is 0x%x, map type is 0x%x", - btrtl_coex.piconet_id, btrtl_coex.mode); - for (kk = 0; kk < 10; kk++) - RTKBT_DBG("afhmap data[%d] is 0x%x", kk, - btrtl_coex.afh_map[kk]); - - if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -static void rtk_notify_btcoex_to_wifi(uint8_t opcode, uint8_t status) -{ - uint8_t para_length = 2; - char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = p_buf; - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_HCI_BT_COEX_NOTIFY); - *p++ = para_length; - *p++ = opcode; - if (!status) - *p++ = 0; - else - *p++ = 1; - - RTKBT_DBG("btcoex, opcode is 0x%x, status is 0x%x", opcode, status); - - if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -static void rtk_notify_btoperation_to_wifi(uint8_t operation, - uint8_t append_data_length, - uint8_t * append_data) -{ - uint8_t para_length = 3 + append_data_length; - char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = p_buf; - uint8_t kk = 0; - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_BT_OPERATION_NOTIFY); - *p++ = para_length; - *p++ = operation; - *p++ = append_data_length; - if (append_data_length) - memcpy(p, append_data, append_data_length); - - RTKBT_DBG("btoperation: op 0x%02x, append_data_length %u", - operation, append_data_length); - if (append_data_length) { - for (kk = 0; kk < append_data_length; kk++) - RTKBT_DBG("append data is 0x%x", *(append_data + kk)); - } - - if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -static void rtk_notify_info_to_wifi(uint8_t reason, uint8_t length, - uint8_t *report_info) -{ - uint8_t para_length = 4 + length; - char buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = buf; - struct rtl_btinfo *report = (struct rtl_btinfo *)report_info; - - if (length) { - RTKBT_DBG("bt info: cmd %2.2X", report->cmd); - RTKBT_DBG("bt info: len %2.2X", report->len); - RTKBT_DBG("bt info: data %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X", - report->data[0], report->data[1], report->data[2], - report->data[3], report->data[4], report->data[5]); - } - RTKBT_DBG("bt info: reason 0x%2x, length 0x%2x", reason, length); - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_HCI_BT_INFO_NOTIFY); - *p++ = para_length; - *p++ = btrtl_coex.polling_enable; - *p++ = btrtl_coex.polling_interval; - *p++ = reason; - *p++ = length; - - if (length) - memcpy(p, report_info, length); - - RTKBT_DBG("para length %2x, polling_enable %u, poiiling_interval %u", - para_length, btrtl_coex.polling_enable, - btrtl_coex.polling_interval); - /* send BT INFO to Wi-Fi driver */ - if (udpsocket_send(buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -static void rtk_notify_regester_to_wifi(uint8_t * reg_value) -{ - uint8_t para_length = 9; - char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE]; - char *p = p_buf; - hci_mailbox_register *reg = (hci_mailbox_register *) reg_value; - - if (!btrtl_coex.wifi_on) - return; - - UINT16_TO_STREAM(p, HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY); - *p++ = para_length; - memcpy(p, reg_value, para_length); - - RTKBT_DBG("bt register, register type is %x", reg->type); - RTKBT_DBG("bt register, register offset is %x", reg->offset); - RTKBT_DBG("bt register, register value is %x", reg->value); - - if (udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0) - RTKBT_ERR("%s: sock send error", __func__); -} - -void rtk_btcoex_parse_cmd(uint8_t *buffer, int count) -{ - u16 opcode = (buffer[0]) + (buffer[1] << 8); - - if ((opcode == HCI_OP_INQUIRY) || (opcode == HCI_OP_PERIODIC_INQ)) { - if (!btrtl_coex.isinquirying) { - btrtl_coex.isinquirying = 1; - RTKBT_DBG("hci (periodic)inq, notify wifi " - "inquiry start"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_START, - 0, NULL); - } - } - - if ((opcode == HCI_OP_INQUIRY_CANCEL) - || (opcode == HCI_OP_EXIT_PERIODIC_INQ)) { - if (btrtl_coex.isinquirying) { - btrtl_coex.isinquirying = 0; - RTKBT_DBG("hci (periodic)inq cancel/exit, notify wifi " - "inquiry stop"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, - NULL); - } - } - - if (opcode == HCI_OP_ACCEPT_CONN_REQ) { - if (!btrtl_coex.ispaging) { - btrtl_coex.ispaging = 1; - RTKBT_DBG("hci accept connreq, notify wifi page start"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0, - NULL); - } - } -} - -static void rtk_handle_inquiry_complete(void) -{ - if (btrtl_coex.isinquirying) { - btrtl_coex.isinquirying = 0; - RTKBT_DBG("inq complete, notify wifi inquiry end"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL); - } -} - -static void rtk_handle_pin_code_req(void) -{ - if (!btrtl_coex.ispairing) { - btrtl_coex.ispairing = 1; - RTKBT_DBG("pin code req, notify wifi pair start"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL); - } -} - -static void rtk_handle_io_capa_req(void) -{ - if (!btrtl_coex.ispairing) { - btrtl_coex.ispairing = 1; - RTKBT_DBG("io cap req, notify wifi pair start"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL); - } -} - -static void rtk_handle_auth_request(void) -{ - if (btrtl_coex.ispairing) { - btrtl_coex.ispairing = 0; - RTKBT_DBG("auth req, notify wifi pair end"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL); - } -} - -static void rtk_handle_link_key_notify(void) -{ - if (btrtl_coex.ispairing) { - btrtl_coex.ispairing = 0; - RTKBT_DBG("link key notify, notify wifi pair end"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL); - } -} - -static void rtk_handle_mode_change_evt(u8 * p) -{ - u16 mode_change_handle, mode_interval; - - p++; - STREAM_TO_UINT16(mode_change_handle, p); - p++; - STREAM_TO_UINT16(mode_interval, p); - update_hid_active_state(mode_change_handle, mode_interval); -} - -static void rtk_parse_vendor_mailbox_cmd_evt(u8 * p, u8 total_len) -{ - u8 status, subcmd; - u8 temp_cmd[10]; - - status = *p++; - if (total_len <= 4) { - RTKBT_DBG("receive mailbox cmd from fw, total length <= 4"); - return; - } - subcmd = *p++; - RTKBT_DBG("receive mailbox cmd from fw, subcmd is 0x%x, status is 0x%x", - subcmd, status); - - switch (subcmd) { - case HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO: - if (status == 0) //success - rtk_notify_info_to_wifi(POLLING_RESPONSE, - RTL_BTINFO_LEN, (uint8_t *)p); - break; - - case HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD: - rtk_notify_btcoex_to_wifi(WIFI_BW_CHNL_NOTIFY, status); - break; - - case HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD: - rtk_notify_btcoex_to_wifi(BT_POWER_DECREASE_CONTROL, status); - break; - - case HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD: - rtk_notify_btcoex_to_wifi(IGNORE_WLAN_ACTIVE_CONTROL, status); - break; - - case HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE: - rtk_notify_btcoex_to_wifi(BT_PSD_MODE_CONTROL, status); - break; - - case HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT: - rtk_notify_btcoex_to_wifi(LNA_CONSTRAIN_CONTROL, status); - break; - - case HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE: - break; - - case HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM: - break; - - case HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE: - break; - - case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L: - if (status == 0) { - memcpy(btrtl_coex.afh_map, p + 4, 4); /* cmd_idx, length, piconet_id, mode */ - temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M; - temp_cmd[1] = 2; - temp_cmd[2] = btrtl_coex.piconet_id; - temp_cmd[3] = btrtl_coex.mode; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, - temp_cmd); - } else { - memset(btrtl_coex.afh_map, 0, 10); - rtk_notify_afhmap_to_wifi(); - } - break; - - case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M: - if (status == 0) { - memcpy(btrtl_coex.afh_map + 4, p + 4, 4); - temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H; - temp_cmd[1] = 2; - temp_cmd[2] = btrtl_coex.piconet_id; - temp_cmd[3] = btrtl_coex.mode; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, - temp_cmd); - } else { - memset(btrtl_coex.afh_map, 0, 10); - rtk_notify_afhmap_to_wifi(); - } - break; - - case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H: - if (status == 0) - memcpy(btrtl_coex.afh_map + 8, p + 4, 2); - else - memset(btrtl_coex.afh_map, 0, 10); - - rtk_notify_afhmap_to_wifi(); - break; - - case HCI_VENDOR_SUB_CMD_RD_REG_REQ: - if (status == 0) - rtk_notify_regester_to_wifi(p + 3); /* cmd_idx,length,regist type */ - break; - - case HCI_VENDOR_SUB_CMD_WR_REG_REQ: - rtk_notify_btcoex_to_wifi(BT_REGISTER_ACCESS, status); - break; - - default: - break; - } -} - -static void rtk_handle_cmd_complete_evt(u8 total_len, u8 * p) -{ - u16 opcode; - - p++; - STREAM_TO_UINT16(opcode, p); - //RTKBT_DBG("cmd_complete, opcode is 0x%x", opcode); - - if (opcode == HCI_OP_PERIODIC_INQ) { - if (*p++ && btrtl_coex.isinquirying) { - btrtl_coex.isinquirying = 0; - RTKBT_DBG("hci period inq, start error, notify wifi " - "inquiry stop"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, - NULL); - } - } - - if (opcode == HCI_OP_READ_LOCAL_VERSION) { - if (!(*p++)) { - p++; - STREAM_TO_UINT16(btrtl_coex.hci_reversion, p); - p += 3; - STREAM_TO_UINT16(btrtl_coex.lmp_subversion, p); - RTKBT_DBG("BTCOEX hci_rev 0x%04x", - btrtl_coex.hci_reversion); - RTKBT_DBG("BTCOEX lmp_subver 0x%04x", - btrtl_coex.lmp_subversion); - } - } - - if (opcode == HCI_VENDOR_MAILBOX_CMD) { - rtk_parse_vendor_mailbox_cmd_evt(p, total_len); - } -} - -static void rtk_handle_cmd_status_evt(u8 * p) -{ - u16 opcode; - u8 status; - - status = *p++; - p++; - STREAM_TO_UINT16(opcode, p); - //RTKBT_DBG("cmd_status, opcode is 0x%x", opcode); - if ((opcode == HCI_OP_INQUIRY) && (status)) { - if (btrtl_coex.isinquirying) { - btrtl_coex.isinquirying = 0; - RTKBT_DBG("hci inq, start error, notify wifi inq stop"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, - NULL); - } - } - - if (opcode == HCI_OP_CREATE_CONN) { - if (!status && !btrtl_coex.ispaging) { - btrtl_coex.ispaging = 1; - RTKBT_DBG("hci create conn, notify wifi start page"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0, - NULL); - } - } -} - -static void rtk_handle_connection_complete_evt(u8 * p) -{ - u16 handle; - u8 status, link_type; - rtk_conn_prof *hci_conn = NULL; - - status = *p++; - STREAM_TO_UINT16(handle, p); - p += 6; - link_type = *p++; - - if (status == 0) { - if (btrtl_coex.ispaging) { - btrtl_coex.ispaging = 0; - RTKBT_DBG("notify wifi page success end"); - rtk_notify_btoperation_to_wifi - (BT_OPCODE_PAGE_SUCCESS_END, 0, NULL); - } - - hci_conn = find_connection_by_handle(&btrtl_coex, handle); - if (hci_conn == NULL) { - hci_conn = allocate_connection_by_handle(handle); - if (hci_conn) { - add_connection_to_hash(&btrtl_coex, - hci_conn); - hci_conn->profile_bitmap = 0; - memset(hci_conn->profile_refcount, 0, 8); - if ((0 == link_type) || (2 == link_type)) { //sco or esco - hci_conn->type = 1; - update_profile_connection(hci_conn, - profile_sco, - TRUE); - } else - hci_conn->type = 0; - } else { - RTKBT_ERR("hci connection allocate fail"); - } - } else { - RTKBT_DBG("hci conn handle 0x%04x already existed!", - handle); - hci_conn->profile_bitmap = 0; - memset(hci_conn->profile_refcount, 0, 8); - if ((0 == link_type) || (2 == link_type)) { //sco or esco - hci_conn->type = 1; - update_profile_connection(hci_conn, profile_sco, - TRUE); - } else - hci_conn->type = 0; - } - } else if (btrtl_coex.ispaging) { - btrtl_coex.ispaging = 0; - RTKBT_DBG("notify wifi page unsuccess end"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0, - NULL); - } -} - -static void rtk_handle_le_connection_complete_evt(u8 * p) -{ - u16 handle, interval; - u8 status; - rtk_conn_prof *hci_conn = NULL; - - status = *p++; - STREAM_TO_UINT16(handle, p); - p += 8; //role, address type, address - STREAM_TO_UINT16(interval, p); - - if (status == 0) { - if (btrtl_coex.ispaging) { - btrtl_coex.ispaging = 0; - RTKBT_DBG("notify wifi page success end"); - rtk_notify_btoperation_to_wifi - (BT_OPCODE_PAGE_SUCCESS_END, 0, NULL); - } - - hci_conn = find_connection_by_handle(&btrtl_coex, handle); - if (hci_conn == NULL) { - hci_conn = allocate_connection_by_handle(handle); - if (hci_conn) { - add_connection_to_hash(&btrtl_coex, - hci_conn); - hci_conn->profile_bitmap = 0; - memset(hci_conn->profile_refcount, 0, 8); - hci_conn->type = 2; - update_profile_connection(hci_conn, profile_hid, TRUE); //for coex, le is the same as hid - update_hid_active_state(handle, interval); - } else { - RTKBT_ERR("hci connection allocate fail"); - } - } else { - RTKBT_DBG("hci conn handle 0x%04x already existed!", - handle); - hci_conn->profile_bitmap = 0; - memset(hci_conn->profile_refcount, 0, 8); - hci_conn->type = 2; - update_profile_connection(hci_conn, profile_hid, TRUE); - update_hid_active_state(handle, interval); - } - } else if (btrtl_coex.ispaging) { - btrtl_coex.ispaging = 0; - RTKBT_DBG("notify wifi page unsuccess end"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0, - NULL); - } -} - -static void rtk_handle_le_connection_update_complete_evt(u8 * p) -{ - u16 handle, interval; - /* u8 status; */ - - /* status = *p++; */ - p++; - - STREAM_TO_UINT16(handle, p); - STREAM_TO_UINT16(interval, p); - update_hid_active_state(handle, interval); -} - -static void rtk_handle_le_meta_evt(u8 * p) -{ - u8 sub_event = *p++; - switch (sub_event) { - case HCI_EV_LE_CONN_COMPLETE: - rtk_handle_le_connection_complete_evt(p); - break; - - case HCI_EV_LE_CONN_UPDATE_COMPLETE: - rtk_handle_le_connection_update_complete_evt(p); - break; - - default: - break; - } -} - -static void disconn_acl(u16 handle, struct rtl_hci_conn *conn) -{ - struct rtl_coex_struct *coex = &btrtl_coex; - rtk_prof_info *prof_info = NULL; - struct list_head *iter = NULL, *temp = NULL; - - spin_lock(&coex->spin_lock_profile); - - list_for_each_safe(iter, temp, &coex->profile_list) { - prof_info = list_entry(iter, rtk_prof_info, list); - if (handle == prof_info->handle && prof_info->scid - && prof_info->dcid) { - RTKBT_DBG("hci disconn, hndl %x, psm %x, dcid %x, " - "scid %x", prof_info->handle, - prof_info->psm, prof_info->dcid, - prof_info->scid); - //If both scid and dcid > 0, L2cap connection is exist. - update_profile_connection(conn, - prof_info->profile_index, FALSE); - delete_profile_from_hash(prof_info); - } - } - spin_unlock(&coex->spin_lock_profile); -} - -static void rtk_handle_disconnect_complete_evt(u8 * p) -{ - u16 handle; - u8 status; - /* u8 reason; */ - rtk_conn_prof *hci_conn = NULL; - - if (btrtl_coex.ispairing) { //for slave: connection will be disconnected if authentication fail - btrtl_coex.ispairing = 0; - RTKBT_DBG("hci disc complete, notify wifi pair end"); - rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL); - } - - status = *p++; - STREAM_TO_UINT16(handle, p); - - /* reason = *p; */ - - if (status == 0) { - RTKBT_DBG("process disconn complete event."); - hci_conn = find_connection_by_handle(&btrtl_coex, handle); - if (hci_conn) { - switch (hci_conn->type) { - case 0: - /* FIXME: If this is interrupted by l2cap rx, - * there may be deadlock on spin_lock_profile */ - disconn_acl(handle, hci_conn); - break; - - case 1: - update_profile_connection(hci_conn, profile_sco, - FALSE); - break; - - case 2: - update_profile_connection(hci_conn, profile_hid, - FALSE); - break; - - default: - break; - } - delete_connection_from_hash(hci_conn); - } else - RTKBT_ERR("hci conn handle 0x%04x not found", handle); - } -} - -static void rtk_handle_specific_evt(u8 * p) -{ - u16 subcode; - - STREAM_TO_UINT16(subcode, p); - if (subcode == HCI_VENDOR_PTA_AUTO_REPORT_EVENT) { - RTKBT_DBG("notify wifi driver with autoreport data"); - rtk_notify_info_to_wifi(AUTO_REPORT, RTL_BTINFO_LEN, - (uint8_t *)p); - } -} - -static void rtk_parse_event_data(struct rtl_coex_struct *coex, - u8 *data, u16 len) -{ - u8 *p = data; - u8 event_code = *p++; - u8 total_len = *p++; - - (void)coex; - (void)&len; - - switch (event_code) { - case HCI_EV_INQUIRY_COMPLETE: - rtk_handle_inquiry_complete(); - break; - - case HCI_EV_PIN_CODE_REQ: - rtk_handle_pin_code_req(); - break; - - case HCI_EV_IO_CAPA_REQUEST: - rtk_handle_io_capa_req(); - break; - - case HCI_EV_AUTH_COMPLETE: - rtk_handle_auth_request(); - break; - - case HCI_EV_LINK_KEY_NOTIFY: - rtk_handle_link_key_notify(); - break; - - case HCI_EV_MODE_CHANGE: - rtk_handle_mode_change_evt(p); - break; - - case HCI_EV_CMD_COMPLETE: - rtk_handle_cmd_complete_evt(total_len, p); - break; - - case HCI_EV_CMD_STATUS: - rtk_handle_cmd_status_evt(p); - break; - - case HCI_EV_CONN_COMPLETE: - case HCI_EV_SYNC_CONN_COMPLETE: - rtk_handle_connection_complete_evt(p); - break; - - case HCI_EV_DISCONN_COMPLETE: - rtk_handle_disconnect_complete_evt(p); - break; - - case HCI_EV_LE_META: - rtk_handle_le_meta_evt(p); - break; - - case HCI_EV_VENDOR_SPECIFIC: - rtk_handle_specific_evt(p); - break; - - default: - break; - } -} - -const char l2_dir_str[][4] = { - "RX", "TX", -}; - -void rtl_process_l2_sig(struct rtl_l2_buff *l2) -{ - /* u8 flag; */ - u8 code; - /* u8 identifier; */ - u16 handle; - /* u16 total_len; */ - /* u16 pdu_len, channel_id; */ - /* u16 command_len; */ - u16 psm, scid, dcid, result; - /* u16 status; */ - u8 *pp = l2->data; - - STREAM_TO_UINT16(handle, pp); - /* flag = handle >> 12; */ - handle = handle & 0x0FFF; - /* STREAM_TO_UINT16(total_len, pp); */ - pp += 2; /* data total length */ - - /* STREAM_TO_UINT16(pdu_len, pp); - * STREAM_TO_UINT16(channel_id, pp); */ - pp += 4; /* l2 len and channel id */ - - code = *pp++; - switch (code) { - case L2CAP_CONN_REQ: - /* identifier = *pp++; */ - pp++; - /* STREAM_TO_UINT16(command_len, pp); */ - pp += 2; - STREAM_TO_UINT16(psm, pp); - STREAM_TO_UINT16(scid, pp); - RTKBT_DBG("%s l2cap conn req, hndl 0x%04x, PSM 0x%04x, " - "scid 0x%04x", l2_dir_str[l2->out], handle, psm, - scid); - handle_l2cap_con_req(handle, psm, scid, l2->out); - break; - - case L2CAP_CONN_RSP: - /* identifier = *pp++; */ - pp++; - /* STREAM_TO_UINT16(command_len, pp); */ - pp += 2; - STREAM_TO_UINT16(dcid, pp); - STREAM_TO_UINT16(scid, pp); - STREAM_TO_UINT16(result, pp); - /* STREAM_TO_UINT16(status, pp); */ - pp += 2; - RTKBT_DBG("%s l2cap conn rsp, hndl 0x%04x, dcid 0x%04x, " - "scid 0x%04x, result 0x%04x", l2_dir_str[l2->out], - handle, dcid, scid, result); - handle_l2cap_con_rsp(handle, dcid, scid, l2->out, result); - break; - - case L2CAP_DISCONN_REQ: - /* identifier = *pp++; */ - pp++; - /* STREAM_TO_UINT16(command_len, pp); */ - pp += 2; - STREAM_TO_UINT16(dcid, pp); - STREAM_TO_UINT16(scid, pp); - RTKBT_DBG("%s l2cap disconn req, hndl 0x%04x, dcid 0x%04x, " - "scid 0x%04x", l2_dir_str[l2->out], handle, dcid, scid); - handle_l2cap_discon_req(handle, dcid, scid, l2->out); - break; - default: - RTKBT_DBG("undesired l2 command %u", code); - break; - } -} - -static void rtl_l2_data_process(u8 *pp, u16 len, int dir) -{ - u8 code; - u8 flag; - u16 handle, pdu_len, channel_id; - /* u16 total_len; */ - struct rtl_l2_buff *l2 = NULL; - u8 *hd = pp; - - /* RTKBT_DBG("l2 sig data %p, len %u, dir %d", pp, len, dir); */ - - STREAM_TO_UINT16(handle, pp); - flag = handle >> 12; - handle = handle & 0x0FFF; - /* STREAM_TO_UINT16(total_len, pp); */ - pp += 2; /* data total length */ - - STREAM_TO_UINT16(pdu_len, pp); - STREAM_TO_UINT16(channel_id, pp); - - if (channel_id == 0x0001) { - code = *pp++; - switch (code) { - case L2CAP_CONN_REQ: - case L2CAP_CONN_RSP: - case L2CAP_DISCONN_REQ: - RTKBT_DBG("l2cap op %u, len %u, out %d", code, len, - dir); - l2 = rtl_l2_node_get(&btrtl_coex); - if (l2) { - u16 n; - n = min_t(uint, len, L2_MAX_SUBSEC_LEN); - memcpy(l2->data, hd, n); - l2->out = dir; - rtl_l2_node_to_used(&btrtl_coex, l2); - queue_delayed_work(btrtl_coex.fw_wq, - &btrtl_coex.l2_work, 0); - } else - RTKBT_ERR("%s: failed to get l2 node", - __func__); - break; - case L2CAP_DISCONN_RSP: - break; - default: - break; - } - } else { - if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || - is_profile_connected(profile_pan))) - /* Do not count the continuous packets */ - packets_count(handle, channel_id, pdu_len, dir, pp); - } - return; -} - - -static void rtl_l2_work(struct work_struct *work) -{ - struct rtl_coex_struct *coex; - struct rtl_l2_buff *l2; - unsigned long flags; - - coex = container_of(work, struct rtl_coex_struct, l2_work.work); - - spin_lock_irqsave(&coex->buff_lock, flags); - while (!list_empty(&coex->l2_used_list)) { - l2 = list_entry(coex->l2_used_list.next, struct rtl_l2_buff, - list); - list_del(&l2->list); - - spin_unlock_irqrestore(&coex->buff_lock, flags); - - rtl_process_l2_sig(l2); - - spin_lock_irqsave(&coex->buff_lock, flags); - - list_add_tail(&l2->list, &coex->l2_free_list); - } - spin_unlock_irqrestore(&coex->buff_lock, flags); - - return; -} - -static void rtl_ev_work(struct work_struct *work) -{ - struct rtl_coex_struct *coex; - struct rtl_hci_ev *ev; - unsigned long flags; - - coex = container_of(work, struct rtl_coex_struct, fw_work.work); - - spin_lock_irqsave(&coex->buff_lock, flags); - while (!list_empty(&coex->ev_used_list)) { - ev = list_entry(coex->ev_used_list.next, struct rtl_hci_ev, - list); - list_del(&ev->list); - spin_unlock_irqrestore(&coex->buff_lock, flags); - - rtk_parse_event_data(coex, ev->data, ev->len); - - spin_lock_irqsave(&coex->buff_lock, flags); - list_add_tail(&ev->list, &coex->ev_free_list); - } - spin_unlock_irqrestore(&coex->buff_lock, flags); -} - -int ev_filter_out(u8 ev_code) -{ - switch (ev_code) { - case HCI_EV_INQUIRY_COMPLETE: - case HCI_EV_PIN_CODE_REQ: - case HCI_EV_IO_CAPA_REQUEST: - case HCI_EV_AUTH_COMPLETE: - case HCI_EV_LINK_KEY_NOTIFY: - case HCI_EV_MODE_CHANGE: - case HCI_EV_CMD_COMPLETE: - case HCI_EV_CMD_STATUS: - case HCI_EV_CONN_COMPLETE: - case HCI_EV_SYNC_CONN_COMPLETE: - case HCI_EV_DISCONN_COMPLETE: - case HCI_EV_LE_META: - case HCI_EV_VENDOR_SPECIFIC: - return 0; - default: - return 1; - } -} - -/* Context: in_interrupt() */ -void rtk_btcoex_parse_event(uint8_t *buffer, int count) -{ - struct rtl_coex_struct *coex = &btrtl_coex; - struct rtl_hci_ev *ev; - u8 *s; - struct sk_buff *skb; - struct sk_buff *ev_sk = NULL; - - /* RTKBT_DBG("%s: parse ev.", __func__); */ - - spin_lock(&coex->rxlock); - skb = coex->evt_skb; - - while (count) { - int len; - - if (!skb) { - skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC); - if (!skb) { - RTKBT_ERR("failed to alloc skb"); - break; - } - - coex->pkt_type = HCI_EVENT_PKT; - coex->expect = HCI_EVENT_HDR_SIZE; - } - - len = min_t(uint, coex->expect, count); - memcpy(skb_put(skb, len), buffer, len); - - count -= len; - buffer += len; - coex->expect -= len; - - if (skb->len == HCI_EVENT_HDR_SIZE) { - /* Complete event header */ - coex->expect = hci_event_hdr(skb)->plen; - - if (skb_tailroom(skb) < coex->expect) { - kfree_skb(skb); - skb = NULL; - - RTKBT_ERR("skb room is not enough"); - break; - } - } - - if (coex->expect == 0) { - /* Complete frame */ - ev_sk = skb; - skb = NULL; - } - } - - /* evt_skb would be NULL only there is a complete frame found. */ - coex->evt_skb = skb; - spin_unlock(&coex->rxlock); - - /* no complete frame */ - if (!ev_sk) - return; - - s = (u8 *)ev_sk->data; - - if (ev_filter_out(s[0])) - return; - - ev = rtl_ev_node_get(&btrtl_coex); - if (!ev) { - RTKBT_ERR("%s: no free ev node.", __func__); - return; - } - - if (ev_sk->len > MAX_LEN_OF_HCI_EV) { - memcpy(ev->data, ev_sk->data, MAX_LEN_OF_HCI_EV); - ev->len = MAX_LEN_OF_HCI_EV; - } else { - memcpy(ev->data, ev_sk->data, ev_sk->len); - ev->len = ev_sk->len; - } - - rtl_ev_node_to_used(&btrtl_coex, ev); - - queue_delayed_work(btrtl_coex.fw_wq, &btrtl_coex.fw_work, 0); - - /* free complete frame here */ - kfree_skb(ev_sk); -} - - -void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count) -{ - rtl_l2_data_process(buffer, count, 1); - //u16 handle, total_len, pdu_len, channel_ID, command_len, psm, scid, - // dcid, result, status; - //u8 flag, code, identifier; - //u8 *pp = (u8 *) (skb->data); - //STREAM_TO_UINT16(handle, pp); - //flag = handle >> 12; - //handle = handle & 0x0FFF; - //STREAM_TO_UINT16(total_len, pp); - //STREAM_TO_UINT16(pdu_len, pp); - //STREAM_TO_UINT16(channel_ID, pp); - - //if (channel_ID == 0x0001) { - // code = *pp++; - // switch (code) { - // case L2CAP_CONN_REQ: - // identifier = *pp++; - // STREAM_TO_UINT16(command_len, pp); - // STREAM_TO_UINT16(psm, pp); - // STREAM_TO_UINT16(scid, pp); - // RTKBT_DBG("TX l2cap conn req, hndl %x, PSM %x, scid=%x", - // handle, psm, scid); - // handle_l2cap_con_req(handle, psm, scid, 1); - // break; - - // case L2CAP_CONN_RSP: - // identifier = *pp++; - // STREAM_TO_UINT16(command_len, pp); - // STREAM_TO_UINT16(dcid, pp); - // STREAM_TO_UINT16(scid, pp); - // STREAM_TO_UINT16(result, pp); - // STREAM_TO_UINT16(status, pp); - // RTKBT_DBG("TX l2cap conn rsp, hndl %x, dcid %x, " - // "scid %x, result %x", - // handle, dcid, scid, result); - // handle_l2cap_con_rsp(handle, dcid, scid, 1, result); - // break; - - // case L2CAP_DISCONN_REQ: - // identifier = *pp++; - // STREAM_TO_UINT16(command_len, pp); - // STREAM_TO_UINT16(dcid, pp); - // STREAM_TO_UINT16(scid, pp); - // RTKBT_DBG("TX l2cap disconn req, hndl %x, dcid %x, " - // "scid %x", handle, dcid, scid); - // handle_l2cap_discon_req(handle, dcid, scid, 1); - // break; - - // case L2CAP_DISCONN_RSP: - // break; - - // default: - // break; - // } - //} else { - // if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan))) //Do not count the continuous packets - // packets_count(handle, channel_ID, pdu_len, 1, pp); - //} -} - -void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count) -{ - rtl_l2_data_process(buffer, count, 0); - //u16 handle, total_len, pdu_len, channel_ID, command_len, psm, scid, - // dcid, result, status; - //u8 flag, code, identifier; - //u8 *pp = urb->transfer_buffer; - //STREAM_TO_UINT16(handle, pp); - //flag = handle >> 12; - //handle = handle & 0x0FFF; - //STREAM_TO_UINT16(total_len, pp); - //STREAM_TO_UINT16(pdu_len, pp); - //STREAM_TO_UINT16(channel_ID, pp); - - //if (channel_ID == 0x0001) { - // code = *pp++; - // switch (code) { - // case L2CAP_CONN_REQ: - // identifier = *pp++; - // STREAM_TO_UINT16(command_len, pp); - // STREAM_TO_UINT16(psm, pp); - // STREAM_TO_UINT16(scid, pp); - // RTKBT_DBG("RX l2cap conn req, hndl %x, PSM %x, scid %x", - // handle, psm, scid); - // handle_l2cap_con_req(handle, psm, scid, 0); - // break; - - // case L2CAP_CONN_RSP: - // identifier = *pp++; - // STREAM_TO_UINT16(command_len, pp); - // STREAM_TO_UINT16(dcid, pp); - // STREAM_TO_UINT16(scid, pp); - // STREAM_TO_UINT16(result, pp); - // STREAM_TO_UINT16(status, pp); - // RTKBT_DBG("RX l2cap conn rsp, hndl %x, dcid %x, " - // "scid %x, result %x", - // handle, dcid, scid, result); - // handle_l2cap_con_rsp(handle, dcid, scid, 0, result); - // break; - - // case L2CAP_DISCONN_REQ: - // identifier = *pp++; - // STREAM_TO_UINT16(command_len, pp); - // STREAM_TO_UINT16(dcid, pp); - // STREAM_TO_UINT16(scid, pp); - // RTKBT_DBG("RX l2cap disconn req, hndl %x, dcid %x, " - // "scid %x", handle, dcid, scid); - // handle_l2cap_discon_req(handle, dcid, scid, 0); - // break; - - // case L2CAP_DISCONN_RSP: - // break; - - // default: - // break; - // } - //} else { - // if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan))) //Do not count the continuous packets - // packets_count(handle, channel_ID, pdu_len, 0, pp); - //} -} - -static void polling_bt_info(unsigned long data) -{ - uint8_t temp_cmd[1]; - RTKBT_DBG("polling timer"); - if (btrtl_coex.polling_enable) { - //temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 1, temp_cmd); - } - mod_timer(&(btrtl_coex.polling_timer), - jiffies + - msecs_to_jiffies(1000 * btrtl_coex.polling_interval)); -} - -static void rtk_handle_bt_info_control(uint8_t *p) -{ - uint8_t temp_cmd[20]; - struct rtl_btinfo_ctl *ctl = (struct rtl_btinfo_ctl*)p; - RTKBT_DBG("Received polling_enable %u, polling_time %u, " - "autoreport_enable %u", ctl->polling_enable, - ctl->polling_time, ctl->autoreport_enable); - RTKBT_DBG("coex: original polling_enable %u", - btrtl_coex.polling_enable); - - if (ctl->polling_enable && !btrtl_coex.polling_enable) { - /* setup polling timer for getting bt info from firmware */ - setup_timer(&(btrtl_coex.polling_timer), polling_bt_info, 0); - btrtl_coex.polling_timer.expires = - jiffies + msecs_to_jiffies(ctl->polling_time * 1000); - add_timer(&(btrtl_coex.polling_timer)); - } - - /* Close bt info polling timer */ - if (!ctl->polling_enable && btrtl_coex.polling_enable) - del_timer(&(btrtl_coex.polling_timer)); - - if (btrtl_coex.autoreport != ctl->autoreport_enable) { - temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE; - temp_cmd[1] = 1; - temp_cmd[2] = ctl->autoreport_enable; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); - } - - btrtl_coex.polling_enable = ctl->polling_enable; - btrtl_coex.polling_interval = ctl->polling_time; - btrtl_coex.autoreport = ctl->autoreport_enable; - - rtk_notify_info_to_wifi(HOST_RESPONSE, 0, NULL); -} - -static void rtk_handle_bt_coex_control(uint8_t * p) -{ - uint8_t temp_cmd[20]; - uint8_t opcode, opcode_len, value, power_decrease, psd_mode, - access_type; - - opcode = *p++; - RTKBT_DBG("receive bt coex control event from wifi, op 0x%02x", opcode); - - switch (opcode) { - case BT_PATCH_VERSION_QUERY: - rtk_notify_btpatch_version_to_wifi(); - break; - - case IGNORE_WLAN_ACTIVE_CONTROL: - opcode_len = *p++; - value = *p++; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD; - temp_cmd[1] = 1; - temp_cmd[2] = value; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); - break; - - case LNA_CONSTRAIN_CONTROL: - opcode_len = *p++; - value = *p++; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT; - temp_cmd[1] = 1; - temp_cmd[2] = value; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); - break; - - case BT_POWER_DECREASE_CONTROL: - opcode_len = *p++; - power_decrease = *p++; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD; - temp_cmd[1] = 1; - temp_cmd[2] = power_decrease; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); - break; - - case BT_PSD_MODE_CONTROL: - opcode_len = *p++; - psd_mode = *p++; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE; - temp_cmd[1] = 1; - temp_cmd[2] = psd_mode; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd); - break; - - case WIFI_BW_CHNL_NOTIFY: - opcode_len = *p++; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD; - temp_cmd[1] = 3; - memcpy(temp_cmd + 2, p, 3); //wifi_state, wifi_centralchannel, chnnels_btnotuse - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 5, temp_cmd); - break; - - case QUERY_BT_AFH_MAP: - opcode_len = *p++; - btrtl_coex.piconet_id = *p++; - btrtl_coex.mode = *p++; - temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L; - temp_cmd[1] = 2; - temp_cmd[2] = btrtl_coex.piconet_id; - temp_cmd[3] = btrtl_coex.mode; - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd); - break; - - case BT_REGISTER_ACCESS: - opcode_len = *p++; - access_type = *p++; - if (access_type == 0) { //read - temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ; - temp_cmd[1] = 5; - temp_cmd[2] = *p++; - memcpy(temp_cmd + 3, p, 4); - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 7, - temp_cmd); - } else { //write - temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ; - temp_cmd[1] = 5; - temp_cmd[2] = *p++; - memcpy(temp_cmd + 3, p, 8); - rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 11, - temp_cmd); - } - break; - - default: - break; - } -} - -static void rtk_handle_event_from_wifi(uint8_t * msg) -{ - uint8_t *p = msg; - uint8_t event_code = *p++; - uint8_t total_length; - uint8_t extension_event; - uint8_t operation; - uint16_t wifi_opcode; - uint8_t op_status; - - if (memcmp(msg, invite_rsp, sizeof(invite_rsp)) == 0) { - RTKBT_DBG("receive invite rsp from wifi, wifi is already on"); - btrtl_coex.wifi_on = 1; - rtk_notify_extension_version_to_wifi(); - } - - if (memcmp(msg, attend_req, sizeof(attend_req)) == 0) { - RTKBT_DBG("receive attend req from wifi, wifi turn on"); - btrtl_coex.wifi_on = 1; - udpsocket_send(attend_ack, sizeof(attend_ack)); - rtk_notify_extension_version_to_wifi(); - } - - if (memcmp(msg, wifi_leave, sizeof(wifi_leave)) == 0) { - RTKBT_DBG("receive wifi leave from wifi, wifi turn off"); - btrtl_coex.wifi_on = 0; - udpsocket_send(leave_ack, sizeof(leave_ack)); - if (btrtl_coex.polling_enable) { - btrtl_coex.polling_enable = 0; - del_timer(&(btrtl_coex.polling_timer)); - } - } - - if (memcmp(msg, leave_ack, sizeof(leave_ack)) == 0) { - RTKBT_DBG("receive leave ack from wifi"); - } - - if (event_code == 0xFE) { - total_length = *p++; - extension_event = *p++; - switch (extension_event) { - case RTK_HS_EXTENSION_EVENT_WIFI_SCAN: - operation = *p; - RTKBT_DBG("Recv WiFi scan notify event from WiFi, " - "op 0x%02x", operation); - break; - - case RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL: - rtk_handle_bt_info_control(p); - break; - - case RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL: - rtk_handle_bt_coex_control(p); - break; - - default: - break; - } - } - - if (event_code == 0x0E) { - p += 2; //length, number of complete packets - STREAM_TO_UINT16(wifi_opcode, p); - op_status = *p; - RTKBT_DBG("Recv cmd complete event from WiFi, op 0x%02x, " - "status 0x%02x", wifi_opcode, op_status); - } -} - -static inline void rtl_free_frags(struct rtl_coex_struct *coex) -{ - unsigned long flags; - - spin_lock_irqsave(&coex->rxlock, flags); - - kfree_skb(coex->evt_skb); - coex->evt_skb = NULL; - - spin_unlock_irqrestore(&coex->rxlock, flags); -} - -void rtk_btcoex_open(struct hci_dev *hdev) -{ - if (test_and_set_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { - RTKBT_WARN("RTL COEX is already running."); - return; - } - - RTKBT_INFO("Open BTCOEX"); - - /* Just for test */ - //struct rtl_btinfo_ctl ctl; - - INIT_DELAYED_WORK(&btrtl_coex.fw_work, (void *)rtl_ev_work); - INIT_DELAYED_WORK(&btrtl_coex.sock_work, - (void *)udpsocket_recv_data); - INIT_DELAYED_WORK(&btrtl_coex.l2_work, (void *)rtl_l2_work); - - btrtl_coex.hdev = hdev; - btrtl_coex.wifi_on = 0; - - init_profile_hash(&btrtl_coex); - init_connection_hash(&btrtl_coex); - - btrtl_coex.pkt_type = 0; - btrtl_coex.expect = 0; - btrtl_coex.evt_skb = NULL; - - create_udpsocket(); - udpsocket_send(invite_req, sizeof(invite_req)); - - /* Just for test */ - //ctl.polling_enable = 1; - //ctl.polling_time = 1; - //ctl.autoreport_enable = 1; - //rtk_handle_bt_info_control((u8 *)&ctl); -} - -void rtk_btcoex_close(void) -{ - int kk = 0; - - if (!test_and_clear_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) { - RTKBT_WARN("RTL COEX is already closed."); - return; - } - - RTKBT_INFO("Close BTCOEX"); - - if (btrtl_coex.wifi_on) - udpsocket_send(bt_leave, sizeof(bt_leave)); - - if (btrtl_coex.polling_enable) { - btrtl_coex.polling_enable = 0; - del_timer(&(btrtl_coex.polling_timer)); - } - - del_timer(&(btrtl_coex.a2dp_count_timer)); - del_timer(&(btrtl_coex.pan_count_timer)); - - cancel_delayed_work(&btrtl_coex.sock_work); - cancel_delayed_work(&btrtl_coex.fw_work); - cancel_delayed_work(&btrtl_coex.l2_work); - - if (btrtl_coex.sock_open) { - btrtl_coex.sock_open = 0; - RTKBT_DBG("release udp socket"); - sock_release(btrtl_coex.udpsock); - } - - flush_connection_hash(&btrtl_coex); - flush_profile_hash(&btrtl_coex); - btrtl_coex.profile_bitmap = 0; - btrtl_coex.profile_status = 0; - for (kk = 0; kk < 8; kk++) - btrtl_coex.profile_refcount[kk] = 0; - - rtl_free_frags(&btrtl_coex); - RTKBT_DBG("-x"); -} - -void rtk_btcoex_probe(struct hci_dev *hdev) -{ - btrtl_coex.hdev = hdev; - spin_lock_init(&btrtl_coex.spin_lock_sock); - spin_lock_init(&btrtl_coex.spin_lock_profile); -} - -void rtk_btcoex_init(void) -{ - RTKBT_DBG("%s: version: %s", __func__, RTK_VERSION); - RTKBT_DBG("create workqueue"); - btrtl_coex.sock_wq = create_workqueue("btudpwork"); - btrtl_coex.fw_wq = create_workqueue("btfwwork"); - rtl_alloc_buff(&btrtl_coex); - spin_lock_init(&btrtl_coex.rxlock); -} - -void rtk_btcoex_exit(void) -{ - RTKBT_DBG("%s: destroy workqueue", __func__); - flush_workqueue(btrtl_coex.sock_wq); - destroy_workqueue(btrtl_coex.sock_wq); - flush_workqueue(btrtl_coex.fw_wq); - destroy_workqueue(btrtl_coex.fw_wq); - rtl_free_buff(&btrtl_coex); -} diff --git a/drivers/bluetooth/rtk_coex.h b/drivers/bluetooth/rtk_coex.h deleted file mode 100644 index 77d94c49b236..000000000000 --- a/drivers/bluetooth/rtk_coex.h +++ /dev/null @@ -1,334 +0,0 @@ -#include -#include - -/*********************************** -** Realtek - For coexistence ** -***********************************/ -#define BTRTL_HCIUSB 0 -#define BTRTL_HCIUART 1 - -#define BTRTL_HCI_IF BTRTL_HCIUART - -#define TRUE 1 -#define FALSE 0 - -#define CONNECT_PORT 30001 -#define CONNECT_PORT_WIFI 30000 - -#define invite_req "INVITE_REQ" -#define invite_rsp "INVITE_RSP" -#define attend_req "ATTEND_REQ" -#define attend_ack "ATTEND_ACK" -#define wifi_leave "WIFI_LEAVE" -#define leave_ack "LEAVE_ACK" -#define bt_leave "BT_LEAVE" - -#define HCI_OP_PERIODIC_INQ 0x0403 -#define HCI_EV_LE_META 0x3e -#define HCI_EV_LE_CONN_COMPLETE 0x01 -#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03 - -//vendor cmd to fw -#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18 -#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND 0xfc19 -#define HCI_VENDOR_MAILBOX_CMD 0xfc8f -#define HCI_VENDOR_SET_BITPOOL 0xfc51 - -//subcmd to fw -#define HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD 0x11 -#define HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD 0x17 -#define HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD 0x1B -#define HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO 0x23 -#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO 0x27 -#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE 0x28 -#define HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM 0x29 -#define HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE 0x2A -#define HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE 0x31 -#define HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT 0x32 -#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L 0x40 -#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M 0x41 -#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H 0x42 -#define HCI_VENDOR_SUB_CMD_RD_REG_REQ 0x43 -#define HCI_VENDOR_SUB_CMD_WR_REG_REQ 0x44 - -#define HCI_EV_VENDOR_SPECIFIC 0xff - -//sub event from fw start -#define HCI_VENDOR_PTA_REPORT_EVENT 0x24 -#define HCI_VENDOR_PTA_AUTO_REPORT_EVENT 0x25 - -//vendor cmd to wifi driver -#define HCI_GRP_VENDOR_SPECIFIC (0x3f << 10) -#define HCI_OP_HCI_EXTENSION_VERSION_NOTIFY (0x0100 | HCI_GRP_VENDOR_SPECIFIC) -#define HCI_OP_BT_OPERATION_NOTIFY (0x0102 | HCI_GRP_VENDOR_SPECIFIC) -#define HCI_OP_HCI_BT_INFO_NOTIFY (0x0106 | HCI_GRP_VENDOR_SPECIFIC) -#define HCI_OP_HCI_BT_COEX_NOTIFY (0x0107 | HCI_GRP_VENDOR_SPECIFIC) -#define HCI_OP_HCI_BT_PATCH_VER_NOTIFY (0x0108 | HCI_GRP_VENDOR_SPECIFIC) -#define HCI_OP_HCI_BT_AFH_MAP_NOTIFY (0x0109 | HCI_GRP_VENDOR_SPECIFIC) -#define HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY (0x010a | HCI_GRP_VENDOR_SPECIFIC) - -//bt info reason to wifi -#define HOST_RESPONSE 0 //Host response when receive the BT Info Control Event -#define POLLING_RESPONSE 1 //The BT Info response for polling by BT firmware. -#define AUTO_REPORT 2 //BT auto report by BT firmware. -#define STACK_REPORT_WHILE_DEVICE_D2 3 //Stack report when BT firmware is under power save state(ex:D2) - -// vendor event from wifi -#define RTK_HS_EXTENSION_EVENT_WIFI_SCAN 0x01 -#define RTK_HS_EXTENSION_EVENT_RADIO_STATUS_NOTIFY 0x02 -#define RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL 0x03 -#define RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL 0x04 - -//op code from wifi -#define BT_PATCH_VERSION_QUERY 0x00 -#define IGNORE_WLAN_ACTIVE_CONTROL 0x01 -#define LNA_CONSTRAIN_CONTROL 0x02 -#define BT_POWER_DECREASE_CONTROL 0x03 -#define BT_PSD_MODE_CONTROL 0x04 -#define WIFI_BW_CHNL_NOTIFY 0x05 -#define QUERY_BT_AFH_MAP 0x06 -#define BT_REGISTER_ACCESS 0x07 - -//bt operation to notify -#define BT_OPCODE_NONE 0 -#define BT_OPCODE_INQUIRY_START 1 -#define BT_OPCODE_INQUIRY_END 2 -#define BT_OPCODE_PAGE_START 3 -#define BT_OPCODE_PAGE_SUCCESS_END 4 -#define BT_OPCODE_PAGE_UNSUCCESS_END 5 -#define BT_OPCODE_PAIR_START 6 -#define BT_OPCODE_PAIR_END 7 -#define BT_OPCODE_ENABLE_BT 8 -#define BT_OPCODE_DISABLE_BT 9 - -#define HCI_EXTENSION_VERSION 0x0004 -#define HCI_CMD_PREAMBLE_SIZE 3 -#define PAN_PACKET_COUNT 5 - -#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;} -#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} - -#define PSM_SDP 0x0001 -#define PSM_RFCOMM 0x0003 -#define PSM_PAN 0x000F -#define PSM_HID 0x0011 -#define PSM_HID_INT 0x0013 -#define PSM_AVCTP 0x0017 -#define PSM_AVDTP 0x0019 -#define PSM_FTP 0x1001 -#define PSM_BIP 0x1003 -#define PSM_OPP 0x1015 -//--add more if needed--// - -enum { - profile_sco = 0, - profile_hid = 1, - profile_a2dp = 2, - profile_pan = 3, - profile_hid_interval = 4, - profile_hogp = 5, - profile_voice = 6, - profile_max = 7 -}; - -//profile info data -typedef struct { - struct list_head list; - uint16_t handle; - uint16_t psm; - uint16_t dcid; - uint16_t scid; - uint8_t profile_index; -} rtk_prof_info, *prtk_prof_info; - -//profile info for each connection -typedef struct rtl_hci_conn { - struct list_head list; - uint16_t handle; - uint8_t type; // 0:l2cap, 1:sco/esco, 2:le - uint8_t profile_bitmap; - int8_t profile_refcount[8]; -} rtk_conn_prof, *prtk_conn_prof; - -struct rtl_btinfo { - u8 cmd; - u8 len; - u8 data[6]; -}; -#define RTL_BTINFO_LEN (sizeof(struct rtl_btinfo)) -/* typedef struct { - * uint8_t cmd_index; - * uint8_t cmd_length; - * uint8_t link_status; - * uint8_t retry_cnt; - * uint8_t rssi; - * uint8_t mailbox_info; - * uint16_t acl_throughput; - * } hci_linkstatus_report; */ - -typedef struct { - uint8_t type; - uint32_t offset; - uint32_t value; -} hci_mailbox_register; - -struct rtl_btinfo_ctl { - uint8_t polling_enable; - uint8_t polling_time; - uint8_t autoreport_enable; -}; - -#define MAX_LEN_OF_HCI_EV 32 -#define NUM_RTL_HCI_EV 32 -struct rtl_hci_ev { - __u8 data[MAX_LEN_OF_HCI_EV]; - __u16 len; - struct list_head list; -}; - -#define L2_MAX_SUBSEC_LEN 128 -#define L2_MAX_PKTS 16 -struct rtl_l2_buff { - __u8 data[L2_MAX_SUBSEC_LEN]; - __u16 len; - __u16 out; - struct list_head list; -}; - -struct rtl_coex_struct { - struct list_head conn_hash; //hash for connections - struct list_head profile_list; //hash for profile info - struct hci_dev *hdev; - struct socket *udpsock; - struct sockaddr_in addr; - struct sockaddr_in wifi_addr; - struct timer_list polling_timer; - struct timer_list a2dp_count_timer; - struct timer_list pan_count_timer; - struct timer_list hogp_count_timer; - struct workqueue_struct *sock_wq; - struct workqueue_struct *fw_wq; - struct delayed_work sock_work; - struct delayed_work fw_work; - struct delayed_work l2_work; - struct sock *sk; - struct urb *urb; - spinlock_t spin_lock_sock; - spinlock_t spin_lock_profile; - uint32_t a2dp_packet_count; - uint32_t pan_packet_count; - uint32_t hogp_packet_count; - uint32_t voice_packet_count; - uint8_t profile_bitmap; - uint8_t profile_status; - int8_t profile_refcount[8]; - uint8_t ispairing; - uint8_t isinquirying; - uint8_t ispaging; - uint8_t wifi_state; - uint8_t autoreport; - uint8_t polling_enable; - uint8_t polling_interval; - uint8_t piconet_id; - uint8_t mode; - uint8_t afh_map[10]; - uint16_t hci_reversion; - uint16_t lmp_subversion; - uint8_t wifi_on; - uint8_t sock_open; - unsigned long cmd_last_tx; - - /* hci ev buff */ - struct list_head ev_used_list; - struct list_head ev_free_list; - - spinlock_t rxlock; - __u8 pkt_type; - __u16 expect; - struct sk_buff *evt_skb; - - /* l2cap rx buff */ - struct list_head l2_used_list; - struct list_head l2_free_list; - - /* buff addr and size */ - spinlock_t buff_lock; - unsigned long pages_addr; - unsigned long buff_size; - -#define RTL_COEX_RUNNING (1 << 0) - unsigned long flags; - -}; - -/* #if __BYTE_ORDER == __LITTLE_ENDIAN */ -/* Little endian */ -struct sbc_frame_hdr { - uint8_t syncword:8; /* Sync word */ - uint8_t subbands:1; /* Subbands */ - uint8_t allocation_method:1; /* Allocation method */ - uint8_t channel_mode:2; /* Channel mode */ - uint8_t blocks:2; /* Blocks */ - uint8_t sampling_frequency:2; /* Sampling frequency */ - uint8_t bitpool:8; /* Bitpool */ - uint8_t crc_check:8; /* CRC check */ -} __attribute__ ((packed)); - -/* NOTE: The code is copied from pa. - * only the bit field in 8-bit is affected by endian, not the 16-bit or 32-bit. - * why? - */ -struct rtp_header { - unsigned cc:4; - unsigned x:1; - unsigned p:1; - unsigned v:2; - - unsigned pt:7; - unsigned m:1; - - uint16_t sequence_number; - uint32_t timestamp; - uint32_t ssrc; - uint32_t csrc[0]; -} __attribute__ ((packed)); - -/* #elif __BYTE_ORDER == __BIG_ENDIAN - * struct sbc_frame_hdr { - * uint8_t syncword; - * uint8_t sampling_frequency:2; - * uint8_t blocks:2; - * uint8_t channel_mode:2; - * uint8_t allocation_method:1; - * uint8_t subbands:1; - * uint8_t bitpool:8; - * uint8_t crc_check:8; - * } __attribute__ ((packed)); - * - * struct rtp_header { - * unsigned v:2; - * unsigned p:1; - * unsigned x:1; - * unsigned cc:4; - * - * unsigned m:1; - * unsigned pt:7; - * - * uint16_t sequence_number; - * uint32_t timestamp; - * uint32_t ssrc; - * uint32_t csrc[0]; - * } __attribute__ ((packed)); - * - * #endif */ - -void rtk_btcoex_parse_event(uint8_t *buffer, int count); -void rtk_btcoex_parse_cmd(uint8_t *buffer, int count); -void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count); -void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count); - -void rtk_btcoex_open(struct hci_dev *hdev); -void rtk_btcoex_close(void); -void rtk_btcoex_probe(struct hci_dev *hdev); -void rtk_btcoex_init(void); -void rtk_btcoex_exit(void); diff --git a/drivers/bluetooth/vflash.c b/drivers/bluetooth/vflash.c deleted file mode 100755 index bb37c7395718..000000000000 --- a/drivers/bluetooth/vflash.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2010 ROCKCHIP, Inc. - * Author: roger_chen - * - * This program is the virtual flash device - * used to store bd_addr or MAC - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define DBG(x...) printk("vFlash:" x) -#else -#define DBG(x...) -#endif - -#define VERSION "0.1" - -static int minor = MISC_DYNAMIC_MINOR; - -static struct miscdevice vflash_miscdev; - -#define READ_BDADDR_FROM_FLASH 0x01 - -extern char GetSNSectorInfo(char * pbuf); -extern unsigned char wlan_mac_addr[6]; - -static long vflash_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - - DBG("%s---cmd=0x%x---arg=0x%x\n", __FUNCTION__, cmd, arg); - - if(NULL == argp) - return -EFAULT; - - switch(cmd) - { - case READ_BDADDR_FROM_FLASH: - { -#ifdef CONFIG_WIFI_MAC - unsigned char bd_addr[6] = {0}; - int i; - - printk("vflash: wlan_mac_addr:%X:%X:%X:%x:%X:%x\n", wlan_mac_addr[0], - wlan_mac_addr[1], - wlan_mac_addr[2], - wlan_mac_addr[3], - wlan_mac_addr[4], - wlan_mac_addr[5] ); - for (i=1; i<6; i++) { - bd_addr[i] = wlan_mac_addr[5-i]; - } - - bd_addr[0] = wlan_mac_addr[5]+1; - - printk("vflash: bd_addr:%X:%X:%X:%x:%X:%x\n", bd_addr[5], - bd_addr[4], - bd_addr[3], - bd_addr[2], - bd_addr[1], - bd_addr[0] ); - - - if(copy_to_user(argp, bd_addr, 6)) { - printk("ERROR: copy_to_user---%s\n", __FUNCTION__); - return -EFAULT; - } -#else - char *tempBuf = (char *)kmalloc(512, GFP_KERNEL); - char bd_addr[7] = {0}; - int i; - - GetSNSectorInfo(tempBuf); - - for(i=498; i<=504; i++) - { - DBG("tempBuf[%d]=%x\n", i, tempBuf[i]); - bd_addr[504-i] = tempBuf[i]; - } - - - //printk("%s: ====> get bt addr from flash=[%02x:%02x:%02x:%02x:%02x:%02x]\n", __FUNCTION__, - // bd_addr[5], bd_addr[4], bd_addr[3], bd_addr[2], bd_addr[1], bd_addr[0]); - if(copy_to_user(argp, bd_addr, 6)) - { - printk("ERROR: copy_to_user---%s\n", __FUNCTION__); - kfree(tempBuf); - return -EFAULT; - } - - kfree(tempBuf); -#endif - } - break; - default: - break; - } - - return 0; -} - -static int vflash_open(struct inode *inode, struct file *file) -{ - DBG("%s\n", __FUNCTION__); - return 0; -} - -static int vflash_release(struct inode *inode, struct file *file) -{ - DBG("%s\n", __FUNCTION__); - return 0; -} - - -static const struct file_operations vflash_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = vflash_ioctl, - .open = vflash_open, - .release = vflash_release, -}; - -static struct miscdevice vflash_miscdev= { - .name = "vflash", - .fops = &vflash_fops, -}; - - -static int vflash_init(void) -{ - vflash_miscdev.minor = minor; - - if (misc_register(&vflash_miscdev) < 0) { - printk(KERN_ERR"Can't register misc device with minor %d", minor); - return -EIO; - } - return 0; -} - -static void vflash_exit(void) -{ - if (misc_deregister(&vflash_miscdev) < 0) - printk(KERN_ERR"Can't unregister misc device with minor %d", minor); -} - - -module_init(vflash_init); -module_exit(vflash_exit); - -module_param(minor, int, 0444); -MODULE_PARM_DESC(minor, "Miscellaneous minor device number"); - -MODULE_AUTHOR("roger_chen "); -MODULE_DESCRIPTION("Bluetooth virtual flash driver ver " VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); -