Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc4 279 lines 6.0 kB view raw
1/* 2 * Atheros Communication Bluetooth HCIATH3K UART protocol 3 * 4 * HCIATH3K (HCI Atheros AR300x Protocol) is a Atheros Communication's 5 * power management protocol extension to H4 to support AR300x Bluetooth Chip. 6 * 7 * Copyright (c) 2009-2010 Atheros Communications Inc. 8 * 9 * Acknowledgements: 10 * This file is based on hci_h4.c, which was written 11 * by Maxim Krasnyansky and Marcel Holtmann. 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 * 27 */ 28 29#include <linux/module.h> 30#include <linux/kernel.h> 31 32#include <linux/init.h> 33#include <linux/slab.h> 34#include <linux/tty.h> 35#include <linux/errno.h> 36#include <linux/ioctl.h> 37#include <linux/skbuff.h> 38 39#include <net/bluetooth/bluetooth.h> 40#include <net/bluetooth/hci_core.h> 41 42#include "hci_uart.h" 43 44struct ath_struct { 45 struct hci_uart *hu; 46 unsigned int cur_sleep; 47 48 struct sk_buff *rx_skb; 49 struct sk_buff_head txq; 50 struct work_struct ctxtsw; 51}; 52 53#define OP_WRITE_TAG 0x01 54 55#define INDEX_BDADDR 0x01 56 57struct ath_vendor_cmd { 58 __u8 opcode; 59 __le16 index; 60 __u8 len; 61 __u8 data[251]; 62} __packed; 63 64static int ath_wakeup_ar3k(struct tty_struct *tty) 65{ 66 int status = tty->driver->ops->tiocmget(tty); 67 68 if (status & TIOCM_CTS) 69 return status; 70 71 /* Clear RTS first */ 72 tty->driver->ops->tiocmget(tty); 73 tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS); 74 msleep(20); 75 76 /* Set RTS, wake up board */ 77 tty->driver->ops->tiocmget(tty); 78 tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00); 79 msleep(20); 80 81 status = tty->driver->ops->tiocmget(tty); 82 return status; 83} 84 85static void ath_hci_uart_work(struct work_struct *work) 86{ 87 int status; 88 struct ath_struct *ath; 89 struct hci_uart *hu; 90 struct tty_struct *tty; 91 92 ath = container_of(work, struct ath_struct, ctxtsw); 93 94 hu = ath->hu; 95 tty = hu->tty; 96 97 /* verify and wake up controller */ 98 if (ath->cur_sleep) { 99 status = ath_wakeup_ar3k(tty); 100 if (!(status & TIOCM_CTS)) 101 return; 102 } 103 104 /* Ready to send Data */ 105 clear_bit(HCI_UART_SENDING, &hu->tx_state); 106 hci_uart_tx_wakeup(hu); 107} 108 109static int ath_open(struct hci_uart *hu) 110{ 111 struct ath_struct *ath; 112 113 BT_DBG("hu %p", hu); 114 115 ath = kzalloc(sizeof(*ath), GFP_KERNEL); 116 if (!ath) 117 return -ENOMEM; 118 119 skb_queue_head_init(&ath->txq); 120 121 hu->priv = ath; 122 ath->hu = hu; 123 124 INIT_WORK(&ath->ctxtsw, ath_hci_uart_work); 125 126 return 0; 127} 128 129static int ath_close(struct hci_uart *hu) 130{ 131 struct ath_struct *ath = hu->priv; 132 133 BT_DBG("hu %p", hu); 134 135 skb_queue_purge(&ath->txq); 136 137 kfree_skb(ath->rx_skb); 138 139 cancel_work_sync(&ath->ctxtsw); 140 141 hu->priv = NULL; 142 kfree(ath); 143 144 return 0; 145} 146 147static int ath_flush(struct hci_uart *hu) 148{ 149 struct ath_struct *ath = hu->priv; 150 151 BT_DBG("hu %p", hu); 152 153 skb_queue_purge(&ath->txq); 154 155 return 0; 156} 157 158static int ath_vendor_cmd(struct hci_dev *hdev, uint8_t opcode, uint16_t index, 159 const void *data, size_t dlen) 160{ 161 struct sk_buff *skb; 162 struct ath_vendor_cmd cmd; 163 164 if (dlen > sizeof(cmd.data)) 165 return -EINVAL; 166 167 cmd.opcode = opcode; 168 cmd.index = cpu_to_le16(index); 169 cmd.len = dlen; 170 memcpy(cmd.data, data, dlen); 171 172 skb = __hci_cmd_sync(hdev, 0xfc0b, dlen + 4, &cmd, HCI_INIT_TIMEOUT); 173 if (IS_ERR(skb)) 174 return PTR_ERR(skb); 175 kfree_skb(skb); 176 177 return 0; 178} 179 180static int ath_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 181{ 182 return ath_vendor_cmd(hdev, OP_WRITE_TAG, INDEX_BDADDR, bdaddr, 183 sizeof(*bdaddr)); 184} 185 186static int ath_setup(struct hci_uart *hu) 187{ 188 BT_DBG("hu %p", hu); 189 190 hu->hdev->set_bdaddr = ath_set_bdaddr; 191 192 return 0; 193} 194 195static const struct h4_recv_pkt ath_recv_pkts[] = { 196 { H4_RECV_ACL, .recv = hci_recv_frame }, 197 { H4_RECV_SCO, .recv = hci_recv_frame }, 198 { H4_RECV_EVENT, .recv = hci_recv_frame }, 199}; 200 201static int ath_recv(struct hci_uart *hu, const void *data, int count) 202{ 203 struct ath_struct *ath = hu->priv; 204 205 ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, 206 ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); 207 if (IS_ERR(ath->rx_skb)) { 208 int err = PTR_ERR(ath->rx_skb); 209 bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err); 210 ath->rx_skb = NULL; 211 return err; 212 } 213 214 return count; 215} 216 217#define HCI_OP_ATH_SLEEP 0xFC04 218 219static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) 220{ 221 struct ath_struct *ath = hu->priv; 222 223 if (hci_skb_pkt_type(skb) == HCI_SCODATA_PKT) { 224 kfree_skb(skb); 225 return 0; 226 } 227 228 /* Update power management enable flag with parameters of 229 * HCI sleep enable vendor specific HCI command. 230 */ 231 if (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT) { 232 struct hci_command_hdr *hdr = (void *)skb->data; 233 234 if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP) 235 ath->cur_sleep = skb->data[HCI_COMMAND_HDR_SIZE]; 236 } 237 238 BT_DBG("hu %p skb %p", hu, skb); 239 240 /* Prepend skb with frame type */ 241 memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); 242 243 skb_queue_tail(&ath->txq, skb); 244 set_bit(HCI_UART_SENDING, &hu->tx_state); 245 246 schedule_work(&ath->ctxtsw); 247 248 return 0; 249} 250 251static struct sk_buff *ath_dequeue(struct hci_uart *hu) 252{ 253 struct ath_struct *ath = hu->priv; 254 255 return skb_dequeue(&ath->txq); 256} 257 258static const struct hci_uart_proto athp = { 259 .id = HCI_UART_ATH3K, 260 .name = "ATH3K", 261 .manufacturer = 69, 262 .open = ath_open, 263 .close = ath_close, 264 .flush = ath_flush, 265 .setup = ath_setup, 266 .recv = ath_recv, 267 .enqueue = ath_enqueue, 268 .dequeue = ath_dequeue, 269}; 270 271int __init ath_init(void) 272{ 273 return hci_uart_register_proto(&athp); 274} 275 276int __exit ath_deinit(void) 277{ 278 return hci_uart_unregister_proto(&athp); 279}