blob: 4ed7288f99db26b34f0790eb1dd1f33309cc0731 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
3 * Driver for Bluetooth PCMCIA cards with HCI UART interface
4 *
5 * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation;
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
16 *
17 * The initial developer of the original code is David A. Hinds
18 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20 *
21 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
26#include <linux/init.h>
27#include <linux/slab.h>
28#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/delay.h>
30#include <linux/errno.h>
31#include <linux/ptrace.h>
32#include <linux/ioport.h>
33#include <linux/spinlock.h>
34#include <linux/moduleparam.h>
35
36#include <linux/skbuff.h>
37#include <linux/string.h>
38#include <linux/serial.h>
39#include <linux/serial_reg.h>
40#include <linux/bitops.h>
41#include <asm/system.h>
42#include <asm/io.h>
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <pcmcia/cs_types.h>
45#include <pcmcia/cs.h>
46#include <pcmcia/cistpl.h>
47#include <pcmcia/ciscode.h>
48#include <pcmcia/ds.h>
49#include <pcmcia/cisreg.h>
50
51#include <net/bluetooth/bluetooth.h>
52#include <net/bluetooth/hci_core.h>
53
54
55
56/* ======================== Module parameters ======================== */
57
58
59MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
60MODULE_DESCRIPTION("Bluetooth driver for Bluetooth PCMCIA cards with HCI UART interface");
61MODULE_LICENSE("GPL");
62
63
64
65/* ======================== Local structures ======================== */
66
67
68typedef struct btuart_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010069 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 struct hci_dev *hdev;
72
73 spinlock_t lock; /* For serializing operations */
74
75 struct sk_buff_head txq;
76 unsigned long tx_state;
77
78 unsigned long rx_state;
79 unsigned long rx_count;
80 struct sk_buff *rx_skb;
81} btuart_info_t;
82
83
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020084static int btuart_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020085static void btuart_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010087static void btuart_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90/* Maximum baud rate */
91#define SPEED_MAX 115200
92
93/* Default baud rate: 57600, 115200, 230400 or 460800 */
94#define DEFAULT_BAUD_RATE 115200
95
96
97/* Transmit states */
98#define XMIT_SENDING 1
99#define XMIT_WAKEUP 2
100#define XMIT_WAITING 8
101
102/* Receiver states */
103#define RECV_WAIT_PACKET_TYPE 0
104#define RECV_WAIT_EVENT_HEADER 1
105#define RECV_WAIT_ACL_HEADER 2
106#define RECV_WAIT_SCO_HEADER 3
107#define RECV_WAIT_DATA 4
108
109
110
111/* ======================== Interrupt handling ======================== */
112
113
114static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
115{
116 int actual = 0;
117
118 /* Tx FIFO should be empty */
119 if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
120 return 0;
121
122 /* Fill FIFO with current frame */
123 while ((fifo_size-- > 0) && (actual < len)) {
124 /* Transmit next byte */
125 outb(buf[actual], iobase + UART_TX);
126 actual++;
127 }
128
129 return actual;
130}
131
132
133static void btuart_write_wakeup(btuart_info_t *info)
134{
135 if (!info) {
136 BT_ERR("Unknown device");
137 return;
138 }
139
140 if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
141 set_bit(XMIT_WAKEUP, &(info->tx_state));
142 return;
143 }
144
145 do {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100146 register unsigned int iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 register struct sk_buff *skb;
148 register int len;
149
150 clear_bit(XMIT_WAKEUP, &(info->tx_state));
151
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100152 if (!pcmcia_dev_present(info->p_dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return;
154
155 if (!(skb = skb_dequeue(&(info->txq))))
156 break;
157
158 /* Send frame */
159 len = btuart_write(iobase, 16, skb->data, skb->len);
160 set_bit(XMIT_WAKEUP, &(info->tx_state));
161
162 if (len == skb->len) {
163 kfree_skb(skb);
164 } else {
165 skb_pull(skb, len);
166 skb_queue_head(&(info->txq), skb);
167 }
168
169 info->hdev->stat.byte_tx += len;
170
171 } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
172
173 clear_bit(XMIT_SENDING, &(info->tx_state));
174}
175
176
177static void btuart_receive(btuart_info_t *info)
178{
179 unsigned int iobase;
180 int boguscount = 0;
181
182 if (!info) {
183 BT_ERR("Unknown device");
184 return;
185 }
186
Dominik Brodowskifd238232006-03-05 10:45:09 +0100187 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 do {
190 info->hdev->stat.byte_rx++;
191
192 /* Allocate packet */
193 if (info->rx_skb == NULL) {
194 info->rx_state = RECV_WAIT_PACKET_TYPE;
195 info->rx_count = 0;
196 if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
197 BT_ERR("Can't allocate mem for new packet");
198 return;
199 }
200 }
201
202 if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
203
204 info->rx_skb->dev = (void *) info->hdev;
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700205 bt_cb(info->rx_skb)->pkt_type = inb(iobase + UART_RX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700207 switch (bt_cb(info->rx_skb)->pkt_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 case HCI_EVENT_PKT:
210 info->rx_state = RECV_WAIT_EVENT_HEADER;
211 info->rx_count = HCI_EVENT_HDR_SIZE;
212 break;
213
214 case HCI_ACLDATA_PKT:
215 info->rx_state = RECV_WAIT_ACL_HEADER;
216 info->rx_count = HCI_ACL_HDR_SIZE;
217 break;
218
219 case HCI_SCODATA_PKT:
220 info->rx_state = RECV_WAIT_SCO_HEADER;
221 info->rx_count = HCI_SCO_HDR_SIZE;
222 break;
223
224 default:
225 /* Unknown packet */
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700226 BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 info->hdev->stat.err_rx++;
228 clear_bit(HCI_RUNNING, &(info->hdev->flags));
229
230 kfree_skb(info->rx_skb);
231 info->rx_skb = NULL;
232 break;
233
234 }
235
236 } else {
237
238 *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
239 info->rx_count--;
240
241 if (info->rx_count == 0) {
242
243 int dlen;
244 struct hci_event_hdr *eh;
245 struct hci_acl_hdr *ah;
246 struct hci_sco_hdr *sh;
247
248
249 switch (info->rx_state) {
250
251 case RECV_WAIT_EVENT_HEADER:
Arnaldo Carvalho de Melo2a123b82007-03-27 18:38:07 -0300252 eh = hci_event_hdr(info->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 info->rx_state = RECV_WAIT_DATA;
254 info->rx_count = eh->plen;
255 break;
256
257 case RECV_WAIT_ACL_HEADER:
Arnaldo Carvalho de Melo2a123b82007-03-27 18:38:07 -0300258 ah = hci_acl_hdr(info->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 dlen = __le16_to_cpu(ah->dlen);
260 info->rx_state = RECV_WAIT_DATA;
261 info->rx_count = dlen;
262 break;
263
264 case RECV_WAIT_SCO_HEADER:
Arnaldo Carvalho de Melo2a123b82007-03-27 18:38:07 -0300265 sh = hci_sco_hdr(info->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 info->rx_state = RECV_WAIT_DATA;
267 info->rx_count = sh->dlen;
268 break;
269
270 case RECV_WAIT_DATA:
271 hci_recv_frame(info->rx_skb);
272 info->rx_skb = NULL;
273 break;
274
275 }
276
277 }
278
279 }
280
281 /* Make sure we don't stay here too long */
282 if (boguscount++ > 16)
283 break;
284
285 } while (inb(iobase + UART_LSR) & UART_LSR_DR);
286}
287
288
David Howells7d12e782006-10-05 14:55:46 +0100289static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 btuart_info_t *info = dev_inst;
292 unsigned int iobase;
293 int boguscount = 0;
294 int iir, lsr;
Alan Coxaafcf992008-10-05 17:35:41 +0100295 irqreturn_t r = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Mike Frysinger74278472009-09-14 13:43:49 -0400297 if (!info || !info->hdev)
298 /* our irq handler is shared */
299 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Dominik Brodowskifd238232006-03-05 10:45:09 +0100301 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 spin_lock(&(info->lock));
304
305 iir = inb(iobase + UART_IIR) & UART_IIR_ID;
306 while (iir) {
Alan Coxaafcf992008-10-05 17:35:41 +0100307 r = IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 /* Clear interrupt */
310 lsr = inb(iobase + UART_LSR);
311
312 switch (iir) {
313 case UART_IIR_RLSI:
314 BT_ERR("RLSI");
315 break;
316 case UART_IIR_RDI:
317 /* Receive interrupt */
318 btuart_receive(info);
319 break;
320 case UART_IIR_THRI:
321 if (lsr & UART_LSR_THRE) {
322 /* Transmitter ready for data */
323 btuart_write_wakeup(info);
324 }
325 break;
326 default:
327 BT_ERR("Unhandled IIR=%#x", iir);
328 break;
329 }
330
331 /* Make sure we don't stay here too long */
332 if (boguscount++ > 100)
333 break;
334
335 iir = inb(iobase + UART_IIR) & UART_IIR_ID;
336
337 }
338
339 spin_unlock(&(info->lock));
340
Alan Coxaafcf992008-10-05 17:35:41 +0100341 return r;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
343
344
345static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
346{
347 unsigned long flags;
348 unsigned int iobase;
349 int fcr; /* FIFO control reg */
350 int lcr; /* Line control reg */
351 int divisor;
352
353 if (!info) {
354 BT_ERR("Unknown device");
355 return;
356 }
357
Dominik Brodowskifd238232006-03-05 10:45:09 +0100358 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 spin_lock_irqsave(&(info->lock), flags);
361
362 /* Turn off interrupts */
363 outb(0, iobase + UART_IER);
364
365 divisor = SPEED_MAX / speed;
366
367 fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
368
369 /*
370 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
371 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
372 * about this timeout since it will always be fast enough.
373 */
374
375 if (speed < 38400)
376 fcr |= UART_FCR_TRIGGER_1;
377 else
378 fcr |= UART_FCR_TRIGGER_14;
379
380 /* Bluetooth cards use 8N1 */
381 lcr = UART_LCR_WLEN8;
382
383 outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
384 outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
385 outb(divisor >> 8, iobase + UART_DLM);
386 outb(lcr, iobase + UART_LCR); /* Set 8N1 */
387 outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
388
Joe Perchesb92b1c52008-02-03 17:10:31 +0200389 /* Turn on interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
391
392 spin_unlock_irqrestore(&(info->lock), flags);
393}
394
395
396
397/* ======================== HCI interface ======================== */
398
399
400static int btuart_hci_flush(struct hci_dev *hdev)
401{
402 btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
403
404 /* Drop TX queue */
405 skb_queue_purge(&(info->txq));
406
407 return 0;
408}
409
410
411static int btuart_hci_open(struct hci_dev *hdev)
412{
413 set_bit(HCI_RUNNING, &(hdev->flags));
414
415 return 0;
416}
417
418
419static int btuart_hci_close(struct hci_dev *hdev)
420{
421 if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
422 return 0;
423
424 btuart_hci_flush(hdev);
425
426 return 0;
427}
428
429
430static int btuart_hci_send_frame(struct sk_buff *skb)
431{
432 btuart_info_t *info;
433 struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
434
435 if (!hdev) {
436 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
437 return -ENODEV;
438 }
439
440 info = (btuart_info_t *)(hdev->driver_data);
441
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700442 switch (bt_cb(skb)->pkt_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 case HCI_COMMAND_PKT:
444 hdev->stat.cmd_tx++;
445 break;
446 case HCI_ACLDATA_PKT:
447 hdev->stat.acl_tx++;
448 break;
449 case HCI_SCODATA_PKT:
450 hdev->stat.sco_tx++;
451 break;
452 };
453
454 /* Prepend skb with frame type */
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700455 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 skb_queue_tail(&(info->txq), skb);
457
458 btuart_write_wakeup(info);
459
460 return 0;
461}
462
463
464static void btuart_hci_destruct(struct hci_dev *hdev)
465{
466}
467
468
469static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
470{
471 return -ENOIOCTLCMD;
472}
473
474
475
476/* ======================== Card services HCI interaction ======================== */
477
478
479static int btuart_open(btuart_info_t *info)
480{
481 unsigned long flags;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100482 unsigned int iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 struct hci_dev *hdev;
484
485 spin_lock_init(&(info->lock));
486
487 skb_queue_head_init(&(info->txq));
488
489 info->rx_state = RECV_WAIT_PACKET_TYPE;
490 info->rx_count = 0;
491 info->rx_skb = NULL;
492
493 /* Initialize HCI device */
494 hdev = hci_alloc_dev();
495 if (!hdev) {
496 BT_ERR("Can't allocate HCI device");
497 return -ENOMEM;
498 }
499
500 info->hdev = hdev;
501
Marcel Holtmannc13854ce2010-02-08 15:27:07 +0100502 hdev->bus = HCI_PCCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 hdev->driver_data = info;
Marcel Holtmann27d35282006-07-03 10:02:37 +0200504 SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 hdev->open = btuart_hci_open;
507 hdev->close = btuart_hci_close;
508 hdev->flush = btuart_hci_flush;
509 hdev->send = btuart_hci_send_frame;
510 hdev->destruct = btuart_hci_destruct;
511 hdev->ioctl = btuart_hci_ioctl;
512
513 hdev->owner = THIS_MODULE;
514
515 spin_lock_irqsave(&(info->lock), flags);
516
517 /* Reset UART */
518 outb(0, iobase + UART_MCR);
519
520 /* Turn off interrupts */
521 outb(0, iobase + UART_IER);
522
523 /* Initialize UART */
524 outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
525 outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
526
527 /* Turn on interrupts */
528 // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
529
530 spin_unlock_irqrestore(&(info->lock), flags);
531
532 btuart_change_speed(info, DEFAULT_BAUD_RATE);
533
534 /* Timeout before it is safe to send the first HCI packet */
535 msleep(1000);
536
537 /* Register HCI device */
538 if (hci_register_dev(hdev) < 0) {
539 BT_ERR("Can't register HCI device");
540 info->hdev = NULL;
541 hci_free_dev(hdev);
542 return -ENODEV;
543 }
544
545 return 0;
546}
547
548
549static int btuart_close(btuart_info_t *info)
550{
551 unsigned long flags;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100552 unsigned int iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 struct hci_dev *hdev = info->hdev;
554
555 if (!hdev)
556 return -ENODEV;
557
558 btuart_hci_close(hdev);
559
560 spin_lock_irqsave(&(info->lock), flags);
561
562 /* Reset UART */
563 outb(0, iobase + UART_MCR);
564
565 /* Turn off interrupts */
566 outb(0, iobase + UART_IER);
567
568 spin_unlock_irqrestore(&(info->lock), flags);
569
570 if (hci_unregister_dev(hdev) < 0)
571 BT_ERR("Can't unregister HCI device %s", hdev->name);
572
573 hci_free_dev(hdev);
574
575 return 0;
576}
577
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200578static int btuart_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 btuart_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582 /* Create new info device */
Deepak Saxena089b1db2005-11-07 01:01:26 -0800583 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (!info)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100585 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200587 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 link->priv = info;
589
590 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
591 link->io.NumPorts1 = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 link->conf.IntType = INT_MEMORY_AND_IO;
595
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200596 return btuart_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
599
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200600static void btuart_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 btuart_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100604 btuart_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 kfree(info);
606}
607
Dominik Brodowskied588722008-07-29 08:38:55 +0200608static int btuart_check_config(struct pcmcia_device *p_dev,
609 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200610 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200611 unsigned int vcc,
Dominik Brodowskied588722008-07-29 08:38:55 +0200612 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200614 int *try = priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Dominik Brodowskied588722008-07-29 08:38:55 +0200616 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
617 p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
618 if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
619 (cf->io.win[0].base != 0)) {
Dominik Brodowskied588722008-07-29 08:38:55 +0200620 p_dev->io.BasePort1 = cf->io.win[0].base;
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200621 p_dev->io.IOAddrLines = (*try == 0) ? 16 :
Dominik Brodowskied588722008-07-29 08:38:55 +0200622 cf->io.flags & CISTPL_IO_LINES_MASK;
623 if (!pcmcia_request_io(p_dev, &p_dev->io))
624 return 0;
625 }
626 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627}
628
Dominik Brodowskied588722008-07-29 08:38:55 +0200629static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
630 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200631 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200632 unsigned int vcc,
Dominik Brodowskied588722008-07-29 08:38:55 +0200633 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Dominik Brodowskied588722008-07-29 08:38:55 +0200635 static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
636 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Dominik Brodowskied588722008-07-29 08:38:55 +0200638 if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
Dominik Brodowskied588722008-07-29 08:38:55 +0200639 for (j = 0; j < 5; j++) {
640 p_dev->io.BasePort1 = base[j];
641 p_dev->io.IOAddrLines = base[j] ? 16 : 3;
642 if (!pcmcia_request_io(p_dev, &p_dev->io))
643 return 0;
644 }
645 }
646 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200649static int btuart_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 btuart_info_t *info = link->priv;
Dominik Brodowskied588722008-07-29 08:38:55 +0200652 int i;
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200653 int try;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Dominik Brodowskied588722008-07-29 08:38:55 +0200655 /* First pass: look for a config entry that looks normal.
656 Two tries: without IO aliases, then with aliases */
657 for (try = 0; try < 2; try++)
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200658 if (!pcmcia_loop_config(link, btuart_check_config, &try))
Dominik Brodowskied588722008-07-29 08:38:55 +0200659 goto found_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 /* Second pass: try to find an entry that isn't picky about
662 its base address, then try to grab any standard serial port
663 address, and finally try to get any free port. */
Dominik Brodowskied588722008-07-29 08:38:55 +0200664 if (!pcmcia_loop_config(link, btuart_check_config_notpicky, NULL))
665 goto found_port;
666
667 BT_ERR("No usable port range found");
Dominik Brodowskied588722008-07-29 08:38:55 +0200668 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
670found_port:
Dominik Brodowskieb141202010-03-07 12:21:16 +0100671 i = pcmcia_request_irq(link, btuart_interrupt);
Dominik Brodowski9ac3e582009-10-24 15:45:06 +0200672 if (i != 0)
Dominik Brodowskieb141202010-03-07 12:21:16 +0100673 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200675 i = pcmcia_request_configuration(link, &link->conf);
Dominik Brodowski9ac3e582009-10-24 15:45:06 +0200676 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 if (btuart_open(info) != 0)
680 goto failed;
681
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200682 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684failed:
685 btuart_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200686 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200690static void btuart_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
692 btuart_info_t *info = link->priv;
693
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100694 btuart_close(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200696 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
Dominik Brodowski279c9362005-06-27 16:28:38 -0700699static struct pcmcia_device_id btuart_ids[] = {
700 /* don't use this driver. Use serial_cs + hci_uart instead */
701 PCMCIA_DEVICE_NULL
702};
703MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705static struct pcmcia_driver btuart_driver = {
706 .owner = THIS_MODULE,
707 .drv = {
708 .name = "btuart_cs",
709 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200710 .probe = btuart_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100711 .remove = btuart_detach,
Dominik Brodowski279c9362005-06-27 16:28:38 -0700712 .id_table = btuart_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713};
714
715static int __init init_btuart_cs(void)
716{
717 return pcmcia_register_driver(&btuart_driver);
718}
719
720
721static void __exit exit_btuart_cs(void)
722{
723 pcmcia_unregister_driver(&btuart_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724}
725
726module_init(init_btuart_cs);
727module_exit(exit_btuart_cs);