]>
Commit | Line | Data |
---|---|---|
6115d2f3 KK |
1 | /* |
2 | * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards | |
3 | * Thanks to AVM, Berlin for informations | |
4 | * | |
5 | * Author Karsten Keil <keil@isdn4linux.de> | |
6 | * | |
7 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | * | |
22 | */ | |
23 | #include <linux/module.h> | |
24 | #include <linux/pci.h> | |
25 | #include <linux/delay.h> | |
26 | #include <linux/mISDNhw.h> | |
5a0e3ad6 | 27 | #include <linux/slab.h> |
6115d2f3 KK |
28 | #include <asm/unaligned.h> |
29 | #include "ipac.h" | |
30 | ||
31 | ||
32 | #define AVMFRITZ_REV "2.1" | |
33 | ||
34 | static int AVM_cnt; | |
35 | static int debug; | |
36 | ||
37 | enum { | |
38 | AVM_FRITZ_PCI, | |
39 | AVM_FRITZ_PCIV2, | |
40 | }; | |
41 | ||
42 | #define HDLC_FIFO 0x0 | |
43 | #define HDLC_STATUS 0x4 | |
44 | #define CHIP_WINDOW 0x10 | |
45 | ||
46 | #define CHIP_INDEX 0x4 | |
47 | #define AVM_HDLC_1 0x00 | |
48 | #define AVM_HDLC_2 0x01 | |
49 | #define AVM_ISAC_FIFO 0x02 | |
50 | #define AVM_ISAC_REG_LOW 0x04 | |
51 | #define AVM_ISAC_REG_HIGH 0x06 | |
52 | ||
53 | #define AVM_STATUS0_IRQ_ISAC 0x01 | |
54 | #define AVM_STATUS0_IRQ_HDLC 0x02 | |
55 | #define AVM_STATUS0_IRQ_TIMER 0x04 | |
56 | #define AVM_STATUS0_IRQ_MASK 0x07 | |
57 | ||
58 | #define AVM_STATUS0_RESET 0x01 | |
59 | #define AVM_STATUS0_DIS_TIMER 0x02 | |
60 | #define AVM_STATUS0_RES_TIMER 0x04 | |
61 | #define AVM_STATUS0_ENA_IRQ 0x08 | |
62 | #define AVM_STATUS0_TESTBIT 0x10 | |
63 | ||
64 | #define AVM_STATUS1_INT_SEL 0x0f | |
65 | #define AVM_STATUS1_ENA_IOM 0x80 | |
66 | ||
67 | #define HDLC_MODE_ITF_FLG 0x01 | |
68 | #define HDLC_MODE_TRANS 0x02 | |
69 | #define HDLC_MODE_CCR_7 0x04 | |
70 | #define HDLC_MODE_CCR_16 0x08 | |
71 | #define HDLC_MODE_TESTLOOP 0x80 | |
72 | ||
73 | #define HDLC_INT_XPR 0x80 | |
74 | #define HDLC_INT_XDU 0x40 | |
75 | #define HDLC_INT_RPR 0x20 | |
76 | #define HDLC_INT_MASK 0xE0 | |
77 | ||
78 | #define HDLC_STAT_RME 0x01 | |
79 | #define HDLC_STAT_RDO 0x10 | |
80 | #define HDLC_STAT_CRCVFRRAB 0x0E | |
81 | #define HDLC_STAT_CRCVFR 0x06 | |
82 | #define HDLC_STAT_RML_MASK 0x3f00 | |
83 | ||
84 | #define HDLC_CMD_XRS 0x80 | |
85 | #define HDLC_CMD_XME 0x01 | |
86 | #define HDLC_CMD_RRS 0x20 | |
87 | #define HDLC_CMD_XML_MASK 0x3f00 | |
88 | #define HDLC_FIFO_SIZE 32 | |
89 | ||
90 | /* Fritz PCI v2.0 */ | |
91 | ||
92 | #define AVM_HDLC_FIFO_1 0x10 | |
93 | #define AVM_HDLC_FIFO_2 0x18 | |
94 | ||
95 | #define AVM_HDLC_STATUS_1 0x14 | |
96 | #define AVM_HDLC_STATUS_2 0x1c | |
97 | ||
98 | #define AVM_ISACX_INDEX 0x04 | |
99 | #define AVM_ISACX_DATA 0x08 | |
100 | ||
101 | /* data struct */ | |
102 | #define LOG_SIZE 63 | |
103 | ||
104 | struct hdlc_stat_reg { | |
105 | #ifdef __BIG_ENDIAN | |
106 | u8 fill; | |
107 | u8 mode; | |
108 | u8 xml; | |
109 | u8 cmd; | |
110 | #else | |
111 | u8 cmd; | |
112 | u8 xml; | |
113 | u8 mode; | |
114 | u8 fill; | |
115 | #endif | |
116 | } __attribute__((packed)); | |
117 | ||
118 | struct hdlc_hw { | |
119 | union { | |
120 | u32 ctrl; | |
121 | struct hdlc_stat_reg sr; | |
122 | } ctrl; | |
123 | u32 stat; | |
124 | }; | |
125 | ||
126 | struct fritzcard { | |
127 | struct list_head list; | |
128 | struct pci_dev *pdev; | |
129 | char name[MISDN_MAX_IDLEN]; | |
130 | u8 type; | |
131 | u8 ctrlreg; | |
132 | u16 irq; | |
133 | u32 irqcnt; | |
134 | u32 addr; | |
135 | spinlock_t lock; /* hw lock */ | |
136 | struct isac_hw isac; | |
137 | struct hdlc_hw hdlc[2]; | |
138 | struct bchannel bch[2]; | |
139 | char log[LOG_SIZE + 1]; | |
140 | }; | |
141 | ||
142 | static LIST_HEAD(Cards); | |
143 | static DEFINE_RWLOCK(card_lock); /* protect Cards */ | |
144 | ||
145 | static void | |
146 | _set_debug(struct fritzcard *card) | |
147 | { | |
148 | card->isac.dch.debug = debug; | |
149 | card->bch[0].debug = debug; | |
150 | card->bch[1].debug = debug; | |
151 | } | |
152 | ||
153 | static int | |
154 | set_debug(const char *val, struct kernel_param *kp) | |
155 | { | |
156 | int ret; | |
157 | struct fritzcard *card; | |
158 | ||
159 | ret = param_set_uint(val, kp); | |
160 | if (!ret) { | |
161 | read_lock(&card_lock); | |
162 | list_for_each_entry(card, &Cards, list) | |
163 | _set_debug(card); | |
164 | read_unlock(&card_lock); | |
165 | } | |
166 | return ret; | |
167 | } | |
168 | ||
169 | MODULE_AUTHOR("Karsten Keil"); | |
170 | MODULE_LICENSE("GPL v2"); | |
171 | MODULE_VERSION(AVMFRITZ_REV); | |
172 | module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); | |
173 | MODULE_PARM_DESC(debug, "avmfritz debug mask"); | |
174 | ||
175 | /* Interface functions */ | |
176 | ||
177 | static u8 | |
178 | ReadISAC_V1(void *p, u8 offset) | |
179 | { | |
180 | struct fritzcard *fc = p; | |
181 | u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; | |
182 | ||
183 | outb(idx, fc->addr + CHIP_INDEX); | |
184 | return inb(fc->addr + CHIP_WINDOW + (offset & 0xf)); | |
185 | } | |
186 | ||
187 | static void | |
188 | WriteISAC_V1(void *p, u8 offset, u8 value) | |
189 | { | |
190 | struct fritzcard *fc = p; | |
191 | u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; | |
192 | ||
193 | outb(idx, fc->addr + CHIP_INDEX); | |
194 | outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf)); | |
195 | } | |
196 | ||
197 | static void | |
198 | ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size) | |
199 | { | |
200 | struct fritzcard *fc = p; | |
201 | ||
202 | outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); | |
203 | insb(fc->addr + CHIP_WINDOW, data, size); | |
204 | } | |
205 | ||
206 | static void | |
207 | WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size) | |
208 | { | |
209 | struct fritzcard *fc = p; | |
210 | ||
211 | outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); | |
212 | outsb(fc->addr + CHIP_WINDOW, data, size); | |
213 | } | |
214 | ||
215 | static u8 | |
216 | ReadISAC_V2(void *p, u8 offset) | |
217 | { | |
218 | struct fritzcard *fc = p; | |
219 | ||
220 | outl(offset, fc->addr + AVM_ISACX_INDEX); | |
221 | return 0xff & inl(fc->addr + AVM_ISACX_DATA); | |
222 | } | |
223 | ||
224 | static void | |
225 | WriteISAC_V2(void *p, u8 offset, u8 value) | |
226 | { | |
227 | struct fritzcard *fc = p; | |
228 | ||
229 | outl(offset, fc->addr + AVM_ISACX_INDEX); | |
230 | outl(value, fc->addr + AVM_ISACX_DATA); | |
231 | } | |
232 | ||
233 | static void | |
234 | ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size) | |
235 | { | |
236 | struct fritzcard *fc = p; | |
237 | int i; | |
238 | ||
239 | outl(off, fc->addr + AVM_ISACX_INDEX); | |
240 | for (i = 0; i < size; i++) | |
241 | data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA); | |
242 | } | |
243 | ||
244 | static void | |
245 | WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size) | |
246 | { | |
247 | struct fritzcard *fc = p; | |
248 | int i; | |
249 | ||
250 | outl(off, fc->addr + AVM_ISACX_INDEX); | |
251 | for (i = 0; i < size; i++) | |
252 | outl(data[i], fc->addr + AVM_ISACX_DATA); | |
253 | } | |
254 | ||
255 | static struct bchannel * | |
256 | Sel_BCS(struct fritzcard *fc, u32 channel) | |
257 | { | |
258 | if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && | |
259 | (fc->bch[0].nr & channel)) | |
260 | return &fc->bch[0]; | |
261 | else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && | |
262 | (fc->bch[1].nr & channel)) | |
263 | return &fc->bch[1]; | |
264 | else | |
265 | return NULL; | |
266 | } | |
267 | ||
268 | static inline void | |
269 | __write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { | |
270 | u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1; | |
271 | ||
272 | outl(idx, fc->addr + CHIP_INDEX); | |
273 | outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS); | |
274 | } | |
275 | ||
276 | static inline void | |
277 | __write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { | |
278 | outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 : | |
279 | AVM_HDLC_STATUS_1)); | |
280 | } | |
281 | ||
282 | void | |
283 | write_ctrl(struct bchannel *bch, int which) { | |
284 | struct fritzcard *fc = bch->hw; | |
285 | struct hdlc_hw *hdlc; | |
286 | ||
287 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | |
288 | pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr, | |
289 | which, hdlc->ctrl.ctrl); | |
290 | switch (fc->type) { | |
291 | case AVM_FRITZ_PCIV2: | |
292 | __write_ctrl_pciv2(fc, hdlc, bch->nr); | |
293 | break; | |
294 | case AVM_FRITZ_PCI: | |
295 | __write_ctrl_pci(fc, hdlc, bch->nr); | |
296 | break; | |
297 | } | |
298 | } | |
299 | ||
300 | ||
301 | static inline u32 | |
302 | __read_status_pci(u_long addr, u32 channel) | |
303 | { | |
304 | outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX); | |
305 | return inl(addr + CHIP_WINDOW + HDLC_STATUS); | |
306 | } | |
307 | ||
308 | static inline u32 | |
309 | __read_status_pciv2(u_long addr, u32 channel) | |
310 | { | |
311 | return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 : | |
312 | AVM_HDLC_STATUS_1)); | |
313 | } | |
314 | ||
315 | ||
316 | static u32 | |
317 | read_status(struct fritzcard *fc, u32 channel) | |
318 | { | |
319 | switch (fc->type) { | |
320 | case AVM_FRITZ_PCIV2: | |
321 | return __read_status_pciv2(fc->addr, channel); | |
322 | case AVM_FRITZ_PCI: | |
323 | return __read_status_pci(fc->addr, channel); | |
324 | } | |
325 | /* dummy */ | |
326 | return 0; | |
327 | } | |
328 | ||
329 | static void | |
330 | enable_hwirq(struct fritzcard *fc) | |
331 | { | |
332 | fc->ctrlreg |= AVM_STATUS0_ENA_IRQ; | |
333 | outb(fc->ctrlreg, fc->addr + 2); | |
334 | } | |
335 | ||
336 | static void | |
337 | disable_hwirq(struct fritzcard *fc) | |
338 | { | |
339 | fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ; | |
340 | outb(fc->ctrlreg, fc->addr + 2); | |
341 | } | |
342 | ||
343 | static int | |
344 | modehdlc(struct bchannel *bch, int protocol) | |
345 | { | |
346 | struct fritzcard *fc = bch->hw; | |
347 | struct hdlc_hw *hdlc; | |
348 | ||
349 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | |
350 | pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, | |
351 | '@' + bch->nr, bch->state, protocol, bch->nr); | |
352 | hdlc->ctrl.ctrl = 0; | |
353 | switch (protocol) { | |
354 | case -1: /* used for init */ | |
355 | bch->state = -1; | |
356 | case ISDN_P_NONE: | |
357 | if (bch->state == ISDN_P_NONE) | |
358 | break; | |
359 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; | |
360 | hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; | |
361 | write_ctrl(bch, 5); | |
362 | bch->state = ISDN_P_NONE; | |
363 | test_and_clear_bit(FLG_HDLC, &bch->Flags); | |
364 | test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); | |
365 | break; | |
366 | case ISDN_P_B_RAW: | |
367 | bch->state = protocol; | |
368 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; | |
369 | hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; | |
370 | write_ctrl(bch, 5); | |
371 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; | |
372 | write_ctrl(bch, 1); | |
373 | hdlc->ctrl.sr.cmd = 0; | |
374 | test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); | |
375 | break; | |
376 | case ISDN_P_B_HDLC: | |
377 | bch->state = protocol; | |
378 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; | |
379 | hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG; | |
380 | write_ctrl(bch, 5); | |
381 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; | |
382 | write_ctrl(bch, 1); | |
383 | hdlc->ctrl.sr.cmd = 0; | |
384 | test_and_set_bit(FLG_HDLC, &bch->Flags); | |
385 | break; | |
386 | default: | |
387 | pr_info("%s: protocol not known %x\n", fc->name, protocol); | |
388 | return -ENOPROTOOPT; | |
389 | } | |
390 | return 0; | |
391 | } | |
392 | ||
393 | static void | |
394 | hdlc_empty_fifo(struct bchannel *bch, int count) | |
395 | { | |
396 | u32 *ptr; | |
397 | u8 *p; | |
398 | u32 val, addr; | |
399 | int cnt = 0; | |
400 | struct fritzcard *fc = bch->hw; | |
401 | ||
402 | pr_debug("%s: %s %d\n", fc->name, __func__, count); | |
403 | if (!bch->rx_skb) { | |
404 | bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); | |
405 | if (!bch->rx_skb) { | |
406 | pr_info("%s: B receive out of memory\n", | |
407 | fc->name); | |
408 | return; | |
409 | } | |
410 | } | |
411 | if ((bch->rx_skb->len + count) > bch->maxlen) { | |
412 | pr_debug("%s: overrun %d\n", fc->name, | |
413 | bch->rx_skb->len + count); | |
414 | return; | |
415 | } | |
416 | p = skb_put(bch->rx_skb, count); | |
417 | ptr = (u32 *)p; | |
418 | if (AVM_FRITZ_PCIV2 == fc->type) | |
419 | addr = fc->addr + (bch->nr == 2 ? | |
420 | AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); | |
421 | else { | |
422 | addr = fc->addr + CHIP_WINDOW; | |
423 | outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); | |
424 | } | |
425 | while (cnt < count) { | |
426 | val = le32_to_cpu(inl(addr)); | |
427 | put_unaligned(val, ptr); | |
428 | ptr++; | |
429 | cnt += 4; | |
430 | } | |
431 | if (debug & DEBUG_HW_BFIFO) { | |
432 | snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", | |
433 | bch->nr, fc->name, count); | |
434 | print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); | |
435 | } | |
436 | } | |
437 | ||
438 | static void | |
439 | hdlc_fill_fifo(struct bchannel *bch) | |
440 | { | |
441 | struct fritzcard *fc = bch->hw; | |
442 | struct hdlc_hw *hdlc; | |
443 | int count, cnt = 0; | |
444 | u8 *p; | |
445 | u32 *ptr, val, addr; | |
446 | ||
447 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | |
448 | if (!bch->tx_skb) | |
449 | return; | |
450 | count = bch->tx_skb->len - bch->tx_idx; | |
451 | if (count <= 0) | |
452 | return; | |
453 | p = bch->tx_skb->data + bch->tx_idx; | |
454 | hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; | |
455 | if (count > HDLC_FIFO_SIZE) { | |
456 | count = HDLC_FIFO_SIZE; | |
457 | } else { | |
458 | if (test_bit(FLG_HDLC, &bch->Flags)) | |
459 | hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; | |
460 | } | |
461 | pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, | |
462 | bch->tx_idx, bch->tx_skb->len); | |
463 | ptr = (u32 *)p; | |
464 | bch->tx_idx += count; | |
465 | hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count); | |
466 | if (AVM_FRITZ_PCIV2 == fc->type) { | |
467 | __write_ctrl_pciv2(fc, hdlc, bch->nr); | |
468 | addr = fc->addr + (bch->nr == 2 ? | |
469 | AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); | |
470 | } else { | |
471 | __write_ctrl_pci(fc, hdlc, bch->nr); | |
472 | addr = fc->addr + CHIP_WINDOW; | |
473 | } | |
474 | while (cnt < count) { | |
475 | val = get_unaligned(ptr); | |
476 | outl(cpu_to_le32(val), addr); | |
477 | ptr++; | |
478 | cnt += 4; | |
479 | } | |
480 | if (debug & DEBUG_HW_BFIFO) { | |
481 | snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", | |
482 | bch->nr, fc->name, count); | |
483 | print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); | |
484 | } | |
485 | } | |
486 | ||
487 | static void | |
488 | HDLC_irq_xpr(struct bchannel *bch) | |
489 | { | |
490 | if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) | |
491 | hdlc_fill_fifo(bch); | |
492 | else { | |
493 | if (bch->tx_skb) { | |
494 | /* send confirm, on trans, free on hdlc. */ | |
495 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | |
496 | confirm_Bsend(bch); | |
497 | dev_kfree_skb(bch->tx_skb); | |
498 | } | |
499 | if (get_next_bframe(bch)) | |
500 | hdlc_fill_fifo(bch); | |
501 | } | |
502 | } | |
503 | ||
504 | static void | |
505 | HDLC_irq(struct bchannel *bch, u32 stat) | |
506 | { | |
507 | struct fritzcard *fc = bch->hw; | |
508 | int len; | |
509 | struct hdlc_hw *hdlc; | |
510 | ||
511 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | |
512 | pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); | |
513 | if (stat & HDLC_INT_RPR) { | |
514 | if (stat & HDLC_STAT_RDO) { | |
515 | hdlc->ctrl.sr.xml = 0; | |
516 | hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; | |
517 | write_ctrl(bch, 1); | |
518 | hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS; | |
519 | write_ctrl(bch, 1); | |
520 | if (bch->rx_skb) | |
521 | skb_trim(bch->rx_skb, 0); | |
522 | } else { | |
523 | len = (stat & HDLC_STAT_RML_MASK) >> 8; | |
524 | if (!len) | |
525 | len = 32; | |
526 | hdlc_empty_fifo(bch, len); | |
527 | if (!bch->rx_skb) | |
528 | goto handle_tx; | |
529 | if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, | |
530 | &bch->Flags)) { | |
531 | if (((stat & HDLC_STAT_CRCVFRRAB) == | |
532 | HDLC_STAT_CRCVFR) || | |
533 | test_bit(FLG_TRANSPARENT, &bch->Flags)) { | |
534 | recv_Bchannel(bch, 0); | |
535 | } else { | |
536 | pr_debug("%s: got invalid frame\n", | |
537 | fc->name); | |
538 | skb_trim(bch->rx_skb, 0); | |
539 | } | |
540 | } | |
541 | } | |
542 | } | |
543 | handle_tx: | |
544 | if (stat & HDLC_INT_XDU) { | |
545 | /* Here we lost an TX interrupt, so | |
546 | * restart transmitting the whole frame on HDLC | |
547 | * in transparent mode we send the next data | |
548 | */ | |
549 | if (bch->tx_skb) | |
550 | pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n", | |
551 | fc->name, bch->nr, bch->tx_skb->len, | |
552 | bch->tx_idx, bch->Flags); | |
553 | else | |
554 | pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n", | |
555 | fc->name, bch->nr, bch->Flags); | |
556 | if (bch->tx_skb && bch->tx_skb->len) { | |
557 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | |
558 | bch->tx_idx = 0; | |
559 | } | |
560 | hdlc->ctrl.sr.xml = 0; | |
561 | hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; | |
562 | write_ctrl(bch, 1); | |
563 | hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS; | |
564 | HDLC_irq_xpr(bch); | |
565 | return; | |
566 | } else if (stat & HDLC_INT_XPR) | |
567 | HDLC_irq_xpr(bch); | |
568 | } | |
569 | ||
570 | static inline void | |
571 | HDLC_irq_main(struct fritzcard *fc) | |
572 | { | |
573 | u32 stat; | |
574 | struct bchannel *bch; | |
575 | ||
576 | stat = read_status(fc, 1); | |
577 | if (stat & HDLC_INT_MASK) { | |
578 | bch = Sel_BCS(fc, 1); | |
579 | if (bch) | |
580 | HDLC_irq(bch, stat); | |
581 | else | |
582 | pr_debug("%s: spurious ch1 IRQ\n", fc->name); | |
583 | } | |
584 | stat = read_status(fc, 2); | |
585 | if (stat & HDLC_INT_MASK) { | |
586 | bch = Sel_BCS(fc, 2); | |
587 | if (bch) | |
588 | HDLC_irq(bch, stat); | |
589 | else | |
590 | pr_debug("%s: spurious ch2 IRQ\n", fc->name); | |
591 | } | |
592 | } | |
593 | ||
594 | static irqreturn_t | |
595 | avm_fritz_interrupt(int intno, void *dev_id) | |
596 | { | |
597 | struct fritzcard *fc = dev_id; | |
598 | u8 val; | |
599 | u8 sval; | |
600 | ||
601 | spin_lock(&fc->lock); | |
602 | sval = inb(fc->addr + 2); | |
603 | pr_debug("%s: irq stat0 %x\n", fc->name, sval); | |
604 | if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { | |
605 | /* shared IRQ from other HW */ | |
606 | spin_unlock(&fc->lock); | |
607 | return IRQ_NONE; | |
608 | } | |
609 | fc->irqcnt++; | |
610 | ||
611 | if (!(sval & AVM_STATUS0_IRQ_ISAC)) { | |
612 | val = ReadISAC_V1(fc, ISAC_ISTA); | |
613 | mISDNisac_irq(&fc->isac, val); | |
614 | } | |
615 | if (!(sval & AVM_STATUS0_IRQ_HDLC)) | |
616 | HDLC_irq_main(fc); | |
617 | spin_unlock(&fc->lock); | |
618 | return IRQ_HANDLED; | |
619 | } | |
620 | ||
621 | static irqreturn_t | |
622 | avm_fritzv2_interrupt(int intno, void *dev_id) | |
623 | { | |
624 | struct fritzcard *fc = dev_id; | |
625 | u8 val; | |
626 | u8 sval; | |
627 | ||
628 | spin_lock(&fc->lock); | |
629 | sval = inb(fc->addr + 2); | |
630 | pr_debug("%s: irq stat0 %x\n", fc->name, sval); | |
631 | if (!(sval & AVM_STATUS0_IRQ_MASK)) { | |
632 | /* shared IRQ from other HW */ | |
633 | spin_unlock(&fc->lock); | |
634 | return IRQ_NONE; | |
635 | } | |
636 | fc->irqcnt++; | |
637 | ||
638 | if (sval & AVM_STATUS0_IRQ_HDLC) | |
639 | HDLC_irq_main(fc); | |
640 | if (sval & AVM_STATUS0_IRQ_ISAC) { | |
641 | val = ReadISAC_V2(fc, ISACX_ISTA); | |
642 | mISDNisac_irq(&fc->isac, val); | |
643 | } | |
644 | if (sval & AVM_STATUS0_IRQ_TIMER) { | |
645 | pr_debug("%s: timer irq\n", fc->name); | |
646 | outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2); | |
647 | udelay(1); | |
648 | outb(fc->ctrlreg, fc->addr + 2); | |
649 | } | |
650 | spin_unlock(&fc->lock); | |
651 | return IRQ_HANDLED; | |
652 | } | |
653 | ||
654 | static int | |
655 | avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) | |
656 | { | |
657 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | |
658 | struct fritzcard *fc = bch->hw; | |
659 | int ret = -EINVAL; | |
660 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | |
661 | u32 id; | |
662 | u_long flags; | |
663 | ||
664 | switch (hh->prim) { | |
665 | case PH_DATA_REQ: | |
666 | spin_lock_irqsave(&fc->lock, flags); | |
667 | ret = bchannel_senddata(bch, skb); | |
668 | if (ret > 0) { /* direct TX */ | |
669 | id = hh->id; /* skb can be freed */ | |
670 | hdlc_fill_fifo(bch); | |
671 | ret = 0; | |
672 | spin_unlock_irqrestore(&fc->lock, flags); | |
673 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | |
674 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | |
675 | } else | |
676 | spin_unlock_irqrestore(&fc->lock, flags); | |
677 | return ret; | |
678 | case PH_ACTIVATE_REQ: | |
679 | spin_lock_irqsave(&fc->lock, flags); | |
680 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | |
681 | ret = modehdlc(bch, ch->protocol); | |
682 | else | |
683 | ret = 0; | |
684 | spin_unlock_irqrestore(&fc->lock, flags); | |
685 | if (!ret) | |
686 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | |
687 | NULL, GFP_KERNEL); | |
688 | break; | |
689 | case PH_DEACTIVATE_REQ: | |
690 | spin_lock_irqsave(&fc->lock, flags); | |
691 | mISDN_clear_bchannel(bch); | |
692 | modehdlc(bch, ISDN_P_NONE); | |
693 | spin_unlock_irqrestore(&fc->lock, flags); | |
694 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | |
695 | NULL, GFP_KERNEL); | |
696 | ret = 0; | |
697 | break; | |
698 | } | |
699 | if (!ret) | |
700 | dev_kfree_skb(skb); | |
701 | return ret; | |
702 | } | |
703 | ||
704 | static void | |
705 | inithdlc(struct fritzcard *fc) | |
706 | { | |
707 | modehdlc(&fc->bch[0], -1); | |
708 | modehdlc(&fc->bch[1], -1); | |
709 | } | |
710 | ||
711 | void | |
712 | clear_pending_hdlc_ints(struct fritzcard *fc) | |
713 | { | |
714 | u32 val; | |
715 | ||
716 | val = read_status(fc, 1); | |
717 | pr_debug("%s: HDLC 1 STA %x\n", fc->name, val); | |
718 | val = read_status(fc, 2); | |
719 | pr_debug("%s: HDLC 2 STA %x\n", fc->name, val); | |
720 | } | |
721 | ||
722 | static void | |
723 | reset_avm(struct fritzcard *fc) | |
724 | { | |
725 | switch (fc->type) { | |
726 | case AVM_FRITZ_PCI: | |
727 | fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER; | |
728 | break; | |
729 | case AVM_FRITZ_PCIV2: | |
730 | fc->ctrlreg = AVM_STATUS0_RESET; | |
731 | break; | |
732 | } | |
733 | if (debug & DEBUG_HW) | |
734 | pr_notice("%s: reset\n", fc->name); | |
735 | disable_hwirq(fc); | |
736 | mdelay(5); | |
737 | switch (fc->type) { | |
738 | case AVM_FRITZ_PCI: | |
739 | fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER; | |
740 | disable_hwirq(fc); | |
741 | outb(AVM_STATUS1_ENA_IOM, fc->addr + 3); | |
742 | break; | |
743 | case AVM_FRITZ_PCIV2: | |
744 | fc->ctrlreg = 0; | |
745 | disable_hwirq(fc); | |
746 | break; | |
747 | } | |
748 | mdelay(1); | |
749 | if (debug & DEBUG_HW) | |
750 | pr_notice("%s: S0/S1 %x/%x\n", fc->name, | |
751 | inb(fc->addr + 2), inb(fc->addr + 3)); | |
752 | } | |
753 | ||
754 | static int | |
755 | init_card(struct fritzcard *fc) | |
756 | { | |
757 | int ret, cnt = 3; | |
758 | u_long flags; | |
759 | ||
760 | reset_avm(fc); /* disable IRQ */ | |
761 | if (fc->type == AVM_FRITZ_PCIV2) | |
762 | ret = request_irq(fc->irq, avm_fritzv2_interrupt, | |
763 | IRQF_SHARED, fc->name, fc); | |
764 | else | |
765 | ret = request_irq(fc->irq, avm_fritz_interrupt, | |
766 | IRQF_SHARED, fc->name, fc); | |
767 | if (ret) { | |
768 | pr_info("%s: couldn't get interrupt %d\n", | |
769 | fc->name, fc->irq); | |
770 | return ret; | |
771 | } | |
772 | while (cnt--) { | |
773 | spin_lock_irqsave(&fc->lock, flags); | |
774 | ret = fc->isac.init(&fc->isac); | |
775 | if (ret) { | |
776 | spin_unlock_irqrestore(&fc->lock, flags); | |
777 | pr_info("%s: ISAC init failed with %d\n", | |
778 | fc->name, ret); | |
779 | break; | |
780 | } | |
781 | clear_pending_hdlc_ints(fc); | |
782 | inithdlc(fc); | |
783 | enable_hwirq(fc); | |
784 | /* RESET Receiver and Transmitter */ | |
785 | if (AVM_FRITZ_PCIV2 == fc->type) { | |
786 | WriteISAC_V2(fc, ISACX_MASK, 0); | |
787 | WriteISAC_V2(fc, ISACX_CMDRD, 0x41); | |
788 | } else { | |
789 | WriteISAC_V1(fc, ISAC_MASK, 0); | |
790 | WriteISAC_V1(fc, ISAC_CMDR, 0x41); | |
791 | } | |
792 | spin_unlock_irqrestore(&fc->lock, flags); | |
793 | /* Timeout 10ms */ | |
794 | msleep_interruptible(10); | |
795 | if (debug & DEBUG_HW) | |
796 | pr_notice("%s: IRQ %d count %d\n", fc->name, | |
797 | fc->irq, fc->irqcnt); | |
798 | if (!fc->irqcnt) { | |
799 | pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", | |
800 | fc->name, fc->irq, 3 - cnt); | |
801 | reset_avm(fc); | |
802 | } else | |
803 | return 0; | |
804 | } | |
805 | free_irq(fc->irq, fc); | |
806 | return -EIO; | |
807 | } | |
808 | ||
809 | static int | |
810 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | |
811 | { | |
812 | int ret = 0; | |
813 | struct fritzcard *fc = bch->hw; | |
814 | ||
815 | switch (cq->op) { | |
816 | case MISDN_CTRL_GETOP: | |
817 | cq->op = 0; | |
818 | break; | |
819 | /* Nothing implemented yet */ | |
820 | case MISDN_CTRL_FILL_EMPTY: | |
821 | default: | |
822 | pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); | |
823 | ret = -EINVAL; | |
824 | break; | |
825 | } | |
826 | return ret; | |
827 | } | |
828 | ||
829 | static int | |
830 | avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |
831 | { | |
832 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | |
833 | struct fritzcard *fc = bch->hw; | |
834 | int ret = -EINVAL; | |
835 | u_long flags; | |
836 | ||
837 | pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); | |
838 | switch (cmd) { | |
839 | case CLOSE_CHANNEL: | |
840 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | |
841 | if (test_bit(FLG_ACTIVE, &bch->Flags)) { | |
842 | spin_lock_irqsave(&fc->lock, flags); | |
843 | mISDN_freebchannel(bch); | |
844 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | |
845 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | |
846 | modehdlc(bch, ISDN_P_NONE); | |
847 | spin_unlock_irqrestore(&fc->lock, flags); | |
848 | } | |
849 | ch->protocol = ISDN_P_NONE; | |
850 | ch->peer = NULL; | |
851 | module_put(THIS_MODULE); | |
852 | ret = 0; | |
853 | break; | |
854 | case CONTROL_CHANNEL: | |
855 | ret = channel_bctrl(bch, arg); | |
856 | break; | |
857 | default: | |
858 | pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd); | |
859 | } | |
860 | return ret; | |
861 | } | |
862 | ||
863 | static int | |
864 | channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) | |
865 | { | |
866 | int ret = 0; | |
867 | ||
868 | switch (cq->op) { | |
869 | case MISDN_CTRL_GETOP: | |
870 | cq->op = MISDN_CTRL_LOOP; | |
871 | break; | |
872 | case MISDN_CTRL_LOOP: | |
873 | /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ | |
874 | if (cq->channel < 0 || cq->channel > 3) { | |
875 | ret = -EINVAL; | |
876 | break; | |
877 | } | |
878 | ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); | |
879 | break; | |
880 | default: | |
881 | pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); | |
882 | ret = -EINVAL; | |
883 | break; | |
884 | } | |
885 | return ret; | |
886 | } | |
887 | ||
888 | static int | |
889 | open_bchannel(struct fritzcard *fc, struct channel_req *rq) | |
890 | { | |
891 | struct bchannel *bch; | |
892 | ||
893 | if (rq->adr.channel > 2) | |
894 | return -EINVAL; | |
895 | if (rq->protocol == ISDN_P_NONE) | |
896 | return -EINVAL; | |
897 | bch = &fc->bch[rq->adr.channel - 1]; | |
898 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | |
899 | return -EBUSY; /* b-channel can be only open once */ | |
900 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | |
901 | bch->ch.protocol = rq->protocol; | |
902 | rq->ch = &bch->ch; | |
903 | return 0; | |
904 | } | |
905 | ||
906 | /* | |
907 | * device control function | |
908 | */ | |
909 | static int | |
910 | avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |
911 | { | |
912 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | |
913 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | |
914 | struct fritzcard *fc = dch->hw; | |
915 | struct channel_req *rq; | |
916 | int err = 0; | |
917 | ||
918 | pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); | |
919 | switch (cmd) { | |
920 | case OPEN_CHANNEL: | |
921 | rq = arg; | |
922 | if (rq->protocol == ISDN_P_TE_S0) | |
923 | err = fc->isac.open(&fc->isac, rq); | |
924 | else | |
925 | err = open_bchannel(fc, rq); | |
926 | if (err) | |
927 | break; | |
928 | if (!try_module_get(THIS_MODULE)) | |
929 | pr_info("%s: cannot get module\n", fc->name); | |
930 | break; | |
931 | case CLOSE_CHANNEL: | |
932 | pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id, | |
933 | __builtin_return_address(0)); | |
934 | module_put(THIS_MODULE); | |
935 | break; | |
936 | case CONTROL_CHANNEL: | |
937 | err = channel_ctrl(fc, arg); | |
938 | break; | |
939 | default: | |
940 | pr_debug("%s: %s unknown command %x\n", | |
941 | fc->name, __func__, cmd); | |
942 | return -EINVAL; | |
943 | } | |
944 | return err; | |
945 | } | |
946 | ||
947 | int | |
948 | setup_fritz(struct fritzcard *fc) | |
949 | { | |
950 | u32 val, ver; | |
951 | ||
952 | if (!request_region(fc->addr, 32, fc->name)) { | |
953 | pr_info("%s: AVM config port %x-%x already in use\n", | |
954 | fc->name, fc->addr, fc->addr + 31); | |
955 | return -EIO; | |
956 | } | |
957 | switch (fc->type) { | |
958 | case AVM_FRITZ_PCI: | |
959 | val = inl(fc->addr); | |
960 | outl(AVM_HDLC_1, fc->addr + CHIP_INDEX); | |
961 | ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24; | |
962 | if (debug & DEBUG_HW) { | |
963 | pr_notice("%s: PCI stat %#x\n", fc->name, val); | |
964 | pr_notice("%s: PCI Class %X Rev %d\n", fc->name, | |
965 | val & 0xff, (val >> 8) & 0xff); | |
966 | pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); | |
967 | } | |
968 | ASSIGN_FUNC(V1, ISAC, fc->isac); | |
969 | fc->isac.type = IPAC_TYPE_ISAC; | |
970 | break; | |
971 | case AVM_FRITZ_PCIV2: | |
972 | val = inl(fc->addr); | |
973 | ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24; | |
974 | if (debug & DEBUG_HW) { | |
975 | pr_notice("%s: PCI V2 stat %#x\n", fc->name, val); | |
976 | pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name, | |
977 | val & 0xff, (val>>8) & 0xff); | |
978 | pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); | |
979 | } | |
980 | ASSIGN_FUNC(V2, ISAC, fc->isac); | |
981 | fc->isac.type = IPAC_TYPE_ISACX; | |
982 | break; | |
983 | default: | |
984 | release_region(fc->addr, 32); | |
985 | pr_info("%s: AVM unknown type %d\n", fc->name, fc->type); | |
986 | return -ENODEV; | |
987 | } | |
988 | pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name, | |
989 | (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" : | |
990 | "AVM Fritz!CARD PCIv2", fc->irq, fc->addr); | |
991 | return 0; | |
992 | } | |
993 | ||
994 | static void | |
995 | release_card(struct fritzcard *card) | |
996 | { | |
997 | u_long flags; | |
998 | ||
999 | disable_hwirq(card); | |
1000 | spin_lock_irqsave(&card->lock, flags); | |
1001 | modehdlc(&card->bch[0], ISDN_P_NONE); | |
1002 | modehdlc(&card->bch[1], ISDN_P_NONE); | |
1003 | spin_unlock_irqrestore(&card->lock, flags); | |
1004 | card->isac.release(&card->isac); | |
1005 | free_irq(card->irq, card); | |
1006 | mISDN_freebchannel(&card->bch[1]); | |
1007 | mISDN_freebchannel(&card->bch[0]); | |
1008 | mISDN_unregister_device(&card->isac.dch.dev); | |
1009 | release_region(card->addr, 32); | |
1010 | pci_disable_device(card->pdev); | |
1011 | pci_set_drvdata(card->pdev, NULL); | |
1012 | write_lock_irqsave(&card_lock, flags); | |
1013 | list_del(&card->list); | |
1014 | write_unlock_irqrestore(&card_lock, flags); | |
1015 | kfree(card); | |
1016 | AVM_cnt--; | |
1017 | } | |
1018 | ||
1019 | static int __devinit | |
1020 | setup_instance(struct fritzcard *card) | |
1021 | { | |
1022 | int i, err; | |
1023 | u_long flags; | |
1024 | ||
1025 | snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); | |
1026 | write_lock_irqsave(&card_lock, flags); | |
1027 | list_add_tail(&card->list, &Cards); | |
1028 | write_unlock_irqrestore(&card_lock, flags); | |
1029 | ||
1030 | _set_debug(card); | |
1031 | card->isac.name = card->name; | |
1032 | spin_lock_init(&card->lock); | |
1033 | card->isac.hwlock = &card->lock; | |
1034 | mISDNisac_init(&card->isac, card); | |
1035 | ||
1036 | card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | |
1037 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | |
1038 | card->isac.dch.dev.D.ctrl = avm_dctrl; | |
1039 | for (i = 0; i < 2; i++) { | |
1040 | card->bch[i].nr = i + 1; | |
1041 | set_channelmap(i + 1, card->isac.dch.dev.channelmap); | |
1042 | mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); | |
1043 | card->bch[i].hw = card; | |
1044 | card->bch[i].ch.send = avm_l2l1B; | |
1045 | card->bch[i].ch.ctrl = avm_bctrl; | |
1046 | card->bch[i].ch.nr = i + 1; | |
1047 | list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels); | |
1048 | } | |
1049 | err = setup_fritz(card); | |
1050 | if (err) | |
1051 | goto error; | |
1052 | err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, | |
1053 | card->name); | |
1054 | if (err) | |
1055 | goto error_reg; | |
1056 | err = init_card(card); | |
1057 | if (!err) { | |
1058 | AVM_cnt++; | |
1059 | pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt); | |
1060 | return 0; | |
1061 | } | |
1062 | mISDN_unregister_device(&card->isac.dch.dev); | |
1063 | error_reg: | |
1064 | release_region(card->addr, 32); | |
1065 | error: | |
1066 | card->isac.release(&card->isac); | |
1067 | mISDN_freebchannel(&card->bch[1]); | |
1068 | mISDN_freebchannel(&card->bch[0]); | |
1069 | write_lock_irqsave(&card_lock, flags); | |
1070 | list_del(&card->list); | |
1071 | write_unlock_irqrestore(&card_lock, flags); | |
1072 | kfree(card); | |
1073 | return err; | |
1074 | } | |
1075 | ||
1076 | static int __devinit | |
1077 | fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1078 | { | |
1079 | int err = -ENOMEM; | |
1080 | struct fritzcard *card; | |
1081 | ||
1082 | card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL); | |
1083 | if (!card) { | |
1084 | pr_info("No kmem for fritzcard\n"); | |
1085 | return err; | |
1086 | } | |
1087 | if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) | |
1088 | card->type = AVM_FRITZ_PCIV2; | |
1089 | else | |
1090 | card->type = AVM_FRITZ_PCI; | |
1091 | card->pdev = pdev; | |
1092 | err = pci_enable_device(pdev); | |
1093 | if (err) { | |
1094 | kfree(card); | |
1095 | return err; | |
1096 | } | |
1097 | ||
1098 | pr_notice("mISDN: found adapter %s at %s\n", | |
1099 | (char *) ent->driver_data, pci_name(pdev)); | |
1100 | ||
1101 | card->addr = pci_resource_start(pdev, 1); | |
1102 | card->irq = pdev->irq; | |
1103 | pci_set_drvdata(pdev, card); | |
1104 | err = setup_instance(card); | |
1105 | if (err) | |
1106 | pci_set_drvdata(pdev, NULL); | |
1107 | return err; | |
1108 | } | |
1109 | ||
1110 | static void __devexit | |
1111 | fritz_remove_pci(struct pci_dev *pdev) | |
1112 | { | |
1113 | struct fritzcard *card = pci_get_drvdata(pdev); | |
1114 | ||
1115 | if (card) | |
1116 | release_card(card); | |
1117 | else | |
1118 | if (debug) | |
1119 | pr_info("%s: drvdata allready removed\n", __func__); | |
1120 | } | |
1121 | ||
1122 | static struct pci_device_id fcpci_ids[] __devinitdata = { | |
1123 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID, | |
1124 | 0, 0, (unsigned long) "Fritz!Card PCI"}, | |
1125 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID, | |
1126 | 0, 0, (unsigned long) "Fritz!Card PCI v2" }, | |
1127 | { } | |
1128 | }; | |
1129 | MODULE_DEVICE_TABLE(pci, fcpci_ids); | |
1130 | ||
1131 | static struct pci_driver fcpci_driver = { | |
1132 | .name = "fcpci", | |
1133 | .probe = fritzpci_probe, | |
1134 | .remove = __devexit_p(fritz_remove_pci), | |
1135 | .id_table = fcpci_ids, | |
1136 | }; | |
1137 | ||
1138 | static int __init AVM_init(void) | |
1139 | { | |
1140 | int err; | |
1141 | ||
1142 | pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV); | |
1143 | err = pci_register_driver(&fcpci_driver); | |
1144 | return err; | |
1145 | } | |
1146 | ||
1147 | static void __exit AVM_cleanup(void) | |
1148 | { | |
1149 | pci_unregister_driver(&fcpci_driver); | |
1150 | } | |
1151 | ||
1152 | module_init(AVM_init); | |
1153 | module_exit(AVM_cleanup); |