blob: 34e5555cb917d999b33f54815b7baf4d2426c8fa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
3 * Driver for the 3Com Bluetooth PCMCIA card
4 *
5 * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
6 * Jose Orlando Pereira <jop@di.uminho.pt>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation;
12 *
13 * Software distributed under the License is distributed on an "AS
14 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15 * implied. See the License for the specific language governing
16 * rights and limitations under the License.
17 *
18 * The initial developer of the original code is David A. Hinds
19 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
20 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21 *
22 */
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/module.h>
25
26#include <linux/kernel.h>
27#include <linux/init.h>
28#include <linux/slab.h>
29#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/delay.h>
31#include <linux/errno.h>
32#include <linux/ptrace.h>
33#include <linux/ioport.h>
34#include <linux/spinlock.h>
35#include <linux/moduleparam.h>
36
37#include <linux/skbuff.h>
38#include <linux/string.h>
39#include <linux/serial.h>
40#include <linux/serial_reg.h>
41#include <linux/bitops.h>
42#include <asm/system.h>
43#include <asm/io.h>
44
45#include <linux/device.h>
46#include <linux/firmware.h>
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <pcmcia/cs_types.h>
49#include <pcmcia/cs.h>
50#include <pcmcia/cistpl.h>
51#include <pcmcia/ciscode.h>
52#include <pcmcia/ds.h>
53#include <pcmcia/cisreg.h>
54
55#include <net/bluetooth/bluetooth.h>
56#include <net/bluetooth/hci_core.h>
57
58
59
60/* ======================== Module parameters ======================== */
61
62
63MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
64MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
65MODULE_LICENSE("GPL");
66
67
68
69/* ======================== Local structures ======================== */
70
71
72typedef struct bt3c_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010073 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 dev_node_t node;
75
76 struct hci_dev *hdev;
77
78 spinlock_t lock; /* For serializing operations */
79
80 struct sk_buff_head txq;
81 unsigned long tx_state;
82
83 unsigned long rx_state;
84 unsigned long rx_count;
85 struct sk_buff *rx_skb;
86} bt3c_info_t;
87
88
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020089static int bt3c_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020090static void bt3c_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010092static void bt3c_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* Transmit states */
96#define XMIT_SENDING 1
97#define XMIT_WAKEUP 2
98#define XMIT_WAITING 8
99
100/* Receiver states */
101#define RECV_WAIT_PACKET_TYPE 0
102#define RECV_WAIT_EVENT_HEADER 1
103#define RECV_WAIT_ACL_HEADER 2
104#define RECV_WAIT_SCO_HEADER 3
105#define RECV_WAIT_DATA 4
106
107
108
109/* ======================== Special I/O functions ======================== */
110
111
112#define DATA_L 0
113#define DATA_H 1
114#define ADDR_L 2
115#define ADDR_H 3
116#define CONTROL 4
117
118
119static inline void bt3c_address(unsigned int iobase, unsigned short addr)
120{
121 outb(addr & 0xff, iobase + ADDR_L);
122 outb((addr >> 8) & 0xff, iobase + ADDR_H);
123}
124
125
126static inline void bt3c_put(unsigned int iobase, unsigned short value)
127{
128 outb(value & 0xff, iobase + DATA_L);
129 outb((value >> 8) & 0xff, iobase + DATA_H);
130}
131
132
133static inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
134{
135 bt3c_address(iobase, addr);
136 bt3c_put(iobase, value);
137}
138
139
140static inline unsigned short bt3c_get(unsigned int iobase)
141{
142 unsigned short value = inb(iobase + DATA_L);
143
144 value |= inb(iobase + DATA_H) << 8;
145
146 return value;
147}
148
149
150static inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
151{
152 bt3c_address(iobase, addr);
153
154 return bt3c_get(iobase);
155}
156
157
158
159/* ======================== Interrupt handling ======================== */
160
161
162static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
163{
164 int actual = 0;
165
166 bt3c_address(iobase, 0x7080);
167
168 /* Fill FIFO with current frame */
169 while (actual < len) {
170 /* Transmit next byte */
171 bt3c_put(iobase, buf[actual]);
172 actual++;
173 }
174
175 bt3c_io_write(iobase, 0x7005, actual);
176
177 return actual;
178}
179
180
181static void bt3c_write_wakeup(bt3c_info_t *info)
182{
183 if (!info) {
184 BT_ERR("Unknown device");
185 return;
186 }
187
188 if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
189 return;
190
191 do {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100192 register unsigned int iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 register struct sk_buff *skb;
194 register int len;
195
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100196 if (!pcmcia_dev_present(info->p_dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 break;
198
199
200 if (!(skb = skb_dequeue(&(info->txq)))) {
201 clear_bit(XMIT_SENDING, &(info->tx_state));
202 break;
203 }
204
205 /* Send frame */
206 len = bt3c_write(iobase, 256, skb->data, skb->len);
207
208 if (len != skb->len) {
209 BT_ERR("Very strange");
210 }
211
212 kfree_skb(skb);
213
214 info->hdev->stat.byte_tx += len;
215
216 } while (0);
217}
218
219
220static void bt3c_receive(bt3c_info_t *info)
221{
222 unsigned int iobase;
223 int size = 0, avail;
224
225 if (!info) {
226 BT_ERR("Unknown device");
227 return;
228 }
229
Dominik Brodowskifd238232006-03-05 10:45:09 +0100230 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 avail = bt3c_read(iobase, 0x7006);
233 //printk("bt3c_cs: receiving %d bytes\n", avail);
234
235 bt3c_address(iobase, 0x7480);
236 while (size < avail) {
237 size++;
238 info->hdev->stat.byte_rx++;
239
240 /* Allocate packet */
241 if (info->rx_skb == NULL) {
242 info->rx_state = RECV_WAIT_PACKET_TYPE;
243 info->rx_count = 0;
244 if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
245 BT_ERR("Can't allocate mem for new packet");
246 return;
247 }
248 }
249
250
251 if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
252
253 info->rx_skb->dev = (void *) info->hdev;
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700254 bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 inb(iobase + DATA_H);
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700256 //printk("bt3c: PACKET_TYPE=%02x\n", bt_cb(info->rx_skb)->pkt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700258 switch (bt_cb(info->rx_skb)->pkt_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 case HCI_EVENT_PKT:
261 info->rx_state = RECV_WAIT_EVENT_HEADER;
262 info->rx_count = HCI_EVENT_HDR_SIZE;
263 break;
264
265 case HCI_ACLDATA_PKT:
266 info->rx_state = RECV_WAIT_ACL_HEADER;
267 info->rx_count = HCI_ACL_HDR_SIZE;
268 break;
269
270 case HCI_SCODATA_PKT:
271 info->rx_state = RECV_WAIT_SCO_HEADER;
272 info->rx_count = HCI_SCO_HDR_SIZE;
273 break;
274
275 default:
276 /* Unknown packet */
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700277 BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 info->hdev->stat.err_rx++;
279 clear_bit(HCI_RUNNING, &(info->hdev->flags));
280
281 kfree_skb(info->rx_skb);
282 info->rx_skb = NULL;
283 break;
284
285 }
286
287 } else {
288
289 __u8 x = inb(iobase + DATA_L);
290
291 *skb_put(info->rx_skb, 1) = x;
292 inb(iobase + DATA_H);
293 info->rx_count--;
294
295 if (info->rx_count == 0) {
296
297 int dlen;
298 struct hci_event_hdr *eh;
299 struct hci_acl_hdr *ah;
300 struct hci_sco_hdr *sh;
301
302 switch (info->rx_state) {
303
304 case RECV_WAIT_EVENT_HEADER:
305 eh = (struct hci_event_hdr *)(info->rx_skb->data);
306 info->rx_state = RECV_WAIT_DATA;
307 info->rx_count = eh->plen;
308 break;
309
310 case RECV_WAIT_ACL_HEADER:
311 ah = (struct hci_acl_hdr *)(info->rx_skb->data);
312 dlen = __le16_to_cpu(ah->dlen);
313 info->rx_state = RECV_WAIT_DATA;
314 info->rx_count = dlen;
315 break;
316
317 case RECV_WAIT_SCO_HEADER:
318 sh = (struct hci_sco_hdr *)(info->rx_skb->data);
319 info->rx_state = RECV_WAIT_DATA;
320 info->rx_count = sh->dlen;
321 break;
322
323 case RECV_WAIT_DATA:
324 hci_recv_frame(info->rx_skb);
325 info->rx_skb = NULL;
326 break;
327
328 }
329
330 }
331
332 }
333
334 }
335
336 bt3c_io_write(iobase, 0x7006, 0x0000);
337}
338
339
David Howells7d12e782006-10-05 14:55:46 +0100340static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 bt3c_info_t *info = dev_inst;
343 unsigned int iobase;
344 int iir;
345
346 if (!info || !info->hdev) {
347 BT_ERR("Call of irq %d for unknown device", irq);
348 return IRQ_NONE;
349 }
350
Dominik Brodowskifd238232006-03-05 10:45:09 +0100351 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353 spin_lock(&(info->lock));
354
355 iir = inb(iobase + CONTROL);
356 if (iir & 0x80) {
357 int stat = bt3c_read(iobase, 0x7001);
358
359 if ((stat & 0xff) == 0x7f) {
360 BT_ERR("Very strange (stat=0x%04x)", stat);
361 } else if ((stat & 0xff) != 0xff) {
362 if (stat & 0x0020) {
363 int stat = bt3c_read(iobase, 0x7002) & 0x10;
364 BT_INFO("%s: Antenna %s", info->hdev->name,
365 stat ? "out" : "in");
366 }
367 if (stat & 0x0001)
368 bt3c_receive(info);
369 if (stat & 0x0002) {
370 //BT_ERR("Ack (stat=0x%04x)", stat);
371 clear_bit(XMIT_SENDING, &(info->tx_state));
372 bt3c_write_wakeup(info);
373 }
374
375 bt3c_io_write(iobase, 0x7001, 0x0000);
376
377 outb(iir, iobase + CONTROL);
378 }
379 }
380
381 spin_unlock(&(info->lock));
382
383 return IRQ_HANDLED;
384}
385
386
387
388/* ======================== HCI interface ======================== */
389
390
391static int bt3c_hci_flush(struct hci_dev *hdev)
392{
393 bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
394
395 /* Drop TX queue */
396 skb_queue_purge(&(info->txq));
397
398 return 0;
399}
400
401
402static int bt3c_hci_open(struct hci_dev *hdev)
403{
404 set_bit(HCI_RUNNING, &(hdev->flags));
405
406 return 0;
407}
408
409
410static int bt3c_hci_close(struct hci_dev *hdev)
411{
412 if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
413 return 0;
414
415 bt3c_hci_flush(hdev);
416
417 return 0;
418}
419
420
421static int bt3c_hci_send_frame(struct sk_buff *skb)
422{
423 bt3c_info_t *info;
424 struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
425 unsigned long flags;
426
427 if (!hdev) {
428 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
429 return -ENODEV;
430 }
431
432 info = (bt3c_info_t *) (hdev->driver_data);
433
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700434 switch (bt_cb(skb)->pkt_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 case HCI_COMMAND_PKT:
436 hdev->stat.cmd_tx++;
437 break;
438 case HCI_ACLDATA_PKT:
439 hdev->stat.acl_tx++;
440 break;
441 case HCI_SCODATA_PKT:
442 hdev->stat.sco_tx++;
443 break;
444 };
445
446 /* Prepend skb with frame type */
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700447 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 skb_queue_tail(&(info->txq), skb);
449
450 spin_lock_irqsave(&(info->lock), flags);
451
452 bt3c_write_wakeup(info);
453
454 spin_unlock_irqrestore(&(info->lock), flags);
455
456 return 0;
457}
458
459
460static void bt3c_hci_destruct(struct hci_dev *hdev)
461{
462}
463
464
465static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
466{
467 return -ENOIOCTLCMD;
468}
469
470
471
472/* ======================== Card services HCI interaction ======================== */
473
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count)
476{
477 char *ptr = (char *) firmware;
478 char b[9];
479 unsigned int iobase, size, addr, fcs, tmp;
480 int i, err = 0;
481
Dominik Brodowskifd238232006-03-05 10:45:09 +0100482 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 /* Reset */
485 bt3c_io_write(iobase, 0x8040, 0x0404);
486 bt3c_io_write(iobase, 0x8040, 0x0400);
487
488 udelay(1);
489
490 bt3c_io_write(iobase, 0x8040, 0x0404);
491
492 udelay(17);
493
494 /* Load */
495 while (count) {
496 if (ptr[0] != 'S') {
497 BT_ERR("Bad address in firmware");
498 err = -EFAULT;
499 goto error;
500 }
501
502 memset(b, 0, sizeof(b));
503 memcpy(b, ptr + 2, 2);
504 size = simple_strtol(b, NULL, 16);
505
506 memset(b, 0, sizeof(b));
507 memcpy(b, ptr + 4, 8);
508 addr = simple_strtol(b, NULL, 16);
509
510 memset(b, 0, sizeof(b));
511 memcpy(b, ptr + (size * 2) + 2, 2);
512 fcs = simple_strtol(b, NULL, 16);
513
514 memset(b, 0, sizeof(b));
515 for (tmp = 0, i = 0; i < size; i++) {
516 memcpy(b, ptr + (i * 2) + 2, 2);
517 tmp += simple_strtol(b, NULL, 16);
518 }
519
520 if (((tmp + fcs) & 0xff) != 0xff) {
521 BT_ERR("Checksum error in firmware");
522 err = -EILSEQ;
523 goto error;
524 }
525
526 if (ptr[1] == '3') {
527 bt3c_address(iobase, addr);
528
529 memset(b, 0, sizeof(b));
530 for (i = 0; i < (size - 4) / 2; i++) {
531 memcpy(b, ptr + (i * 4) + 12, 4);
532 tmp = simple_strtol(b, NULL, 16);
533 bt3c_put(iobase, tmp);
534 }
535 }
536
537 ptr += (size * 2) + 6;
538 count -= (size * 2) + 6;
539 }
540
541 udelay(17);
542
543 /* Boot */
544 bt3c_address(iobase, 0x3000);
545 outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
546
547error:
548 udelay(17);
549
550 /* Clear */
551 bt3c_io_write(iobase, 0x7006, 0x0000);
552 bt3c_io_write(iobase, 0x7005, 0x0000);
553 bt3c_io_write(iobase, 0x7001, 0x0000);
554
555 return err;
556}
557
558
559static int bt3c_open(bt3c_info_t *info)
560{
561 const struct firmware *firmware;
562 struct hci_dev *hdev;
563 int err;
564
565 spin_lock_init(&(info->lock));
566
567 skb_queue_head_init(&(info->txq));
568
569 info->rx_state = RECV_WAIT_PACKET_TYPE;
570 info->rx_count = 0;
571 info->rx_skb = NULL;
572
573 /* Initialize HCI device */
574 hdev = hci_alloc_dev();
575 if (!hdev) {
576 BT_ERR("Can't allocate HCI device");
577 return -ENOMEM;
578 }
579
580 info->hdev = hdev;
581
582 hdev->type = HCI_PCCARD;
583 hdev->driver_data = info;
Marcel Holtmann27d35282006-07-03 10:02:37 +0200584 SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 hdev->open = bt3c_hci_open;
587 hdev->close = bt3c_hci_close;
588 hdev->flush = bt3c_hci_flush;
589 hdev->send = bt3c_hci_send_frame;
590 hdev->destruct = bt3c_hci_destruct;
591 hdev->ioctl = bt3c_hci_ioctl;
592
593 hdev->owner = THIS_MODULE;
594
595 /* Load firmware */
Dominik Brodowskifd238232006-03-05 10:45:09 +0100596 err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if (err < 0) {
598 BT_ERR("Firmware request failed");
599 goto error;
600 }
601
602 err = bt3c_load_firmware(info, firmware->data, firmware->size);
603
604 release_firmware(firmware);
605
606 if (err < 0) {
607 BT_ERR("Firmware loading failed");
608 goto error;
609 }
610
611 /* Timeout before it is safe to send the first HCI packet */
612 msleep(1000);
613
614 /* Register HCI device */
615 err = hci_register_dev(hdev);
616 if (err < 0) {
617 BT_ERR("Can't register HCI device");
618 goto error;
619 }
620
621 return 0;
622
623error:
624 info->hdev = NULL;
625 hci_free_dev(hdev);
626 return err;
627}
628
629
630static int bt3c_close(bt3c_info_t *info)
631{
632 struct hci_dev *hdev = info->hdev;
633
634 if (!hdev)
635 return -ENODEV;
636
637 bt3c_hci_close(hdev);
638
639 if (hci_unregister_dev(hdev) < 0)
640 BT_ERR("Can't unregister HCI device %s", hdev->name);
641
642 hci_free_dev(hdev);
643
644 return 0;
645}
646
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200647static int bt3c_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 bt3c_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 /* Create new info device */
Deepak Saxena089b1db2005-11-07 01:01:26 -0800652 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 if (!info)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100654 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200656 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 link->priv = info;
658
659 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
660 link->io.NumPorts1 = 8;
661 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
662 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
663
664 link->irq.Handler = bt3c_interrupt;
665 link->irq.Instance = info;
666
667 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 link->conf.IntType = INT_MEMORY_AND_IO;
669
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200670 return bt3c_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671}
672
673
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200674static void bt3c_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 bt3c_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100678 bt3c_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 kfree(info);
680}
681
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200682static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 int i;
685
686 i = pcmcia_get_tuple_data(handle, tuple);
687 if (i != CS_SUCCESS)
688 return i;
689
690 return pcmcia_parse_tuple(handle, tuple, parse);
691}
692
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200693static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
696 return CS_NO_MORE_ITEMS;
697 return get_tuple(handle, tuple, parse);
698}
699
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200700static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
702 if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
703 return CS_NO_MORE_ITEMS;
704 return get_tuple(handle, tuple, parse);
705}
706
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200707static int bt3c_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 bt3c_info_t *info = link->priv;
711 tuple_t tuple;
712 u_short buf[256];
713 cisparse_t parse;
714 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400715 int i, j, try;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* First pass: look for a config entry that looks normal. */
718 tuple.TupleData = (cisdata_t *)buf;
719 tuple.TupleOffset = 0;
720 tuple.TupleDataMax = 255;
721 tuple.Attributes = 0;
722 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
723 /* Two tries: without IO aliases, then with aliases */
724 for (try = 0; try < 2; try++) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200725 i = first_tuple(link, &tuple, &parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 while (i != CS_NO_MORE_ITEMS) {
727 if (i != CS_SUCCESS)
728 goto next_entry;
729 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
Dominik Brodowski70294b42006-01-15 12:43:16 +0100730 link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
732 link->conf.ConfigIndex = cf->index;
733 link->io.BasePort1 = cf->io.win[0].base;
734 link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200735 i = pcmcia_request_io(link, &link->io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (i == CS_SUCCESS)
737 goto found_port;
738 }
739next_entry:
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200740 i = next_tuple(link, &tuple, &parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
742 }
743
744 /* Second pass: try to find an entry that isn't picky about
745 its base address, then try to grab any standard serial port
746 address, and finally try to get any free port. */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200747 i = first_tuple(link, &tuple, &parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 while (i != CS_NO_MORE_ITEMS) {
749 if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
750 link->conf.ConfigIndex = cf->index;
751 for (j = 0; j < 5; j++) {
752 link->io.BasePort1 = base[j];
753 link->io.IOAddrLines = base[j] ? 16 : 3;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200754 i = pcmcia_request_io(link, &link->io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (i == CS_SUCCESS)
756 goto found_port;
757 }
758 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200759 i = next_tuple(link, &tuple, &parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
761
762found_port:
763 if (i != CS_SUCCESS) {
764 BT_ERR("No usable port range found");
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200765 cs_error(link, RequestIO, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 goto failed;
767 }
768
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200769 i = pcmcia_request_irq(link, &link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (i != CS_SUCCESS) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200771 cs_error(link, RequestIRQ, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 link->irq.AssignedIRQ = 0;
773 }
774
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200775 i = pcmcia_request_configuration(link, &link->conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (i != CS_SUCCESS) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200777 cs_error(link, RequestConfiguration, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 goto failed;
779 }
780
781 if (bt3c_open(info) != 0)
782 goto failed;
783
784 strcpy(info->node.dev_name, info->hdev->name);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100785 link->dev_node = &info->node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200787 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789failed:
790 bt3c_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200791 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
794
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200795static void bt3c_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 bt3c_info_t *info = link->priv;
798
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100799 bt3c_close(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200801 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802}
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Dominik Brodowskia01c3ed2005-06-27 16:28:37 -0700805static struct pcmcia_device_id bt3c_ids[] = {
806 PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
807 PCMCIA_DEVICE_NULL
808};
809MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811static struct pcmcia_driver bt3c_driver = {
812 .owner = THIS_MODULE,
813 .drv = {
814 .name = "bt3c_cs",
815 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200816 .probe = bt3c_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100817 .remove = bt3c_detach,
Dominik Brodowskia01c3ed2005-06-27 16:28:37 -0700818 .id_table = bt3c_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819};
820
821static int __init init_bt3c_cs(void)
822{
823 return pcmcia_register_driver(&bt3c_driver);
824}
825
826
827static void __exit exit_bt3c_cs(void)
828{
829 pcmcia_unregister_driver(&bt3c_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830}
831
832module_init(init_bt3c_cs);
833module_exit(exit_bt3c_cs);