OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2009-2010 Atheros Communications Inc. |
| 3 * |
| 4 * This program is free software; you can redistribute it and/or modify |
| 5 * it under the terms of the GNU General Public License as published by |
| 6 * the Free Software Foundation; either version 2 of the License, or |
| 7 * (at your option) any later version. |
| 8 * |
| 9 * This program is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. |
| 13 * |
| 14 * You should have received a copy of the GNU General Public License |
| 15 * along with this program; if not, write to the Free Software |
| 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 17 * |
| 18 */ |
| 19 |
| 20 #include <linux/module.h> |
| 21 #include <linux/kernel.h> |
| 22 |
| 23 #include <linux/init.h> |
| 24 #include <linux/slab.h> |
| 25 #include <linux/tty.h> |
| 26 #include <linux/errno.h> |
| 27 #include <linux/ioctl.h> |
| 28 #include <linux/skbuff.h> |
| 29 |
| 30 #include <net/bluetooth/bluetooth.h> |
| 31 #include <net/bluetooth/hci_core.h> |
| 32 |
| 33 #include "hci_uart.h" |
| 34 |
| 35 |
| 36 /* HCIATH receiver States */ |
| 37 #define HCIATH_W4_PACKET_TYPE 0 |
| 38 #define HCIATH_W4_EVENT_HDR 1 |
| 39 #define HCIATH_W4_ACL_HDR 2 |
| 40 #define HCIATH_W4_SCO_HDR 3 |
| 41 #define HCIATH_W4_DATA 4 |
| 42 |
| 43 struct ath_struct { |
| 44 struct hci_uart *hu; |
| 45 unsigned int rx_state; |
| 46 unsigned int rx_count; |
| 47 unsigned int cur_sleep; |
| 48 |
| 49 spinlock_t hciath_lock; |
| 50 struct sk_buff *rx_skb; |
| 51 struct sk_buff_head txq; |
| 52 wait_queue_head_t wqevt; |
| 53 struct work_struct ctxtsw; |
| 54 }; |
| 55 |
| 56 int ath_wakeup_ar3001(struct tty_struct *tty) |
| 57 { |
| 58 struct termios settings; |
| 59 int status = 0x00; |
| 60 mm_segment_t oldfs; |
| 61 status = tty->driver->ops->tiocmget(tty, NULL); |
| 62 |
| 63 if ((status & TIOCM_CTS)) |
| 64 return status; |
| 65 |
| 66 oldfs = get_fs(); |
| 67 set_fs(KERNEL_DS); |
| 68 n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings); |
| 69 |
| 70 settings.c_cflag &= ~CRTSCTS; |
| 71 n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings); |
| 72 set_fs(oldfs); |
| 73 status = tty->driver->ops->tiocmget(tty, NULL); |
| 74 |
| 75 /* Wake up board */ |
| 76 tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS); |
| 77 mdelay(20); |
| 78 |
| 79 status = tty->driver->ops->tiocmget(tty, NULL); |
| 80 |
| 81 tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00); |
| 82 mdelay(20); |
| 83 |
| 84 status = tty->driver->ops->tiocmget(tty, NULL); |
| 85 oldfs = get_fs(); |
| 86 set_fs(KERNEL_DS); |
| 87 n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings); |
| 88 |
| 89 settings.c_cflag |= CRTSCTS; |
| 90 n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings); |
| 91 set_fs(oldfs); |
| 92 return status; |
| 93 } |
| 94 |
| 95 static void ath_context_switch(struct work_struct *work) |
| 96 { |
| 97 int status; |
| 98 struct ath_struct *ath; |
| 99 struct hci_uart *hu; |
| 100 struct tty_struct *tty; |
| 101 |
| 102 ath = container_of(work, struct ath_struct, ctxtsw); |
| 103 |
| 104 hu = ath->hu; |
| 105 tty = hu->tty; |
| 106 |
| 107 /* verify and wake up controller */ |
| 108 if (ath->cur_sleep) { |
| 109 |
| 110 status = ath_wakeup_ar3001(tty); |
| 111 if (!(status & TIOCM_CTS)) |
| 112 return; |
| 113 } |
| 114 |
| 115 /* Ready to send Data */ |
| 116 clear_bit(HCI_UART_SENDING, &hu->tx_state); |
| 117 hci_uart_tx_wakeup(hu); |
| 118 } |
| 119 |
| 120 int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet) |
| 121 { |
| 122 if (packet[0] == 0x04 && packet[1] == 0xFC) |
| 123 ath->cur_sleep = packet[3]; |
| 124 |
| 125 return 0; |
| 126 } |
| 127 |
| 128 |
| 129 /* Initialize protocol */ |
| 130 static int ath_open(struct hci_uart *hu) |
| 131 { |
| 132 struct ath_struct *ath; |
| 133 BT_DBG("hu %p", hu); |
| 134 |
| 135 ath = kzalloc(sizeof(*ath), GFP_ATOMIC); |
| 136 if (!ath) |
| 137 return -ENOMEM; |
| 138 |
| 139 skb_queue_head_init(&ath->txq); |
| 140 spin_lock_init(&ath->hciath_lock); |
| 141 |
| 142 ath->cur_sleep = 0; |
| 143 hu->priv = ath; |
| 144 ath->hu = hu; |
| 145 |
| 146 init_waitqueue_head(&ath->wqevt); |
| 147 INIT_WORK(&ath->ctxtsw, ath_context_switch); |
| 148 return 0; |
| 149 } |
| 150 |
| 151 /* Flush protocol data */ |
| 152 static int ath_flush(struct hci_uart *hu) |
| 153 { |
| 154 struct ath_struct *ath = hu->priv; |
| 155 BT_DBG("hu %p", hu); |
| 156 skb_queue_purge(&ath->txq); |
| 157 |
| 158 return 0; |
| 159 } |
| 160 |
| 161 /* Close protocol */ |
| 162 static int ath_close(struct hci_uart *hu) |
| 163 { |
| 164 struct ath_struct *ath = hu->priv; |
| 165 BT_DBG("hu %p", hu); |
| 166 |
| 167 skb_queue_purge(&ath->txq); |
| 168 |
| 169 if (ath->rx_skb) |
| 170 kfree_skb(ath->rx_skb); |
| 171 |
| 172 wake_up_interruptible(&ath->wqevt); |
| 173 hu->priv = NULL; |
| 174 kfree(ath); |
| 175 return 0; |
| 176 } |
| 177 |
| 178 /* Enqueue frame for transmittion */ |
| 179 static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) |
| 180 { |
| 181 struct ath_struct *ath = hu->priv; |
| 182 if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) { |
| 183 |
| 184 /* Discard SCO packet.AR3001 does not support SCO over HCI */ |
| 185 BT_DBG("SCO Packet over HCI received Dropping\n"); |
| 186 kfree(skb); |
| 187 return 0; |
| 188 } |
| 189 BT_DBG("hu %p skb %p", hu, skb); |
| 190 |
| 191 /* Prepend skb with frame type */ |
| 192 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); |
| 193 |
| 194 skb_queue_tail(&ath->txq, skb); |
| 195 set_bit(HCI_UART_SENDING, &hu->tx_state); |
| 196 |
| 197 schedule_work(&ath->ctxtsw); |
| 198 return 0; |
| 199 } |
| 200 |
| 201 static struct sk_buff *ath_dequeue(struct hci_uart *hu) |
| 202 { |
| 203 struct ath_struct *ath = hu->priv; |
| 204 struct sk_buff *skbuf; |
| 205 |
| 206 skbuf = skb_dequeue(&ath->txq); |
| 207 if (skbuf != NULL) |
| 208 ath_check_sleep_cmd(ath, &skbuf->data[1]); |
| 209 |
| 210 return skbuf; |
| 211 } |
| 212 |
| 213 static inline int ath_check_data_len(struct ath_struct *ath, int len) |
| 214 { |
| 215 register int room = skb_tailroom(ath->rx_skb); |
| 216 BT_DBG("len %d room %d", len, room); |
| 217 |
| 218 if (len > room) { |
| 219 BT_ERR("Data length is too large"); |
| 220 kfree_skb(ath->rx_skb); |
| 221 ath->rx_state = HCIATH_W4_PACKET_TYPE; |
| 222 ath->rx_skb = NULL; |
| 223 ath->rx_count = 0; |
| 224 } else { |
| 225 ath->rx_state = HCIATH_W4_DATA; |
| 226 ath->rx_count = len; |
| 227 return len; |
| 228 } |
| 229 |
| 230 return 0; |
| 231 } |
| 232 |
| 233 /* Recv data */ |
| 234 static int ath_recv(struct hci_uart *hu, void *data, int count) |
| 235 { |
| 236 struct ath_struct *ath = hu->priv; |
| 237 register char *ptr; |
| 238 struct hci_event_hdr *eh; |
| 239 struct hci_acl_hdr *ah; |
| 240 struct hci_sco_hdr *sh; |
| 241 struct sk_buff *skbuf; |
| 242 register int len, type, dlen; |
| 243 |
| 244 skbuf = NULL; |
| 245 BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count, |
| 246 ath->rx_state, ath->rx_count); |
| 247 ptr = data; |
| 248 while (count) { |
| 249 if (ath->rx_count) { |
| 250 |
| 251 len = min_t(unsigned int, ath->rx_count, count); |
| 252 memcpy(skb_put(ath->rx_skb, len), ptr, len); |
| 253 ath->rx_count -= len; |
| 254 count -= len; |
| 255 ptr += len; |
| 256 |
| 257 if (ath->rx_count) |
| 258 continue; |
| 259 switch (ath->rx_state) { |
| 260 case HCIATH_W4_DATA: |
| 261 hci_recv_frame(ath->rx_skb); |
| 262 ath->rx_state = HCIATH_W4_PACKET_TYPE; |
| 263 ath->rx_skb = NULL; |
| 264 ath->rx_count = 0; |
| 265 continue; |
| 266 case HCIATH_W4_EVENT_HDR: |
| 267 eh = (struct hci_event_hdr *)ath->rx_skb->data; |
| 268 BT_DBG("Event header: evt 0x%2.2x plen %d", |
| 269 eh->evt, eh->plen); |
| 270 ath_check_data_len(ath, eh->plen); |
| 271 continue; |
| 272 case HCIATH_W4_ACL_HDR: |
| 273 ah = (struct hci_acl_hdr *)ath->rx_skb->data; |
| 274 dlen = __le16_to_cpu(ah->dlen); |
| 275 BT_DBG("ACL header: dlen %d", dlen); |
| 276 ath_check_data_len(ath, dlen); |
| 277 continue; |
| 278 case HCIATH_W4_SCO_HDR: |
| 279 sh = (struct hci_sco_hdr *)ath->rx_skb->data; |
| 280 BT_DBG("SCO header: dlen %d", sh->dlen); |
| 281 ath_check_data_len(ath, sh->dlen); |
| 282 continue; |
| 283 } |
| 284 } |
| 285 |
| 286 /* HCIATH_W4_PACKET_TYPE */ |
| 287 switch (*ptr) { |
| 288 case HCI_EVENT_PKT: |
| 289 BT_DBG("Event packet"); |
| 290 ath->rx_state = HCIATH_W4_EVENT_HDR; |
| 291 ath->rx_count = HCI_EVENT_HDR_SIZE; |
| 292 type = HCI_EVENT_PKT; |
| 293 break; |
| 294 case HCI_ACLDATA_PKT: |
| 295 BT_DBG("ACL packet"); |
| 296 ath->rx_state = HCIATH_W4_ACL_HDR; |
| 297 ath->rx_count = HCI_ACL_HDR_SIZE; |
| 298 type = HCI_ACLDATA_PKT; |
| 299 break; |
| 300 case HCI_SCODATA_PKT: |
| 301 BT_DBG("SCO packet"); |
| 302 ath->rx_state = HCIATH_W4_SCO_HDR; |
| 303 ath->rx_count = HCI_SCO_HDR_SIZE; |
| 304 type = HCI_SCODATA_PKT; |
| 305 break; |
| 306 default: |
| 307 BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr); |
| 308 hu->hdev->stat.err_rx++; |
| 309 ptr++; |
| 310 count--; |
| 311 continue; |
| 312 }; |
| 313 ptr++; |
| 314 count--; |
| 315 |
| 316 /* Allocate packet */ |
| 317 ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); |
| 318 if (!ath->rx_skb) { |
| 319 BT_ERR("Can't allocate mem for new packet"); |
| 320 ath->rx_state = HCIATH_W4_PACKET_TYPE; |
| 321 ath->rx_count = 0; |
| 322 return -ENOMEM; |
| 323 } |
| 324 ath->rx_skb->dev = (void *)hu->hdev; |
| 325 bt_cb(ath->rx_skb)->pkt_type = type; |
| 326 } return count; |
| 327 } |
| 328 |
| 329 static struct hci_uart_proto athp = { |
| 330 .id = HCI_UART_ATH, |
| 331 .open = ath_open, |
| 332 .close = ath_close, |
| 333 .recv = ath_recv, |
| 334 .enqueue = ath_enqueue, |
| 335 .dequeue = ath_dequeue, |
| 336 .flush = ath_flush, |
| 337 }; |
| 338 |
| 339 int ath_init(void) |
| 340 { |
| 341 int err = hci_uart_register_proto(&athp); |
| 342 if (!err) |
| 343 BT_INFO("HCIATH protocol initialized"); |
| 344 |
| 345 else |
| 346 BT_ERR("HCIATH protocol registration failed with err %d", err); |
| 347 return err; |
| 348 } |
| 349 |
| 350 int ath_deinit(void) |
| 351 { |
| 352 return hci_uart_unregister_proto(&athp); |
| 353 } |
OLD | NEW |