diff options
Diffstat (limited to 'drivers/isdn/hardware/avm/t1pci.c')
-rw-r--r-- | drivers/isdn/hardware/avm/t1pci.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c new file mode 100644 index 000000000000..2ceec8e8419f --- /dev/null +++ b/drivers/isdn/hardware/avm/t1pci.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM T1 PCI-card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.de> | ||
6 | * | ||
7 | * This software may be used and distributed according to the terms | ||
8 | * of the GNU General Public License, incorporated herein by reference. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/capi.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/isdn/capicmd.h> | ||
25 | #include <linux/isdn/capiutil.h> | ||
26 | #include <linux/isdn/capilli.h> | ||
27 | #include "avmcard.h" | ||
28 | |||
29 | #undef CONFIG_T1PCI_DEBUG | ||
30 | #undef CONFIG_T1PCI_POLLDEBUG | ||
31 | |||
32 | /* ------------------------------------------------------------- */ | ||
33 | static char *revision = "$Revision: 1.1.2.2 $"; | ||
34 | /* ------------------------------------------------------------- */ | ||
35 | |||
36 | static struct pci_device_id t1pci_pci_tbl[] = { | ||
37 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID }, | ||
38 | { } /* Terminating entry */ | ||
39 | }; | ||
40 | |||
41 | MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl); | ||
42 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card"); | ||
43 | MODULE_AUTHOR("Carsten Paeth"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | /* ------------------------------------------------------------- */ | ||
47 | |||
48 | static char *t1pci_procinfo(struct capi_ctr *ctrl); | ||
49 | |||
50 | static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) | ||
51 | { | ||
52 | avmcard *card; | ||
53 | avmctrl_info *cinfo; | ||
54 | int retval; | ||
55 | |||
56 | card = b1_alloc_card(1); | ||
57 | if (!card) { | ||
58 | printk(KERN_WARNING "t1pci: no memory.\n"); | ||
59 | retval = -ENOMEM; | ||
60 | goto err; | ||
61 | } | ||
62 | |||
63 | card->dma = avmcard_dma_alloc("t1pci", pdev, 2048+128, 2048+128); | ||
64 | if (!card->dma) { | ||
65 | printk(KERN_WARNING "t1pci: no memory.\n"); | ||
66 | retval = -ENOMEM; | ||
67 | goto err_free; | ||
68 | } | ||
69 | |||
70 | cinfo = card->ctrlinfo; | ||
71 | sprintf(card->name, "t1pci-%x", p->port); | ||
72 | card->port = p->port; | ||
73 | card->irq = p->irq; | ||
74 | card->membase = p->membase; | ||
75 | card->cardtype = avm_t1pci; | ||
76 | |||
77 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
78 | printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n", | ||
79 | card->port, card->port + AVMB1_PORTLEN); | ||
80 | retval = -EBUSY; | ||
81 | goto err_free_dma; | ||
82 | } | ||
83 | |||
84 | card->mbase = ioremap(card->membase, 64); | ||
85 | if (!card->mbase) { | ||
86 | printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n", | ||
87 | card->membase); | ||
88 | retval = -EIO; | ||
89 | goto err_release_region; | ||
90 | } | ||
91 | |||
92 | b1dma_reset(card); | ||
93 | |||
94 | retval = t1pci_detect(card); | ||
95 | if (retval != 0) { | ||
96 | if (retval < 6) | ||
97 | printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n", | ||
98 | card->port, retval); | ||
99 | else | ||
100 | printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n", | ||
101 | card->port, retval); | ||
102 | retval = -EIO; | ||
103 | goto err_unmap; | ||
104 | } | ||
105 | b1dma_reset(card); | ||
106 | |||
107 | retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); | ||
108 | if (retval) { | ||
109 | printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq); | ||
110 | retval = -EBUSY; | ||
111 | goto err_unmap; | ||
112 | } | ||
113 | |||
114 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
115 | cinfo->capi_ctrl.driver_name = "t1pci"; | ||
116 | cinfo->capi_ctrl.driverdata = cinfo; | ||
117 | cinfo->capi_ctrl.register_appl = b1dma_register_appl; | ||
118 | cinfo->capi_ctrl.release_appl = b1dma_release_appl; | ||
119 | cinfo->capi_ctrl.send_message = b1dma_send_message; | ||
120 | cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; | ||
121 | cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; | ||
122 | cinfo->capi_ctrl.procinfo = t1pci_procinfo; | ||
123 | cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; | ||
124 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
125 | |||
126 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
127 | if (retval) { | ||
128 | printk(KERN_ERR "t1pci: attach controller failed.\n"); | ||
129 | retval = -EBUSY; | ||
130 | goto err_free_irq; | ||
131 | } | ||
132 | card->cardnr = cinfo->capi_ctrl.cnr; | ||
133 | |||
134 | printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n", | ||
135 | card->port, card->irq, card->membase); | ||
136 | |||
137 | pci_set_drvdata(pdev, card); | ||
138 | return 0; | ||
139 | |||
140 | err_free_irq: | ||
141 | free_irq(card->irq, card); | ||
142 | err_unmap: | ||
143 | iounmap(card->mbase); | ||
144 | err_release_region: | ||
145 | release_region(card->port, AVMB1_PORTLEN); | ||
146 | err_free_dma: | ||
147 | avmcard_dma_free(card->dma); | ||
148 | err_free: | ||
149 | b1_free_card(card); | ||
150 | err: | ||
151 | return retval; | ||
152 | } | ||
153 | |||
154 | /* ------------------------------------------------------------- */ | ||
155 | |||
156 | static void t1pci_remove(struct pci_dev *pdev) | ||
157 | { | ||
158 | avmcard *card = pci_get_drvdata(pdev); | ||
159 | avmctrl_info *cinfo = card->ctrlinfo; | ||
160 | |||
161 | b1dma_reset(card); | ||
162 | |||
163 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
164 | free_irq(card->irq, card); | ||
165 | iounmap(card->mbase); | ||
166 | release_region(card->port, AVMB1_PORTLEN); | ||
167 | avmcard_dma_free(card->dma); | ||
168 | b1_free_card(card); | ||
169 | } | ||
170 | |||
171 | /* ------------------------------------------------------------- */ | ||
172 | |||
173 | static char *t1pci_procinfo(struct capi_ctr *ctrl) | ||
174 | { | ||
175 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
176 | |||
177 | if (!cinfo) | ||
178 | return ""; | ||
179 | sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", | ||
180 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
181 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
182 | cinfo->card ? cinfo->card->port : 0x0, | ||
183 | cinfo->card ? cinfo->card->irq : 0, | ||
184 | cinfo->card ? cinfo->card->membase : 0 | ||
185 | ); | ||
186 | return cinfo->infobuf; | ||
187 | } | ||
188 | |||
189 | /* ------------------------------------------------------------- */ | ||
190 | |||
191 | static int __devinit t1pci_probe(struct pci_dev *dev, | ||
192 | const struct pci_device_id *ent) | ||
193 | { | ||
194 | struct capicardparams param; | ||
195 | int retval; | ||
196 | |||
197 | if (pci_enable_device(dev) < 0) { | ||
198 | printk(KERN_ERR "t1pci: failed to enable AVM-T1-PCI\n"); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | pci_set_master(dev); | ||
202 | |||
203 | param.port = pci_resource_start(dev, 1); | ||
204 | param.irq = dev->irq; | ||
205 | param.membase = pci_resource_start(dev, 0); | ||
206 | |||
207 | printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n", | ||
208 | param.port, param.irq, param.membase); | ||
209 | |||
210 | retval = t1pci_add_card(¶m, dev); | ||
211 | if (retval != 0) { | ||
212 | printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n", | ||
213 | param.port, param.irq, param.membase); | ||
214 | return -ENODEV; | ||
215 | } | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static struct pci_driver t1pci_pci_driver = { | ||
220 | .name = "t1pci", | ||
221 | .id_table = t1pci_pci_tbl, | ||
222 | .probe = t1pci_probe, | ||
223 | .remove = t1pci_remove, | ||
224 | }; | ||
225 | |||
226 | static struct capi_driver capi_driver_t1pci = { | ||
227 | .name = "t1pci", | ||
228 | .revision = "1.0", | ||
229 | }; | ||
230 | |||
231 | static int __init t1pci_init(void) | ||
232 | { | ||
233 | char *p; | ||
234 | char rev[32]; | ||
235 | int err; | ||
236 | |||
237 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
238 | strlcpy(rev, p + 2, 32); | ||
239 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
240 | *(p-1) = 0; | ||
241 | } else | ||
242 | strcpy(rev, "1.0"); | ||
243 | |||
244 | err = pci_register_driver(&t1pci_pci_driver); | ||
245 | if (!err) { | ||
246 | strlcpy(capi_driver_t1pci.revision, rev, 32); | ||
247 | register_capi_driver(&capi_driver_t1pci); | ||
248 | printk(KERN_INFO "t1pci: revision %s\n", rev); | ||
249 | } | ||
250 | return err; | ||
251 | } | ||
252 | |||
253 | static void __exit t1pci_exit(void) | ||
254 | { | ||
255 | unregister_capi_driver(&capi_driver_t1pci); | ||
256 | pci_unregister_driver(&t1pci_pci_driver); | ||
257 | } | ||
258 | |||
259 | module_init(t1pci_init); | ||
260 | module_exit(t1pci_exit); | ||