blob: 21e05fdc912196d38f7ce5e73389338f9cd5b672 [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
Marcel Holtmann63fbd242008-08-18 13:23:53 +020063MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070064MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
65MODULE_LICENSE("GPL");
Marcel Holtmann23121192007-02-17 23:59:02 +010066MODULE_FIRMWARE("BT3CPCC.bin");
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68
69
70/* ======================== Local structures ======================== */
71
72
73typedef struct bt3c_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010074 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
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:
Arnaldo Carvalho de Melo2a123b82007-03-27 18:38:07 -0300305 eh = hci_event_hdr(info->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 info->rx_state = RECV_WAIT_DATA;
307 info->rx_count = eh->plen;
308 break;
309
310 case RECV_WAIT_ACL_HEADER:
Arnaldo Carvalho de Melo2a123b82007-03-27 18:38:07 -0300311 ah = hci_acl_hdr(info->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 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:
Arnaldo Carvalho de Melo2a123b82007-03-27 18:38:07 -0300318 sh = hci_sco_hdr(info->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 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;
Alan Coxaafcf992008-10-05 17:35:41 +0100345 irqreturn_t r = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Mike Frysinger74278472009-09-14 13:43:49 -0400347 if (!info || !info->hdev)
348 /* our irq handler is shared */
349 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
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) {
Andre Haupt34a55ed2009-02-02 14:45:11 -0800363 int status = bt3c_read(iobase, 0x7002) & 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 BT_INFO("%s: Antenna %s", info->hdev->name,
Andre Haupt34a55ed2009-02-02 14:45:11 -0800365 status ? "out" : "in");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
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 }
Alan Coxaafcf992008-10-05 17:35:41 +0100379 r = IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381
382 spin_unlock(&(info->lock));
383
Alan Coxaafcf992008-10-05 17:35:41 +0100384 return r;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
387
388
389/* ======================== HCI interface ======================== */
390
391
392static int bt3c_hci_flush(struct hci_dev *hdev)
393{
394 bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
395
396 /* Drop TX queue */
397 skb_queue_purge(&(info->txq));
398
399 return 0;
400}
401
402
403static int bt3c_hci_open(struct hci_dev *hdev)
404{
405 set_bit(HCI_RUNNING, &(hdev->flags));
406
407 return 0;
408}
409
410
411static int bt3c_hci_close(struct hci_dev *hdev)
412{
413 if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
414 return 0;
415
416 bt3c_hci_flush(hdev);
417
418 return 0;
419}
420
421
422static int bt3c_hci_send_frame(struct sk_buff *skb)
423{
424 bt3c_info_t *info;
425 struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
426 unsigned long flags;
427
428 if (!hdev) {
429 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
430 return -ENODEV;
431 }
432
433 info = (bt3c_info_t *) (hdev->driver_data);
434
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700435 switch (bt_cb(skb)->pkt_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 case HCI_COMMAND_PKT:
437 hdev->stat.cmd_tx++;
438 break;
439 case HCI_ACLDATA_PKT:
440 hdev->stat.acl_tx++;
441 break;
442 case HCI_SCODATA_PKT:
443 hdev->stat.sco_tx++;
444 break;
445 };
446
447 /* Prepend skb with frame type */
Marcel Holtmann0d48d932005-08-09 20:30:28 -0700448 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 skb_queue_tail(&(info->txq), skb);
450
451 spin_lock_irqsave(&(info->lock), flags);
452
453 bt3c_write_wakeup(info);
454
455 spin_unlock_irqrestore(&(info->lock), flags);
456
457 return 0;
458}
459
460
461static void bt3c_hci_destruct(struct hci_dev *hdev)
462{
463}
464
465
466static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
467{
468 return -ENOIOCTLCMD;
469}
470
471
472
473/* ======================== Card services HCI interaction ======================== */
474
475
David Woodhouse8187b4f2008-05-23 23:56:51 +0100476static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
477 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
479 char *ptr = (char *) firmware;
480 char b[9];
481 unsigned int iobase, size, addr, fcs, tmp;
482 int i, err = 0;
483
Dominik Brodowskifd238232006-03-05 10:45:09 +0100484 iobase = info->p_dev->io.BasePort1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 /* Reset */
487 bt3c_io_write(iobase, 0x8040, 0x0404);
488 bt3c_io_write(iobase, 0x8040, 0x0400);
489
490 udelay(1);
491
492 bt3c_io_write(iobase, 0x8040, 0x0404);
493
494 udelay(17);
495
496 /* Load */
497 while (count) {
498 if (ptr[0] != 'S') {
499 BT_ERR("Bad address in firmware");
500 err = -EFAULT;
501 goto error;
502 }
503
504 memset(b, 0, sizeof(b));
505 memcpy(b, ptr + 2, 2);
Julia Lawall51a6fbc2008-11-30 12:17:20 +0100506 size = simple_strtoul(b, NULL, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 memset(b, 0, sizeof(b));
509 memcpy(b, ptr + 4, 8);
Julia Lawall51a6fbc2008-11-30 12:17:20 +0100510 addr = simple_strtoul(b, NULL, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 memset(b, 0, sizeof(b));
513 memcpy(b, ptr + (size * 2) + 2, 2);
Julia Lawall51a6fbc2008-11-30 12:17:20 +0100514 fcs = simple_strtoul(b, NULL, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 memset(b, 0, sizeof(b));
517 for (tmp = 0, i = 0; i < size; i++) {
518 memcpy(b, ptr + (i * 2) + 2, 2);
519 tmp += simple_strtol(b, NULL, 16);
520 }
521
522 if (((tmp + fcs) & 0xff) != 0xff) {
523 BT_ERR("Checksum error in firmware");
524 err = -EILSEQ;
525 goto error;
526 }
527
528 if (ptr[1] == '3') {
529 bt3c_address(iobase, addr);
530
531 memset(b, 0, sizeof(b));
532 for (i = 0; i < (size - 4) / 2; i++) {
533 memcpy(b, ptr + (i * 4) + 12, 4);
Julia Lawall51a6fbc2008-11-30 12:17:20 +0100534 tmp = simple_strtoul(b, NULL, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 bt3c_put(iobase, tmp);
536 }
537 }
538
539 ptr += (size * 2) + 6;
540 count -= (size * 2) + 6;
541 }
542
543 udelay(17);
544
545 /* Boot */
546 bt3c_address(iobase, 0x3000);
547 outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
548
549error:
550 udelay(17);
551
552 /* Clear */
553 bt3c_io_write(iobase, 0x7006, 0x0000);
554 bt3c_io_write(iobase, 0x7005, 0x0000);
555 bt3c_io_write(iobase, 0x7001, 0x0000);
556
557 return err;
558}
559
560
561static int bt3c_open(bt3c_info_t *info)
562{
563 const struct firmware *firmware;
564 struct hci_dev *hdev;
565 int err;
566
567 spin_lock_init(&(info->lock));
568
569 skb_queue_head_init(&(info->txq));
570
571 info->rx_state = RECV_WAIT_PACKET_TYPE;
572 info->rx_count = 0;
573 info->rx_skb = NULL;
574
575 /* Initialize HCI device */
576 hdev = hci_alloc_dev();
577 if (!hdev) {
578 BT_ERR("Can't allocate HCI device");
579 return -ENOMEM;
580 }
581
582 info->hdev = hdev;
583
Marcel Holtmannc13854c2010-02-08 15:27:07 +0100584 hdev->bus = HCI_PCCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 hdev->driver_data = info;
Marcel Holtmann27d35282006-07-03 10:02:37 +0200586 SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 hdev->open = bt3c_hci_open;
589 hdev->close = bt3c_hci_close;
590 hdev->flush = bt3c_hci_flush;
591 hdev->send = bt3c_hci_send_frame;
592 hdev->destruct = bt3c_hci_destruct;
593 hdev->ioctl = bt3c_hci_ioctl;
594
595 hdev->owner = THIS_MODULE;
596
597 /* Load firmware */
Dominik Brodowskifd238232006-03-05 10:45:09 +0100598 err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 if (err < 0) {
600 BT_ERR("Firmware request failed");
601 goto error;
602 }
603
604 err = bt3c_load_firmware(info, firmware->data, firmware->size);
605
606 release_firmware(firmware);
607
608 if (err < 0) {
609 BT_ERR("Firmware loading failed");
610 goto error;
611 }
612
613 /* Timeout before it is safe to send the first HCI packet */
614 msleep(1000);
615
616 /* Register HCI device */
617 err = hci_register_dev(hdev);
618 if (err < 0) {
619 BT_ERR("Can't register HCI device");
620 goto error;
621 }
622
623 return 0;
624
625error:
626 info->hdev = NULL;
627 hci_free_dev(hdev);
628 return err;
629}
630
631
632static int bt3c_close(bt3c_info_t *info)
633{
634 struct hci_dev *hdev = info->hdev;
635
636 if (!hdev)
637 return -ENODEV;
638
639 bt3c_hci_close(hdev);
640
641 if (hci_unregister_dev(hdev) < 0)
642 BT_ERR("Can't unregister HCI device %s", hdev->name);
643
644 hci_free_dev(hdev);
645
646 return 0;
647}
648
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200649static int bt3c_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650{
651 bt3c_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 /* Create new info device */
Deepak Saxena089b1db2005-11-07 01:01:26 -0800654 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if (!info)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100656 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200658 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 link->priv = info;
660
661 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
662 link->io.NumPorts1 = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 link->conf.IntType = INT_MEMORY_AND_IO;
666
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200667 return bt3c_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668}
669
670
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200671static void bt3c_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
673 bt3c_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100675 bt3c_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 kfree(info);
677}
678
Dominik Brodowskied588722008-07-29 08:38:55 +0200679static int bt3c_check_config(struct pcmcia_device *p_dev,
680 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200681 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200682 unsigned int vcc,
Dominik Brodowskied588722008-07-29 08:38:55 +0200683 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
Dominik Brodowskied588722008-07-29 08:38:55 +0200685 unsigned long try = (unsigned long) priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Dominik Brodowskied588722008-07-29 08:38:55 +0200687 if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
688 p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
689 if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
690 (cf->io.win[0].base != 0)) {
Dominik Brodowskied588722008-07-29 08:38:55 +0200691 p_dev->io.BasePort1 = cf->io.win[0].base;
692 p_dev->io.IOAddrLines = (try == 0) ? 16 :
693 cf->io.flags & CISTPL_IO_LINES_MASK;
694 if (!pcmcia_request_io(p_dev, &p_dev->io))
695 return 0;
696 }
697 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698}
699
Dominik Brodowskied588722008-07-29 08:38:55 +0200700static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
701 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200702 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200703 unsigned int vcc,
Dominik Brodowskied588722008-07-29 08:38:55 +0200704 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
Dominik Brodowskied588722008-07-29 08:38:55 +0200706 static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
707 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Dominik Brodowskied588722008-07-29 08:38:55 +0200709 if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
Dominik Brodowskied588722008-07-29 08:38:55 +0200710 for (j = 0; j < 5; j++) {
711 p_dev->io.BasePort1 = base[j];
712 p_dev->io.IOAddrLines = base[j] ? 16 : 3;
713 if (!pcmcia_request_io(p_dev, &p_dev->io))
714 return 0;
715 }
716 }
717 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718}
719
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200720static int bt3c_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 bt3c_info_t *info = link->priv;
Dominik Brodowskied588722008-07-29 08:38:55 +0200723 int i;
724 unsigned long try;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Dominik Brodowskied588722008-07-29 08:38:55 +0200726 /* First pass: look for a config entry that looks normal.
727 Two tries: without IO aliases, then with aliases */
728 for (try = 0; try < 2; try++)
729 if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try))
730 goto found_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 /* Second pass: try to find an entry that isn't picky about
733 its base address, then try to grab any standard serial port
734 address, and finally try to get any free port. */
Dominik Brodowskied588722008-07-29 08:38:55 +0200735 if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL))
736 goto found_port;
737
738 BT_ERR("No usable port range found");
Dominik Brodowskied588722008-07-29 08:38:55 +0200739 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741found_port:
Dominik Brodowskieb141202010-03-07 12:21:16 +0100742 i = pcmcia_request_irq(link, &bt3c_interrupt);
Dominik Brodowski9ac3e582009-10-24 15:45:06 +0200743 if (i != 0)
Dominik Brodowskieb141202010-03-07 12:21:16 +0100744 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200746 i = pcmcia_request_configuration(link, &link->conf);
Dominik Brodowski9ac3e582009-10-24 15:45:06 +0200747 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 if (bt3c_open(info) != 0)
751 goto failed;
752
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200753 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755failed:
756 bt3c_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200757 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
760
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200761static void bt3c_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 bt3c_info_t *info = link->priv;
764
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100765 bt3c_close(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200767 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768}
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Dominik Brodowskia01c3ed2005-06-27 16:28:37 -0700771static struct pcmcia_device_id bt3c_ids[] = {
772 PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
773 PCMCIA_DEVICE_NULL
774};
775MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777static struct pcmcia_driver bt3c_driver = {
778 .owner = THIS_MODULE,
779 .drv = {
780 .name = "bt3c_cs",
781 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200782 .probe = bt3c_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100783 .remove = bt3c_detach,
Dominik Brodowskia01c3ed2005-06-27 16:28:37 -0700784 .id_table = bt3c_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785};
786
787static int __init init_bt3c_cs(void)
788{
789 return pcmcia_register_driver(&bt3c_driver);
790}
791
792
793static void __exit exit_bt3c_cs(void)
794{
795 pcmcia_unregister_driver(&bt3c_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796}
797
798module_init(init_bt3c_cs);
799module_exit(exit_bt3c_cs);