File: /usr/src/linux/drivers/isdn/avmb1/b1pcmcia.c

1     /*
2      * $Id: b1pcmcia.c,v 1.12.6.4 2001/05/17 20:41:51 kai Exp $
3      * 
4      * Module for AVM B1/M1/M2 PCMCIA-card.
5      * 
6      * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
7      * 
8      */
9     
10     #include <linux/module.h>
11     #include <linux/kernel.h>
12     #include <linux/skbuff.h>
13     #include <linux/delay.h>
14     #include <linux/mm.h>
15     #include <linux/interrupt.h>
16     #include <linux/ioport.h>
17     #include <linux/init.h>
18     #include <asm/io.h>
19     #include <linux/capi.h>
20     #include <linux/b1pcmcia.h>
21     #include "capicmd.h"
22     #include "capiutil.h"
23     #include "capilli.h"
24     #include "avmcard.h"
25     
26     static char *revision = "$Revision: 1.12.6.4 $";
27     
28     /* ------------------------------------------------------------- */
29     
30     MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
31     
32     /* ------------------------------------------------------------- */
33     
34     static struct capi_driver_interface *di;
35     
36     /* ------------------------------------------------------------- */
37     
38     static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
39     {
40     	avmcard *card;
41     
42     	card = (avmcard *) devptr;
43     
44     	if (!card) {
45     		printk(KERN_WARNING "b1pcmcia: interrupt: wrong device\n");
46     		return;
47     	}
48     	if (card->interrupt) {
49     		printk(KERN_ERR "%s: reentering interrupt hander.\n",
50     			card->name);
51     		return;
52     	}
53     
54     	card->interrupt = 1;
55     
56     	b1_handle_interrupt(card);
57     
58     	card->interrupt = 0;
59     }
60     /* ------------------------------------------------------------- */
61     
62     static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
63     {
64     	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
65     	avmcard *card = cinfo->card;
66     	unsigned int port = card->port;
67     
68     	b1_reset(port);
69     	b1_reset(port);
70     
71     	di->detach_ctr(ctrl);
72     	free_irq(card->irq, card);
73     	/* io addrsses managent by CardServices 
74     	 * release_region(card->port, AVMB1_PORTLEN);
75     	 */
76     	kfree(card);
77     
78     	MOD_DEC_USE_COUNT;
79     }
80     
81     /* ------------------------------------------------------------- */
82     
83     static int b1pcmcia_add_card(struct capi_driver *driver,
84     				unsigned int port,
85     				unsigned irq,
86     				enum avmcardtype cardtype)
87     {
88     	avmctrl_info *cinfo;
89     	avmcard *card;
90     	char *cardname;
91     	int retval;
92     
93     	MOD_INC_USE_COUNT;
94     
95     	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
96     
97     	if (!card) {
98     		printk(KERN_WARNING "%s: no memory.\n", driver->name);
99     	        MOD_DEC_USE_COUNT;
100     		return -ENOMEM;
101     	}
102     	memset(card, 0, sizeof(avmcard));
103             cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
104     	if (!cinfo) {
105     		printk(KERN_WARNING "%s: no memory.\n", driver->name);
106     		kfree(card);
107     	        MOD_DEC_USE_COUNT;
108     		return -ENOMEM;
109     	}
110     	memset(cinfo, 0, sizeof(avmctrl_info));
111     	card->ctrlinfo = cinfo;
112     	cinfo->card = card;
113     	switch (cardtype) {
114     		case avm_m1: sprintf(card->name, "m1-%x", port); break;
115     		case avm_m2: sprintf(card->name, "m2-%x", port); break;
116     		default: sprintf(card->name, "b1pcmcia-%x", port); break;
117     	}
118     	card->port = port;
119     	card->irq = irq;
120     	card->cardtype = cardtype;
121     
122     	b1_reset(card->port);
123     	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
124     		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
125     					driver->name, card->port, retval);
126     	        kfree(card->ctrlinfo);
127     		kfree(card);
128     	        MOD_DEC_USE_COUNT;
129     		return -EIO;
130     	}
131     	b1_reset(card->port);
132     	b1_getrevision(card);
133     
134     	retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
135     	if (retval) {
136     		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
137     				driver->name, card->irq);
138     	        kfree(card->ctrlinfo);
139     		kfree(card);
140     	        MOD_DEC_USE_COUNT;
141     		return -EBUSY;
142     	}
143     
144     	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
145     	if (!cinfo->capi_ctrl) {
146     		printk(KERN_ERR "%s: attach controller failed.\n",
147     				driver->name);
148     		free_irq(card->irq, card);
149     	        kfree(card->ctrlinfo);
150     		kfree(card);
151     	        MOD_DEC_USE_COUNT;
152     		return -EBUSY;
153     	}
154     	switch (cardtype) {
155     		case avm_m1: cardname = "M1"; break;
156     		case avm_m2: cardname = "M2"; break;
157     		default    : cardname = "B1 PCMCIA"; break;
158     	}
159     
160     	printk(KERN_INFO
161     		"%s: AVM %s at i/o %#x, irq %d, revision %d\n",
162     		driver->name, cardname, card->port, card->irq, card->revision);
163     
164     	return cinfo->capi_ctrl->cnr;
165     }
166     
167     /* ------------------------------------------------------------- */
168     
169     static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
170     {
171     	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
172     
173     	if (!cinfo)
174     		return "";
175     	sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
176     		cinfo->cardname[0] ? cinfo->cardname : "-",
177     		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
178     		cinfo->card ? cinfo->card->port : 0x0,
179     		cinfo->card ? cinfo->card->irq : 0,
180     		cinfo->card ? cinfo->card->revision : 0
181     		);
182     	return cinfo->infobuf;
183     }
184     
185     /* ------------------------------------------------------------- */
186     
187     static struct capi_driver b1pcmcia_driver = {
188         name: "b1pcmcia",
189         revision: "0.0",
190         load_firmware: b1_load_firmware,
191         reset_ctr: b1_reset_ctr,
192         remove_ctr: b1pcmcia_remove_ctr,
193         register_appl: b1_register_appl,
194         release_appl: b1_release_appl,
195         send_message: b1_send_message,
196     
197         procinfo: b1pcmcia_procinfo,
198         ctr_read_proc: b1ctl_read_proc,
199         driver_read_proc: 0,	/* use standard driver_read_proc */
200     
201         add_card: 0,
202     };
203     
204     /* ------------------------------------------------------------- */
205     
206     int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
207     {
208     	return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_b1pcmcia);
209     }
210     
211     int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
212     {
213     	return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m1);
214     }
215     
216     int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
217     {
218     	return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m2);
219     }
220     
221     int b1pcmcia_delcard(unsigned int port, unsigned irq)
222     {
223     	struct capi_ctr *ctrl;
224     	avmcard *card;
225     
226     	for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
227     		card = ((avmctrl_info *)(ctrl->driverdata))->card;
228     		if (card->port == port && card->irq == irq) {
229     			b1pcmcia_remove_ctr(ctrl);
230     			return 0;
231     		}
232     	}
233     	return -ESRCH;
234     }
235     
236     EXPORT_SYMBOL(b1pcmcia_addcard_b1);
237     EXPORT_SYMBOL(b1pcmcia_addcard_m1);
238     EXPORT_SYMBOL(b1pcmcia_addcard_m2);
239     EXPORT_SYMBOL(b1pcmcia_delcard);
240     
241     /* ------------------------------------------------------------- */
242     
243     static int __init b1pcmcia_init(void)
244     {
245     	struct capi_driver *driver = &b1pcmcia_driver;
246     	char *p;
247     	int retval = 0;
248     
249     	MOD_INC_USE_COUNT;
250     
251     	if ((p = strchr(revision, ':')) != 0 && p[1]) {
252     		strncpy(driver->revision, p + 2, sizeof(driver->revision));
253     		driver->revision[sizeof(driver->revision)-1] = 0;
254     		if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision)
255     			*(p-1) = 0;
256     	}
257     
258     	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
259     
260             di = attach_capi_driver(driver);
261     
262     	if (!di) {
263     		printk(KERN_ERR "%s: failed to attach capi_driver\n",
264     				driver->name);
265     		retval = -EIO;
266     	}
267     	MOD_DEC_USE_COUNT;
268     	return retval;
269     }
270     
271     static void __exit b1pcmcia_exit(void)
272     {
273         detach_capi_driver(&b1pcmcia_driver);
274     }
275     
276     module_init(b1pcmcia_init);
277     module_exit(b1pcmcia_exit);
278