Blame view

drivers/bluetooth/dtl1_cs.c 13.3 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
40
41
  #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>
  #include <asm/system.h>
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  #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 ======================== */
  
  
  typedef struct dtl1_info_t {
fd238232c   Dominik Brodowski   [PATCH] pcmcia: e...
65
  	struct pcmcia_device *p_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  
  	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;
  } dtl1_info_t;
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
81
  static int dtl1_config(struct pcmcia_device *link);
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
82
  static void dtl1_release(struct pcmcia_device *link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

cc3b4866b   Dominik Brodowski   [PATCH] pcmcia: u...
84
  static void dtl1_detach(struct pcmcia_device *p_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  /* 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
  
  
  typedef struct {
  	u8 type;
  	u8 zero;
  	u16 len;
81ca405ae   Gustavo F. Padovan   Bluetooth: Use __...
101
  } __packed nsh_t;	/* Nokia Specific Header */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  
  #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;
  }
  
  
  static void dtl1_write_wakeup(dtl1_info_t *info)
  {
  	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 {
9a017a910   Dominik Brodowski   pcmcia: do not us...
147
  		register unsigned int iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  		register struct sk_buff *skb;
  		register int len;
  
  		clear_bit(XMIT_WAKEUP, &(info->tx_state));
e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
152
  		if (!pcmcia_dev_present(info->p_dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  			return;
  
  		if (!(skb = skb_dequeue(&(info->txq))))
  			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));
  }
  
  
  static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
  {
  	u8 flowmask = *(u8 *)skb->data;
  	int i;
  
  	printk(KERN_INFO "Bluetooth: Nokia control data =");
  	for (i = 0; i < skb->len; i++) {
  		printk(" %02x", skb->data[i]);
  	}
  	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);
  }
  
  
  static void dtl1_receive(dtl1_info_t *info)
  {
  	unsigned int iobase;
  	nsh_t *nsh;
  	int boguscount = 0;
  
  	if (!info) {
  		BT_ERR("Unknown device");
  		return;
  	}
9a017a910   Dominik Brodowski   pcmcia: do not us...
211
  	iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  
  	do {
  		info->hdev->stat.byte_rx++;
  
  		/* Allocate packet */
  		if (info->rx_skb == NULL)
  			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
  				BT_ERR("Can't allocate mem for new packet");
  				info->rx_state = RECV_WAIT_NSH;
  				info->rx_count = NSHL;
  				return;
  			}
  
  		*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
  		nsh = (nsh_t *)info->rx_skb->data;
  
  		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:
0d48d9394   Marcel Holtmann   [Bluetooth]: Move...
238
  				bt_cb(info->rx_skb)->pkt_type = nsh->type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
246
247
  
  				/* 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);
0d48d9394   Marcel Holtmann   [Bluetooth]: Move...
248
  				switch (bt_cb(info->rx_skb)->pkt_type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
  				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 */
  					info->rx_skb->dev = (void *) info->hdev;
0d48d9394   Marcel Holtmann   [Bluetooth]: Move...
258
  					bt_cb(info->rx_skb)->pkt_type &= 0x0f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
  					hci_recv_frame(info->rx_skb);
  					break;
  				default:
  					/* unknown packet */
0d48d9394   Marcel Holtmann   [Bluetooth]: Move...
263
  					BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  					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...
282
  static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
  {
  	dtl1_info_t *info = dev_inst;
  	unsigned int iobase;
  	unsigned char msr;
  	int boguscount = 0;
  	int iir, lsr;
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
289
  	irqreturn_t r = IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290

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

9a017a910   Dominik Brodowski   pcmcia: do not us...
295
  	iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
  
  	spin_lock(&(info->lock));
  
  	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
  	while (iir) {
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
301
  		r = IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
327
328
329
330
331
332
333
334
335
336
337
  		/* 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_...
338
  		r = IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
  	}
  
  	spin_unlock(&(info->lock));
aafcf998c   Alan Cox   pcmcia: IRQ_TYPE_...
342
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  }
  
  
  
  /* ======================== HCI interface ======================== */
  
  
  static int dtl1_hci_open(struct hci_dev *hdev)
  {
  	set_bit(HCI_RUNNING, &(hdev->flags));
  
  	return 0;
  }
  
  
  static int dtl1_hci_flush(struct hci_dev *hdev)
  {
  	dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
  
  	/* Drop TX queue */
  	skb_queue_purge(&(info->txq));
  
  	return 0;
  }
  
  
  static int dtl1_hci_close(struct hci_dev *hdev)
  {
  	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
  		return 0;
  
  	dtl1_hci_flush(hdev);
  
  	return 0;
  }
  
  
  static int dtl1_hci_send_frame(struct sk_buff *skb)
  {
  	dtl1_info_t *info;
  	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
  	struct sk_buff *s;
  	nsh_t nsh;
  
  	if (!hdev) {
  		BT_ERR("Frame for unknown HCI device (hdev=NULL)");
  		return -ENODEV;
  	}
  
  	info = (dtl1_info_t *)(hdev->driver_data);
0d48d9394   Marcel Holtmann   [Bluetooth]: Move...
393
  	switch (bt_cb(skb)->pkt_type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
400
401
402
403
404
405
  	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...
406
407
  	default:
  		return -EILSEQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
412
413
  	};
  
  	nsh.zero = 0;
  	nsh.len = skb->len;
  
  	s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
57136ca6d   Jesper Juhl   [PATCH] Bluetooth...
414
415
  	if (!s)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  	skb_reserve(s, NSHL);
d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
417
  	skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  	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;
  }
  
  
  static void dtl1_hci_destruct(struct hci_dev *hdev)
  {
  }
  
  
  static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
  {
  	return -ENOIOCTLCMD;
  }
  
  
  
  /* ======================== Card services HCI interaction ======================== */
  
  
  static int dtl1_open(dtl1_info_t *info)
  {
  	unsigned long flags;
9a017a910   Dominik Brodowski   pcmcia: do not us...
451
  	unsigned int iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  	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...
472
  	hdev->bus = HCI_PCCARD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  	hdev->driver_data = info;
27d352842   Marcel Holtmann   [Bluetooth] Add p...
474
  	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  
  	hdev->open     = dtl1_hci_open;
  	hdev->close    = dtl1_hci_close;
  	hdev->flush    = dtl1_hci_flush;
  	hdev->send     = dtl1_hci_send_frame;
  	hdev->destruct = dtl1_hci_destruct;
  	hdev->ioctl    = dtl1_hci_ioctl;
  
  	hdev->owner = THIS_MODULE;
  
  	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...
496
497
  	info->ri_latch = inb(info->p_dev->resource[0]->start + UART_MSR)
  				& UART_MSR_RI;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  
  	/* 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;
  }
  
  
  static int dtl1_close(dtl1_info_t *info)
  {
  	unsigned long flags;
9a017a910   Dominik Brodowski   pcmcia: do not us...
522
  	unsigned int iobase = info->p_dev->resource[0]->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  	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...
539
  	hci_unregister_dev(hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
  	hci_free_dev(hdev);
  
  	return 0;
  }
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
544
  static int dtl1_probe(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
  {
  	dtl1_info_t *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
  
  	/* Create new info device */
089b1dbbd   Deepak Saxena   [PATCH] bluetooth...
549
  	info = kzalloc(sizeof(*info), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	if (!info)
f8cfa618d   Dominik Brodowski   [PATCH] pcmcia: u...
551
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552

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

15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
557
  	return dtl1_config(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  }
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
559
  static void dtl1_detach(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
  {
  	dtl1_info_t *info = link->priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562

e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
563
  	dtl1_release(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
  	kfree(info);
  }
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
567
  static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  {
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
569
  	if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8))
90abdc3b9   Dominik Brodowski   pcmcia: do not us...
570
  		return -ENODEV;
00990e7ce   Dominik Brodowski   pcmcia: use autoc...
571
572
  	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...
573
  	return pcmcia_request_io(p_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  }
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
575
  static int dtl1_config(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  	dtl1_info_t *info = link->priv;
af2b3b503   Dominik Brodowski   [PATCH] pcmcia: c...
578
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	/* Look for a generic full-sized window */
90abdc3b9   Dominik Brodowski   pcmcia: do not us...
581
  	link->resource[0]->end = 8;
cb6dbd796   Philipp Zabel   pcmcia: dtl1_cs: ...
582
  	if (pcmcia_loop_config(link, dtl1_confcheck, NULL) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584

eb14120f7   Dominik Brodowski   pcmcia: re-work p...
585
  	i = pcmcia_request_irq(link, dtl1_interrupt);
9ac3e58ce   Dominik Brodowski   pcmcia: deprecate...
586
  	if (i != 0)
eb14120f7   Dominik Brodowski   pcmcia: re-work p...
587
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588

1ac71e5a3   Dominik Brodowski   pcmcia: convert p...
589
  	i = pcmcia_enable_device(link);
9ac3e58ce   Dominik Brodowski   pcmcia: deprecate...
590
  	if (i != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
  
  	if (dtl1_open(info) != 0)
  		goto failed;
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
595
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  failed:
  	dtl1_release(link);
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
599
  	return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  }
fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
601
  static void dtl1_release(struct pcmcia_device *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
  {
  	dtl1_info_t *info = link->priv;
e2d409636   Dominik Brodowski   [PATCH] pcmcia: u...
604
  	dtl1_close(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605

fba395eee   Dominik Brodowski   [PATCH] pcmcia: r...
606
  	pcmcia_disable_device(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608

25f8f54f6   Joe Perches   pcmcia: Convert p...
609
  static const struct pcmcia_device_id dtl1_ids[] = {
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
610
  	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
8602b4fe6   Marcel Holtmann   [Bluetooth] Add m...
611
  	PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
612
  	PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
725a6abfe   Richard Purdie   [PATCH] pcmcia: a...
613
  	PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
614
615
616
  	PCMCIA_DEVICE_NULL
  };
  MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
  static struct pcmcia_driver dtl1_driver = {
  	.owner		= THIS_MODULE,
2e9b981a7   Dominik Brodowski   pcmcia: move driv...
619
  	.name		= "dtl1_cs",
15b99ac17   Dominik Brodowski   [PATCH] pcmcia: a...
620
  	.probe		= dtl1_probe,
cc3b4866b   Dominik Brodowski   [PATCH] pcmcia: u...
621
  	.remove		= dtl1_detach,
88eca2e52   Dominik Brodowski   [PATCH] pcmcia: i...
622
  	.id_table	= dtl1_ids,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
627
628
629
630
631
632
633
  };
  
  static int __init init_dtl1_cs(void)
  {
  	return pcmcia_register_driver(&dtl1_driver);
  }
  
  
  static void __exit exit_dtl1_cs(void)
  {
  	pcmcia_unregister_driver(&dtl1_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
  }
  
  module_init(init_dtl1_cs);
  module_exit(exit_dtl1_cs);