Blame view

drivers/bluetooth/dtl1_cs.c 12.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   *
   *  A driver for Nokia Connectivity Card DTL-1 devices
   *
   *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
   *
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License version 2 as
   *  published by the Free Software Foundation;
   *
   *  Software distributed under the License is distributed on an "AS
   *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
   *  implied. See the License for the specific language governing
   *  rights and limitations under the License.
   *
   *  The initial developer of the original code is David A. Hinds
   *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
   *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
  #include <linux/module.h>
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
37
38
39
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/ptrace.h>
  #include <linux/ioport.h>
  #include <linux/spinlock.h>
  #include <linux/moduleparam.h>
  
  #include <linux/skbuff.h>
  #include <linux/string.h>
  #include <linux/serial.h>
  #include <linux/serial_reg.h>
  #include <linux/bitops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  #include <pcmcia/cistpl.h>
  #include <pcmcia/ciscode.h>
  #include <pcmcia/ds.h>
  #include <pcmcia/cisreg.h>
  
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
  
  
  
  /* ======================== Module parameters ======================== */
  
  
  MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
  MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1");
  MODULE_LICENSE("GPL");
  
  
  
  /* ======================== Local structures ======================== */
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
61
  struct dtl1_info {
fd238232c   Dominik Brodowski   [PATCH] pcmcia: e...
62
  	struct pcmcia_device *p_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  
  	struct hci_dev *hdev;
  
  	spinlock_t lock;		/* For serializing operations */
  
  	unsigned long flowmask;		/* HCI flow mask */
  	int ri_latch;
  
  	struct sk_buff_head txq;
  	unsigned long tx_state;
  
  	unsigned long rx_state;
  	unsigned long rx_count;
  	struct sk_buff *rx_skb;
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
77
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
79
  static int dtl1_config(struct pcmcia_device *link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
87
88
89
  
  /* Transmit states  */
  #define XMIT_SENDING  1
  #define XMIT_WAKEUP   2
  #define XMIT_WAITING  8
  
  /* Receiver States */
  #define RECV_WAIT_NSH   0
  #define RECV_WAIT_DATA  1
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
90
  struct nsh {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
  	u8 type;
  	u8 zero;
  	u16 len;
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
94
  } __packed;	/* Nokia Specific Header */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  
  #define NSHL  4				/* Nokia Specific Header Length */
  
  
  
  /* ======================== Interrupt handling ======================== */
  
  
  static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
  {
  	int actual = 0;
  
  	/* Tx FIFO should be empty */
  	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
  		return 0;
  
  	/* Fill FIFO with current frame */
  	while ((fifo_size-- > 0) && (actual < len)) {
  		/* Transmit next byte */
  		outb(buf[actual], iobase + UART_TX);
  		actual++;
  	}
  
  	return actual;
  }
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
120
  static void dtl1_write_wakeup(struct dtl1_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  {
  	if (!info) {
  		BT_ERR("Unknown device");
  		return;
  	}
  
  	if (test_bit(XMIT_WAITING, &(info->tx_state))) {
  		set_bit(XMIT_WAKEUP, &(info->tx_state));
  		return;
  	}
  
  	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
  		set_bit(XMIT_WAKEUP, &(info->tx_state));
  		return;
  	}
  
  	do {
fc5fef615   Gustavo Padovan   Bluetooth: Remove...
138
  		unsigned int iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  		register struct sk_buff *skb;
fc5fef615   Gustavo Padovan   Bluetooth: Remove...
140
  		int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  
  		clear_bit(XMIT_WAKEUP, &(info->tx_state));
e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
143
  		if (!pcmcia_dev_present(info->p_dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  			return;
a08b15e66   Valentin Ilie   Bluetooth: Remove...
145
146
  		skb = skb_dequeue(&(info->txq));
  		if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  			break;
  
  		/* Send frame */
  		len = dtl1_write(iobase, 32, skb->data, skb->len);
  
  		if (len == skb->len) {
  			set_bit(XMIT_WAITING, &(info->tx_state));
  			kfree_skb(skb);
  		} else {
  			skb_pull(skb, len);
  			skb_queue_head(&(info->txq), skb);
  		}
  
  		info->hdev->stat.byte_tx += len;
  
  	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
  
  	clear_bit(XMIT_SENDING, &(info->tx_state));
  }
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
166
  static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
  {
  	u8 flowmask = *(u8 *)skb->data;
  	int i;
  
  	printk(KERN_INFO "Bluetooth: Nokia control data =");
fac5e5b91   Prasanna Karthik   Bluetooth: dtl1_c...
172
  	for (i = 0; i < skb->len; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  		printk(" %02x", skb->data[i]);
fac5e5b91   Prasanna Karthik   Bluetooth: dtl1_c...
174

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
184
185
186
187
  	printk("
  ");
  
  	/* transition to active state */
  	if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
  		clear_bit(XMIT_WAITING, &(info->tx_state));
  		dtl1_write_wakeup(info);
  	}
  
  	info->flowmask = flowmask;
  
  	kfree_skb(skb);
  }
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
188
  static void dtl1_receive(struct dtl1_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  {
  	unsigned int iobase;
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
191
  	struct nsh *nsh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
  	int boguscount = 0;
  
  	if (!info) {
  		BT_ERR("Unknown device");
  		return;
  	}
9a017a910   Dominik Brodowski   pcmcia: do not us...
198
  	iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
  
  	do {
  		info->hdev->stat.byte_rx++;
  
  		/* Allocate packet */
a08b15e66   Valentin Ilie   Bluetooth: Remove...
204
205
206
  		if (info->rx_skb == NULL) {
  			info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
  			if (!info->rx_skb) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
  				BT_ERR("Can't allocate mem for new packet");
  				info->rx_state = RECV_WAIT_NSH;
  				info->rx_count = NSHL;
  				return;
  			}
a08b15e66   Valentin Ilie   Bluetooth: Remove...
212
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  
  		*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
215
  		nsh = (struct nsh *)info->rx_skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
221
222
223
224
225
226
  
  		info->rx_count--;
  
  		if (info->rx_count == 0) {
  
  			switch (info->rx_state) {
  			case RECV_WAIT_NSH:
  				info->rx_state = RECV_WAIT_DATA;
  				info->rx_count = nsh->len + (nsh->len & 0x0001);
  				break;
  			case RECV_WAIT_DATA:
618e8bc22   Marcel Holtmann   Bluetooth: Use ne...
227
  				hci_skb_pkt_type(info->rx_skb) = nsh->type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
234
235
236
  
  				/* remove PAD byte if it exists */
  				if (nsh->len & 0x0001) {
  					info->rx_skb->tail--;
  					info->rx_skb->len--;
  				}
  
  				/* remove NSH */
  				skb_pull(info->rx_skb, NSHL);
618e8bc22   Marcel Holtmann   Bluetooth: Use ne...
237
  				switch (hci_skb_pkt_type(info->rx_skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
244
245
  				case 0x80:
  					/* control data for the Nokia Card */
  					dtl1_control(info, info->rx_skb);
  					break;
  				case 0x82:
  				case 0x83:
  				case 0x84:
  					/* send frame to the HCI layer */
618e8bc22   Marcel Holtmann   Bluetooth: Use ne...
246
  					hci_skb_pkt_type(info->rx_skb) &= 0x0f;
e1a261706   Marcel Holtmann   Bluetooth: Provid...
247
  					hci_recv_frame(info->hdev, info->rx_skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
  					break;
  				default:
  					/* unknown packet */
618e8bc22   Marcel Holtmann   Bluetooth: Use ne...
251
252
  					BT_ERR("Unknown HCI packet with type 0x%02x received",
  					       hci_skb_pkt_type(info->rx_skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  					kfree_skb(info->rx_skb);
  					break;
  				}
  
  				info->rx_state = RECV_WAIT_NSH;
  				info->rx_count = NSHL;
  				info->rx_skb = NULL;
  				break;
  			}
  
  		}
  
  		/* Make sure we don't stay here too long */
  		if (boguscount++ > 32)
  			break;
  
  	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
  }
7d12e780e   David Howells   IRQ: Maintain reg...
271
  static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  {
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
273
  	struct dtl1_info *info = dev_inst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
  	unsigned int iobase;
  	unsigned char msr;
  	int boguscount = 0;
  	int iir, lsr;
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
278
  	irqreturn_t r = IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279

7427847d2   Mike Frysinger   Bluetooth: Redo c...
280
281
282
  	if (!info || !info->hdev)
  		/* our irq handler is shared */
  		return IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

9a017a910   Dominik Brodowski   pcmcia: do not us...
284
  	iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
  
  	spin_lock(&(info->lock));
  
  	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
  	while (iir) {
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
290
  		r = IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  		/* Clear interrupt */
  		lsr = inb(iobase + UART_LSR);
  
  		switch (iir) {
  		case UART_IIR_RLSI:
  			BT_ERR("RLSI");
  			break;
  		case UART_IIR_RDI:
  			/* Receive interrupt */
  			dtl1_receive(info);
  			break;
  		case UART_IIR_THRI:
  			if (lsr & UART_LSR_THRE) {
  				/* Transmitter ready for data */
  				dtl1_write_wakeup(info);
  			}
  			break;
  		default:
  			BT_ERR("Unhandled IIR=%#x", iir);
  			break;
  		}
  
  		/* Make sure we don't stay here too long */
  		if (boguscount++ > 100)
  			break;
  
  		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
  
  	}
  
  	msr = inb(iobase + UART_MSR);
  
  	if (info->ri_latch ^ (msr & UART_MSR_RI)) {
  		info->ri_latch = msr & UART_MSR_RI;
  		clear_bit(XMIT_WAITING, &(info->tx_state));
  		dtl1_write_wakeup(info);
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
327
  		r = IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
  	}
  
  	spin_unlock(&(info->lock));
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
331
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
339
340
  }
  
  
  
  /* ======================== HCI interface ======================== */
  
  
  static int dtl1_hci_open(struct hci_dev *hdev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
345
346
  	return 0;
  }
  
  
  static int dtl1_hci_flush(struct hci_dev *hdev)
  {
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
347
  	struct dtl1_info *info = hci_get_drvdata(hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
354
355
356
357
  
  	/* Drop TX queue */
  	skb_queue_purge(&(info->txq));
  
  	return 0;
  }
  
  
  static int dtl1_hci_close(struct hci_dev *hdev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
  	dtl1_hci_flush(hdev);
  
  	return 0;
  }
7bd8f09f6   Marcel Holtmann   Bluetooth: Add hd...
362
  static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  {
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
364
  	struct dtl1_info *info = hci_get_drvdata(hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  	struct sk_buff *s;
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
366
  	struct nsh nsh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367

618e8bc22   Marcel Holtmann   Bluetooth: Use ne...
368
  	switch (hci_skb_pkt_type(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
372
373
374
375
376
377
378
379
380
  	case HCI_COMMAND_PKT:
  		hdev->stat.cmd_tx++;
  		nsh.type = 0x81;
  		break;
  	case HCI_ACLDATA_PKT:
  		hdev->stat.acl_tx++;
  		nsh.type = 0x82;
  		break;
  	case HCI_SCODATA_PKT:
  		hdev->stat.sco_tx++;
  		nsh.type = 0x83;
  		break;
3c4bdc4bd   Marcel Holtmann   Bluetooth: Fix is...
381
382
  	default:
  		return -EILSEQ;
20a7e25f4   Prasanna Karthik   Bluetooth: dtl1_c...
383
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
  
  	nsh.zero = 0;
  	nsh.len = skb->len;
  
  	s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
57136ca6d   Jesper Juhl   [PATCH] Bluetooth...
389
390
  	if (!s)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	skb_reserve(s, NSHL);
d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
392
  	skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
397
398
399
400
401
402
403
404
405
  	if (skb->len & 0x0001)
  		*skb_put(s, 1) = 0;	/* PAD */
  
  	/* Prepend skb with Nokia frame header and queue */
  	memcpy(skb_push(s, NSHL), &nsh, NSHL);
  	skb_queue_tail(&(info->txq), s);
  
  	dtl1_write_wakeup(info);
  
  	kfree_skb(skb);
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
  
  /* ======================== Card services HCI interaction ======================== */
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
408
  static int dtl1_open(struct dtl1_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  {
  	unsigned long flags;
9a017a910   Dominik Brodowski   pcmcia: do not us...
411
  	unsigned int iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  	struct hci_dev *hdev;
  
  	spin_lock_init(&(info->lock));
  
  	skb_queue_head_init(&(info->txq));
  
  	info->rx_state = RECV_WAIT_NSH;
  	info->rx_count = NSHL;
  	info->rx_skb = NULL;
  
  	set_bit(XMIT_WAITING, &(info->tx_state));
  
  	/* Initialize HCI device */
  	hdev = hci_alloc_dev();
  	if (!hdev) {
  		BT_ERR("Can't allocate HCI device");
  		return -ENOMEM;
  	}
  
  	info->hdev = hdev;
c13854cef   Marcel Holtmann   Bluetooth: Conver...
432
  	hdev->bus = HCI_PCCARD;
155961e80   David Herrmann   Bluetooth: Remove...
433
  	hci_set_drvdata(hdev, info);
27d352842   Marcel Holtmann   [Bluetooth] Add p...
434
  	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435

3c7288422   Marcel Holtmann   Bluetooth: Remove...
436
437
438
439
  	hdev->open  = dtl1_hci_open;
  	hdev->close = dtl1_hci_close;
  	hdev->flush = dtl1_hci_flush;
  	hdev->send  = dtl1_hci_send_frame;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
449
450
451
  	spin_lock_irqsave(&(info->lock), flags);
  
  	/* Reset UART */
  	outb(0, iobase + UART_MCR);
  
  	/* Turn off interrupts */
  	outb(0, iobase + UART_IER);
  
  	/* Initialize UART */
  	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
  	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
9a017a910   Dominik Brodowski   pcmcia: do not us...
452
453
  	info->ri_latch = inb(info->p_dev->resource[0]->start + UART_MSR)
  				& UART_MSR_RI;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  
  	/* Turn on interrupts */
  	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
  
  	spin_unlock_irqrestore(&(info->lock), flags);
  
  	/* Timeout before it is safe to send the first HCI packet */
  	msleep(2000);
  
  	/* Register HCI device */
  	if (hci_register_dev(hdev) < 0) {
  		BT_ERR("Can't register HCI device");
  		info->hdev = NULL;
  		hci_free_dev(hdev);
  		return -ENODEV;
  	}
  
  	return 0;
  }
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
473
  static int dtl1_close(struct dtl1_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
  {
  	unsigned long flags;
9a017a910   Dominik Brodowski   pcmcia: do not us...
476
  	unsigned int iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  	struct hci_dev *hdev = info->hdev;
  
  	if (!hdev)
  		return -ENODEV;
  
  	dtl1_hci_close(hdev);
  
  	spin_lock_irqsave(&(info->lock), flags);
  
  	/* Reset UART */
  	outb(0, iobase + UART_MCR);
  
  	/* Turn off interrupts */
  	outb(0, iobase + UART_IER);
  
  	spin_unlock_irqrestore(&(info->lock), flags);
13ea4015d   David Herrmann   Bluetooth: Ignore...
493
  	hci_unregister_dev(hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
  	hci_free_dev(hdev);
  
  	return 0;
  }
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
498
  static int dtl1_probe(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  {
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
500
  	struct dtl1_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
  
  	/* Create new info device */
cd7cf78e9   Sachin Kamat   Bluetooth: Use de...
503
  	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  	if (!info)
f8cfa618d   Dominik Brodowski   [PATCH] pcmcia: u...
505
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
507
  	info->p_dev = link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  	link->priv = info;
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
509
  	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510

15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
511
  	return dtl1_config(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  }
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
513
  static void dtl1_detach(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  {
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
515
  	struct dtl1_info *info = link->priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516

5a0b8159e   David Herrmann   Bluetooth: dtl1: ...
517
518
  	dtl1_close(info);
  	pcmcia_disable_device(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  }
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
520
  static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  {
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
522
  	if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8))
90abdc3b9   Dominik Brodowski   pcmcia: do not us...
523
  		return -ENODEV;
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
524
525
  	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
  	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
90abdc3b9   Dominik Brodowski   pcmcia: do not us...
526
  	return pcmcia_request_io(p_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  }
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
528
  static int dtl1_config(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  {
66f4e0e43   Himangi Saraogi   Bluetooth: Remove...
530
  	struct dtl1_info *info = link->priv;
46afededc   Devendra Naga   Bluetooth: cleanu...
531
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  	/* Look for a generic full-sized window */
90abdc3b9   Dominik Brodowski   pcmcia: do not us...
534
  	link->resource[0]->end = 8;
46afededc   Devendra Naga   Bluetooth: cleanu...
535
536
  	ret = pcmcia_loop_config(link, dtl1_confcheck, NULL);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538

46afededc   Devendra Naga   Bluetooth: cleanu...
539
540
  	ret = pcmcia_request_irq(link, dtl1_interrupt);
  	if (ret)
eb14120f7   Dominik Brodowski   pcmcia: re-work p...
541
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542

46afededc   Devendra Naga   Bluetooth: cleanu...
543
544
  	ret = pcmcia_enable_device(link);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546

46afededc   Devendra Naga   Bluetooth: cleanu...
547
548
  	ret = dtl1_open(info);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  		goto failed;
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
550
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
  failed:
5a0b8159e   David Herrmann   Bluetooth: dtl1: ...
553
  	dtl1_detach(link);
46afededc   Devendra Naga   Bluetooth: cleanu...
554
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  }
25f8f54f6   Joe Perches   pcmcia: Convert p...
556
  static const struct pcmcia_device_id dtl1_ids[] = {
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
557
  	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
8602b4fe6   Marcel Holtmann   [Bluetooth] Add m...
558
  	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
559
  	PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
725a6abfe   Richard Purdie   [PATCH] pcmcia: a...
560
  	PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
561
562
563
  	PCMCIA_DEVICE_NULL
  };
  MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
  static struct pcmcia_driver dtl1_driver = {
  	.owner		= THIS_MODULE,
2e9b981a7   Dominik Brodowski   pcmcia: move driv...
566
  	.name		= "dtl1_cs",
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
567
  	.probe		= dtl1_probe,
cc3b4866b   Dominik Brodowski   [PATCH] pcmcia: u...
568
  	.remove		= dtl1_detach,
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
569
  	.id_table	= dtl1_ids,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  };
e0c005f4b   H Hartley Sweeten   drivers/bluetooth...
571
  module_pcmcia_driver(dtl1_driver);