diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/bluetooth/btuart_cs.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/bluetooth/btuart_cs.c')
-rw-r--r-- | drivers/bluetooth/btuart_cs.c | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c new file mode 100644 index 000000000000..ad8d972444a5 --- /dev/null +++ b/drivers/bluetooth/btuart_cs.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* | ||
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 | |||
23 | #include <linux/config.h> | ||
24 | #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> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/ptrace.h> | ||
34 | #include <linux/ioport.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | |||
38 | #include <linux/skbuff.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/serial.h> | ||
41 | #include <linux/serial_reg.h> | ||
42 | #include <linux/bitops.h> | ||
43 | #include <asm/system.h> | ||
44 | #include <asm/io.h> | ||
45 | |||
46 | #include <pcmcia/version.h> | ||
47 | #include <pcmcia/cs_types.h> | ||
48 | #include <pcmcia/cs.h> | ||
49 | #include <pcmcia/cistpl.h> | ||
50 | #include <pcmcia/ciscode.h> | ||
51 | #include <pcmcia/ds.h> | ||
52 | #include <pcmcia/cisreg.h> | ||
53 | |||
54 | #include <net/bluetooth/bluetooth.h> | ||
55 | #include <net/bluetooth/hci_core.h> | ||
56 | |||
57 | |||
58 | |||
59 | /* ======================== Module parameters ======================== */ | ||
60 | |||
61 | |||
62 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
63 | MODULE_DESCRIPTION("Bluetooth driver for Bluetooth PCMCIA cards with HCI UART interface"); | ||
64 | MODULE_LICENSE("GPL"); | ||
65 | |||
66 | |||
67 | |||
68 | /* ======================== Local structures ======================== */ | ||
69 | |||
70 | |||
71 | typedef struct btuart_info_t { | ||
72 | dev_link_t link; | ||
73 | dev_node_t node; | ||
74 | |||
75 | struct hci_dev *hdev; | ||
76 | |||
77 | spinlock_t lock; /* For serializing operations */ | ||
78 | |||
79 | struct sk_buff_head txq; | ||
80 | unsigned long tx_state; | ||
81 | |||
82 | unsigned long rx_state; | ||
83 | unsigned long rx_count; | ||
84 | struct sk_buff *rx_skb; | ||
85 | } btuart_info_t; | ||
86 | |||
87 | |||
88 | static void btuart_config(dev_link_t *link); | ||
89 | static void btuart_release(dev_link_t *link); | ||
90 | static int btuart_event(event_t event, int priority, event_callback_args_t *args); | ||
91 | |||
92 | static dev_info_t dev_info = "btuart_cs"; | ||
93 | |||
94 | static dev_link_t *btuart_attach(void); | ||
95 | static void btuart_detach(dev_link_t *); | ||
96 | |||
97 | static dev_link_t *dev_list = NULL; | ||
98 | |||
99 | |||
100 | /* Maximum baud rate */ | ||
101 | #define SPEED_MAX 115200 | ||
102 | |||
103 | /* Default baud rate: 57600, 115200, 230400 or 460800 */ | ||
104 | #define DEFAULT_BAUD_RATE 115200 | ||
105 | |||
106 | |||
107 | /* Transmit states */ | ||
108 | #define XMIT_SENDING 1 | ||
109 | #define XMIT_WAKEUP 2 | ||
110 | #define XMIT_WAITING 8 | ||
111 | |||
112 | /* Receiver states */ | ||
113 | #define RECV_WAIT_PACKET_TYPE 0 | ||
114 | #define RECV_WAIT_EVENT_HEADER 1 | ||
115 | #define RECV_WAIT_ACL_HEADER 2 | ||
116 | #define RECV_WAIT_SCO_HEADER 3 | ||
117 | #define RECV_WAIT_DATA 4 | ||
118 | |||
119 | |||
120 | |||
121 | /* ======================== Interrupt handling ======================== */ | ||
122 | |||
123 | |||
124 | static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) | ||
125 | { | ||
126 | int actual = 0; | ||
127 | |||
128 | /* Tx FIFO should be empty */ | ||
129 | if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) | ||
130 | return 0; | ||
131 | |||
132 | /* Fill FIFO with current frame */ | ||
133 | while ((fifo_size-- > 0) && (actual < len)) { | ||
134 | /* Transmit next byte */ | ||
135 | outb(buf[actual], iobase + UART_TX); | ||
136 | actual++; | ||
137 | } | ||
138 | |||
139 | return actual; | ||
140 | } | ||
141 | |||
142 | |||
143 | static void btuart_write_wakeup(btuart_info_t *info) | ||
144 | { | ||
145 | if (!info) { | ||
146 | BT_ERR("Unknown device"); | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { | ||
151 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | do { | ||
156 | register unsigned int iobase = info->link.io.BasePort1; | ||
157 | register struct sk_buff *skb; | ||
158 | register int len; | ||
159 | |||
160 | clear_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
161 | |||
162 | if (!(info->link.state & DEV_PRESENT)) | ||
163 | return; | ||
164 | |||
165 | if (!(skb = skb_dequeue(&(info->txq)))) | ||
166 | break; | ||
167 | |||
168 | /* Send frame */ | ||
169 | len = btuart_write(iobase, 16, skb->data, skb->len); | ||
170 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
171 | |||
172 | if (len == skb->len) { | ||
173 | kfree_skb(skb); | ||
174 | } else { | ||
175 | skb_pull(skb, len); | ||
176 | skb_queue_head(&(info->txq), skb); | ||
177 | } | ||
178 | |||
179 | info->hdev->stat.byte_tx += len; | ||
180 | |||
181 | } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); | ||
182 | |||
183 | clear_bit(XMIT_SENDING, &(info->tx_state)); | ||
184 | } | ||
185 | |||
186 | |||
187 | static void btuart_receive(btuart_info_t *info) | ||
188 | { | ||
189 | unsigned int iobase; | ||
190 | int boguscount = 0; | ||
191 | |||
192 | if (!info) { | ||
193 | BT_ERR("Unknown device"); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | iobase = info->link.io.BasePort1; | ||
198 | |||
199 | do { | ||
200 | info->hdev->stat.byte_rx++; | ||
201 | |||
202 | /* Allocate packet */ | ||
203 | if (info->rx_skb == NULL) { | ||
204 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
205 | info->rx_count = 0; | ||
206 | if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { | ||
207 | BT_ERR("Can't allocate mem for new packet"); | ||
208 | return; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | if (info->rx_state == RECV_WAIT_PACKET_TYPE) { | ||
213 | |||
214 | info->rx_skb->dev = (void *) info->hdev; | ||
215 | info->rx_skb->pkt_type = inb(iobase + UART_RX); | ||
216 | |||
217 | switch (info->rx_skb->pkt_type) { | ||
218 | |||
219 | case HCI_EVENT_PKT: | ||
220 | info->rx_state = RECV_WAIT_EVENT_HEADER; | ||
221 | info->rx_count = HCI_EVENT_HDR_SIZE; | ||
222 | break; | ||
223 | |||
224 | case HCI_ACLDATA_PKT: | ||
225 | info->rx_state = RECV_WAIT_ACL_HEADER; | ||
226 | info->rx_count = HCI_ACL_HDR_SIZE; | ||
227 | break; | ||
228 | |||
229 | case HCI_SCODATA_PKT: | ||
230 | info->rx_state = RECV_WAIT_SCO_HEADER; | ||
231 | info->rx_count = HCI_SCO_HDR_SIZE; | ||
232 | break; | ||
233 | |||
234 | default: | ||
235 | /* Unknown packet */ | ||
236 | BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type); | ||
237 | info->hdev->stat.err_rx++; | ||
238 | clear_bit(HCI_RUNNING, &(info->hdev->flags)); | ||
239 | |||
240 | kfree_skb(info->rx_skb); | ||
241 | info->rx_skb = NULL; | ||
242 | break; | ||
243 | |||
244 | } | ||
245 | |||
246 | } else { | ||
247 | |||
248 | *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); | ||
249 | info->rx_count--; | ||
250 | |||
251 | if (info->rx_count == 0) { | ||
252 | |||
253 | int dlen; | ||
254 | struct hci_event_hdr *eh; | ||
255 | struct hci_acl_hdr *ah; | ||
256 | struct hci_sco_hdr *sh; | ||
257 | |||
258 | |||
259 | switch (info->rx_state) { | ||
260 | |||
261 | case RECV_WAIT_EVENT_HEADER: | ||
262 | eh = (struct hci_event_hdr *)(info->rx_skb->data); | ||
263 | info->rx_state = RECV_WAIT_DATA; | ||
264 | info->rx_count = eh->plen; | ||
265 | break; | ||
266 | |||
267 | case RECV_WAIT_ACL_HEADER: | ||
268 | ah = (struct hci_acl_hdr *)(info->rx_skb->data); | ||
269 | dlen = __le16_to_cpu(ah->dlen); | ||
270 | info->rx_state = RECV_WAIT_DATA; | ||
271 | info->rx_count = dlen; | ||
272 | break; | ||
273 | |||
274 | case RECV_WAIT_SCO_HEADER: | ||
275 | sh = (struct hci_sco_hdr *)(info->rx_skb->data); | ||
276 | info->rx_state = RECV_WAIT_DATA; | ||
277 | info->rx_count = sh->dlen; | ||
278 | break; | ||
279 | |||
280 | case RECV_WAIT_DATA: | ||
281 | hci_recv_frame(info->rx_skb); | ||
282 | info->rx_skb = NULL; | ||
283 | break; | ||
284 | |||
285 | } | ||
286 | |||
287 | } | ||
288 | |||
289 | } | ||
290 | |||
291 | /* Make sure we don't stay here too long */ | ||
292 | if (boguscount++ > 16) | ||
293 | break; | ||
294 | |||
295 | } while (inb(iobase + UART_LSR) & UART_LSR_DR); | ||
296 | } | ||
297 | |||
298 | |||
299 | static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) | ||
300 | { | ||
301 | btuart_info_t *info = dev_inst; | ||
302 | unsigned int iobase; | ||
303 | int boguscount = 0; | ||
304 | int iir, lsr; | ||
305 | |||
306 | if (!info || !info->hdev) { | ||
307 | BT_ERR("Call of irq %d for unknown device", irq); | ||
308 | return IRQ_NONE; | ||
309 | } | ||
310 | |||
311 | iobase = info->link.io.BasePort1; | ||
312 | |||
313 | spin_lock(&(info->lock)); | ||
314 | |||
315 | iir = inb(iobase + UART_IIR) & UART_IIR_ID; | ||
316 | while (iir) { | ||
317 | |||
318 | /* Clear interrupt */ | ||
319 | lsr = inb(iobase + UART_LSR); | ||
320 | |||
321 | switch (iir) { | ||
322 | case UART_IIR_RLSI: | ||
323 | BT_ERR("RLSI"); | ||
324 | break; | ||
325 | case UART_IIR_RDI: | ||
326 | /* Receive interrupt */ | ||
327 | btuart_receive(info); | ||
328 | break; | ||
329 | case UART_IIR_THRI: | ||
330 | if (lsr & UART_LSR_THRE) { | ||
331 | /* Transmitter ready for data */ | ||
332 | btuart_write_wakeup(info); | ||
333 | } | ||
334 | break; | ||
335 | default: | ||
336 | BT_ERR("Unhandled IIR=%#x", iir); | ||
337 | break; | ||
338 | } | ||
339 | |||
340 | /* Make sure we don't stay here too long */ | ||
341 | if (boguscount++ > 100) | ||
342 | break; | ||
343 | |||
344 | iir = inb(iobase + UART_IIR) & UART_IIR_ID; | ||
345 | |||
346 | } | ||
347 | |||
348 | spin_unlock(&(info->lock)); | ||
349 | |||
350 | return IRQ_HANDLED; | ||
351 | } | ||
352 | |||
353 | |||
354 | static void btuart_change_speed(btuart_info_t *info, unsigned int speed) | ||
355 | { | ||
356 | unsigned long flags; | ||
357 | unsigned int iobase; | ||
358 | int fcr; /* FIFO control reg */ | ||
359 | int lcr; /* Line control reg */ | ||
360 | int divisor; | ||
361 | |||
362 | if (!info) { | ||
363 | BT_ERR("Unknown device"); | ||
364 | return; | ||
365 | } | ||
366 | |||
367 | iobase = info->link.io.BasePort1; | ||
368 | |||
369 | spin_lock_irqsave(&(info->lock), flags); | ||
370 | |||
371 | /* Turn off interrupts */ | ||
372 | outb(0, iobase + UART_IER); | ||
373 | |||
374 | divisor = SPEED_MAX / speed; | ||
375 | |||
376 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; | ||
377 | |||
378 | /* | ||
379 | * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and | ||
380 | * almost 1,7 ms at 19200 bps. At speeds above that we can just forget | ||
381 | * about this timeout since it will always be fast enough. | ||
382 | */ | ||
383 | |||
384 | if (speed < 38400) | ||
385 | fcr |= UART_FCR_TRIGGER_1; | ||
386 | else | ||
387 | fcr |= UART_FCR_TRIGGER_14; | ||
388 | |||
389 | /* Bluetooth cards use 8N1 */ | ||
390 | lcr = UART_LCR_WLEN8; | ||
391 | |||
392 | outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ | ||
393 | outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ | ||
394 | outb(divisor >> 8, iobase + UART_DLM); | ||
395 | outb(lcr, iobase + UART_LCR); /* Set 8N1 */ | ||
396 | outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ | ||
397 | |||
398 | /* Turn on interrups */ | ||
399 | outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); | ||
400 | |||
401 | spin_unlock_irqrestore(&(info->lock), flags); | ||
402 | } | ||
403 | |||
404 | |||
405 | |||
406 | /* ======================== HCI interface ======================== */ | ||
407 | |||
408 | |||
409 | static int btuart_hci_flush(struct hci_dev *hdev) | ||
410 | { | ||
411 | btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); | ||
412 | |||
413 | /* Drop TX queue */ | ||
414 | skb_queue_purge(&(info->txq)); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | |||
420 | static int btuart_hci_open(struct hci_dev *hdev) | ||
421 | { | ||
422 | set_bit(HCI_RUNNING, &(hdev->flags)); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | |||
428 | static int btuart_hci_close(struct hci_dev *hdev) | ||
429 | { | ||
430 | if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) | ||
431 | return 0; | ||
432 | |||
433 | btuart_hci_flush(hdev); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | |||
439 | static int btuart_hci_send_frame(struct sk_buff *skb) | ||
440 | { | ||
441 | btuart_info_t *info; | ||
442 | struct hci_dev *hdev = (struct hci_dev *)(skb->dev); | ||
443 | |||
444 | if (!hdev) { | ||
445 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); | ||
446 | return -ENODEV; | ||
447 | } | ||
448 | |||
449 | info = (btuart_info_t *)(hdev->driver_data); | ||
450 | |||
451 | switch (skb->pkt_type) { | ||
452 | case HCI_COMMAND_PKT: | ||
453 | hdev->stat.cmd_tx++; | ||
454 | break; | ||
455 | case HCI_ACLDATA_PKT: | ||
456 | hdev->stat.acl_tx++; | ||
457 | break; | ||
458 | case HCI_SCODATA_PKT: | ||
459 | hdev->stat.sco_tx++; | ||
460 | break; | ||
461 | }; | ||
462 | |||
463 | /* Prepend skb with frame type */ | ||
464 | memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); | ||
465 | skb_queue_tail(&(info->txq), skb); | ||
466 | |||
467 | btuart_write_wakeup(info); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | |||
473 | static void btuart_hci_destruct(struct hci_dev *hdev) | ||
474 | { | ||
475 | } | ||
476 | |||
477 | |||
478 | static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) | ||
479 | { | ||
480 | return -ENOIOCTLCMD; | ||
481 | } | ||
482 | |||
483 | |||
484 | |||
485 | /* ======================== Card services HCI interaction ======================== */ | ||
486 | |||
487 | |||
488 | static int btuart_open(btuart_info_t *info) | ||
489 | { | ||
490 | unsigned long flags; | ||
491 | unsigned int iobase = info->link.io.BasePort1; | ||
492 | struct hci_dev *hdev; | ||
493 | |||
494 | spin_lock_init(&(info->lock)); | ||
495 | |||
496 | skb_queue_head_init(&(info->txq)); | ||
497 | |||
498 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
499 | info->rx_count = 0; | ||
500 | info->rx_skb = NULL; | ||
501 | |||
502 | /* Initialize HCI device */ | ||
503 | hdev = hci_alloc_dev(); | ||
504 | if (!hdev) { | ||
505 | BT_ERR("Can't allocate HCI device"); | ||
506 | return -ENOMEM; | ||
507 | } | ||
508 | |||
509 | info->hdev = hdev; | ||
510 | |||
511 | hdev->type = HCI_PCCARD; | ||
512 | hdev->driver_data = info; | ||
513 | |||
514 | hdev->open = btuart_hci_open; | ||
515 | hdev->close = btuart_hci_close; | ||
516 | hdev->flush = btuart_hci_flush; | ||
517 | hdev->send = btuart_hci_send_frame; | ||
518 | hdev->destruct = btuart_hci_destruct; | ||
519 | hdev->ioctl = btuart_hci_ioctl; | ||
520 | |||
521 | hdev->owner = THIS_MODULE; | ||
522 | |||
523 | spin_lock_irqsave(&(info->lock), flags); | ||
524 | |||
525 | /* Reset UART */ | ||
526 | outb(0, iobase + UART_MCR); | ||
527 | |||
528 | /* Turn off interrupts */ | ||
529 | outb(0, iobase + UART_IER); | ||
530 | |||
531 | /* Initialize UART */ | ||
532 | outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ | ||
533 | outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); | ||
534 | |||
535 | /* Turn on interrupts */ | ||
536 | // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); | ||
537 | |||
538 | spin_unlock_irqrestore(&(info->lock), flags); | ||
539 | |||
540 | btuart_change_speed(info, DEFAULT_BAUD_RATE); | ||
541 | |||
542 | /* Timeout before it is safe to send the first HCI packet */ | ||
543 | msleep(1000); | ||
544 | |||
545 | /* Register HCI device */ | ||
546 | if (hci_register_dev(hdev) < 0) { | ||
547 | BT_ERR("Can't register HCI device"); | ||
548 | info->hdev = NULL; | ||
549 | hci_free_dev(hdev); | ||
550 | return -ENODEV; | ||
551 | } | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | |||
557 | static int btuart_close(btuart_info_t *info) | ||
558 | { | ||
559 | unsigned long flags; | ||
560 | unsigned int iobase = info->link.io.BasePort1; | ||
561 | struct hci_dev *hdev = info->hdev; | ||
562 | |||
563 | if (!hdev) | ||
564 | return -ENODEV; | ||
565 | |||
566 | btuart_hci_close(hdev); | ||
567 | |||
568 | spin_lock_irqsave(&(info->lock), flags); | ||
569 | |||
570 | /* Reset UART */ | ||
571 | outb(0, iobase + UART_MCR); | ||
572 | |||
573 | /* Turn off interrupts */ | ||
574 | outb(0, iobase + UART_IER); | ||
575 | |||
576 | spin_unlock_irqrestore(&(info->lock), flags); | ||
577 | |||
578 | if (hci_unregister_dev(hdev) < 0) | ||
579 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
580 | |||
581 | hci_free_dev(hdev); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static dev_link_t *btuart_attach(void) | ||
587 | { | ||
588 | btuart_info_t *info; | ||
589 | client_reg_t client_reg; | ||
590 | dev_link_t *link; | ||
591 | int ret; | ||
592 | |||
593 | /* Create new info device */ | ||
594 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
595 | if (!info) | ||
596 | return NULL; | ||
597 | memset(info, 0, sizeof(*info)); | ||
598 | |||
599 | link = &info->link; | ||
600 | link->priv = info; | ||
601 | |||
602 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
603 | link->io.NumPorts1 = 8; | ||
604 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
605 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
606 | |||
607 | link->irq.Handler = btuart_interrupt; | ||
608 | link->irq.Instance = info; | ||
609 | |||
610 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
611 | link->conf.Vcc = 50; | ||
612 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
613 | |||
614 | /* Register with Card Services */ | ||
615 | link->next = dev_list; | ||
616 | dev_list = link; | ||
617 | client_reg.dev_info = &dev_info; | ||
618 | client_reg.EventMask = | ||
619 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
620 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
621 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
622 | client_reg.event_handler = &btuart_event; | ||
623 | client_reg.Version = 0x0210; | ||
624 | client_reg.event_callback_args.client_data = link; | ||
625 | |||
626 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
627 | if (ret != CS_SUCCESS) { | ||
628 | cs_error(link->handle, RegisterClient, ret); | ||
629 | btuart_detach(link); | ||
630 | return NULL; | ||
631 | } | ||
632 | |||
633 | return link; | ||
634 | } | ||
635 | |||
636 | |||
637 | static void btuart_detach(dev_link_t *link) | ||
638 | { | ||
639 | btuart_info_t *info = link->priv; | ||
640 | dev_link_t **linkp; | ||
641 | int ret; | ||
642 | |||
643 | /* Locate device structure */ | ||
644 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
645 | if (*linkp == link) | ||
646 | break; | ||
647 | |||
648 | if (*linkp == NULL) | ||
649 | return; | ||
650 | |||
651 | if (link->state & DEV_CONFIG) | ||
652 | btuart_release(link); | ||
653 | |||
654 | if (link->handle) { | ||
655 | ret = pcmcia_deregister_client(link->handle); | ||
656 | if (ret != CS_SUCCESS) | ||
657 | cs_error(link->handle, DeregisterClient, ret); | ||
658 | } | ||
659 | |||
660 | /* Unlink device structure, free bits */ | ||
661 | *linkp = link->next; | ||
662 | |||
663 | kfree(info); | ||
664 | } | ||
665 | |||
666 | static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
667 | { | ||
668 | int i; | ||
669 | |||
670 | i = pcmcia_get_tuple_data(handle, tuple); | ||
671 | if (i != CS_SUCCESS) | ||
672 | return i; | ||
673 | |||
674 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
675 | } | ||
676 | |||
677 | static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
678 | { | ||
679 | if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) | ||
680 | return CS_NO_MORE_ITEMS; | ||
681 | return get_tuple(handle, tuple, parse); | ||
682 | } | ||
683 | |||
684 | static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
685 | { | ||
686 | if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) | ||
687 | return CS_NO_MORE_ITEMS; | ||
688 | return get_tuple(handle, tuple, parse); | ||
689 | } | ||
690 | |||
691 | static void btuart_config(dev_link_t *link) | ||
692 | { | ||
693 | static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | ||
694 | client_handle_t handle = link->handle; | ||
695 | btuart_info_t *info = link->priv; | ||
696 | tuple_t tuple; | ||
697 | u_short buf[256]; | ||
698 | cisparse_t parse; | ||
699 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | ||
700 | config_info_t config; | ||
701 | int i, j, try, last_ret, last_fn; | ||
702 | |||
703 | tuple.TupleData = (cisdata_t *)buf; | ||
704 | tuple.TupleOffset = 0; | ||
705 | tuple.TupleDataMax = 255; | ||
706 | tuple.Attributes = 0; | ||
707 | |||
708 | /* Get configuration register information */ | ||
709 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
710 | last_ret = first_tuple(handle, &tuple, &parse); | ||
711 | if (last_ret != CS_SUCCESS) { | ||
712 | last_fn = ParseTuple; | ||
713 | goto cs_failed; | ||
714 | } | ||
715 | link->conf.ConfigBase = parse.config.base; | ||
716 | link->conf.Present = parse.config.rmask[0]; | ||
717 | |||
718 | /* Configure card */ | ||
719 | link->state |= DEV_CONFIG; | ||
720 | i = pcmcia_get_configuration_info(handle, &config); | ||
721 | link->conf.Vcc = config.Vcc; | ||
722 | |||
723 | /* First pass: look for a config entry that looks normal. */ | ||
724 | tuple.TupleData = (cisdata_t *) buf; | ||
725 | tuple.TupleOffset = 0; | ||
726 | tuple.TupleDataMax = 255; | ||
727 | tuple.Attributes = 0; | ||
728 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
729 | /* Two tries: without IO aliases, then with aliases */ | ||
730 | for (try = 0; try < 2; try++) { | ||
731 | i = first_tuple(handle, &tuple, &parse); | ||
732 | while (i != CS_NO_MORE_ITEMS) { | ||
733 | if (i != CS_SUCCESS) | ||
734 | goto next_entry; | ||
735 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
736 | link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
737 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { | ||
738 | link->conf.ConfigIndex = cf->index; | ||
739 | link->io.BasePort1 = cf->io.win[0].base; | ||
740 | link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | ||
741 | i = pcmcia_request_io(link->handle, &link->io); | ||
742 | if (i == CS_SUCCESS) | ||
743 | goto found_port; | ||
744 | } | ||
745 | next_entry: | ||
746 | i = next_tuple(handle, &tuple, &parse); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | /* Second pass: try to find an entry that isn't picky about | ||
751 | its base address, then try to grab any standard serial port | ||
752 | address, and finally try to get any free port. */ | ||
753 | i = first_tuple(handle, &tuple, &parse); | ||
754 | while (i != CS_NO_MORE_ITEMS) { | ||
755 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) | ||
756 | && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | ||
757 | link->conf.ConfigIndex = cf->index; | ||
758 | for (j = 0; j < 5; j++) { | ||
759 | link->io.BasePort1 = base[j]; | ||
760 | link->io.IOAddrLines = base[j] ? 16 : 3; | ||
761 | i = pcmcia_request_io(link->handle, &link->io); | ||
762 | if (i == CS_SUCCESS) | ||
763 | goto found_port; | ||
764 | } | ||
765 | } | ||
766 | i = next_tuple(handle, &tuple, &parse); | ||
767 | } | ||
768 | |||
769 | found_port: | ||
770 | if (i != CS_SUCCESS) { | ||
771 | BT_ERR("No usable port range found"); | ||
772 | cs_error(link->handle, RequestIO, i); | ||
773 | goto failed; | ||
774 | } | ||
775 | |||
776 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
777 | if (i != CS_SUCCESS) { | ||
778 | cs_error(link->handle, RequestIRQ, i); | ||
779 | link->irq.AssignedIRQ = 0; | ||
780 | } | ||
781 | |||
782 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
783 | if (i != CS_SUCCESS) { | ||
784 | cs_error(link->handle, RequestConfiguration, i); | ||
785 | goto failed; | ||
786 | } | ||
787 | |||
788 | if (btuart_open(info) != 0) | ||
789 | goto failed; | ||
790 | |||
791 | strcpy(info->node.dev_name, info->hdev->name); | ||
792 | link->dev = &info->node; | ||
793 | link->state &= ~DEV_CONFIG_PENDING; | ||
794 | |||
795 | return; | ||
796 | |||
797 | cs_failed: | ||
798 | cs_error(link->handle, last_fn, last_ret); | ||
799 | |||
800 | failed: | ||
801 | btuart_release(link); | ||
802 | } | ||
803 | |||
804 | |||
805 | static void btuart_release(dev_link_t *link) | ||
806 | { | ||
807 | btuart_info_t *info = link->priv; | ||
808 | |||
809 | if (link->state & DEV_PRESENT) | ||
810 | btuart_close(info); | ||
811 | |||
812 | link->dev = NULL; | ||
813 | |||
814 | pcmcia_release_configuration(link->handle); | ||
815 | pcmcia_release_io(link->handle, &link->io); | ||
816 | pcmcia_release_irq(link->handle, &link->irq); | ||
817 | |||
818 | link->state &= ~DEV_CONFIG; | ||
819 | } | ||
820 | |||
821 | |||
822 | static int btuart_event(event_t event, int priority, event_callback_args_t *args) | ||
823 | { | ||
824 | dev_link_t *link = args->client_data; | ||
825 | btuart_info_t *info = link->priv; | ||
826 | |||
827 | switch (event) { | ||
828 | case CS_EVENT_CARD_REMOVAL: | ||
829 | link->state &= ~DEV_PRESENT; | ||
830 | if (link->state & DEV_CONFIG) { | ||
831 | btuart_close(info); | ||
832 | btuart_release(link); | ||
833 | } | ||
834 | break; | ||
835 | case CS_EVENT_CARD_INSERTION: | ||
836 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
837 | btuart_config(link); | ||
838 | break; | ||
839 | case CS_EVENT_PM_SUSPEND: | ||
840 | link->state |= DEV_SUSPEND; | ||
841 | /* Fall through... */ | ||
842 | case CS_EVENT_RESET_PHYSICAL: | ||
843 | if (link->state & DEV_CONFIG) | ||
844 | pcmcia_release_configuration(link->handle); | ||
845 | break; | ||
846 | case CS_EVENT_PM_RESUME: | ||
847 | link->state &= ~DEV_SUSPEND; | ||
848 | /* Fall through... */ | ||
849 | case CS_EVENT_CARD_RESET: | ||
850 | if (DEV_OK(link)) | ||
851 | pcmcia_request_configuration(link->handle, &link->conf); | ||
852 | break; | ||
853 | } | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static struct pcmcia_driver btuart_driver = { | ||
859 | .owner = THIS_MODULE, | ||
860 | .drv = { | ||
861 | .name = "btuart_cs", | ||
862 | }, | ||
863 | .attach = btuart_attach, | ||
864 | .detach = btuart_detach, | ||
865 | }; | ||
866 | |||
867 | static int __init init_btuart_cs(void) | ||
868 | { | ||
869 | return pcmcia_register_driver(&btuart_driver); | ||
870 | } | ||
871 | |||
872 | |||
873 | static void __exit exit_btuart_cs(void) | ||
874 | { | ||
875 | pcmcia_unregister_driver(&btuart_driver); | ||
876 | BUG_ON(dev_list != NULL); | ||
877 | } | ||
878 | |||
879 | module_init(init_btuart_cs); | ||
880 | module_exit(exit_btuart_cs); | ||