diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hysdn |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hysdn')
-rw-r--r-- | drivers/isdn/hysdn/Kconfig | 18 | ||||
-rw-r--r-- | drivers/isdn/hysdn/Makefile | 11 | ||||
-rw-r--r-- | drivers/isdn/hysdn/boardergo.c | 453 | ||||
-rw-r--r-- | drivers/isdn/hysdn/boardergo.h | 100 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hycapi.c | 797 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_boot.c | 399 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_defs.h | 298 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_init.c | 254 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_net.c | 348 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_pof.h | 78 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_procconf.c | 443 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_proclog.c | 441 | ||||
-rw-r--r-- | drivers/isdn/hysdn/hysdn_sched.c | 207 | ||||
-rw-r--r-- | drivers/isdn/hysdn/ince1pc.h | 134 |
14 files changed, 3981 insertions, 0 deletions
diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/isdn/hysdn/Kconfig new file mode 100644 index 000000000000..c6d8a7042988 --- /dev/null +++ b/drivers/isdn/hysdn/Kconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | # | ||
2 | # Config.in for HYSDN ISDN driver | ||
3 | # | ||
4 | config HYSDN | ||
5 | tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)" | ||
6 | depends on m && PROC_FS && PCI && BROKEN_ON_SMP | ||
7 | help | ||
8 | Say Y here if you have one of Hypercope's active PCI ISDN cards | ||
9 | Champ, Ergo and Metro. You will then get a module called hysdn. | ||
10 | Please read the file <file:Documentation/isdn/README.hysdn> for more | ||
11 | information. | ||
12 | |||
13 | config HYSDN_CAPI | ||
14 | bool "HYSDN CAPI 2.0 support" | ||
15 | depends on HYSDN && ISDN_CAPI | ||
16 | help | ||
17 | Say Y here if you like to use Hypercope's CAPI 2.0 interface. | ||
18 | |||
diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile new file mode 100644 index 000000000000..da63b636267d --- /dev/null +++ b/drivers/isdn/hysdn/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # Makefile for the hysdn ISDN device driver | ||
2 | |||
3 | # Each configuration option enables a list of files. | ||
4 | |||
5 | obj-$(CONFIG_HYSDN) += hysdn.o | ||
6 | |||
7 | # Multipart objects. | ||
8 | |||
9 | hysdn-y := hysdn_procconf.o hysdn_proclog.o boardergo.o \ | ||
10 | hysdn_boot.o hysdn_sched.o hysdn_net.o hysdn_init.o | ||
11 | hysdn-$(CONFIG_HYSDN_CAPI) += hycapi.o | ||
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c new file mode 100644 index 000000000000..e19a01a305a9 --- /dev/null +++ b/drivers/isdn/hysdn/boardergo.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* $Id: boardergo.c,v 1.5.6.7 2001/11/06 21:58:19 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, specific routines for ergo type boards. | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same | ||
12 | * DPRAM interface and layout with only minor differences all related | ||
13 | * stuff is done here, not in separate modules. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/signal.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <asm/io.h> | ||
26 | |||
27 | #include "hysdn_defs.h" | ||
28 | #include "boardergo.h" | ||
29 | |||
30 | #define byteout(addr,val) outb(val,addr) | ||
31 | #define bytein(addr) inb(addr) | ||
32 | |||
33 | /***************************************************/ | ||
34 | /* The cards interrupt handler. Called from system */ | ||
35 | /***************************************************/ | ||
36 | static irqreturn_t | ||
37 | ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs) | ||
38 | { | ||
39 | hysdn_card *card = dev_id; /* parameter from irq */ | ||
40 | tErgDpram *dpr; | ||
41 | ulong flags; | ||
42 | uchar volatile b; | ||
43 | |||
44 | if (!card) | ||
45 | return IRQ_NONE; /* error -> spurious interrupt */ | ||
46 | if (!card->irq_enabled) | ||
47 | return IRQ_NONE; /* other device interrupting or irq switched off */ | ||
48 | |||
49 | save_flags(flags); | ||
50 | cli(); /* no further irqs allowed */ | ||
51 | |||
52 | if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) { | ||
53 | restore_flags(flags); /* restore old state */ | ||
54 | return IRQ_NONE; /* no interrupt requested by E1 */ | ||
55 | } | ||
56 | /* clear any pending ints on the board */ | ||
57 | dpr = card->dpram; | ||
58 | b = dpr->ToPcInt; /* clear for ergo */ | ||
59 | b |= dpr->ToPcIntMetro; /* same for metro */ | ||
60 | b |= dpr->ToHyInt; /* and for champ */ | ||
61 | |||
62 | /* start kernel task immediately after leaving all interrupts */ | ||
63 | if (!card->hw_lock) | ||
64 | schedule_work(&card->irq_queue); | ||
65 | restore_flags(flags); | ||
66 | return IRQ_HANDLED; | ||
67 | } /* ergo_interrupt */ | ||
68 | |||
69 | /******************************************************************************/ | ||
70 | /* ergo_irq_bh is the function called by the immediate kernel task list after */ | ||
71 | /* being activated with queue_task and no interrupts active. This task is the */ | ||
72 | /* only one handling data transfer from or to the card after booting. The task */ | ||
73 | /* may be queued from everywhere (interrupts included). */ | ||
74 | /******************************************************************************/ | ||
75 | static void | ||
76 | ergo_irq_bh(hysdn_card * card) | ||
77 | { | ||
78 | tErgDpram *dpr; | ||
79 | int again; | ||
80 | ulong flags; | ||
81 | |||
82 | if (card->state != CARD_STATE_RUN) | ||
83 | return; /* invalid call */ | ||
84 | |||
85 | dpr = card->dpram; /* point to DPRAM */ | ||
86 | |||
87 | save_flags(flags); | ||
88 | cli(); | ||
89 | if (card->hw_lock) { | ||
90 | restore_flags(flags); /* hardware currently unavailable */ | ||
91 | return; | ||
92 | } | ||
93 | card->hw_lock = 1; /* we now lock the hardware */ | ||
94 | |||
95 | do { | ||
96 | sti(); /* reenable other ints */ | ||
97 | again = 0; /* assume loop not to be repeated */ | ||
98 | |||
99 | if (!dpr->ToHyFlag) { | ||
100 | /* we are able to send a buffer */ | ||
101 | |||
102 | if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel, | ||
103 | ERG_TO_HY_BUF_SIZE)) { | ||
104 | dpr->ToHyFlag = 1; /* enable tx */ | ||
105 | again = 1; /* restart loop */ | ||
106 | } | ||
107 | } /* we are able to send a buffer */ | ||
108 | if (dpr->ToPcFlag) { | ||
109 | /* a message has arrived for us, handle it */ | ||
110 | |||
111 | if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) { | ||
112 | dpr->ToPcFlag = 0; /* we worked the data */ | ||
113 | again = 1; /* restart loop */ | ||
114 | } | ||
115 | } /* a message has arrived for us */ | ||
116 | cli(); /* no further ints */ | ||
117 | if (again) { | ||
118 | dpr->ToHyInt = 1; | ||
119 | dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ | ||
120 | } else | ||
121 | card->hw_lock = 0; /* free hardware again */ | ||
122 | } while (again); /* until nothing more to do */ | ||
123 | |||
124 | restore_flags(flags); | ||
125 | } /* ergo_irq_bh */ | ||
126 | |||
127 | |||
128 | /*********************************************************/ | ||
129 | /* stop the card (hardware reset) and disable interrupts */ | ||
130 | /*********************************************************/ | ||
131 | static void | ||
132 | ergo_stopcard(hysdn_card * card) | ||
133 | { | ||
134 | ulong flags; | ||
135 | uchar val; | ||
136 | |||
137 | hysdn_net_release(card); /* first release the net device if existing */ | ||
138 | #ifdef CONFIG_HYSDN_CAPI | ||
139 | hycapi_capi_stop(card); | ||
140 | #endif /* CONFIG_HYSDN_CAPI */ | ||
141 | save_flags(flags); | ||
142 | cli(); | ||
143 | val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ | ||
144 | val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */ | ||
145 | byteout(card->iobase + PCI9050_INTR_REG, val); | ||
146 | card->irq_enabled = 0; | ||
147 | byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */ | ||
148 | card->state = CARD_STATE_UNUSED; | ||
149 | card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */ | ||
150 | |||
151 | restore_flags(flags); | ||
152 | } /* ergo_stopcard */ | ||
153 | |||
154 | /**************************************************************************/ | ||
155 | /* enable or disable the cards error log. The event is queued if possible */ | ||
156 | /**************************************************************************/ | ||
157 | static void | ||
158 | ergo_set_errlog_state(hysdn_card * card, int on) | ||
159 | { | ||
160 | ulong flags; | ||
161 | |||
162 | if (card->state != CARD_STATE_RUN) { | ||
163 | card->err_log_state = ERRLOG_STATE_OFF; /* must be off */ | ||
164 | return; | ||
165 | } | ||
166 | save_flags(flags); | ||
167 | cli(); | ||
168 | |||
169 | if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) || | ||
170 | ((card->err_log_state == ERRLOG_STATE_ON) && on)) { | ||
171 | restore_flags(flags); | ||
172 | return; /* nothing to do */ | ||
173 | } | ||
174 | if (on) | ||
175 | card->err_log_state = ERRLOG_STATE_START; /* request start */ | ||
176 | else | ||
177 | card->err_log_state = ERRLOG_STATE_STOP; /* request stop */ | ||
178 | |||
179 | restore_flags(flags); | ||
180 | schedule_work(&card->irq_queue); | ||
181 | } /* ergo_set_errlog_state */ | ||
182 | |||
183 | /******************************************/ | ||
184 | /* test the cards RAM and return 0 if ok. */ | ||
185 | /******************************************/ | ||
186 | static const char TestText[36] = "This Message is filler, why read it"; | ||
187 | |||
188 | static int | ||
189 | ergo_testram(hysdn_card * card) | ||
190 | { | ||
191 | tErgDpram *dpr = card->dpram; | ||
192 | |||
193 | memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */ | ||
194 | dpr->ToHyInt = 1; /* E1 INTR state forced */ | ||
195 | |||
196 | memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, | ||
197 | sizeof(TestText)); | ||
198 | if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, | ||
199 | sizeof(TestText))) | ||
200 | return (-1); | ||
201 | |||
202 | memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, | ||
203 | sizeof(TestText)); | ||
204 | if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, | ||
205 | sizeof(TestText))) | ||
206 | return (-1); | ||
207 | |||
208 | return (0); | ||
209 | } /* ergo_testram */ | ||
210 | |||
211 | /*****************************************************************************/ | ||
212 | /* this function is intended to write stage 1 boot image to the cards buffer */ | ||
213 | /* this is done in two steps. First the 1024 hi-words are written (offs=0), */ | ||
214 | /* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */ | ||
215 | /* PCI-write-buffers flushed and the card is taken out of reset. */ | ||
216 | /* The function then waits for a reaction of the E1 processor or a timeout. */ | ||
217 | /* Negative return values are interpreted as errors. */ | ||
218 | /*****************************************************************************/ | ||
219 | static int | ||
220 | ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs) | ||
221 | { | ||
222 | uchar *dst; | ||
223 | tErgDpram *dpram; | ||
224 | int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ | ||
225 | |||
226 | if (card->debug_flags & LOG_POF_CARD) | ||
227 | hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); | ||
228 | |||
229 | dst = card->dpram; /* pointer to start of DPRAM */ | ||
230 | dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */ | ||
231 | while (cnt--) { | ||
232 | *dst++ = *(buf + 1); /* high byte */ | ||
233 | *dst++ = *buf; /* low byte */ | ||
234 | dst += 2; /* point to next longword */ | ||
235 | buf += 2; /* buffer only filled with words */ | ||
236 | } | ||
237 | |||
238 | /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */ | ||
239 | /* flush the PCI-write-buffer and take the E1 out of reset */ | ||
240 | if (offs) { | ||
241 | memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */ | ||
242 | dpram = card->dpram; /* get pointer to dpram structure */ | ||
243 | dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */ | ||
244 | while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */ | ||
245 | |||
246 | byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */ | ||
247 | /* the interrupts are still masked */ | ||
248 | |||
249 | sti(); | ||
250 | msleep_interruptible(20); /* Timeout 20ms */ | ||
251 | |||
252 | if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) { | ||
253 | if (card->debug_flags & LOG_POF_CARD) | ||
254 | hysdn_addlog(card, "ERGO: write bootldr no answer"); | ||
255 | return (-ERR_BOOTIMG_FAIL); | ||
256 | } | ||
257 | } /* start_boot_img */ | ||
258 | return (0); /* successful */ | ||
259 | } /* ergo_writebootimg */ | ||
260 | |||
261 | /********************************************************************************/ | ||
262 | /* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */ | ||
263 | /* using the boot spool mechanism. If everything works fine 0 is returned. In */ | ||
264 | /* case of errors a negative error value is returned. */ | ||
265 | /********************************************************************************/ | ||
266 | static int | ||
267 | ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len) | ||
268 | { | ||
269 | tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram; | ||
270 | uchar *dst; | ||
271 | uchar buflen; | ||
272 | int nr_write; | ||
273 | uchar tmp_rdptr; | ||
274 | uchar wr_mirror; | ||
275 | int i; | ||
276 | |||
277 | if (card->debug_flags & LOG_POF_CARD) | ||
278 | hysdn_addlog(card, "ERGO: write boot seq len=%d ", len); | ||
279 | |||
280 | dst = sp->Data; /* point to data in spool structure */ | ||
281 | buflen = sp->Len; /* maximum len of spooled data */ | ||
282 | wr_mirror = sp->WrPtr; /* only once read */ | ||
283 | sti(); | ||
284 | |||
285 | /* try until all bytes written or error */ | ||
286 | i = 0x1000; /* timeout value */ | ||
287 | while (len) { | ||
288 | |||
289 | /* first determine the number of bytes that may be buffered */ | ||
290 | do { | ||
291 | tmp_rdptr = sp->RdPtr; /* first read the pointer */ | ||
292 | i--; /* decrement timeout */ | ||
293 | } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */ | ||
294 | |||
295 | if (!i) { | ||
296 | if (card->debug_flags & LOG_POF_CARD) | ||
297 | hysdn_addlog(card, "ERGO: write boot seq timeout"); | ||
298 | return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */ | ||
299 | } | ||
300 | if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0) | ||
301 | nr_write += buflen; /* now we got number of free bytes - 1 in buffer */ | ||
302 | |||
303 | if (!nr_write) | ||
304 | continue; /* no free bytes in buffer */ | ||
305 | |||
306 | if (nr_write > len) | ||
307 | nr_write = len; /* limit if last few bytes */ | ||
308 | i = 0x1000; /* reset timeout value */ | ||
309 | |||
310 | /* now we know how much bytes we may put in the puffer */ | ||
311 | len -= nr_write; /* we savely could adjust len before output */ | ||
312 | while (nr_write--) { | ||
313 | *(dst + wr_mirror) = *buf++; /* output one byte */ | ||
314 | if (++wr_mirror >= buflen) | ||
315 | wr_mirror = 0; | ||
316 | sp->WrPtr = wr_mirror; /* announce the next byte to E1 */ | ||
317 | } /* while (nr_write) */ | ||
318 | |||
319 | } /* while (len) */ | ||
320 | return (0); | ||
321 | } /* ergo_writebootseq */ | ||
322 | |||
323 | /***********************************************************************************/ | ||
324 | /* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */ | ||
325 | /* boot process. If the process has been successful 0 is returned otherwise a */ | ||
326 | /* negative error code is returned. */ | ||
327 | /***********************************************************************************/ | ||
328 | static int | ||
329 | ergo_waitpofready(struct HYSDN_CARD *card) | ||
330 | { | ||
331 | tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */ | ||
332 | int timecnt = 10000 / 50; /* timeout is 10 secs max. */ | ||
333 | ulong flags; | ||
334 | int msg_size; | ||
335 | int i; | ||
336 | |||
337 | if (card->debug_flags & LOG_POF_CARD) | ||
338 | hysdn_addlog(card, "ERGO: waiting for pof ready"); | ||
339 | while (timecnt--) { | ||
340 | /* wait until timeout */ | ||
341 | |||
342 | if (dpr->ToPcFlag) { | ||
343 | /* data has arrived */ | ||
344 | |||
345 | if ((dpr->ToPcChannel != CHAN_SYSTEM) || | ||
346 | (dpr->ToPcSize < MIN_RDY_MSG_SIZE) || | ||
347 | (dpr->ToPcSize > MAX_RDY_MSG_SIZE) || | ||
348 | ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC)) | ||
349 | break; /* an error occurred */ | ||
350 | |||
351 | /* Check for additional data delivered during SysReady */ | ||
352 | msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE; | ||
353 | if (msg_size > 0) | ||
354 | if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size)) | ||
355 | break; | ||
356 | |||
357 | if (card->debug_flags & LOG_POF_RECORD) | ||
358 | hysdn_addlog(card, "ERGO: pof boot success"); | ||
359 | save_flags(flags); | ||
360 | cli(); | ||
361 | |||
362 | card->state = CARD_STATE_RUN; /* now card is running */ | ||
363 | /* enable the cards interrupt */ | ||
364 | byteout(card->iobase + PCI9050_INTR_REG, | ||
365 | bytein(card->iobase + PCI9050_INTR_REG) | | ||
366 | (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1)); | ||
367 | card->irq_enabled = 1; /* we are ready to receive interrupts */ | ||
368 | |||
369 | dpr->ToPcFlag = 0; /* reset data indicator */ | ||
370 | dpr->ToHyInt = 1; | ||
371 | dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ | ||
372 | |||
373 | restore_flags(flags); | ||
374 | if ((hynet_enable & (1 << card->myid)) | ||
375 | && (i = hysdn_net_create(card))) | ||
376 | { | ||
377 | ergo_stopcard(card); | ||
378 | card->state = CARD_STATE_BOOTERR; | ||
379 | return (i); | ||
380 | } | ||
381 | #ifdef CONFIG_HYSDN_CAPI | ||
382 | if((i = hycapi_capi_create(card))) { | ||
383 | printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n"); | ||
384 | } | ||
385 | #endif /* CONFIG_HYSDN_CAPI */ | ||
386 | return (0); /* success */ | ||
387 | } /* data has arrived */ | ||
388 | sti(); | ||
389 | msleep_interruptible(50); /* Timeout 50ms */ | ||
390 | } /* wait until timeout */ | ||
391 | |||
392 | if (card->debug_flags & LOG_POF_CARD) | ||
393 | hysdn_addlog(card, "ERGO: pof boot ready timeout"); | ||
394 | return (-ERR_POF_TIMEOUT); | ||
395 | } /* ergo_waitpofready */ | ||
396 | |||
397 | |||
398 | |||
399 | /************************************************************************************/ | ||
400 | /* release the cards hardware. Before releasing do a interrupt disable and hardware */ | ||
401 | /* reset. Also unmap dpram. */ | ||
402 | /* Use only during module release. */ | ||
403 | /************************************************************************************/ | ||
404 | static void | ||
405 | ergo_releasehardware(hysdn_card * card) | ||
406 | { | ||
407 | ergo_stopcard(card); /* first stop the card if not already done */ | ||
408 | free_irq(card->irq, card); /* release interrupt */ | ||
409 | release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */ | ||
410 | release_region(card->iobase + PCI9050_USER_IO, 1); | ||
411 | vfree(card->dpram); | ||
412 | card->dpram = NULL; /* release shared mem */ | ||
413 | } /* ergo_releasehardware */ | ||
414 | |||
415 | |||
416 | /*********************************************************************************/ | ||
417 | /* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */ | ||
418 | /* value is returned. */ | ||
419 | /* Use only during module init. */ | ||
420 | /*********************************************************************************/ | ||
421 | int | ||
422 | ergo_inithardware(hysdn_card * card) | ||
423 | { | ||
424 | if (!request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN")) | ||
425 | return (-1); | ||
426 | if (!request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN")) { | ||
427 | release_region(card->iobase + PCI9050_INTR_REG, 1); | ||
428 | return (-1); /* ports already in use */ | ||
429 | } | ||
430 | card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1; | ||
431 | if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE))) { | ||
432 | release_region(card->iobase + PCI9050_INTR_REG, 1); | ||
433 | release_region(card->iobase + PCI9050_USER_IO, 1); | ||
434 | return (-1); | ||
435 | } | ||
436 | |||
437 | ergo_stopcard(card); /* disable interrupts */ | ||
438 | if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) { | ||
439 | ergo_releasehardware(card); /* return the acquired hardware */ | ||
440 | return (-1); | ||
441 | } | ||
442 | /* success, now setup the function pointers */ | ||
443 | card->stopcard = ergo_stopcard; | ||
444 | card->releasehardware = ergo_releasehardware; | ||
445 | card->testram = ergo_testram; | ||
446 | card->writebootimg = ergo_writebootimg; | ||
447 | card->writebootseq = ergo_writebootseq; | ||
448 | card->waitpofready = ergo_waitpofready; | ||
449 | card->set_errlog_state = ergo_set_errlog_state; | ||
450 | INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card); | ||
451 | |||
452 | return (0); | ||
453 | } /* ergo_inithardware */ | ||
diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h new file mode 100644 index 000000000000..b56ff0889ead --- /dev/null +++ b/drivers/isdn/hysdn/boardergo.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* $Id: boardergo.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..). | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | |||
14 | /************************************************/ | ||
15 | /* defines for the dual port memory of the card */ | ||
16 | /************************************************/ | ||
17 | #define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */ | ||
18 | #define BOOT_IMG_SIZE 4096 | ||
19 | #define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE) | ||
20 | |||
21 | #define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */ | ||
22 | #define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */ | ||
23 | |||
24 | /* following DPRAM layout copied from OS2-driver boarderg.h */ | ||
25 | typedef struct ErgDpram_tag { | ||
26 | /*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE]; | ||
27 | /*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE]; | ||
28 | |||
29 | /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART]; | ||
30 | /* size 0x1B0 */ | ||
31 | |||
32 | /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64]; | ||
33 | /* size 64 bytes */ | ||
34 | /*1DB0 ulong ulErrType; */ | ||
35 | /*1DB4 ulong ulErrSubtype; */ | ||
36 | /*1DB8 ulong ucTextSize; */ | ||
37 | /*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */ | ||
38 | /*1DF0 */ | ||
39 | |||
40 | /*1DF0 */ word volatile ToHyChannel; | ||
41 | /*1DF2 */ word volatile ToHySize; | ||
42 | /*1DF4 */ uchar volatile ToHyFlag; | ||
43 | /* !=0: msg for Hy waiting */ | ||
44 | /*1DF5 */ uchar volatile ToPcFlag; | ||
45 | /* !=0: msg for PC waiting */ | ||
46 | /*1DF6 */ word volatile ToPcChannel; | ||
47 | /*1DF8 */ word volatile ToPcSize; | ||
48 | /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA]; | ||
49 | /* 6 bytes */ | ||
50 | |||
51 | /*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00]; | ||
52 | /*1F00 */ ulong TrapTable[62]; | ||
53 | /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8]; | ||
54 | /* low part of reset vetor */ | ||
55 | /*1FFB */ uchar ToPcIntMetro; | ||
56 | /* notes: | ||
57 | * - metro has 32-bit boot ram - accessing | ||
58 | * ToPcInt and ToHyInt would be the same; | ||
59 | * so we moved ToPcInt to 1FFB. | ||
60 | * Because on the PC side both vars are | ||
61 | * readonly (reseting on int from E1 to PC), | ||
62 | * we can read both vars on both cards | ||
63 | * without destroying anything. | ||
64 | * - 1FFB is the high byte of the reset vector, | ||
65 | * so E1 side should NOT change this byte | ||
66 | * when writing! | ||
67 | */ | ||
68 | /*1FFC */ uchar volatile ToHyNoDpramErrLog; | ||
69 | /* note: ToHyNoDpramErrLog is used to inform | ||
70 | * boot loader, not to use DPRAM based | ||
71 | * ErrLog; when DOS driver is rewritten | ||
72 | * this becomes obsolete | ||
73 | */ | ||
74 | /*1FFD */ uchar bRes1FFD; | ||
75 | /*1FFE */ uchar ToPcInt; | ||
76 | /* E1_intclear; on CHAMP2: E1_intset */ | ||
77 | /*1FFF */ uchar ToHyInt; | ||
78 | /* E1_intset; on CHAMP2: E1_intclear */ | ||
79 | } tErgDpram; | ||
80 | |||
81 | /**********************************************/ | ||
82 | /* PCI9050 controller local register offsets: */ | ||
83 | /* copied from boarderg.c */ | ||
84 | /**********************************************/ | ||
85 | #define PCI9050_INTR_REG 0x4C /* Interrupt register */ | ||
86 | #define PCI9050_USER_IO 0x51 /* User I/O register */ | ||
87 | |||
88 | /* bitmask for PCI9050_INTR_REG: */ | ||
89 | #define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */ | ||
90 | #define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */ | ||
91 | #define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */ | ||
92 | #define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */ | ||
93 | |||
94 | /* bitmask for PCI9050_USER_IO: */ | ||
95 | #define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */ | ||
96 | #define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */ | ||
97 | #define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */ | ||
98 | |||
99 | #define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */ | ||
100 | #define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */ | ||
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c new file mode 100644 index 000000000000..8ee25b2ccce1 --- /dev/null +++ b/drivers/isdn/hysdn/hycapi.c | |||
@@ -0,0 +1,797 @@ | |||
1 | /* $Id: hycapi.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, CAPI2.0-Interface. | ||
4 | * | ||
5 | * Author Ulrich Albrecht <u.albrecht@hypercope.de> for Hypercope GmbH | ||
6 | * Copyright 2000 by Hypercope GmbH | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/version.h> | ||
15 | #include <linux/signal.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | |||
20 | #define VER_DRIVER 0 | ||
21 | #define VER_CARDTYPE 1 | ||
22 | #define VER_HWID 2 | ||
23 | #define VER_SERIAL 3 | ||
24 | #define VER_OPTION 4 | ||
25 | #define VER_PROTO 5 | ||
26 | #define VER_PROFILE 6 | ||
27 | #define VER_CAPI 7 | ||
28 | |||
29 | #include "hysdn_defs.h" | ||
30 | #include <linux/kernelcapi.h> | ||
31 | |||
32 | static char hycapi_revision[]="$Revision: 1.8.6.4 $"; | ||
33 | |||
34 | unsigned int hycapi_enable = 0xffffffff; | ||
35 | MODULE_PARM(hycapi_enable, "i"); | ||
36 | |||
37 | typedef struct _hycapi_appl { | ||
38 | unsigned int ctrl_mask; | ||
39 | capi_register_params rp; | ||
40 | struct sk_buff *listen_req[CAPI_MAXCONTR]; | ||
41 | } hycapi_appl; | ||
42 | |||
43 | static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; | ||
44 | |||
45 | static inline int _hycapi_appCheck(int app_id, int ctrl_no) | ||
46 | { | ||
47 | if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || | ||
48 | (app_id > CAPI_MAXAPPL)) | ||
49 | { | ||
50 | printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no); | ||
51 | return -1; | ||
52 | } | ||
53 | return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0); | ||
54 | } | ||
55 | |||
56 | /****************************** | ||
57 | Kernel-Capi callback reset_ctr | ||
58 | ******************************/ | ||
59 | |||
60 | void | ||
61 | hycapi_reset_ctr(struct capi_ctr *ctrl) | ||
62 | { | ||
63 | hycapictrl_info *cinfo = ctrl->driverdata; | ||
64 | |||
65 | #ifdef HYCAPI_PRINTFNAMES | ||
66 | printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); | ||
67 | #endif | ||
68 | capilib_release(&cinfo->ncci_head); | ||
69 | capi_ctr_reseted(ctrl); | ||
70 | } | ||
71 | |||
72 | /****************************** | ||
73 | Kernel-Capi callback remove_ctr | ||
74 | ******************************/ | ||
75 | |||
76 | void | ||
77 | hycapi_remove_ctr(struct capi_ctr *ctrl) | ||
78 | { | ||
79 | int i; | ||
80 | hycapictrl_info *cinfo = NULL; | ||
81 | hysdn_card *card = NULL; | ||
82 | #ifdef HYCAPI_PRINTFNAMES | ||
83 | printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n"); | ||
84 | #endif | ||
85 | cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
86 | if(!cinfo) { | ||
87 | printk(KERN_ERR "No hycapictrl_info set!"); | ||
88 | return; | ||
89 | } | ||
90 | card = cinfo->card; | ||
91 | capi_ctr_suspend_output(ctrl); | ||
92 | for(i=0; i<CAPI_MAXAPPL;i++) { | ||
93 | if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { | ||
94 | kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]); | ||
95 | hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL; | ||
96 | } | ||
97 | } | ||
98 | detach_capi_ctr(ctrl); | ||
99 | ctrl->driverdata = NULL; | ||
100 | kfree(card->hyctrlinfo); | ||
101 | |||
102 | |||
103 | card->hyctrlinfo = NULL; | ||
104 | } | ||
105 | |||
106 | /*********************************************************** | ||
107 | |||
108 | Queue a CAPI-message to the controller. | ||
109 | |||
110 | ***********************************************************/ | ||
111 | |||
112 | static void | ||
113 | hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb) | ||
114 | { | ||
115 | hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
116 | hysdn_card *card = cinfo->card; | ||
117 | |||
118 | spin_lock_irq(&cinfo->lock); | ||
119 | #ifdef HYCAPI_PRINTFNAMES | ||
120 | printk(KERN_NOTICE "hycapi_send_message\n"); | ||
121 | #endif | ||
122 | cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */ | ||
123 | if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB) | ||
124 | cinfo->in_idx = 0; /* wrap around */ | ||
125 | cinfo->sk_count++; /* adjust counter */ | ||
126 | if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) { | ||
127 | /* inform upper layers we're full */ | ||
128 | printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n", | ||
129 | card->myid); | ||
130 | capi_ctr_suspend_output(ctrl); | ||
131 | } | ||
132 | cinfo->tx_skb = skb; | ||
133 | spin_unlock_irq(&cinfo->lock); | ||
134 | schedule_work(&card->irq_queue); | ||
135 | } | ||
136 | |||
137 | /*********************************************************** | ||
138 | hycapi_register_internal | ||
139 | |||
140 | Send down the CAPI_REGISTER-Command to the controller. | ||
141 | This functions will also be used if the adapter has been rebooted to | ||
142 | re-register any applications in the private list. | ||
143 | |||
144 | ************************************************************/ | ||
145 | |||
146 | static void | ||
147 | hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, | ||
148 | capi_register_params *rp) | ||
149 | { | ||
150 | char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*"; | ||
151 | hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
152 | hysdn_card *card = cinfo->card; | ||
153 | struct sk_buff *skb; | ||
154 | __u16 len; | ||
155 | __u8 _command = 0xa0, _subcommand = 0x80; | ||
156 | __u16 MessageNumber = 0x0000; | ||
157 | __u16 MessageBufferSize = 0; | ||
158 | int slen = strlen(ExtFeatureDefaults); | ||
159 | #ifdef HYCAPI_PRINTFNAMES | ||
160 | printk(KERN_NOTICE "hycapi_register_appl\n"); | ||
161 | #endif | ||
162 | MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; | ||
163 | |||
164 | len = CAPI_MSG_BASELEN + 8 + slen + 1; | ||
165 | if (!(skb = alloc_skb(len, GFP_ATOMIC))) { | ||
166 | printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", | ||
167 | card->myid); | ||
168 | return; | ||
169 | } | ||
170 | memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); | ||
171 | memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); | ||
172 | memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); | ||
173 | memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); | ||
174 | memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); | ||
175 | memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); | ||
176 | memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16)); | ||
177 | memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16)); | ||
178 | memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16)); | ||
179 | memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen); | ||
180 | hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1)); | ||
181 | hycapi_send_message(ctrl, skb); | ||
182 | } | ||
183 | |||
184 | /************************************************************ | ||
185 | hycapi_restart_internal | ||
186 | |||
187 | After an adapter has been rebootet, re-register all applications and | ||
188 | send a LISTEN_REQ (if there has been such a thing ) | ||
189 | |||
190 | *************************************************************/ | ||
191 | |||
192 | static void hycapi_restart_internal(struct capi_ctr *ctrl) | ||
193 | { | ||
194 | int i; | ||
195 | struct sk_buff *skb; | ||
196 | #ifdef HYCAPI_PRINTFNAMES | ||
197 | printk(KERN_WARNING "HYSDN: hycapi_restart_internal"); | ||
198 | #endif | ||
199 | for(i=0; i<CAPI_MAXAPPL; i++) { | ||
200 | if(_hycapi_appCheck(i+1, ctrl->cnr) == 1) { | ||
201 | hycapi_register_internal(ctrl, i+1, | ||
202 | &hycapi_applications[i].rp); | ||
203 | if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { | ||
204 | skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC); | ||
205 | hycapi_sendmsg_internal(ctrl, skb); | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | /************************************************************* | ||
212 | Register an application. | ||
213 | Error-checking is done for CAPI-compliance. | ||
214 | |||
215 | The application is recorded in the internal list. | ||
216 | *************************************************************/ | ||
217 | |||
218 | void | ||
219 | hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, | ||
220 | capi_register_params *rp) | ||
221 | { | ||
222 | int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0; | ||
223 | hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
224 | hysdn_card *card = cinfo->card; | ||
225 | int chk = _hycapi_appCheck(appl, ctrl->cnr); | ||
226 | if(chk < 0) { | ||
227 | return; | ||
228 | } | ||
229 | if(chk == 1) { | ||
230 | printk(KERN_INFO "HYSDN: apl %d already registered\n", appl); | ||
231 | return; | ||
232 | } | ||
233 | MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt; | ||
234 | rp->datablkcnt = MaxBDataBlocks; | ||
235 | MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ; | ||
236 | rp->datablklen = MaxBDataLen; | ||
237 | |||
238 | MaxLogicalConnections = rp->level3cnt; | ||
239 | if (MaxLogicalConnections < 0) { | ||
240 | MaxLogicalConnections = card->bchans * -MaxLogicalConnections; | ||
241 | } | ||
242 | if (MaxLogicalConnections == 0) { | ||
243 | MaxLogicalConnections = card->bchans; | ||
244 | } | ||
245 | |||
246 | rp->level3cnt = MaxLogicalConnections; | ||
247 | memcpy(&hycapi_applications[appl-1].rp, | ||
248 | rp, sizeof(capi_register_params)); | ||
249 | } | ||
250 | |||
251 | /********************************************************************* | ||
252 | |||
253 | hycapi_release_internal | ||
254 | |||
255 | Send down a CAPI_RELEASE to the controller. | ||
256 | *********************************************************************/ | ||
257 | |||
258 | static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) | ||
259 | { | ||
260 | hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
261 | hysdn_card *card = cinfo->card; | ||
262 | struct sk_buff *skb; | ||
263 | __u16 len; | ||
264 | __u8 _command = 0xa1, _subcommand = 0x80; | ||
265 | __u16 MessageNumber = 0x0000; | ||
266 | |||
267 | capilib_release_appl(&cinfo->ncci_head, appl); | ||
268 | |||
269 | #ifdef HYCAPI_PRINTFNAMES | ||
270 | printk(KERN_NOTICE "hycapi_release_appl\n"); | ||
271 | #endif | ||
272 | len = CAPI_MSG_BASELEN; | ||
273 | if (!(skb = alloc_skb(len, GFP_ATOMIC))) { | ||
274 | printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", | ||
275 | card->myid); | ||
276 | return; | ||
277 | } | ||
278 | memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); | ||
279 | memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); | ||
280 | memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); | ||
281 | memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); | ||
282 | memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); | ||
283 | hycapi_send_message(ctrl, skb); | ||
284 | hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1)); | ||
285 | } | ||
286 | |||
287 | /****************************************************************** | ||
288 | hycapi_release_appl | ||
289 | |||
290 | Release the application from the internal list an remove it's | ||
291 | registration at controller-level | ||
292 | ******************************************************************/ | ||
293 | |||
294 | void | ||
295 | hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) | ||
296 | { | ||
297 | int chk; | ||
298 | |||
299 | chk = _hycapi_appCheck(appl, ctrl->cnr); | ||
300 | if(chk<0) { | ||
301 | printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr); | ||
302 | return; | ||
303 | } | ||
304 | if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) { | ||
305 | kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]); | ||
306 | hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL; | ||
307 | } | ||
308 | if(chk == 1) | ||
309 | { | ||
310 | hycapi_release_internal(ctrl, appl); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | |||
315 | /************************************************************** | ||
316 | Kill a single controller. | ||
317 | **************************************************************/ | ||
318 | |||
319 | int hycapi_capi_release(hysdn_card *card) | ||
320 | { | ||
321 | hycapictrl_info *cinfo = card->hyctrlinfo; | ||
322 | struct capi_ctr *ctrl; | ||
323 | #ifdef HYCAPI_PRINTFNAMES | ||
324 | printk(KERN_NOTICE "hycapi_capi_release\n"); | ||
325 | #endif | ||
326 | if(cinfo) { | ||
327 | ctrl = &cinfo->capi_ctrl; | ||
328 | hycapi_remove_ctr(ctrl); | ||
329 | } | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /************************************************************** | ||
334 | hycapi_capi_stop | ||
335 | |||
336 | Stop CAPI-Output on a card. (e.g. during reboot) | ||
337 | ***************************************************************/ | ||
338 | |||
339 | int hycapi_capi_stop(hysdn_card *card) | ||
340 | { | ||
341 | hycapictrl_info *cinfo = card->hyctrlinfo; | ||
342 | struct capi_ctr *ctrl; | ||
343 | #ifdef HYCAPI_PRINTFNAMES | ||
344 | printk(KERN_NOTICE "hycapi_capi_stop\n"); | ||
345 | #endif | ||
346 | if(cinfo) { | ||
347 | ctrl = &cinfo->capi_ctrl; | ||
348 | /* ctrl->suspend_output(ctrl); */ | ||
349 | capi_ctr_reseted(ctrl); | ||
350 | } | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /*************************************************************** | ||
355 | hycapi_send_message | ||
356 | |||
357 | Send a message to the controller. | ||
358 | |||
359 | Messages are parsed for their Command/Subcommand-type, and appropriate | ||
360 | action's are performed. | ||
361 | |||
362 | Note that we have to muck around with a 64Bit-DATA_REQ as there are | ||
363 | firmware-releases that do not check the MsgLen-Indication! | ||
364 | |||
365 | ***************************************************************/ | ||
366 | |||
367 | u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | ||
368 | { | ||
369 | __u16 appl_id; | ||
370 | int _len, _len2; | ||
371 | __u8 msghead[64]; | ||
372 | hycapictrl_info *cinfo = ctrl->driverdata; | ||
373 | u16 retval = CAPI_NOERROR; | ||
374 | |||
375 | appl_id = CAPIMSG_APPID(skb->data); | ||
376 | switch(_hycapi_appCheck(appl_id, ctrl->cnr)) | ||
377 | { | ||
378 | case 0: | ||
379 | /* printk(KERN_INFO "Need to register\n"); */ | ||
380 | hycapi_register_internal(ctrl, | ||
381 | appl_id, | ||
382 | &(hycapi_applications[appl_id-1].rp)); | ||
383 | break; | ||
384 | case 1: | ||
385 | break; | ||
386 | default: | ||
387 | printk(KERN_ERR "HYCAPI: Controller mixup!\n"); | ||
388 | retval = CAPI_ILLAPPNR; | ||
389 | goto out; | ||
390 | } | ||
391 | switch(CAPIMSG_CMD(skb->data)) { | ||
392 | case CAPI_DISCONNECT_B3_RESP: | ||
393 | capilib_free_ncci(&cinfo->ncci_head, appl_id, | ||
394 | CAPIMSG_NCCI(skb->data)); | ||
395 | break; | ||
396 | case CAPI_DATA_B3_REQ: | ||
397 | _len = CAPIMSG_LEN(skb->data); | ||
398 | if (_len > 22) { | ||
399 | _len2 = _len - 22; | ||
400 | memcpy(msghead, skb->data, 22); | ||
401 | memcpy(skb->data + _len2, msghead, 22); | ||
402 | skb_pull(skb, _len2); | ||
403 | CAPIMSG_SETLEN(skb->data, 22); | ||
404 | retval = capilib_data_b3_req(&cinfo->ncci_head, | ||
405 | CAPIMSG_APPID(skb->data), | ||
406 | CAPIMSG_NCCI(skb->data), | ||
407 | CAPIMSG_MSGID(skb->data)); | ||
408 | } | ||
409 | break; | ||
410 | case CAPI_LISTEN_REQ: | ||
411 | if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]) | ||
412 | { | ||
413 | kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]); | ||
414 | hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL; | ||
415 | } | ||
416 | if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC))) | ||
417 | { | ||
418 | printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n"); | ||
419 | } | ||
420 | break; | ||
421 | default: | ||
422 | break; | ||
423 | } | ||
424 | out: | ||
425 | if (retval == CAPI_NOERROR) | ||
426 | hycapi_sendmsg_internal(ctrl, skb); | ||
427 | else | ||
428 | dev_kfree_skb_any(skb); | ||
429 | |||
430 | return retval; | ||
431 | } | ||
432 | |||
433 | /********************************************************************* | ||
434 | hycapi_read_proc | ||
435 | |||
436 | Informations provided in the /proc/capi-entries. | ||
437 | |||
438 | *********************************************************************/ | ||
439 | |||
440 | int hycapi_read_proc(char *page, char **start, off_t off, | ||
441 | int count, int *eof, struct capi_ctr *ctrl) | ||
442 | { | ||
443 | hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
444 | hysdn_card *card = cinfo->card; | ||
445 | int len = 0; | ||
446 | char *s; | ||
447 | #ifdef HYCAPI_PRINTFNAMES | ||
448 | printk(KERN_NOTICE "hycapi_read_proc\n"); | ||
449 | #endif | ||
450 | len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname); | ||
451 | len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase); | ||
452 | len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); | ||
453 | |||
454 | switch (card->brdtype) { | ||
455 | case BD_PCCARD: s = "HYSDN Hycard"; break; | ||
456 | case BD_ERGO: s = "HYSDN Ergo2"; break; | ||
457 | case BD_METRO: s = "HYSDN Metro4"; break; | ||
458 | case BD_CHAMP2: s = "HYSDN Champ2"; break; | ||
459 | case BD_PLEXUS: s = "HYSDN Plexus30"; break; | ||
460 | default: s = "???"; break; | ||
461 | } | ||
462 | len += sprintf(page+len, "%-16s %s\n", "type", s); | ||
463 | if ((s = cinfo->version[VER_DRIVER]) != 0) | ||
464 | len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); | ||
465 | if ((s = cinfo->version[VER_CARDTYPE]) != 0) | ||
466 | len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); | ||
467 | if ((s = cinfo->version[VER_SERIAL]) != 0) | ||
468 | len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); | ||
469 | |||
470 | len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); | ||
471 | |||
472 | if (off+count >= len) | ||
473 | *eof = 1; | ||
474 | if (len < off) | ||
475 | return 0; | ||
476 | *start = page + off; | ||
477 | return ((count < len-off) ? count : len-off); | ||
478 | } | ||
479 | |||
480 | /************************************************************** | ||
481 | hycapi_load_firmware | ||
482 | |||
483 | This does NOT load any firmware, but the callback somehow is needed | ||
484 | on capi-interface registration. | ||
485 | |||
486 | **************************************************************/ | ||
487 | |||
488 | int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) | ||
489 | { | ||
490 | #ifdef HYCAPI_PRINTFNAMES | ||
491 | printk(KERN_NOTICE "hycapi_load_firmware\n"); | ||
492 | #endif | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | |||
497 | char *hycapi_procinfo(struct capi_ctr *ctrl) | ||
498 | { | ||
499 | hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); | ||
500 | #ifdef HYCAPI_PRINTFNAMES | ||
501 | printk(KERN_NOTICE "hycapi_proc_info\n"); | ||
502 | #endif | ||
503 | if (!cinfo) | ||
504 | return ""; | ||
505 | sprintf(cinfo->infobuf, "%s %s 0x%x %d %s", | ||
506 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
507 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
508 | cinfo->card ? cinfo->card->iobase : 0x0, | ||
509 | cinfo->card ? cinfo->card->irq : 0, | ||
510 | hycapi_revision | ||
511 | ); | ||
512 | return cinfo->infobuf; | ||
513 | } | ||
514 | |||
515 | /****************************************************************** | ||
516 | hycapi_rx_capipkt | ||
517 | |||
518 | Receive a capi-message. | ||
519 | |||
520 | All B3_DATA_IND are converted to 64K-extension compatible format. | ||
521 | New nccis are created if necessary. | ||
522 | *******************************************************************/ | ||
523 | |||
524 | void | ||
525 | hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len) | ||
526 | { | ||
527 | struct sk_buff *skb; | ||
528 | hycapictrl_info *cinfo = card->hyctrlinfo; | ||
529 | struct capi_ctr *ctrl; | ||
530 | __u16 ApplId; | ||
531 | __u16 MsgLen, info; | ||
532 | __u16 len2, CapiCmd; | ||
533 | __u32 CP64[2] = {0,0}; | ||
534 | #ifdef HYCAPI_PRINTFNAMES | ||
535 | printk(KERN_NOTICE "hycapi_rx_capipkt\n"); | ||
536 | #endif | ||
537 | if(!cinfo) { | ||
538 | return; | ||
539 | } | ||
540 | ctrl = &cinfo->capi_ctrl; | ||
541 | if(len < CAPI_MSG_BASELEN) { | ||
542 | printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n", | ||
543 | card->myid, len); | ||
544 | return; | ||
545 | } | ||
546 | MsgLen = CAPIMSG_LEN(buf); | ||
547 | ApplId = CAPIMSG_APPID(buf); | ||
548 | CapiCmd = CAPIMSG_CMD(buf); | ||
549 | |||
550 | if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) { | ||
551 | len2 = len + (30 - MsgLen); | ||
552 | if (!(skb = alloc_skb(len2, GFP_ATOMIC))) { | ||
553 | printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", | ||
554 | card->myid); | ||
555 | return; | ||
556 | } | ||
557 | memcpy(skb_put(skb, MsgLen), buf, MsgLen); | ||
558 | memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32)); | ||
559 | memcpy(skb_put(skb, len - MsgLen), buf + MsgLen, | ||
560 | len - MsgLen); | ||
561 | CAPIMSG_SETLEN(skb->data, 30); | ||
562 | } else { | ||
563 | if (!(skb = alloc_skb(len, GFP_ATOMIC))) { | ||
564 | printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", | ||
565 | card->myid); | ||
566 | return; | ||
567 | } | ||
568 | memcpy(skb_put(skb, len), buf, len); | ||
569 | } | ||
570 | switch(CAPIMSG_CMD(skb->data)) | ||
571 | { | ||
572 | case CAPI_CONNECT_B3_CONF: | ||
573 | /* Check info-field for error-indication: */ | ||
574 | info = CAPIMSG_U16(skb->data, 12); | ||
575 | switch(info) | ||
576 | { | ||
577 | case 0: | ||
578 | capilib_new_ncci(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data), | ||
579 | hycapi_applications[ApplId-1].rp.datablkcnt); | ||
580 | |||
581 | break; | ||
582 | case 0x0001: | ||
583 | printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current " | ||
584 | "protocol. NCPI ignored.\n", card->myid); | ||
585 | break; | ||
586 | case 0x2001: | ||
587 | printk(KERN_ERR "HYSDN Card%d: Message not supported in" | ||
588 | " current state\n", card->myid); | ||
589 | break; | ||
590 | case 0x2002: | ||
591 | printk(KERN_ERR "HYSDN Card%d: invalid PLCI\n", card->myid); | ||
592 | break; | ||
593 | case 0x2004: | ||
594 | printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid); | ||
595 | break; | ||
596 | case 0x3008: | ||
597 | printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", | ||
598 | card->myid); | ||
599 | break; | ||
600 | default: | ||
601 | printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", | ||
602 | card->myid, info); | ||
603 | break; | ||
604 | } | ||
605 | break; | ||
606 | case CAPI_CONNECT_B3_IND: | ||
607 | capilib_new_ncci(&cinfo->ncci_head, ApplId, | ||
608 | CAPIMSG_NCCI(skb->data), | ||
609 | hycapi_applications[ApplId-1].rp.datablkcnt); | ||
610 | break; | ||
611 | case CAPI_DATA_B3_CONF: | ||
612 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | ||
613 | CAPIMSG_NCCI(skb->data), | ||
614 | CAPIMSG_MSGID(skb->data)); | ||
615 | break; | ||
616 | default: | ||
617 | break; | ||
618 | } | ||
619 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
620 | } | ||
621 | |||
622 | /****************************************************************** | ||
623 | hycapi_tx_capiack | ||
624 | |||
625 | Internally acknowledge a msg sent. This will remove the msg from the | ||
626 | internal queue. | ||
627 | |||
628 | *******************************************************************/ | ||
629 | |||
630 | void hycapi_tx_capiack(hysdn_card * card) | ||
631 | { | ||
632 | hycapictrl_info *cinfo = card->hyctrlinfo; | ||
633 | #ifdef HYCAPI_PRINTFNAMES | ||
634 | printk(KERN_NOTICE "hycapi_tx_capiack\n"); | ||
635 | #endif | ||
636 | if(!cinfo) { | ||
637 | return; | ||
638 | } | ||
639 | spin_lock_irq(&cinfo->lock); | ||
640 | kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */ | ||
641 | cinfo->skbs[cinfo->out_idx++] = NULL; | ||
642 | if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB) | ||
643 | cinfo->out_idx = 0; /* wrap around */ | ||
644 | |||
645 | if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */ | ||
646 | capi_ctr_resume_output(&cinfo->capi_ctrl); | ||
647 | spin_unlock_irq(&cinfo->lock); | ||
648 | } | ||
649 | |||
650 | /*************************************************************** | ||
651 | hycapi_tx_capiget(hysdn_card *card) | ||
652 | |||
653 | This is called when polling for messages to SEND. | ||
654 | |||
655 | ****************************************************************/ | ||
656 | |||
657 | struct sk_buff * | ||
658 | hycapi_tx_capiget(hysdn_card *card) | ||
659 | { | ||
660 | hycapictrl_info *cinfo = card->hyctrlinfo; | ||
661 | if(!cinfo) { | ||
662 | return (struct sk_buff *)NULL; | ||
663 | } | ||
664 | if (!cinfo->sk_count) | ||
665 | return (struct sk_buff *)NULL; /* nothing available */ | ||
666 | |||
667 | return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */ | ||
668 | } | ||
669 | |||
670 | |||
671 | /********************************************************** | ||
672 | int hycapi_init() | ||
673 | |||
674 | attach the capi-driver to the kernel-capi. | ||
675 | |||
676 | ***********************************************************/ | ||
677 | |||
678 | int hycapi_init(void) | ||
679 | { | ||
680 | int i; | ||
681 | for(i=0;i<CAPI_MAXAPPL;i++) { | ||
682 | memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl)); | ||
683 | } | ||
684 | return(0); | ||
685 | } | ||
686 | |||
687 | /************************************************************** | ||
688 | hycapi_cleanup(void) | ||
689 | |||
690 | detach the capi-driver to the kernel-capi. Actually this should | ||
691 | free some more ressources. Do that later. | ||
692 | **************************************************************/ | ||
693 | |||
694 | void | ||
695 | hycapi_cleanup(void) | ||
696 | { | ||
697 | } | ||
698 | |||
699 | /******************************************************************** | ||
700 | hycapi_capi_create(hysdn_card *card) | ||
701 | |||
702 | Attach the card with its capi-ctrl. | ||
703 | *********************************************************************/ | ||
704 | |||
705 | static void hycapi_fill_profile(hysdn_card *card) | ||
706 | { | ||
707 | hycapictrl_info *cinfo = NULL; | ||
708 | struct capi_ctr *ctrl = NULL; | ||
709 | cinfo = card->hyctrlinfo; | ||
710 | if(!cinfo) return; | ||
711 | ctrl = &cinfo->capi_ctrl; | ||
712 | strcpy(ctrl->manu, "Hypercope"); | ||
713 | ctrl->version.majorversion = 2; | ||
714 | ctrl->version.minorversion = 0; | ||
715 | ctrl->version.majormanuversion = 3; | ||
716 | ctrl->version.minormanuversion = 2; | ||
717 | ctrl->profile.ncontroller = card->myid; | ||
718 | ctrl->profile.nbchannel = card->bchans; | ||
719 | ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER | | ||
720 | GLOBAL_OPTION_B_CHANNEL_OPERATION; | ||
721 | ctrl->profile.support1 = B1_PROT_64KBIT_HDLC | | ||
722 | (card->faxchans ? B1_PROT_T30 : 0) | | ||
723 | B1_PROT_64KBIT_TRANSPARENT; | ||
724 | ctrl->profile.support2 = B2_PROT_ISO7776 | | ||
725 | (card->faxchans ? B2_PROT_T30 : 0) | | ||
726 | B2_PROT_TRANSPARENT; | ||
727 | ctrl->profile.support3 = B3_PROT_TRANSPARENT | | ||
728 | B3_PROT_T90NL | | ||
729 | (card->faxchans ? B3_PROT_T30 : 0) | | ||
730 | (card->faxchans ? B3_PROT_T30EXT : 0) | | ||
731 | B3_PROT_ISO8208; | ||
732 | } | ||
733 | |||
734 | int | ||
735 | hycapi_capi_create(hysdn_card *card) | ||
736 | { | ||
737 | hycapictrl_info *cinfo = NULL; | ||
738 | struct capi_ctr *ctrl = NULL; | ||
739 | int retval; | ||
740 | #ifdef HYCAPI_PRINTFNAMES | ||
741 | printk(KERN_NOTICE "hycapi_capi_create\n"); | ||
742 | #endif | ||
743 | if((hycapi_enable & (1 << card->myid)) == 0) { | ||
744 | return 1; | ||
745 | } | ||
746 | if (!card->hyctrlinfo) { | ||
747 | cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC); | ||
748 | if (!cinfo) { | ||
749 | printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n"); | ||
750 | return -ENOMEM; | ||
751 | } | ||
752 | memset(cinfo, 0, sizeof(hycapictrl_info)); | ||
753 | card->hyctrlinfo = cinfo; | ||
754 | cinfo->card = card; | ||
755 | spin_lock_init(&cinfo->lock); | ||
756 | INIT_LIST_HEAD(&cinfo->ncci_head); | ||
757 | |||
758 | switch (card->brdtype) { | ||
759 | case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break; | ||
760 | case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break; | ||
761 | case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break; | ||
762 | case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break; | ||
763 | case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break; | ||
764 | default: strcpy(cinfo->cardname,"HYSDN ???"); break; | ||
765 | } | ||
766 | |||
767 | ctrl = &cinfo->capi_ctrl; | ||
768 | ctrl->driver_name = "hycapi"; | ||
769 | ctrl->driverdata = cinfo; | ||
770 | ctrl->register_appl = hycapi_register_appl; | ||
771 | ctrl->release_appl = hycapi_release_appl; | ||
772 | ctrl->send_message = hycapi_send_message; | ||
773 | ctrl->load_firmware = hycapi_load_firmware; | ||
774 | ctrl->reset_ctr = hycapi_reset_ctr; | ||
775 | ctrl->procinfo = hycapi_procinfo; | ||
776 | ctrl->ctr_read_proc = hycapi_read_proc; | ||
777 | strcpy(ctrl->name, cinfo->cardname); | ||
778 | ctrl->owner = THIS_MODULE; | ||
779 | |||
780 | retval = attach_capi_ctr(ctrl); | ||
781 | if (retval) { | ||
782 | printk(KERN_ERR "hycapi: attach controller failed.\n"); | ||
783 | return -EBUSY; | ||
784 | } | ||
785 | /* fill in the blanks: */ | ||
786 | hycapi_fill_profile(card); | ||
787 | capi_ctr_ready(ctrl); | ||
788 | } else { | ||
789 | /* resume output on stopped ctrl */ | ||
790 | ctrl = &card->hyctrlinfo->capi_ctrl; | ||
791 | hycapi_fill_profile(card); | ||
792 | capi_ctr_ready(ctrl); | ||
793 | hycapi_restart_internal(ctrl); | ||
794 | /* ctrl->resume_output(ctrl); */ | ||
795 | } | ||
796 | return 0; | ||
797 | } | ||
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c new file mode 100644 index 000000000000..6c04281e57b8 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_boot.c | |||
@@ -0,0 +1,399 @@ | |||
1 | /* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards | ||
4 | * specific routines for booting and pof handling | ||
5 | * | ||
6 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
7 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/vmalloc.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <asm/uaccess.h> | ||
17 | |||
18 | #include "hysdn_defs.h" | ||
19 | #include "hysdn_pof.h" | ||
20 | |||
21 | /********************************/ | ||
22 | /* defines for pof read handler */ | ||
23 | /********************************/ | ||
24 | #define POF_READ_FILE_HEAD 0 | ||
25 | #define POF_READ_TAG_HEAD 1 | ||
26 | #define POF_READ_TAG_DATA 2 | ||
27 | |||
28 | /************************************************************/ | ||
29 | /* definition of boot specific data area. This data is only */ | ||
30 | /* needed during boot and so allocated dynamically. */ | ||
31 | /************************************************************/ | ||
32 | struct boot_data { | ||
33 | word Cryptor; /* for use with Decrypt function */ | ||
34 | word Nrecs; /* records remaining in file */ | ||
35 | uchar pof_state; /* actual state of read handler */ | ||
36 | uchar is_crypted; /* card data is crypted */ | ||
37 | int BufSize; /* actual number of bytes bufferd */ | ||
38 | int last_error; /* last occurred error */ | ||
39 | word pof_recid; /* actual pof recid */ | ||
40 | ulong pof_reclen; /* total length of pof record data */ | ||
41 | ulong pof_recoffset; /* actual offset inside pof record */ | ||
42 | union { | ||
43 | uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */ | ||
44 | tPofRecHdr PofRecHdr; /* header for actual record/chunk */ | ||
45 | tPofFileHdr PofFileHdr; /* header from POF file */ | ||
46 | tPofTimeStamp PofTime; /* time information */ | ||
47 | } buf; | ||
48 | }; | ||
49 | |||
50 | /*****************************************************/ | ||
51 | /* start decryption of successive POF file chuncks. */ | ||
52 | /* */ | ||
53 | /* to be called at start of POF file reading, */ | ||
54 | /* before starting any decryption on any POF record. */ | ||
55 | /*****************************************************/ | ||
56 | void | ||
57 | StartDecryption(struct boot_data *boot) | ||
58 | { | ||
59 | boot->Cryptor = CRYPT_STARTTERM; | ||
60 | } /* StartDecryption */ | ||
61 | |||
62 | |||
63 | /***************************************************************/ | ||
64 | /* decrypt complete BootBuf */ | ||
65 | /* NOTE: decryption must be applied to all or none boot tags - */ | ||
66 | /* to HI and LO boot loader and (all) seq tags, because */ | ||
67 | /* global Cryptor is started for whole POF. */ | ||
68 | /***************************************************************/ | ||
69 | void | ||
70 | DecryptBuf(struct boot_data *boot, int cnt) | ||
71 | { | ||
72 | uchar *bufp = boot->buf.BootBuf; | ||
73 | |||
74 | while (cnt--) { | ||
75 | boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); | ||
76 | *bufp++ ^= (uchar) boot->Cryptor; | ||
77 | } | ||
78 | } /* DecryptBuf */ | ||
79 | |||
80 | /********************************************************************************/ | ||
81 | /* pof_handle_data executes the required actions dependent on the active record */ | ||
82 | /* id. If successful 0 is returned, a negative value shows an error. */ | ||
83 | /********************************************************************************/ | ||
84 | static int | ||
85 | pof_handle_data(hysdn_card * card, int datlen) | ||
86 | { | ||
87 | struct boot_data *boot = card->boot; /* pointer to boot specific data */ | ||
88 | long l; | ||
89 | uchar *imgp; | ||
90 | int img_len; | ||
91 | |||
92 | /* handle the different record types */ | ||
93 | switch (boot->pof_recid) { | ||
94 | |||
95 | case TAG_TIMESTMP: | ||
96 | if (card->debug_flags & LOG_POF_RECORD) | ||
97 | hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); | ||
98 | break; | ||
99 | |||
100 | case TAG_CBOOTDTA: | ||
101 | DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ | ||
102 | case TAG_BOOTDTA: | ||
103 | if (card->debug_flags & LOG_POF_RECORD) | ||
104 | hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", | ||
105 | (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", | ||
106 | datlen, boot->pof_recoffset); | ||
107 | |||
108 | if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { | ||
109 | boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */ | ||
110 | return (boot->last_error); | ||
111 | } | ||
112 | imgp = boot->buf.BootBuf; /* start of buffer */ | ||
113 | img_len = datlen; /* maximum length to transfer */ | ||
114 | |||
115 | l = POF_BOOT_LOADER_OFF_IN_PAGE - | ||
116 | (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); | ||
117 | if (l > 0) { | ||
118 | /* buffer needs to be truncated */ | ||
119 | imgp += l; /* advance pointer */ | ||
120 | img_len -= l; /* adjust len */ | ||
121 | } | ||
122 | /* at this point no special handling for data wrapping over buffer */ | ||
123 | /* is necessary, because the boot image always will be adjusted to */ | ||
124 | /* match a page boundary inside the buffer. */ | ||
125 | /* The buffer for the boot image on the card is filled in 2 cycles */ | ||
126 | /* first the 1024 hi-words are put in the buffer, then the low 1024 */ | ||
127 | /* word are handled in the same way with different offset. */ | ||
128 | |||
129 | if (img_len > 0) { | ||
130 | /* data available for copy */ | ||
131 | if ((boot->last_error = | ||
132 | card->writebootimg(card, imgp, | ||
133 | (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) | ||
134 | return (boot->last_error); | ||
135 | } | ||
136 | break; /* end of case boot image hi/lo */ | ||
137 | |||
138 | case TAG_CABSDATA: | ||
139 | DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ | ||
140 | case TAG_ABSDATA: | ||
141 | if (card->debug_flags & LOG_POF_RECORD) | ||
142 | hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", | ||
143 | (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", | ||
144 | datlen, boot->pof_recoffset); | ||
145 | |||
146 | if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0)) | ||
147 | return (boot->last_error); /* error writing data */ | ||
148 | |||
149 | if (boot->pof_recoffset + datlen >= boot->pof_reclen) | ||
150 | return (card->waitpofready(card)); /* data completely spooled, wait for ready */ | ||
151 | |||
152 | break; /* end of case boot seq data */ | ||
153 | |||
154 | default: | ||
155 | if (card->debug_flags & LOG_POF_RECORD) | ||
156 | hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, | ||
157 | datlen, boot->pof_recoffset); | ||
158 | |||
159 | break; /* simply skip record */ | ||
160 | } /* switch boot->pof_recid */ | ||
161 | |||
162 | return (0); | ||
163 | } /* pof_handle_data */ | ||
164 | |||
165 | |||
166 | /******************************************************************************/ | ||
167 | /* pof_write_buffer is called when the buffer has been filled with the needed */ | ||
168 | /* number of data bytes. The number delivered is additionally supplied for */ | ||
169 | /* verification. The functions handles the data and returns the needed number */ | ||
170 | /* of bytes for the next action. If the returned value is 0 or less an error */ | ||
171 | /* occurred and booting must be aborted. */ | ||
172 | /******************************************************************************/ | ||
173 | int | ||
174 | pof_write_buffer(hysdn_card * card, int datlen) | ||
175 | { | ||
176 | struct boot_data *boot = card->boot; /* pointer to boot specific data */ | ||
177 | |||
178 | if (!boot) | ||
179 | return (-EFAULT); /* invalid call */ | ||
180 | if (boot->last_error < 0) | ||
181 | return (boot->last_error); /* repeated error */ | ||
182 | |||
183 | if (card->debug_flags & LOG_POF_WRITE) | ||
184 | hysdn_addlog(card, "POF write: got %d bytes ", datlen); | ||
185 | |||
186 | switch (boot->pof_state) { | ||
187 | case POF_READ_FILE_HEAD: | ||
188 | if (card->debug_flags & LOG_POF_WRITE) | ||
189 | hysdn_addlog(card, "POF write: checking file header"); | ||
190 | |||
191 | if (datlen != sizeof(tPofFileHdr)) { | ||
192 | boot->last_error = -EPOF_INTERNAL; | ||
193 | break; | ||
194 | } | ||
195 | if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { | ||
196 | boot->last_error = -EPOF_BAD_MAGIC; | ||
197 | break; | ||
198 | } | ||
199 | /* Setup the new state and vars */ | ||
200 | boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */ | ||
201 | boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ | ||
202 | boot->last_error = sizeof(tPofRecHdr); /* new length */ | ||
203 | break; | ||
204 | |||
205 | case POF_READ_TAG_HEAD: | ||
206 | if (card->debug_flags & LOG_POF_WRITE) | ||
207 | hysdn_addlog(card, "POF write: checking tag header"); | ||
208 | |||
209 | if (datlen != sizeof(tPofRecHdr)) { | ||
210 | boot->last_error = -EPOF_INTERNAL; | ||
211 | break; | ||
212 | } | ||
213 | boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */ | ||
214 | boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */ | ||
215 | boot->pof_recoffset = 0; /* no starting offset */ | ||
216 | |||
217 | if (card->debug_flags & LOG_POF_RECORD) | ||
218 | hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", | ||
219 | boot->pof_recid, boot->pof_reclen); | ||
220 | |||
221 | boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */ | ||
222 | if (boot->pof_reclen < BOOT_BUF_SIZE) | ||
223 | boot->last_error = boot->pof_reclen; /* limit size */ | ||
224 | else | ||
225 | boot->last_error = BOOT_BUF_SIZE; /* maximum */ | ||
226 | |||
227 | if (!boot->last_error) { /* no data inside record */ | ||
228 | boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ | ||
229 | boot->last_error = sizeof(tPofRecHdr); /* new length */ | ||
230 | } | ||
231 | break; | ||
232 | |||
233 | case POF_READ_TAG_DATA: | ||
234 | if (card->debug_flags & LOG_POF_WRITE) | ||
235 | hysdn_addlog(card, "POF write: getting tag data"); | ||
236 | |||
237 | if (datlen != boot->last_error) { | ||
238 | boot->last_error = -EPOF_INTERNAL; | ||
239 | break; | ||
240 | } | ||
241 | if ((boot->last_error = pof_handle_data(card, datlen)) < 0) | ||
242 | return (boot->last_error); /* an error occurred */ | ||
243 | boot->pof_recoffset += datlen; | ||
244 | if (boot->pof_recoffset >= boot->pof_reclen) { | ||
245 | boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ | ||
246 | boot->last_error = sizeof(tPofRecHdr); /* new length */ | ||
247 | } else { | ||
248 | if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) | ||
249 | boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */ | ||
250 | else | ||
251 | boot->last_error = BOOT_BUF_SIZE; /* maximum */ | ||
252 | } | ||
253 | break; | ||
254 | |||
255 | default: | ||
256 | boot->last_error = -EPOF_INTERNAL; /* unknown state */ | ||
257 | break; | ||
258 | } /* switch (boot->pof_state) */ | ||
259 | |||
260 | return (boot->last_error); | ||
261 | } /* pof_write_buffer */ | ||
262 | |||
263 | |||
264 | /*******************************************************************************/ | ||
265 | /* pof_write_open is called when an open for boot on the cardlog device occurs. */ | ||
266 | /* The function returns the needed number of bytes for the next operation. If */ | ||
267 | /* the returned number is less or equal 0 an error specified by this code */ | ||
268 | /* occurred. Additionally the pointer to the buffer data area is set on success */ | ||
269 | /*******************************************************************************/ | ||
270 | int | ||
271 | pof_write_open(hysdn_card * card, uchar ** bufp) | ||
272 | { | ||
273 | struct boot_data *boot; /* pointer to boot specific data */ | ||
274 | |||
275 | if (card->boot) { | ||
276 | if (card->debug_flags & LOG_POF_OPEN) | ||
277 | hysdn_addlog(card, "POF open: already opened for boot"); | ||
278 | return (-ERR_ALREADY_BOOT); /* boot already active */ | ||
279 | } | ||
280 | /* error no mem available */ | ||
281 | if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) { | ||
282 | if (card->debug_flags & LOG_MEM_ERR) | ||
283 | hysdn_addlog(card, "POF open: unable to allocate mem"); | ||
284 | return (-EFAULT); | ||
285 | } | ||
286 | card->boot = boot; | ||
287 | card->state = CARD_STATE_BOOTING; | ||
288 | memset(boot, 0, sizeof(struct boot_data)); | ||
289 | |||
290 | card->stopcard(card); /* first stop the card */ | ||
291 | if (card->testram(card)) { | ||
292 | if (card->debug_flags & LOG_POF_OPEN) | ||
293 | hysdn_addlog(card, "POF open: DPRAM test failure"); | ||
294 | boot->last_error = -ERR_BOARD_DPRAM; | ||
295 | card->state = CARD_STATE_BOOTERR; /* show boot error */ | ||
296 | return (boot->last_error); | ||
297 | } | ||
298 | boot->BufSize = 0; /* Buffer is empty */ | ||
299 | boot->pof_state = POF_READ_FILE_HEAD; /* read file header */ | ||
300 | StartDecryption(boot); /* if POF File should be encrypted */ | ||
301 | |||
302 | if (card->debug_flags & LOG_POF_OPEN) | ||
303 | hysdn_addlog(card, "POF open: success"); | ||
304 | |||
305 | *bufp = boot->buf.BootBuf; /* point to buffer */ | ||
306 | return (sizeof(tPofFileHdr)); | ||
307 | } /* pof_write_open */ | ||
308 | |||
309 | /********************************************************************************/ | ||
310 | /* pof_write_close is called when an close of boot on the cardlog device occurs. */ | ||
311 | /* The return value must be 0 if everything has happened as desired. */ | ||
312 | /********************************************************************************/ | ||
313 | int | ||
314 | pof_write_close(hysdn_card * card) | ||
315 | { | ||
316 | struct boot_data *boot = card->boot; /* pointer to boot specific data */ | ||
317 | |||
318 | if (!boot) | ||
319 | return (-EFAULT); /* invalid call */ | ||
320 | |||
321 | card->boot = NULL; /* no boot active */ | ||
322 | kfree(boot); | ||
323 | |||
324 | if (card->state == CARD_STATE_RUN) | ||
325 | card->set_errlog_state(card, 1); /* activate error log */ | ||
326 | |||
327 | if (card->debug_flags & LOG_POF_OPEN) | ||
328 | hysdn_addlog(card, "POF close: success"); | ||
329 | |||
330 | return (0); | ||
331 | } /* pof_write_close */ | ||
332 | |||
333 | /*********************************************************************************/ | ||
334 | /* EvalSysrTokData checks additional records delivered with the Sysready Message */ | ||
335 | /* when POF has been booted. A return value of 0 is used if no error occurred. */ | ||
336 | /*********************************************************************************/ | ||
337 | int | ||
338 | EvalSysrTokData(hysdn_card * card, uchar * cp, int len) | ||
339 | { | ||
340 | u_char *p; | ||
341 | u_char crc; | ||
342 | |||
343 | if (card->debug_flags & LOG_POF_RECORD) | ||
344 | hysdn_addlog(card, "SysReady Token data length %d", len); | ||
345 | |||
346 | if (len < 2) { | ||
347 | hysdn_addlog(card, "SysReady Token Data to short"); | ||
348 | return (1); | ||
349 | } | ||
350 | for (p = cp, crc = 0; p < (cp + len - 2); p++) | ||
351 | if ((crc & 0x80)) | ||
352 | crc = (((u_char) (crc << 1)) + 1) + *p; | ||
353 | else | ||
354 | crc = ((u_char) (crc << 1)) + *p; | ||
355 | crc = ~crc; | ||
356 | if (crc != *(cp + len - 1)) { | ||
357 | hysdn_addlog(card, "SysReady Token Data invalid CRC"); | ||
358 | return (1); | ||
359 | } | ||
360 | len--; /* don't check CRC byte */ | ||
361 | while (len > 0) { | ||
362 | |||
363 | if (*cp == SYSR_TOK_END) | ||
364 | return (0); /* End of Token stream */ | ||
365 | |||
366 | if (len < (*(cp + 1) + 2)) { | ||
367 | hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); | ||
368 | return (1); | ||
369 | } | ||
370 | switch (*cp) { | ||
371 | case SYSR_TOK_B_CHAN: /* 1 */ | ||
372 | if (*(cp + 1) != 1) | ||
373 | return (1); /* length invalid */ | ||
374 | card->bchans = *(cp + 2); | ||
375 | break; | ||
376 | |||
377 | case SYSR_TOK_FAX_CHAN: /* 2 */ | ||
378 | if (*(cp + 1) != 1) | ||
379 | return (1); /* length invalid */ | ||
380 | card->faxchans = *(cp + 2); | ||
381 | break; | ||
382 | |||
383 | case SYSR_TOK_MAC_ADDR: /* 3 */ | ||
384 | if (*(cp + 1) != 6) | ||
385 | return (1); /* length invalid */ | ||
386 | memcpy(card->mac_addr, cp + 2, 6); | ||
387 | break; | ||
388 | |||
389 | default: | ||
390 | hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); | ||
391 | break; | ||
392 | } | ||
393 | len -= (*(cp + 1) + 2); /* adjust len */ | ||
394 | cp += (*(cp + 1) + 2); /* and pointer */ | ||
395 | } | ||
396 | |||
397 | hysdn_addlog(card, "no end token found"); | ||
398 | return (1); | ||
399 | } /* EvalSysrTokData */ | ||
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h new file mode 100644 index 000000000000..4cee26e558ee --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_defs.h | |||
@@ -0,0 +1,298 @@ | |||
1 | /* $Id: hysdn_defs.h,v 1.5.6.3 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards | ||
4 | * global definitions and exported vars and functions. | ||
5 | * | ||
6 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
7 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef HYSDN_DEFS_H | ||
15 | #define HYSDN_DEFS_H | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/hysdn_if.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | #include <linux/skbuff.h> | ||
22 | |||
23 | /****************************/ | ||
24 | /* storage type definitions */ | ||
25 | /****************************/ | ||
26 | #define uchar unsigned char | ||
27 | #define uint unsigned int | ||
28 | #define ulong unsigned long | ||
29 | #define word unsigned short | ||
30 | |||
31 | #include "ince1pc.h" | ||
32 | |||
33 | #ifdef CONFIG_HYSDN_CAPI | ||
34 | #include <linux/capi.h> | ||
35 | #include <linux/isdn/capicmd.h> | ||
36 | #include <linux/isdn/capiutil.h> | ||
37 | #include <linux/isdn/capilli.h> | ||
38 | |||
39 | /***************************/ | ||
40 | /* CAPI-Profile values. */ | ||
41 | /***************************/ | ||
42 | |||
43 | #define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001 | ||
44 | #define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002 | ||
45 | #define GLOBAL_OPTION_HANDSET 0x0004 | ||
46 | #define GLOBAL_OPTION_DTMF 0x0008 | ||
47 | #define GLOBAL_OPTION_SUPPL_SERVICES 0x0010 | ||
48 | #define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020 | ||
49 | #define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040 | ||
50 | |||
51 | #define B1_PROT_64KBIT_HDLC 0x0001 | ||
52 | #define B1_PROT_64KBIT_TRANSPARENT 0x0002 | ||
53 | #define B1_PROT_V110_ASYNCH 0x0004 | ||
54 | #define B1_PROT_V110_SYNCH 0x0008 | ||
55 | #define B1_PROT_T30 0x0010 | ||
56 | #define B1_PROT_64KBIT_INV_HDLC 0x0020 | ||
57 | #define B1_PROT_56KBIT_TRANSPARENT 0x0040 | ||
58 | |||
59 | #define B2_PROT_ISO7776 0x0001 | ||
60 | #define B2_PROT_TRANSPARENT 0x0002 | ||
61 | #define B2_PROT_SDLC 0x0004 | ||
62 | #define B2_PROT_LAPD 0x0008 | ||
63 | #define B2_PROT_T30 0x0010 | ||
64 | #define B2_PROT_PPP 0x0020 | ||
65 | #define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040 | ||
66 | |||
67 | #define B3_PROT_TRANSPARENT 0x0001 | ||
68 | #define B3_PROT_T90NL 0x0002 | ||
69 | #define B3_PROT_ISO8208 0x0004 | ||
70 | #define B3_PROT_X25_DCE 0x0008 | ||
71 | #define B3_PROT_T30 0x0010 | ||
72 | #define B3_PROT_T30EXT 0x0020 | ||
73 | |||
74 | #define HYSDN_MAXVERSION 8 | ||
75 | |||
76 | /* Number of sendbuffers in CAPI-queue */ | ||
77 | #define HYSDN_MAX_CAPI_SKB 20 | ||
78 | |||
79 | #endif /* CONFIG_HYSDN_CAPI*/ | ||
80 | |||
81 | /************************************************/ | ||
82 | /* constants and bits for debugging/log outputs */ | ||
83 | /************************************************/ | ||
84 | #define LOG_MAX_LINELEN 120 | ||
85 | #define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */ | ||
86 | #define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */ | ||
87 | #define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */ | ||
88 | #define LOG_POF_RECORD 0x00000020 /* log pof record parser */ | ||
89 | #define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */ | ||
90 | #define LOG_POF_CARD 0x00000080 /* log pof related card functions */ | ||
91 | #define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */ | ||
92 | #define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */ | ||
93 | #define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */ | ||
94 | #define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */ | ||
95 | #define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */ | ||
96 | #define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */ | ||
97 | #define LOG_NET_INIT 0x00010000 /* network init and deinit logging */ | ||
98 | |||
99 | #define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */ | ||
100 | |||
101 | /**********************************/ | ||
102 | /* proc filesystem name constants */ | ||
103 | /**********************************/ | ||
104 | #define PROC_SUBDIR_NAME "hysdn" | ||
105 | #define PROC_CONF_BASENAME "cardconf" | ||
106 | #define PROC_LOG_BASENAME "cardlog" | ||
107 | |||
108 | /***********************************/ | ||
109 | /* PCI 32 bit parms for IO and MEM */ | ||
110 | /***********************************/ | ||
111 | #define PCI_REG_PLX_MEM_BASE 0 | ||
112 | #define PCI_REG_PLX_IO_BASE 1 | ||
113 | #define PCI_REG_MEMORY_BASE 3 | ||
114 | |||
115 | /**************/ | ||
116 | /* card types */ | ||
117 | /**************/ | ||
118 | #define BD_NONE 0U | ||
119 | #define BD_PERFORMANCE 1U | ||
120 | #define BD_VALUE 2U | ||
121 | #define BD_PCCARD 3U | ||
122 | #define BD_ERGO 4U | ||
123 | #define BD_METRO 5U | ||
124 | #define BD_CHAMP2 6U | ||
125 | #define BD_PLEXUS 7U | ||
126 | |||
127 | /******************************************************/ | ||
128 | /* defined states for cards shown by reading cardconf */ | ||
129 | /******************************************************/ | ||
130 | #define CARD_STATE_UNUSED 0 /* never been used or booted */ | ||
131 | #define CARD_STATE_BOOTING 1 /* booting is in progress */ | ||
132 | #define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */ | ||
133 | #define CARD_STATE_RUN 3 /* card is active */ | ||
134 | |||
135 | /*******************************/ | ||
136 | /* defines for error_log_state */ | ||
137 | /*******************************/ | ||
138 | #define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */ | ||
139 | #define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */ | ||
140 | #define ERRLOG_STATE_START 2 /* start error logging */ | ||
141 | #define ERRLOG_STATE_STOP 3 /* stop error logging */ | ||
142 | |||
143 | /*******************************/ | ||
144 | /* data structure for one card */ | ||
145 | /*******************************/ | ||
146 | typedef struct HYSDN_CARD { | ||
147 | |||
148 | /* general variables for the cards */ | ||
149 | int myid; /* own driver card id */ | ||
150 | uchar bus; /* pci bus the card is connected to */ | ||
151 | uchar devfn; /* slot+function bit encoded */ | ||
152 | word subsysid; /* PCI subsystem id */ | ||
153 | uchar brdtype; /* type of card */ | ||
154 | uint bchans; /* number of available B-channels */ | ||
155 | uint faxchans; /* number of available fax-channels */ | ||
156 | uchar mac_addr[6]; /* MAC Address read from card */ | ||
157 | uint irq; /* interrupt number */ | ||
158 | uint iobase; /* IO-port base address */ | ||
159 | ulong plxbase; /* PLX memory base */ | ||
160 | ulong membase; /* DPRAM memory base */ | ||
161 | ulong memend; /* DPRAM memory end */ | ||
162 | void *dpram; /* mapped dpram */ | ||
163 | int state; /* actual state of card -> CARD_STATE_** */ | ||
164 | struct HYSDN_CARD *next; /* pointer to next card */ | ||
165 | |||
166 | /* data areas for the /proc file system */ | ||
167 | void *proclog; /* pointer to proclog filesystem specific data */ | ||
168 | void *procconf; /* pointer to procconf filesystem specific data */ | ||
169 | |||
170 | /* debugging and logging */ | ||
171 | uchar err_log_state; /* actual error log state of the card */ | ||
172 | ulong debug_flags; /* tells what should be debugged and where */ | ||
173 | void (*set_errlog_state) (struct HYSDN_CARD *, int); | ||
174 | |||
175 | /* interrupt handler + interrupt synchronisation */ | ||
176 | struct work_struct irq_queue; /* interrupt task queue */ | ||
177 | uchar volatile irq_enabled; /* interrupt enabled if != 0 */ | ||
178 | uchar volatile hw_lock; /* hardware is currently locked -> no access */ | ||
179 | |||
180 | /* boot process */ | ||
181 | void *boot; /* pointer to boot private data */ | ||
182 | int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong); | ||
183 | int (*writebootseq) (struct HYSDN_CARD *, uchar *, int); | ||
184 | int (*waitpofready) (struct HYSDN_CARD *); | ||
185 | int (*testram) (struct HYSDN_CARD *); | ||
186 | |||
187 | /* scheduler for data transfer (only async parts) */ | ||
188 | uchar async_data[256]; /* async data to be sent (normally for config) */ | ||
189 | word volatile async_len; /* length of data to sent */ | ||
190 | word volatile async_channel; /* channel number for async transfer */ | ||
191 | int volatile async_busy; /* flag != 0 sending in progress */ | ||
192 | int volatile net_tx_busy; /* a network packet tx is in progress */ | ||
193 | |||
194 | /* network interface */ | ||
195 | void *netif; /* pointer to network structure */ | ||
196 | |||
197 | /* init and deinit stopcard for booting, too */ | ||
198 | void (*stopcard) (struct HYSDN_CARD *); | ||
199 | void (*releasehardware) (struct HYSDN_CARD *); | ||
200 | #ifdef CONFIG_HYSDN_CAPI | ||
201 | struct hycapictrl_info { | ||
202 | char cardname[32]; | ||
203 | spinlock_t lock; | ||
204 | int versionlen; | ||
205 | char versionbuf[1024]; | ||
206 | char *version[HYSDN_MAXVERSION]; | ||
207 | |||
208 | char infobuf[128]; /* for function procinfo */ | ||
209 | |||
210 | struct HYSDN_CARD *card; | ||
211 | struct capi_ctr capi_ctrl; | ||
212 | struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB]; | ||
213 | int in_idx, out_idx; /* indexes to buffer ring */ | ||
214 | int sk_count; /* number of buffers currently in ring */ | ||
215 | struct sk_buff *tx_skb; /* buffer for tx operation */ | ||
216 | |||
217 | struct list_head ncci_head; | ||
218 | } *hyctrlinfo; | ||
219 | #endif /* CONFIG_HYSDN_CAPI */ | ||
220 | } hysdn_card; | ||
221 | |||
222 | #ifdef CONFIG_HYSDN_CAPI | ||
223 | typedef struct hycapictrl_info hycapictrl_info; | ||
224 | #endif /* CONFIG_HYSDN_CAPI */ | ||
225 | |||
226 | |||
227 | /*****************/ | ||
228 | /* exported vars */ | ||
229 | /*****************/ | ||
230 | extern int cardmax; /* number of found cards */ | ||
231 | extern hysdn_card *card_root; /* pointer to first card */ | ||
232 | |||
233 | |||
234 | |||
235 | /*************************/ | ||
236 | /* im/exported functions */ | ||
237 | /*************************/ | ||
238 | extern char *hysdn_getrev(const char *); | ||
239 | |||
240 | /* hysdn_procconf.c */ | ||
241 | extern int hysdn_procconf_init(void); /* init proc config filesys */ | ||
242 | extern void hysdn_procconf_release(void); /* deinit proc config filesys */ | ||
243 | |||
244 | /* hysdn_proclog.c */ | ||
245 | extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */ | ||
246 | extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */ | ||
247 | extern void put_log_buffer(hysdn_card *, char *); /* output log data */ | ||
248 | extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */ | ||
249 | extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */ | ||
250 | |||
251 | /* boardergo.c */ | ||
252 | extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */ | ||
253 | |||
254 | /* hysdn_boot.c */ | ||
255 | extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */ | ||
256 | extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */ | ||
257 | extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */ | ||
258 | extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */ | ||
259 | |||
260 | /* hysdn_sched.c */ | ||
261 | extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *, | ||
262 | word); | ||
263 | extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word); | ||
264 | extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */ | ||
265 | |||
266 | /* hysdn_net.c */ | ||
267 | extern unsigned int hynet_enable; | ||
268 | extern char *hysdn_net_revision; | ||
269 | extern int hysdn_net_create(hysdn_card *); /* create a new net device */ | ||
270 | extern int hysdn_net_release(hysdn_card *); /* delete the device */ | ||
271 | extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ | ||
272 | extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ | ||
273 | extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ | ||
274 | extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ | ||
275 | |||
276 | #ifdef CONFIG_HYSDN_CAPI | ||
277 | extern unsigned int hycapi_enable; | ||
278 | extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ | ||
279 | extern int hycapi_capi_release(hysdn_card *); /* delete the device */ | ||
280 | extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ | ||
281 | extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); | ||
282 | extern void hycapi_reset_ctr(struct capi_ctr *); | ||
283 | extern void hycapi_remove_ctr(struct capi_ctr *); | ||
284 | extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, | ||
285 | capi_register_params *); | ||
286 | extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); | ||
287 | extern u16 hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); | ||
288 | extern char *hycapi_procinfo(struct capi_ctr *); | ||
289 | extern int hycapi_read_proc(char *page, char **start, off_t off, | ||
290 | int count, int *eof, struct capi_ctr *card); | ||
291 | extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); | ||
292 | extern void hycapi_tx_capiack(hysdn_card * card); | ||
293 | extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); | ||
294 | extern int hycapi_init(void); | ||
295 | extern void hycapi_cleanup(void); | ||
296 | #endif /* CONFIG_HYSDN_CAPI */ | ||
297 | |||
298 | #endif /* HYSDN_DEFS_H */ | ||
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c new file mode 100644 index 000000000000..5cac2bf5f4b0 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_init.c | |||
@@ -0,0 +1,254 @@ | |||
1 | /* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, init functions. | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/poll.h> | ||
18 | #include <linux/vmalloc.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/pci.h> | ||
21 | |||
22 | #include "hysdn_defs.h" | ||
23 | |||
24 | static struct pci_device_id hysdn_pci_tbl[] = { | ||
25 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, | ||
26 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, | ||
27 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, | ||
28 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, | ||
29 | { } /* Terminating entry */ | ||
30 | }; | ||
31 | MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); | ||
32 | MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards"); | ||
33 | MODULE_AUTHOR("Werner Cornelius"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; | ||
37 | int cardmax; /* number of found cards */ | ||
38 | hysdn_card *card_root = NULL; /* pointer to first card */ | ||
39 | |||
40 | /**********************************************/ | ||
41 | /* table assigning PCI-sub ids to board types */ | ||
42 | /* the last entry contains all 0 */ | ||
43 | /**********************************************/ | ||
44 | static struct { | ||
45 | word subid; /* PCI sub id */ | ||
46 | uchar cardtyp; /* card type assigned */ | ||
47 | } pci_subid_map[] = { | ||
48 | |||
49 | { | ||
50 | PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO | ||
51 | }, | ||
52 | { | ||
53 | PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 | ||
54 | }, | ||
55 | { | ||
56 | PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO | ||
57 | }, | ||
58 | { | ||
59 | PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO | ||
60 | }, | ||
61 | { | ||
62 | 0, 0 | ||
63 | } /* terminating entry */ | ||
64 | }; | ||
65 | |||
66 | |||
67 | /*********************************************************************/ | ||
68 | /* search_cards searches for available cards in the pci config data. */ | ||
69 | /* If a card is found, the card structure is allocated and the cards */ | ||
70 | /* ressources are reserved. cardmax is incremented. */ | ||
71 | /*********************************************************************/ | ||
72 | static void | ||
73 | search_cards(void) | ||
74 | { | ||
75 | struct pci_dev *akt_pcidev = NULL; | ||
76 | hysdn_card *card, *card_last; | ||
77 | int i; | ||
78 | |||
79 | card_root = NULL; | ||
80 | card_last = NULL; | ||
81 | while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, | ||
82 | akt_pcidev)) != NULL) { | ||
83 | if (pci_enable_device(akt_pcidev)) | ||
84 | continue; | ||
85 | |||
86 | if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) { | ||
87 | printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); | ||
88 | return; | ||
89 | } | ||
90 | memset(card, 0, sizeof(hysdn_card)); | ||
91 | card->myid = cardmax; /* set own id */ | ||
92 | card->bus = akt_pcidev->bus->number; | ||
93 | card->devfn = akt_pcidev->devfn; /* slot + function */ | ||
94 | card->subsysid = akt_pcidev->subsystem_device; | ||
95 | card->irq = akt_pcidev->irq; | ||
96 | card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); | ||
97 | card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); | ||
98 | card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); | ||
99 | card->brdtype = BD_NONE; /* unknown */ | ||
100 | card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ | ||
101 | card->faxchans = 0; /* default no fax channels */ | ||
102 | card->bchans = 2; /* and 2 b-channels */ | ||
103 | for (i = 0; pci_subid_map[i].subid; i++) | ||
104 | if (pci_subid_map[i].subid == card->subsysid) { | ||
105 | card->brdtype = pci_subid_map[i].cardtyp; | ||
106 | break; | ||
107 | } | ||
108 | if (card->brdtype != BD_NONE) { | ||
109 | if (ergo_inithardware(card)) { | ||
110 | printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); | ||
111 | kfree(card); | ||
112 | continue; | ||
113 | } | ||
114 | } else { | ||
115 | printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); | ||
116 | kfree(card); /* release mem */ | ||
117 | continue; | ||
118 | } | ||
119 | cardmax++; | ||
120 | card->next = NULL; /*end of chain */ | ||
121 | if (card_last) | ||
122 | card_last->next = card; /* pointer to next card */ | ||
123 | else | ||
124 | card_root = card; | ||
125 | card_last = card; /* new chain end */ | ||
126 | } /* device found */ | ||
127 | } /* search_cards */ | ||
128 | |||
129 | /************************************************************************************/ | ||
130 | /* free_resources frees the acquired PCI resources and returns the allocated memory */ | ||
131 | /************************************************************************************/ | ||
132 | static void | ||
133 | free_resources(void) | ||
134 | { | ||
135 | hysdn_card *card; | ||
136 | |||
137 | while (card_root) { | ||
138 | card = card_root; | ||
139 | if (card->releasehardware) | ||
140 | card->releasehardware(card); /* free all hardware resources */ | ||
141 | card_root = card_root->next; /* remove card from chain */ | ||
142 | kfree(card); /* return mem */ | ||
143 | |||
144 | } /* while card_root */ | ||
145 | } /* free_resources */ | ||
146 | |||
147 | /**************************************************************************/ | ||
148 | /* stop_cards disables (hardware resets) all cards and disables interrupt */ | ||
149 | /**************************************************************************/ | ||
150 | static void | ||
151 | stop_cards(void) | ||
152 | { | ||
153 | hysdn_card *card; | ||
154 | |||
155 | card = card_root; /* first in chain */ | ||
156 | while (card) { | ||
157 | if (card->stopcard) | ||
158 | card->stopcard(card); | ||
159 | card = card->next; /* remove card from chain */ | ||
160 | } /* while card */ | ||
161 | } /* stop_cards */ | ||
162 | |||
163 | |||
164 | /****************************************************************************/ | ||
165 | /* The module startup and shutdown code. Only compiled when used as module. */ | ||
166 | /* Using the driver as module is always advisable, because the booting */ | ||
167 | /* image becomes smaller and the driver code is only loaded when needed. */ | ||
168 | /* Additionally newer versions may be activated without rebooting. */ | ||
169 | /****************************************************************************/ | ||
170 | |||
171 | /******************************************************/ | ||
172 | /* extract revision number from string for log output */ | ||
173 | /******************************************************/ | ||
174 | char * | ||
175 | hysdn_getrev(const char *revision) | ||
176 | { | ||
177 | char *rev; | ||
178 | char *p; | ||
179 | |||
180 | if ((p = strchr(revision, ':'))) { | ||
181 | rev = p + 2; | ||
182 | p = strchr(rev, '$'); | ||
183 | *--p = 0; | ||
184 | } else | ||
185 | rev = "???"; | ||
186 | return rev; | ||
187 | } | ||
188 | |||
189 | |||
190 | /****************************************************************************/ | ||
191 | /* init_module is called once when the module is loaded to do all necessary */ | ||
192 | /* things like autodetect... */ | ||
193 | /* If the return value of this function is 0 the init has been successful */ | ||
194 | /* and the module is added to the list in /proc/modules, otherwise an error */ | ||
195 | /* is assumed and the module will not be kept in memory. */ | ||
196 | /****************************************************************************/ | ||
197 | static int __init | ||
198 | hysdn_init(void) | ||
199 | { | ||
200 | char tmp[50]; | ||
201 | |||
202 | strcpy(tmp, hysdn_init_revision); | ||
203 | printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); | ||
204 | strcpy(tmp, hysdn_net_revision); | ||
205 | printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); | ||
206 | search_cards(); | ||
207 | printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); | ||
208 | |||
209 | if (hysdn_procconf_init()) { | ||
210 | free_resources(); /* proc file_sys not created */ | ||
211 | return (-1); | ||
212 | } | ||
213 | #ifdef CONFIG_HYSDN_CAPI | ||
214 | if(cardmax > 0) { | ||
215 | if(hycapi_init()) { | ||
216 | printk(KERN_ERR "HYCAPI: init failed\n"); | ||
217 | return(-1); | ||
218 | } | ||
219 | } | ||
220 | #endif /* CONFIG_HYSDN_CAPI */ | ||
221 | return (0); /* no error */ | ||
222 | } /* init_module */ | ||
223 | |||
224 | |||
225 | /***********************************************************************/ | ||
226 | /* cleanup_module is called when the module is released by the kernel. */ | ||
227 | /* The routine is only called if init_module has been successful and */ | ||
228 | /* the module counter has a value of 0. Otherwise this function will */ | ||
229 | /* not be called. This function must release all resources still allo- */ | ||
230 | /* cated as after the return from this function the module code will */ | ||
231 | /* be removed from memory. */ | ||
232 | /***********************************************************************/ | ||
233 | static void __exit | ||
234 | hysdn_exit(void) | ||
235 | { | ||
236 | #ifdef CONFIG_HYSDN_CAPI | ||
237 | hysdn_card *card; | ||
238 | #endif /* CONFIG_HYSDN_CAPI */ | ||
239 | stop_cards(); | ||
240 | #ifdef CONFIG_HYSDN_CAPI | ||
241 | card = card_root; /* first in chain */ | ||
242 | while (card) { | ||
243 | hycapi_capi_release(card); | ||
244 | card = card->next; /* remove card from chain */ | ||
245 | } /* while card */ | ||
246 | hycapi_cleanup(); | ||
247 | #endif /* CONFIG_HYSDN_CAPI */ | ||
248 | hysdn_procconf_release(); | ||
249 | free_resources(); | ||
250 | printk(KERN_NOTICE "HYSDN: module unloaded\n"); | ||
251 | } /* cleanup_module */ | ||
252 | |||
253 | module_init(hysdn_init); | ||
254 | module_exit(hysdn_exit); | ||
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c new file mode 100644 index 000000000000..babec8157ae6 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_net.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* $Id: hysdn_net.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, net (ethernet type) handling routines. | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | * This net module has been inspired by the skeleton driver from | ||
12 | * Donald Becker (becker@CESDIS.gsfc.nasa.gov) | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/version.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/etherdevice.h> | ||
22 | #include <linux/skbuff.h> | ||
23 | #include <linux/inetdevice.h> | ||
24 | |||
25 | #include "hysdn_defs.h" | ||
26 | |||
27 | unsigned int hynet_enable = 0xffffffff; | ||
28 | MODULE_PARM(hynet_enable, "i"); | ||
29 | |||
30 | /* store the actual version for log reporting */ | ||
31 | char *hysdn_net_revision = "$Revision: 1.8.6.4 $"; | ||
32 | |||
33 | #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ | ||
34 | |||
35 | /****************************************************************************/ | ||
36 | /* structure containing the complete network data. The structure is aligned */ | ||
37 | /* in a way that both, the device and statistics are kept inside it. */ | ||
38 | /* for proper access, the device structure MUST be the first var/struct */ | ||
39 | /* inside the definition. */ | ||
40 | /****************************************************************************/ | ||
41 | struct net_local { | ||
42 | struct net_device netdev; /* the network device */ | ||
43 | struct net_device_stats stats; | ||
44 | /* additional vars may be added here */ | ||
45 | char dev_name[9]; /* our own device name */ | ||
46 | |||
47 | /* Tx control lock. This protects the transmit buffer ring | ||
48 | * state along with the "tx full" state of the driver. This | ||
49 | * means all netif_queue flow control actions are protected | ||
50 | * by this lock as well. | ||
51 | */ | ||
52 | spinlock_t lock; | ||
53 | struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */ | ||
54 | int in_idx, out_idx; /* indexes to buffer ring */ | ||
55 | int sk_count; /* number of buffers currently in ring */ | ||
56 | }; /* net_local */ | ||
57 | |||
58 | |||
59 | /*****************************************************/ | ||
60 | /* Get the current statistics for this card. */ | ||
61 | /* This may be called with the card open or closed ! */ | ||
62 | /*****************************************************/ | ||
63 | static struct net_device_stats * | ||
64 | net_get_stats(struct net_device *dev) | ||
65 | { | ||
66 | return (&((struct net_local *) dev)->stats); | ||
67 | } /* net_device_stats */ | ||
68 | |||
69 | /*********************************************************************/ | ||
70 | /* Open/initialize the board. This is called (in the current kernel) */ | ||
71 | /* sometime after booting when the 'ifconfig' program is run. */ | ||
72 | /* This routine should set everything up anew at each open, even */ | ||
73 | /* registers that "should" only need to be set once at boot, so that */ | ||
74 | /* there is non-reboot way to recover if something goes wrong. */ | ||
75 | /*********************************************************************/ | ||
76 | static int | ||
77 | net_open(struct net_device *dev) | ||
78 | { | ||
79 | struct in_device *in_dev; | ||
80 | hysdn_card *card = dev->priv; | ||
81 | int i; | ||
82 | |||
83 | netif_start_queue(dev); /* start tx-queueing */ | ||
84 | |||
85 | /* Fill in the MAC-level header (if not already set) */ | ||
86 | if (!card->mac_addr[0]) { | ||
87 | for (i = 0; i < ETH_ALEN - sizeof(ulong); i++) | ||
88 | dev->dev_addr[i] = 0xfc; | ||
89 | if ((in_dev = dev->ip_ptr) != NULL) { | ||
90 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
91 | if (ifa != NULL) | ||
92 | memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong)); | ||
93 | } | ||
94 | } else | ||
95 | memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN); | ||
96 | |||
97 | return (0); | ||
98 | } /* net_open */ | ||
99 | |||
100 | /*******************************************/ | ||
101 | /* flush the currently occupied tx-buffers */ | ||
102 | /* must only be called when device closed */ | ||
103 | /*******************************************/ | ||
104 | static void | ||
105 | flush_tx_buffers(struct net_local *nl) | ||
106 | { | ||
107 | |||
108 | while (nl->sk_count) { | ||
109 | dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */ | ||
110 | if (nl->out_idx >= MAX_SKB_BUFFERS) | ||
111 | nl->out_idx = 0; /* wrap around */ | ||
112 | nl->sk_count--; | ||
113 | } | ||
114 | } /* flush_tx_buffers */ | ||
115 | |||
116 | |||
117 | /*********************************************************************/ | ||
118 | /* close/decativate the device. The device is not removed, but only */ | ||
119 | /* deactivated. */ | ||
120 | /*********************************************************************/ | ||
121 | static int | ||
122 | net_close(struct net_device *dev) | ||
123 | { | ||
124 | |||
125 | netif_stop_queue(dev); /* disable queueing */ | ||
126 | |||
127 | flush_tx_buffers((struct net_local *) dev); | ||
128 | |||
129 | return (0); /* success */ | ||
130 | } /* net_close */ | ||
131 | |||
132 | /************************************/ | ||
133 | /* send a packet on this interface. */ | ||
134 | /* new style for kernel >= 2.3.33 */ | ||
135 | /************************************/ | ||
136 | static int | ||
137 | net_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
138 | { | ||
139 | struct net_local *lp = (struct net_local *) dev; | ||
140 | |||
141 | spin_lock_irq(&lp->lock); | ||
142 | |||
143 | lp->skbs[lp->in_idx++] = skb; /* add to buffer list */ | ||
144 | if (lp->in_idx >= MAX_SKB_BUFFERS) | ||
145 | lp->in_idx = 0; /* wrap around */ | ||
146 | lp->sk_count++; /* adjust counter */ | ||
147 | dev->trans_start = jiffies; | ||
148 | |||
149 | /* If we just used up the very last entry in the | ||
150 | * TX ring on this device, tell the queueing | ||
151 | * layer to send no more. | ||
152 | */ | ||
153 | if (lp->sk_count >= MAX_SKB_BUFFERS) | ||
154 | netif_stop_queue(dev); | ||
155 | |||
156 | /* When the TX completion hw interrupt arrives, this | ||
157 | * is when the transmit statistics are updated. | ||
158 | */ | ||
159 | |||
160 | spin_unlock_irq(&lp->lock); | ||
161 | |||
162 | if (lp->sk_count <= 3) { | ||
163 | schedule_work(&((hysdn_card *) dev->priv)->irq_queue); | ||
164 | } | ||
165 | return (0); /* success */ | ||
166 | } /* net_send_packet */ | ||
167 | |||
168 | |||
169 | |||
170 | /***********************************************************************/ | ||
171 | /* acknowlegde a packet send. The network layer will be informed about */ | ||
172 | /* completion */ | ||
173 | /***********************************************************************/ | ||
174 | void | ||
175 | hysdn_tx_netack(hysdn_card * card) | ||
176 | { | ||
177 | struct net_local *lp = card->netif; | ||
178 | |||
179 | if (!lp) | ||
180 | return; /* non existing device */ | ||
181 | |||
182 | |||
183 | if (!lp->sk_count) | ||
184 | return; /* error condition */ | ||
185 | |||
186 | lp->stats.tx_packets++; | ||
187 | lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len; | ||
188 | |||
189 | dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */ | ||
190 | if (lp->out_idx >= MAX_SKB_BUFFERS) | ||
191 | lp->out_idx = 0; /* wrap around */ | ||
192 | |||
193 | if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */ | ||
194 | netif_start_queue((struct net_device *) lp); | ||
195 | } /* hysdn_tx_netack */ | ||
196 | |||
197 | /*****************************************************/ | ||
198 | /* we got a packet from the network, go and queue it */ | ||
199 | /*****************************************************/ | ||
200 | void | ||
201 | hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len) | ||
202 | { | ||
203 | struct net_local *lp = card->netif; | ||
204 | struct sk_buff *skb; | ||
205 | |||
206 | if (!lp) | ||
207 | return; /* non existing device */ | ||
208 | |||
209 | lp->stats.rx_bytes += len; | ||
210 | |||
211 | skb = dev_alloc_skb(len); | ||
212 | if (skb == NULL) { | ||
213 | printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", | ||
214 | lp->netdev.name); | ||
215 | lp->stats.rx_dropped++; | ||
216 | return; | ||
217 | } | ||
218 | skb->dev = &lp->netdev; | ||
219 | |||
220 | /* copy the data */ | ||
221 | memcpy(skb_put(skb, len), buf, len); | ||
222 | |||
223 | /* determine the used protocol */ | ||
224 | skb->protocol = eth_type_trans(skb, &lp->netdev); | ||
225 | |||
226 | netif_rx(skb); | ||
227 | lp->stats.rx_packets++; /* adjust packet count */ | ||
228 | |||
229 | } /* hysdn_rx_netpkt */ | ||
230 | |||
231 | /*****************************************************/ | ||
232 | /* return the pointer to a network packet to be send */ | ||
233 | /*****************************************************/ | ||
234 | struct sk_buff * | ||
235 | hysdn_tx_netget(hysdn_card * card) | ||
236 | { | ||
237 | struct net_local *lp = card->netif; | ||
238 | |||
239 | if (!lp) | ||
240 | return (NULL); /* non existing device */ | ||
241 | |||
242 | if (!lp->sk_count) | ||
243 | return (NULL); /* nothing available */ | ||
244 | |||
245 | return (lp->skbs[lp->out_idx]); /* next packet to send */ | ||
246 | } /* hysdn_tx_netget */ | ||
247 | |||
248 | |||
249 | /*******************************************/ | ||
250 | /* init function called by register device */ | ||
251 | /*******************************************/ | ||
252 | static int | ||
253 | net_init(struct net_device *dev) | ||
254 | { | ||
255 | /* setup the function table */ | ||
256 | dev->open = net_open; | ||
257 | dev->stop = net_close; | ||
258 | dev->hard_start_xmit = net_send_packet; | ||
259 | dev->get_stats = net_get_stats; | ||
260 | |||
261 | /* Fill in the fields of the device structure with ethernet values. */ | ||
262 | ether_setup(dev); | ||
263 | |||
264 | return (0); /* success */ | ||
265 | } /* net_init */ | ||
266 | |||
267 | /*****************************************************************************/ | ||
268 | /* hysdn_net_create creates a new net device for the given card. If a device */ | ||
269 | /* already exists, it will be deleted and created a new one. The return value */ | ||
270 | /* 0 announces success, else a negative error code will be returned. */ | ||
271 | /*****************************************************************************/ | ||
272 | int | ||
273 | hysdn_net_create(hysdn_card * card) | ||
274 | { | ||
275 | struct net_device *dev; | ||
276 | int i; | ||
277 | if(!card) { | ||
278 | printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); | ||
279 | return (-ENOMEM); | ||
280 | } | ||
281 | hysdn_net_release(card); /* release an existing net device */ | ||
282 | if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { | ||
283 | printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); | ||
284 | return (-ENOMEM); | ||
285 | } | ||
286 | memset(dev, 0, sizeof(struct net_local)); /* clean the structure */ | ||
287 | |||
288 | spin_lock_init(&((struct net_local *) dev)->lock); | ||
289 | |||
290 | /* initialise necessary or informing fields */ | ||
291 | dev->base_addr = card->iobase; /* IO address */ | ||
292 | dev->irq = card->irq; /* irq */ | ||
293 | dev->init = net_init; /* the init function of the device */ | ||
294 | if(dev->name) { | ||
295 | strcpy(dev->name, ((struct net_local *) dev)->dev_name); | ||
296 | } | ||
297 | if ((i = register_netdev(dev))) { | ||
298 | printk(KERN_WARNING "HYSDN: unable to create network device\n"); | ||
299 | kfree(dev); | ||
300 | return (i); | ||
301 | } | ||
302 | dev->priv = card; /* remember pointer to own data structure */ | ||
303 | card->netif = dev; /* setup the local pointer */ | ||
304 | |||
305 | if (card->debug_flags & LOG_NET_INIT) | ||
306 | hysdn_addlog(card, "network device created"); | ||
307 | return (0); /* and return success */ | ||
308 | } /* hysdn_net_create */ | ||
309 | |||
310 | /***************************************************************************/ | ||
311 | /* hysdn_net_release deletes the net device for the given card. The return */ | ||
312 | /* value 0 announces success, else a negative error code will be returned. */ | ||
313 | /***************************************************************************/ | ||
314 | int | ||
315 | hysdn_net_release(hysdn_card * card) | ||
316 | { | ||
317 | struct net_device *dev = card->netif; | ||
318 | |||
319 | if (!dev) | ||
320 | return (0); /* non existing */ | ||
321 | |||
322 | card->netif = NULL; /* clear out pointer */ | ||
323 | dev->stop(dev); /* close the device */ | ||
324 | |||
325 | flush_tx_buffers((struct net_local *) dev); /* empty buffers */ | ||
326 | |||
327 | unregister_netdev(dev); /* release the device */ | ||
328 | free_netdev(dev); /* release the memory allocated */ | ||
329 | if (card->debug_flags & LOG_NET_INIT) | ||
330 | hysdn_addlog(card, "network device deleted"); | ||
331 | |||
332 | return (0); /* always successful */ | ||
333 | } /* hysdn_net_release */ | ||
334 | |||
335 | /*****************************************************************************/ | ||
336 | /* hysdn_net_getname returns a pointer to the name of the network interface. */ | ||
337 | /* if the interface is not existing, a "-" is returned. */ | ||
338 | /*****************************************************************************/ | ||
339 | char * | ||
340 | hysdn_net_getname(hysdn_card * card) | ||
341 | { | ||
342 | struct net_device *dev = card->netif; | ||
343 | |||
344 | if (!dev) | ||
345 | return ("-"); /* non existing */ | ||
346 | |||
347 | return (dev->name); | ||
348 | } /* hysdn_net_getname */ | ||
diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h new file mode 100644 index 000000000000..6cd81b9b08bc --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_pof.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* $Id: hysdn_pof.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, definitions used for handling pof-files. | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /************************/ | ||
14 | /* POF specific defines */ | ||
15 | /************************/ | ||
16 | #define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */ | ||
17 | #define CRYPT_FEEDTERM 0x8142 | ||
18 | #define CRYPT_STARTTERM 0x81a5 | ||
19 | /* max. timeout time in seconds | ||
20 | * from end of booting to POF is ready | ||
21 | */ | ||
22 | #define POF_READY_TIME_OUT_SEC 10 | ||
23 | |||
24 | /**********************************/ | ||
25 | /* defines for 1.stage boot image */ | ||
26 | /**********************************/ | ||
27 | |||
28 | /* the POF file record containing the boot loader image | ||
29 | * has 2 pages a 16KB: | ||
30 | * 1. page contains the high 16-bit part of the 32-bit E1 words | ||
31 | * 2. page contains the low 16-bit part of the 32-bit E1 words | ||
32 | * | ||
33 | * In each 16KB page we assume the start of the boot loader code | ||
34 | * in the highest 2KB part (at offset 0x3800); | ||
35 | * the rest (0x0000..0x37FF) is assumed to contain 0 bytes. | ||
36 | */ | ||
37 | |||
38 | #define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */ | ||
39 | #define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE) | ||
40 | |||
41 | #define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */ | ||
42 | |||
43 | /* offset in boot page, where loader code may start */ | ||
44 | /* =0x3800= 14336U */ | ||
45 | #define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE) | ||
46 | |||
47 | |||
48 | /*--------------------------------------POF file record structs------------*/ | ||
49 | typedef struct PofFileHdr_tag { /* Pof file header */ | ||
50 | /*00 */ ulong Magic __attribute__((packed)); | ||
51 | /*04 */ ulong N_PofRecs __attribute__((packed)); | ||
52 | /*08 */ | ||
53 | } tPofFileHdr; | ||
54 | |||
55 | typedef struct PofRecHdr_tag { /* Pof record header */ | ||
56 | /*00 */ word PofRecId __attribute__((packed)); | ||
57 | /*02 */ ulong PofRecDataLen __attribute__((packed)); | ||
58 | /*06 */ | ||
59 | } tPofRecHdr; | ||
60 | |||
61 | typedef struct PofTimeStamp_tag { | ||
62 | /*00 */ ulong UnixTime __attribute__((packed)); | ||
63 | /*04 */ uchar DateTimeText[0x28] __attribute__((packed)); | ||
64 | /* =40 */ | ||
65 | /*2C */ | ||
66 | } tPofTimeStamp; | ||
67 | |||
68 | /* tPofFileHdr.Magic value: */ | ||
69 | #define TAGFILEMAGIC 0x464F501AUL | ||
70 | /* tPofRecHdr.PofRecId values: */ | ||
71 | #define TAG_ABSDATA 0x1000 /* abs. data */ | ||
72 | #define TAG_BOOTDTA 0x1001 /* boot data */ | ||
73 | #define TAG_COMMENT 0x0020 | ||
74 | #define TAG_SYSCALL 0x0021 | ||
75 | #define TAG_FLOWCTRL 0x0022 | ||
76 | #define TAG_TIMESTMP 0x0010 /* date/time stamp of version */ | ||
77 | #define TAG_CABSDATA 0x1100 /* crypted abs. data */ | ||
78 | #define TAG_CBOOTDTA 0x1101 /* crypted boot data */ | ||
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c new file mode 100644 index 000000000000..5da507e532fc --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_procconf.c | |||
@@ -0,0 +1,443 @@ | |||
1 | /* $Id: hysdn_procconf.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. | ||
4 | * | ||
5 | * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * | ||
7 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/version.h> | ||
16 | #include <linux/poll.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/smp_lock.h> | ||
20 | |||
21 | #include "hysdn_defs.h" | ||
22 | |||
23 | static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $"; | ||
24 | |||
25 | #define INFO_OUT_LEN 80 /* length of info line including lf */ | ||
26 | |||
27 | /********************************************************/ | ||
28 | /* defines and data structure for conf write operations */ | ||
29 | /********************************************************/ | ||
30 | #define CONF_STATE_DETECT 0 /* waiting for detect */ | ||
31 | #define CONF_STATE_CONF 1 /* writing config data */ | ||
32 | #define CONF_STATE_POF 2 /* writing pof data */ | ||
33 | #define CONF_LINE_LEN 255 /* 255 chars max */ | ||
34 | |||
35 | struct conf_writedata { | ||
36 | hysdn_card *card; /* card the device is connected to */ | ||
37 | int buf_size; /* actual number of bytes in the buffer */ | ||
38 | int needed_size; /* needed size when reading pof */ | ||
39 | int state; /* actual interface states from above constants */ | ||
40 | uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */ | ||
41 | word channel; /* active channel number */ | ||
42 | uchar *pof_buffer; /* buffer when writing pof */ | ||
43 | }; | ||
44 | |||
45 | /***********************************************************************/ | ||
46 | /* process_line parses one config line and transfers it to the card if */ | ||
47 | /* necessary. */ | ||
48 | /* if the return value is negative an error occurred. */ | ||
49 | /***********************************************************************/ | ||
50 | static int | ||
51 | process_line(struct conf_writedata *cnf) | ||
52 | { | ||
53 | uchar *cp = cnf->conf_line; | ||
54 | int i; | ||
55 | |||
56 | if (cnf->card->debug_flags & LOG_CNF_LINE) | ||
57 | hysdn_addlog(cnf->card, "conf line: %s", cp); | ||
58 | |||
59 | if (*cp == '-') { /* option */ | ||
60 | cp++; /* point to option char */ | ||
61 | |||
62 | if (*cp++ != 'c') | ||
63 | return (0); /* option unknown or used */ | ||
64 | i = 0; /* start value for channel */ | ||
65 | while ((*cp <= '9') && (*cp >= '0')) | ||
66 | i = i * 10 + *cp++ - '0'; /* get decimal number */ | ||
67 | if (i > 65535) { | ||
68 | if (cnf->card->debug_flags & LOG_CNF_MISC) | ||
69 | hysdn_addlog(cnf->card, "conf channel invalid %d", i); | ||
70 | return (-ERR_INV_CHAN); /* invalid channel */ | ||
71 | } | ||
72 | cnf->channel = i & 0xFFFF; /* set new channel number */ | ||
73 | return (0); /* success */ | ||
74 | } /* option */ | ||
75 | if (*cp == '*') { /* line to send */ | ||
76 | if (cnf->card->debug_flags & LOG_CNF_DATA) | ||
77 | hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp); | ||
78 | return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1, | ||
79 | cnf->channel)); /* send the line without * */ | ||
80 | } /* line to send */ | ||
81 | return (0); | ||
82 | } /* process_line */ | ||
83 | |||
84 | /***********************************/ | ||
85 | /* conf file operations and tables */ | ||
86 | /***********************************/ | ||
87 | |||
88 | /****************************************************/ | ||
89 | /* write conf file -> boot or send cfg line to card */ | ||
90 | /****************************************************/ | ||
91 | static ssize_t | ||
92 | hysdn_conf_write(struct file *file, const char __user *buf, size_t count, loff_t * off) | ||
93 | { | ||
94 | struct conf_writedata *cnf; | ||
95 | int i; | ||
96 | uchar ch, *cp; | ||
97 | |||
98 | if (!count) | ||
99 | return (0); /* nothing to handle */ | ||
100 | |||
101 | if (!(cnf = file->private_data)) | ||
102 | return (-EFAULT); /* should never happen */ | ||
103 | |||
104 | if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */ | ||
105 | if (copy_from_user(&ch, buf, 1)) /* get first char for detect */ | ||
106 | return (-EFAULT); | ||
107 | |||
108 | if (ch == 0x1A) { | ||
109 | /* we detected a pof file */ | ||
110 | if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0) | ||
111 | return (cnf->needed_size); /* an error occurred -> exit */ | ||
112 | cnf->buf_size = 0; /* buffer is empty */ | ||
113 | cnf->state = CONF_STATE_POF; /* new state */ | ||
114 | } else { | ||
115 | /* conf data has been detected */ | ||
116 | cnf->buf_size = 0; /* buffer is empty */ | ||
117 | cnf->state = CONF_STATE_CONF; /* requested conf data write */ | ||
118 | if (cnf->card->state != CARD_STATE_RUN) | ||
119 | return (-ERR_NOT_BOOTED); | ||
120 | cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */ | ||
121 | cnf->channel = 4098; /* default channel for output */ | ||
122 | } | ||
123 | } /* state was auto detect */ | ||
124 | if (cnf->state == CONF_STATE_POF) { /* pof write active */ | ||
125 | i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */ | ||
126 | if (i <= 0) | ||
127 | return (-EINVAL); /* size error handling pof */ | ||
128 | |||
129 | if (i < count) | ||
130 | count = i; /* limit requested number of bytes */ | ||
131 | if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count)) | ||
132 | return (-EFAULT); /* error while copying */ | ||
133 | cnf->buf_size += count; | ||
134 | |||
135 | if (cnf->needed_size == cnf->buf_size) { | ||
136 | cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */ | ||
137 | if (cnf->needed_size <= 0) { | ||
138 | cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */ | ||
139 | return (cnf->needed_size); /* an error occurred */ | ||
140 | } | ||
141 | cnf->buf_size = 0; /* buffer is empty again */ | ||
142 | } | ||
143 | } | ||
144 | /* pof write active */ | ||
145 | else { /* conf write active */ | ||
146 | |||
147 | if (cnf->card->state != CARD_STATE_RUN) { | ||
148 | if (cnf->card->debug_flags & LOG_CNF_MISC) | ||
149 | hysdn_addlog(cnf->card, "cnf write denied -> not booted"); | ||
150 | return (-ERR_NOT_BOOTED); | ||
151 | } | ||
152 | i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */ | ||
153 | if (i > 0) { | ||
154 | /* copy remaining bytes into buffer */ | ||
155 | |||
156 | if (count > i) | ||
157 | count = i; /* limit transfer */ | ||
158 | if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count)) | ||
159 | return (-EFAULT); /* error while copying */ | ||
160 | |||
161 | i = count; /* number of chars in buffer */ | ||
162 | cp = cnf->conf_line + cnf->buf_size; | ||
163 | while (i) { | ||
164 | /* search for end of line */ | ||
165 | if ((*cp < ' ') && (*cp != 9)) | ||
166 | break; /* end of line found */ | ||
167 | cp++; | ||
168 | i--; | ||
169 | } /* search for end of line */ | ||
170 | |||
171 | if (i) { | ||
172 | /* delimiter found */ | ||
173 | *cp++ = 0; /* string termination */ | ||
174 | count -= (i - 1); /* subtract remaining bytes from count */ | ||
175 | while ((i) && (*cp < ' ') && (*cp != 9)) { | ||
176 | i--; /* discard next char */ | ||
177 | count++; /* mark as read */ | ||
178 | cp++; /* next char */ | ||
179 | } | ||
180 | cnf->buf_size = 0; /* buffer is empty after transfer */ | ||
181 | if ((i = process_line(cnf)) < 0) /* handle the line */ | ||
182 | count = i; /* return the error */ | ||
183 | } | ||
184 | /* delimiter found */ | ||
185 | else { | ||
186 | cnf->buf_size += count; /* add chars to string */ | ||
187 | if (cnf->buf_size >= CONF_LINE_LEN - 1) { | ||
188 | if (cnf->card->debug_flags & LOG_CNF_MISC) | ||
189 | hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count); | ||
190 | return (-ERR_CONF_LONG); | ||
191 | } | ||
192 | } /* not delimited */ | ||
193 | |||
194 | } | ||
195 | /* copy remaining bytes into buffer */ | ||
196 | else { | ||
197 | if (cnf->card->debug_flags & LOG_CNF_MISC) | ||
198 | hysdn_addlog(cnf->card, "cnf line too long"); | ||
199 | return (-ERR_CONF_LONG); | ||
200 | } | ||
201 | } /* conf write active */ | ||
202 | |||
203 | return (count); | ||
204 | } /* hysdn_conf_write */ | ||
205 | |||
206 | /*******************************************/ | ||
207 | /* read conf file -> output card info data */ | ||
208 | /*******************************************/ | ||
209 | static ssize_t | ||
210 | hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t * off) | ||
211 | { | ||
212 | char *cp; | ||
213 | int i; | ||
214 | |||
215 | if (file->f_mode & FMODE_READ) { | ||
216 | if (!(cp = file->private_data)) | ||
217 | return (-EFAULT); /* should never happen */ | ||
218 | i = strlen(cp); /* get total string length */ | ||
219 | if (*off < i) { | ||
220 | /* still bytes to transfer */ | ||
221 | cp += *off; /* point to desired data offset */ | ||
222 | i -= *off; /* remaining length */ | ||
223 | if (i > count) | ||
224 | i = count; /* limit length to transfer */ | ||
225 | if (copy_to_user(buf, cp, i)) | ||
226 | return (-EFAULT); /* copy error */ | ||
227 | *off += i; /* adjust offset */ | ||
228 | } else | ||
229 | return (0); | ||
230 | } else | ||
231 | return (-EPERM); /* no permission to read */ | ||
232 | |||
233 | return (i); | ||
234 | } /* hysdn_conf_read */ | ||
235 | |||
236 | /******************/ | ||
237 | /* open conf file */ | ||
238 | /******************/ | ||
239 | static int | ||
240 | hysdn_conf_open(struct inode *ino, struct file *filep) | ||
241 | { | ||
242 | hysdn_card *card; | ||
243 | struct proc_dir_entry *pd; | ||
244 | struct conf_writedata *cnf; | ||
245 | char *cp, *tmp; | ||
246 | |||
247 | /* now search the addressed card */ | ||
248 | lock_kernel(); | ||
249 | card = card_root; | ||
250 | while (card) { | ||
251 | pd = card->procconf; | ||
252 | if (pd == PDE(ino)) | ||
253 | break; | ||
254 | card = card->next; /* search next entry */ | ||
255 | } | ||
256 | if (!card) { | ||
257 | unlock_kernel(); | ||
258 | return (-ENODEV); /* device is unknown/invalid */ | ||
259 | } | ||
260 | if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) | ||
261 | hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", | ||
262 | filep->f_uid, filep->f_gid, filep->f_mode); | ||
263 | |||
264 | if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { | ||
265 | /* write only access -> write boot file or conf line */ | ||
266 | |||
267 | if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) { | ||
268 | unlock_kernel(); | ||
269 | return (-EFAULT); | ||
270 | } | ||
271 | cnf->card = card; | ||
272 | cnf->buf_size = 0; /* nothing buffered */ | ||
273 | cnf->state = CONF_STATE_DETECT; /* start auto detect */ | ||
274 | filep->private_data = cnf; | ||
275 | |||
276 | } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | ||
277 | /* read access -> output card info data */ | ||
278 | |||
279 | if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) { | ||
280 | unlock_kernel(); | ||
281 | return (-EFAULT); /* out of memory */ | ||
282 | } | ||
283 | filep->private_data = tmp; /* start of string */ | ||
284 | |||
285 | /* first output a headline */ | ||
286 | sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device"); | ||
287 | cp = tmp; /* start of string */ | ||
288 | while (*cp) | ||
289 | cp++; | ||
290 | while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) | ||
291 | *cp++ = ' '; | ||
292 | *cp++ = '\n'; | ||
293 | |||
294 | /* and now the data */ | ||
295 | sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s", | ||
296 | card->myid, | ||
297 | card->bus, | ||
298 | PCI_SLOT(card->devfn), | ||
299 | card->brdtype, | ||
300 | card->irq, | ||
301 | card->iobase, | ||
302 | card->membase, | ||
303 | card->bchans, | ||
304 | card->faxchans, | ||
305 | card->state, | ||
306 | hysdn_net_getname(card)); | ||
307 | while (*cp) | ||
308 | cp++; | ||
309 | while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) | ||
310 | *cp++ = ' '; | ||
311 | *cp++ = '\n'; | ||
312 | *cp = 0; /* end of string */ | ||
313 | } else { /* simultaneous read/write access forbidden ! */ | ||
314 | unlock_kernel(); | ||
315 | return (-EPERM); /* no permission this time */ | ||
316 | } | ||
317 | unlock_kernel(); | ||
318 | return nonseekable_open(ino, filep); | ||
319 | } /* hysdn_conf_open */ | ||
320 | |||
321 | /***************************/ | ||
322 | /* close a config file. */ | ||
323 | /***************************/ | ||
324 | static int | ||
325 | hysdn_conf_close(struct inode *ino, struct file *filep) | ||
326 | { | ||
327 | hysdn_card *card; | ||
328 | struct conf_writedata *cnf; | ||
329 | int retval = 0; | ||
330 | struct proc_dir_entry *pd; | ||
331 | |||
332 | lock_kernel(); | ||
333 | /* search the addressed card */ | ||
334 | card = card_root; | ||
335 | while (card) { | ||
336 | pd = card->procconf; | ||
337 | if (pd == PDE(ino)) | ||
338 | break; | ||
339 | card = card->next; /* search next entry */ | ||
340 | } | ||
341 | if (!card) { | ||
342 | unlock_kernel(); | ||
343 | return (-ENODEV); /* device is unknown/invalid */ | ||
344 | } | ||
345 | if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) | ||
346 | hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", | ||
347 | filep->f_uid, filep->f_gid, filep->f_mode); | ||
348 | |||
349 | if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { | ||
350 | /* write only access -> write boot file or conf line */ | ||
351 | if (filep->private_data) { | ||
352 | cnf = filep->private_data; | ||
353 | |||
354 | if (cnf->state == CONF_STATE_POF) | ||
355 | retval = pof_write_close(cnf->card); /* close the pof write */ | ||
356 | kfree(filep->private_data); /* free allocated memory for buffer */ | ||
357 | |||
358 | } /* handle write private data */ | ||
359 | } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | ||
360 | /* read access -> output card info data */ | ||
361 | |||
362 | if (filep->private_data) | ||
363 | kfree(filep->private_data); /* release memory */ | ||
364 | } | ||
365 | unlock_kernel(); | ||
366 | return (retval); | ||
367 | } /* hysdn_conf_close */ | ||
368 | |||
369 | /******************************************************/ | ||
370 | /* table for conf filesystem functions defined above. */ | ||
371 | /******************************************************/ | ||
372 | static struct file_operations conf_fops = | ||
373 | { | ||
374 | .llseek = no_llseek, | ||
375 | .read = hysdn_conf_read, | ||
376 | .write = hysdn_conf_write, | ||
377 | .open = hysdn_conf_open, | ||
378 | .release = hysdn_conf_close, | ||
379 | }; | ||
380 | |||
381 | /*****************************/ | ||
382 | /* hysdn subdir in /proc/net */ | ||
383 | /*****************************/ | ||
384 | struct proc_dir_entry *hysdn_proc_entry = NULL; | ||
385 | |||
386 | /*******************************************************************************/ | ||
387 | /* hysdn_procconf_init is called when the module is loaded and after the cards */ | ||
388 | /* have been detected. The needed proc dir and card config files are created. */ | ||
389 | /* The log init is called at last. */ | ||
390 | /*******************************************************************************/ | ||
391 | int | ||
392 | hysdn_procconf_init(void) | ||
393 | { | ||
394 | hysdn_card *card; | ||
395 | uchar conf_name[20]; | ||
396 | |||
397 | hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net); | ||
398 | if (!hysdn_proc_entry) { | ||
399 | printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); | ||
400 | return (-1); | ||
401 | } | ||
402 | card = card_root; /* point to first card */ | ||
403 | while (card) { | ||
404 | |||
405 | sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); | ||
406 | if ((card->procconf = (void *) create_proc_entry(conf_name, | ||
407 | S_IFREG | S_IRUGO | S_IWUSR, | ||
408 | hysdn_proc_entry)) != NULL) { | ||
409 | ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; | ||
410 | ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE; | ||
411 | hysdn_proclog_init(card); /* init the log file entry */ | ||
412 | } | ||
413 | card = card->next; /* next entry */ | ||
414 | } | ||
415 | |||
416 | printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision)); | ||
417 | return (0); | ||
418 | } /* hysdn_procconf_init */ | ||
419 | |||
420 | /*************************************************************************************/ | ||
421 | /* hysdn_procconf_release is called when the module is unloaded and before the cards */ | ||
422 | /* resources are released. The module counter is assumed to be 0 ! */ | ||
423 | /*************************************************************************************/ | ||
424 | void | ||
425 | hysdn_procconf_release(void) | ||
426 | { | ||
427 | hysdn_card *card; | ||
428 | uchar conf_name[20]; | ||
429 | |||
430 | card = card_root; /* start with first card */ | ||
431 | while (card) { | ||
432 | |||
433 | sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); | ||
434 | if (card->procconf) | ||
435 | remove_proc_entry(conf_name, hysdn_proc_entry); | ||
436 | |||
437 | hysdn_proclog_release(card); /* init the log file entry */ | ||
438 | |||
439 | card = card->next; /* point to next card */ | ||
440 | } | ||
441 | |||
442 | remove_proc_entry(PROC_SUBDIR_NAME, proc_net); | ||
443 | } | ||
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c new file mode 100644 index 000000000000..8ef2b7c952a6 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_proclog.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* $Id: hysdn_proclog.c,v 1.9.6.3 2001/09/23 22:24:54 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards, /proc/net filesystem log functions. | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
6 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/version.h> | ||
15 | #include <linux/poll.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/smp_lock.h> | ||
19 | |||
20 | #include "hysdn_defs.h" | ||
21 | |||
22 | /* the proc subdir for the interface is defined in the procconf module */ | ||
23 | extern struct proc_dir_entry *hysdn_proc_entry; | ||
24 | |||
25 | /*************************************************/ | ||
26 | /* structure keeping ascii log for device output */ | ||
27 | /*************************************************/ | ||
28 | struct log_data { | ||
29 | struct log_data *next; | ||
30 | ulong usage_cnt; /* number of files still to work */ | ||
31 | void *proc_ctrl; /* pointer to own control procdata structure */ | ||
32 | char log_start[2]; /* log string start (final len aligned by size) */ | ||
33 | }; | ||
34 | |||
35 | /**********************************************/ | ||
36 | /* structure holding proc entrys for one card */ | ||
37 | /**********************************************/ | ||
38 | struct procdata { | ||
39 | struct proc_dir_entry *log; /* log entry */ | ||
40 | char log_name[15]; /* log filename */ | ||
41 | struct log_data *log_head, *log_tail; /* head and tail for queue */ | ||
42 | int if_used; /* open count for interface */ | ||
43 | int volatile del_lock; /* lock for delete operations */ | ||
44 | uchar logtmp[LOG_MAX_LINELEN]; | ||
45 | wait_queue_head_t rd_queue; | ||
46 | }; | ||
47 | |||
48 | |||
49 | /**********************************************/ | ||
50 | /* log function for cards error log interface */ | ||
51 | /**********************************************/ | ||
52 | void | ||
53 | hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize) | ||
54 | { | ||
55 | char buf[ERRLOG_TEXT_SIZE + 40]; | ||
56 | |||
57 | sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText); | ||
58 | put_log_buffer(card, buf); /* output the string */ | ||
59 | } /* hysdn_card_errlog */ | ||
60 | |||
61 | /***************************************************/ | ||
62 | /* Log function using format specifiers for output */ | ||
63 | /***************************************************/ | ||
64 | void | ||
65 | hysdn_addlog(hysdn_card * card, char *fmt,...) | ||
66 | { | ||
67 | struct procdata *pd = card->proclog; | ||
68 | char *cp; | ||
69 | va_list args; | ||
70 | |||
71 | if (!pd) | ||
72 | return; /* log structure non existent */ | ||
73 | |||
74 | cp = pd->logtmp; | ||
75 | cp += sprintf(cp, "HYSDN: card %d ", card->myid); | ||
76 | |||
77 | va_start(args, fmt); | ||
78 | cp += vsprintf(cp, fmt, args); | ||
79 | va_end(args); | ||
80 | *cp++ = '\n'; | ||
81 | *cp = 0; | ||
82 | |||
83 | if (card->debug_flags & DEB_OUT_SYSLOG) | ||
84 | printk(KERN_INFO "%s", pd->logtmp); | ||
85 | else | ||
86 | put_log_buffer(card, pd->logtmp); | ||
87 | |||
88 | } /* hysdn_addlog */ | ||
89 | |||
90 | /********************************************/ | ||
91 | /* put an log buffer into the log queue. */ | ||
92 | /* This buffer will be kept until all files */ | ||
93 | /* opened for read got the contents. */ | ||
94 | /* Flushes buffers not longer in use. */ | ||
95 | /********************************************/ | ||
96 | void | ||
97 | put_log_buffer(hysdn_card * card, char *cp) | ||
98 | { | ||
99 | struct log_data *ib; | ||
100 | struct procdata *pd = card->proclog; | ||
101 | int i; | ||
102 | unsigned long flags; | ||
103 | |||
104 | if (!pd) | ||
105 | return; | ||
106 | if (!cp) | ||
107 | return; | ||
108 | if (!*cp) | ||
109 | return; | ||
110 | if (pd->if_used <= 0) | ||
111 | return; /* no open file for read */ | ||
112 | |||
113 | if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC))) | ||
114 | return; /* no memory */ | ||
115 | strcpy(ib->log_start, cp); /* set output string */ | ||
116 | ib->next = NULL; | ||
117 | ib->proc_ctrl = pd; /* point to own control structure */ | ||
118 | save_flags(flags); | ||
119 | cli(); | ||
120 | ib->usage_cnt = pd->if_used; | ||
121 | if (!pd->log_head) | ||
122 | pd->log_head = ib; /* new head */ | ||
123 | else | ||
124 | pd->log_tail->next = ib; /* follows existing messages */ | ||
125 | pd->log_tail = ib; /* new tail */ | ||
126 | i = pd->del_lock++; /* get lock state */ | ||
127 | restore_flags(flags); | ||
128 | |||
129 | /* delete old entrys */ | ||
130 | if (!i) | ||
131 | while (pd->log_head->next) { | ||
132 | if ((pd->log_head->usage_cnt <= 0) && | ||
133 | (pd->log_head->next->usage_cnt <= 0)) { | ||
134 | ib = pd->log_head; | ||
135 | pd->log_head = pd->log_head->next; | ||
136 | kfree(ib); | ||
137 | } else | ||
138 | break; | ||
139 | } /* pd->log_head->next */ | ||
140 | pd->del_lock--; /* release lock level */ | ||
141 | wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */ | ||
142 | } /* put_log_buffer */ | ||
143 | |||
144 | |||
145 | /******************************/ | ||
146 | /* file operations and tables */ | ||
147 | /******************************/ | ||
148 | |||
149 | /****************************************/ | ||
150 | /* write log file -> set log level bits */ | ||
151 | /****************************************/ | ||
152 | static ssize_t | ||
153 | hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off) | ||
154 | { | ||
155 | ulong u = 0; | ||
156 | int found = 0; | ||
157 | uchar *cp, valbuf[128]; | ||
158 | long base = 10; | ||
159 | hysdn_card *card = (hysdn_card *) file->private_data; | ||
160 | |||
161 | if (count > (sizeof(valbuf) - 1)) | ||
162 | count = sizeof(valbuf) - 1; /* limit length */ | ||
163 | if (copy_from_user(valbuf, buf, count)) | ||
164 | return (-EFAULT); /* copy failed */ | ||
165 | |||
166 | valbuf[count] = 0; /* terminating 0 */ | ||
167 | cp = valbuf; | ||
168 | if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) { | ||
169 | cp += 2; /* pointer after hex modifier */ | ||
170 | base = 16; | ||
171 | } | ||
172 | /* scan the input for debug flags */ | ||
173 | while (*cp) { | ||
174 | if ((*cp >= '0') && (*cp <= '9')) { | ||
175 | found = 1; | ||
176 | u *= base; /* adjust to next digit */ | ||
177 | u += *cp++ - '0'; | ||
178 | continue; | ||
179 | } | ||
180 | if (base != 16) | ||
181 | break; /* end of number */ | ||
182 | |||
183 | if ((*cp >= 'a') && (*cp <= 'f')) { | ||
184 | found = 1; | ||
185 | u *= base; /* adjust to next digit */ | ||
186 | u += *cp++ - 'a' + 10; | ||
187 | continue; | ||
188 | } | ||
189 | break; /* terminated */ | ||
190 | } | ||
191 | |||
192 | if (found) { | ||
193 | card->debug_flags = u; /* remember debug flags */ | ||
194 | hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); | ||
195 | } | ||
196 | return (count); | ||
197 | } /* hysdn_log_write */ | ||
198 | |||
199 | /******************/ | ||
200 | /* read log file */ | ||
201 | /******************/ | ||
202 | static ssize_t | ||
203 | hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t * off) | ||
204 | { | ||
205 | struct log_data *inf; | ||
206 | int len; | ||
207 | struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); | ||
208 | struct procdata *pd = NULL; | ||
209 | hysdn_card *card; | ||
210 | |||
211 | if (!*((struct log_data **) file->private_data)) { | ||
212 | if (file->f_flags & O_NONBLOCK) | ||
213 | return (-EAGAIN); | ||
214 | |||
215 | /* sorry, but we need to search the card */ | ||
216 | card = card_root; | ||
217 | while (card) { | ||
218 | pd = card->proclog; | ||
219 | if (pd->log == pde) | ||
220 | break; | ||
221 | card = card->next; /* search next entry */ | ||
222 | } | ||
223 | if (card) | ||
224 | interruptible_sleep_on(&(pd->rd_queue)); | ||
225 | else | ||
226 | return (-EAGAIN); | ||
227 | |||
228 | } | ||
229 | if (!(inf = *((struct log_data **) file->private_data))) | ||
230 | return (0); | ||
231 | |||
232 | inf->usage_cnt--; /* new usage count */ | ||
233 | file->private_data = &inf->next; /* next structure */ | ||
234 | if ((len = strlen(inf->log_start)) <= count) { | ||
235 | if (copy_to_user(buf, inf->log_start, len)) | ||
236 | return -EFAULT; | ||
237 | *off += len; | ||
238 | return (len); | ||
239 | } | ||
240 | return (0); | ||
241 | } /* hysdn_log_read */ | ||
242 | |||
243 | /******************/ | ||
244 | /* open log file */ | ||
245 | /******************/ | ||
246 | static int | ||
247 | hysdn_log_open(struct inode *ino, struct file *filep) | ||
248 | { | ||
249 | hysdn_card *card; | ||
250 | struct procdata *pd = NULL; | ||
251 | ulong flags; | ||
252 | |||
253 | lock_kernel(); | ||
254 | card = card_root; | ||
255 | while (card) { | ||
256 | pd = card->proclog; | ||
257 | if (pd->log == PDE(ino)) | ||
258 | break; | ||
259 | card = card->next; /* search next entry */ | ||
260 | } | ||
261 | if (!card) { | ||
262 | unlock_kernel(); | ||
263 | return (-ENODEV); /* device is unknown/invalid */ | ||
264 | } | ||
265 | filep->private_data = card; /* remember our own card */ | ||
266 | |||
267 | if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { | ||
268 | /* write only access -> write log level only */ | ||
269 | } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | ||
270 | |||
271 | /* read access -> log/debug read */ | ||
272 | save_flags(flags); | ||
273 | cli(); | ||
274 | pd->if_used++; | ||
275 | if (pd->log_head) | ||
276 | filep->private_data = &pd->log_tail->next; | ||
277 | else | ||
278 | filep->private_data = &pd->log_head; | ||
279 | restore_flags(flags); | ||
280 | } else { /* simultaneous read/write access forbidden ! */ | ||
281 | unlock_kernel(); | ||
282 | return (-EPERM); /* no permission this time */ | ||
283 | } | ||
284 | unlock_kernel(); | ||
285 | return nonseekable_open(ino, filep); | ||
286 | } /* hysdn_log_open */ | ||
287 | |||
288 | /*******************************************************************************/ | ||
289 | /* close a cardlog file. If the file has been opened for exclusive write it is */ | ||
290 | /* assumed as pof data input and the pof loader is noticed about. */ | ||
291 | /* Otherwise file is handled as log output. In this case the interface usage */ | ||
292 | /* count is decremented and all buffers are noticed of closing. If this file */ | ||
293 | /* was the last one to be closed, all buffers are freed. */ | ||
294 | /*******************************************************************************/ | ||
295 | static int | ||
296 | hysdn_log_close(struct inode *ino, struct file *filep) | ||
297 | { | ||
298 | struct log_data *inf; | ||
299 | struct procdata *pd; | ||
300 | hysdn_card *card; | ||
301 | int retval = 0; | ||
302 | unsigned long flags; | ||
303 | |||
304 | |||
305 | lock_kernel(); | ||
306 | if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { | ||
307 | /* write only access -> write debug level written */ | ||
308 | retval = 0; /* success */ | ||
309 | } else { | ||
310 | /* read access -> log/debug read, mark one further file as closed */ | ||
311 | |||
312 | pd = NULL; | ||
313 | save_flags(flags); | ||
314 | cli(); | ||
315 | inf = *((struct log_data **) filep->private_data); /* get first log entry */ | ||
316 | if (inf) | ||
317 | pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ | ||
318 | else { | ||
319 | /* no info available -> search card */ | ||
320 | card = card_root; | ||
321 | while (card) { | ||
322 | pd = card->proclog; | ||
323 | if (pd->log == PDE(ino)) | ||
324 | break; | ||
325 | card = card->next; /* search next entry */ | ||
326 | } | ||
327 | if (card) | ||
328 | pd = card->proclog; /* pointer to procfs log */ | ||
329 | } | ||
330 | if (pd) | ||
331 | pd->if_used--; /* decrement interface usage count by one */ | ||
332 | |||
333 | while (inf) { | ||
334 | inf->usage_cnt--; /* decrement usage count for buffers */ | ||
335 | inf = inf->next; | ||
336 | } | ||
337 | restore_flags(flags); | ||
338 | |||
339 | if (pd) | ||
340 | if (pd->if_used <= 0) /* delete buffers if last file closed */ | ||
341 | while (pd->log_head) { | ||
342 | inf = pd->log_head; | ||
343 | pd->log_head = pd->log_head->next; | ||
344 | kfree(inf); | ||
345 | } | ||
346 | } /* read access */ | ||
347 | unlock_kernel(); | ||
348 | |||
349 | return (retval); | ||
350 | } /* hysdn_log_close */ | ||
351 | |||
352 | /*************************************************/ | ||
353 | /* select/poll routine to be able using select() */ | ||
354 | /*************************************************/ | ||
355 | static unsigned int | ||
356 | hysdn_log_poll(struct file *file, poll_table * wait) | ||
357 | { | ||
358 | unsigned int mask = 0; | ||
359 | struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); | ||
360 | hysdn_card *card; | ||
361 | struct procdata *pd = NULL; | ||
362 | |||
363 | if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) | ||
364 | return (mask); /* no polling for write supported */ | ||
365 | |||
366 | /* we need to search the card */ | ||
367 | card = card_root; | ||
368 | while (card) { | ||
369 | pd = card->proclog; | ||
370 | if (pd->log == pde) | ||
371 | break; | ||
372 | card = card->next; /* search next entry */ | ||
373 | } | ||
374 | if (!card) | ||
375 | return (mask); /* card not found */ | ||
376 | |||
377 | poll_wait(file, &(pd->rd_queue), wait); | ||
378 | |||
379 | if (*((struct log_data **) file->private_data)) | ||
380 | mask |= POLLIN | POLLRDNORM; | ||
381 | |||
382 | return mask; | ||
383 | } /* hysdn_log_poll */ | ||
384 | |||
385 | /**************************************************/ | ||
386 | /* table for log filesystem functions defined above. */ | ||
387 | /**************************************************/ | ||
388 | static struct file_operations log_fops = | ||
389 | { | ||
390 | .llseek = no_llseek, | ||
391 | .read = hysdn_log_read, | ||
392 | .write = hysdn_log_write, | ||
393 | .poll = hysdn_log_poll, | ||
394 | .open = hysdn_log_open, | ||
395 | .release = hysdn_log_close, | ||
396 | }; | ||
397 | |||
398 | |||
399 | /***********************************************************************************/ | ||
400 | /* hysdn_proclog_init is called when the module is loaded after creating the cards */ | ||
401 | /* conf files. */ | ||
402 | /***********************************************************************************/ | ||
403 | int | ||
404 | hysdn_proclog_init(hysdn_card * card) | ||
405 | { | ||
406 | struct procdata *pd; | ||
407 | |||
408 | /* create a cardlog proc entry */ | ||
409 | |||
410 | if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { | ||
411 | memset(pd, 0, sizeof(struct procdata)); | ||
412 | sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); | ||
413 | if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { | ||
414 | pd->log->proc_fops = &log_fops; | ||
415 | pd->log->owner = THIS_MODULE; | ||
416 | } | ||
417 | |||
418 | init_waitqueue_head(&(pd->rd_queue)); | ||
419 | |||
420 | card->proclog = (void *) pd; /* remember procfs structure */ | ||
421 | } | ||
422 | return (0); | ||
423 | } /* hysdn_proclog_init */ | ||
424 | |||
425 | /************************************************************************************/ | ||
426 | /* hysdn_proclog_release is called when the module is unloaded and before the cards */ | ||
427 | /* conf file is released */ | ||
428 | /* The module counter is assumed to be 0 ! */ | ||
429 | /************************************************************************************/ | ||
430 | void | ||
431 | hysdn_proclog_release(hysdn_card * card) | ||
432 | { | ||
433 | struct procdata *pd; | ||
434 | |||
435 | if ((pd = (struct procdata *) card->proclog) != NULL) { | ||
436 | if (pd->log) | ||
437 | remove_proc_entry(pd->log_name, hysdn_proc_entry); | ||
438 | kfree(pd); /* release memory */ | ||
439 | card->proclog = NULL; | ||
440 | } | ||
441 | } /* hysdn_proclog_release */ | ||
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c new file mode 100644 index 000000000000..4fa3b01707cd --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_sched.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $ | ||
2 | * | ||
3 | * Linux driver for HYSDN cards | ||
4 | * scheduler routines for handling exchange card <-> pc. | ||
5 | * | ||
6 | * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH | ||
7 | * Copyright 1999 by Werner Cornelius (werner@titro.de) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/signal.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | #include "hysdn_defs.h" | ||
24 | |||
25 | /*****************************************************************************/ | ||
26 | /* hysdn_sched_rx is called from the cards handler to announce new data is */ | ||
27 | /* available from the card. The routine has to handle the data and return */ | ||
28 | /* with a nonzero code if the data could be worked (or even thrown away), if */ | ||
29 | /* no room to buffer the data is available a zero return tells the card */ | ||
30 | /* to keep the data until later. */ | ||
31 | /*****************************************************************************/ | ||
32 | int | ||
33 | hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan) | ||
34 | { | ||
35 | |||
36 | switch (chan) { | ||
37 | case CHAN_NDIS_DATA: | ||
38 | if (hynet_enable & (1 << card->myid)) { | ||
39 | /* give packet to network handler */ | ||
40 | hysdn_rx_netpkt(card, buf, len); | ||
41 | } | ||
42 | break; | ||
43 | |||
44 | case CHAN_ERRLOG: | ||
45 | hysdn_card_errlog(card, (tErrLogEntry *) buf, len); | ||
46 | if (card->err_log_state == ERRLOG_STATE_ON) | ||
47 | card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ | ||
48 | break; | ||
49 | #ifdef CONFIG_HYSDN_CAPI | ||
50 | case CHAN_CAPI: | ||
51 | /* give packet to CAPI handler */ | ||
52 | if (hycapi_enable & (1 << card->myid)) { | ||
53 | hycapi_rx_capipkt(card, buf, len); | ||
54 | } | ||
55 | break; | ||
56 | #endif /* CONFIG_HYSDN_CAPI */ | ||
57 | default: | ||
58 | printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); | ||
59 | break; | ||
60 | |||
61 | } /* switch rx channel */ | ||
62 | |||
63 | return (1); /* always handled */ | ||
64 | } /* hysdn_sched_rx */ | ||
65 | |||
66 | /*****************************************************************************/ | ||
67 | /* hysdn_sched_tx is called from the cards handler to announce that there is */ | ||
68 | /* room in the tx-buffer to the card and data may be sent if needed. */ | ||
69 | /* If the routine wants to send data it must fill buf, len and chan with the */ | ||
70 | /* appropriate data and return a nonzero value. With a zero return no new */ | ||
71 | /* data to send is assumed. maxlen specifies the buffer size available for */ | ||
72 | /* sending. */ | ||
73 | /*****************************************************************************/ | ||
74 | int | ||
75 | hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen) | ||
76 | { | ||
77 | struct sk_buff *skb; | ||
78 | |||
79 | if (card->net_tx_busy) { | ||
80 | card->net_tx_busy = 0; /* reset flag */ | ||
81 | hysdn_tx_netack(card); /* acknowledge packet send */ | ||
82 | } /* a network packet has completely been transferred */ | ||
83 | /* first of all async requests are handled */ | ||
84 | if (card->async_busy) { | ||
85 | if (card->async_len <= maxlen) { | ||
86 | memcpy(buf, card->async_data, card->async_len); | ||
87 | *len = card->async_len; | ||
88 | *chan = card->async_channel; | ||
89 | card->async_busy = 0; /* reset request */ | ||
90 | return (1); | ||
91 | } | ||
92 | card->async_busy = 0; /* in case of length error */ | ||
93 | } /* async request */ | ||
94 | if ((card->err_log_state == ERRLOG_STATE_START) && | ||
95 | (maxlen >= ERRLOG_CMD_REQ_SIZE)) { | ||
96 | strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */ | ||
97 | *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */ | ||
98 | *chan = CHAN_ERRLOG; /* and channel */ | ||
99 | card->err_log_state = ERRLOG_STATE_ON; /* new state is on */ | ||
100 | return (1); /* tell that data should be send */ | ||
101 | } /* error log start and able to send */ | ||
102 | if ((card->err_log_state == ERRLOG_STATE_STOP) && | ||
103 | (maxlen >= ERRLOG_CMD_STOP_SIZE)) { | ||
104 | strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */ | ||
105 | *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */ | ||
106 | *chan = CHAN_ERRLOG; /* and channel */ | ||
107 | card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */ | ||
108 | return (1); /* tell that data should be send */ | ||
109 | } /* error log start and able to send */ | ||
110 | /* now handle network interface packets */ | ||
111 | if ((hynet_enable & (1 << card->myid)) && | ||
112 | (skb = hysdn_tx_netget(card)) != NULL) | ||
113 | { | ||
114 | if (skb->len <= maxlen) { | ||
115 | memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */ | ||
116 | *len = skb->len; | ||
117 | *chan = CHAN_NDIS_DATA; | ||
118 | card->net_tx_busy = 1; /* we are busy sending network data */ | ||
119 | return (1); /* go and send the data */ | ||
120 | } else | ||
121 | hysdn_tx_netack(card); /* aknowledge packet -> throw away */ | ||
122 | } /* send a network packet if available */ | ||
123 | #ifdef CONFIG_HYSDN_CAPI | ||
124 | if( ((hycapi_enable & (1 << card->myid))) && | ||
125 | ((skb = hycapi_tx_capiget(card)) != NULL) ) | ||
126 | { | ||
127 | if (skb->len <= maxlen) { | ||
128 | memcpy(buf, skb->data, skb->len); | ||
129 | *len = skb->len; | ||
130 | *chan = CHAN_CAPI; | ||
131 | hycapi_tx_capiack(card); | ||
132 | return (1); /* go and send the data */ | ||
133 | } | ||
134 | } | ||
135 | #endif /* CONFIG_HYSDN_CAPI */ | ||
136 | return (0); /* nothing to send */ | ||
137 | } /* hysdn_sched_tx */ | ||
138 | |||
139 | |||
140 | /*****************************************************************************/ | ||
141 | /* send one config line to the card and return 0 if successful, otherwise a */ | ||
142 | /* negative error code. */ | ||
143 | /* The function works with timeouts perhaps not giving the greatest speed */ | ||
144 | /* sending the line, but this should be meaningless beacuse only some lines */ | ||
145 | /* are to be sent and this happens very seldom. */ | ||
146 | /*****************************************************************************/ | ||
147 | int | ||
148 | hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan) | ||
149 | { | ||
150 | int cnt = 50; /* timeout intervalls */ | ||
151 | ulong flags; | ||
152 | |||
153 | if (card->debug_flags & LOG_SCHED_ASYN) | ||
154 | hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); | ||
155 | |||
156 | save_flags(flags); | ||
157 | cli(); | ||
158 | while (card->async_busy) { | ||
159 | sti(); | ||
160 | |||
161 | if (card->debug_flags & LOG_SCHED_ASYN) | ||
162 | hysdn_addlog(card, "async tx-cfg delayed"); | ||
163 | |||
164 | msleep_interruptible(20); /* Timeout 20ms */ | ||
165 | if (!--cnt) { | ||
166 | restore_flags(flags); | ||
167 | return (-ERR_ASYNC_TIME); /* timed out */ | ||
168 | } | ||
169 | cli(); | ||
170 | } /* wait for buffer to become free */ | ||
171 | |||
172 | strcpy(card->async_data, line); | ||
173 | card->async_len = strlen(line) + 1; | ||
174 | card->async_channel = chan; | ||
175 | card->async_busy = 1; /* request transfer */ | ||
176 | |||
177 | /* now queue the task */ | ||
178 | schedule_work(&card->irq_queue); | ||
179 | sti(); | ||
180 | |||
181 | if (card->debug_flags & LOG_SCHED_ASYN) | ||
182 | hysdn_addlog(card, "async tx-cfg data queued"); | ||
183 | |||
184 | cnt++; /* short delay */ | ||
185 | cli(); | ||
186 | |||
187 | while (card->async_busy) { | ||
188 | sti(); | ||
189 | |||
190 | if (card->debug_flags & LOG_SCHED_ASYN) | ||
191 | hysdn_addlog(card, "async tx-cfg waiting for tx-ready"); | ||
192 | |||
193 | msleep_interruptible(20); /* Timeout 20ms */ | ||
194 | if (!--cnt) { | ||
195 | restore_flags(flags); | ||
196 | return (-ERR_ASYNC_TIME); /* timed out */ | ||
197 | } | ||
198 | cli(); | ||
199 | } /* wait for buffer to become free again */ | ||
200 | |||
201 | restore_flags(flags); | ||
202 | |||
203 | if (card->debug_flags & LOG_SCHED_ASYN) | ||
204 | hysdn_addlog(card, "async tx-cfg data send"); | ||
205 | |||
206 | return (0); /* line send correctly */ | ||
207 | } /* hysdn_tx_cfgline */ | ||
diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h new file mode 100644 index 000000000000..4a115a87c782 --- /dev/null +++ b/drivers/isdn/hysdn/ince1pc.h | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Linux driver for HYSDN cards | ||
3 | * common definitions for both sides of the bus: | ||
4 | * - conventions both spoolers must know | ||
5 | * - channel numbers agreed upon | ||
6 | * | ||
7 | * Author M. Steinkopf | ||
8 | * Copyright 1999 by M. Steinkopf | ||
9 | * | ||
10 | * This software may be used and distributed according to the terms | ||
11 | * of the GNU General Public License, incorporated herein by reference. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __INCE1PC_H__ | ||
16 | #define __INCE1PC_H__ | ||
17 | |||
18 | /* basic scalar definitions have same meanning, | ||
19 | * but their declaration location depends on environment | ||
20 | */ | ||
21 | |||
22 | /*--------------------------------------channel numbers---------------------*/ | ||
23 | #define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ | ||
24 | #define CHAN_ERRLOG 0x0005 /* error logger */ | ||
25 | #define CHAN_CAPI 0x0064 /* CAPI interface */ | ||
26 | #define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ | ||
27 | |||
28 | /*--------------------------------------POF ready msg-----------------------*/ | ||
29 | /* NOTE: after booting POF sends system ready message to PC: */ | ||
30 | #define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ | ||
31 | #define RDY_MAGIC_SIZE 4 /* size in bytes */ | ||
32 | |||
33 | #define MAX_N_TOK_BYTES 255 | ||
34 | |||
35 | #define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE | ||
36 | #define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) | ||
37 | |||
38 | #define SYSR_TOK_END 0 | ||
39 | #define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ | ||
40 | #define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ | ||
41 | #define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ | ||
42 | #define SYSR_TOK_ESC 255 /* undefined data size yet */ | ||
43 | /* default values, if not corrected by token: */ | ||
44 | #define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ | ||
45 | #define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ | ||
46 | |||
47 | /* syntax of new SYSR token stream: | ||
48 | * channel: CHAN_SYSTEM | ||
49 | * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE | ||
50 | * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) | ||
51 | * msg : 0 1 2 3 {4 5 6 ..} | ||
52 | * S Y S R MAX_N_TOK_BYTES bytes of TokenStream | ||
53 | * | ||
54 | * TokenStream := empty | ||
55 | * | {NonEndTokenChunk} EndToken RotlCRC | ||
56 | * NonEndTokenChunk:= NonEndTokenId DataLen [Data] | ||
57 | * NonEndTokenId := 0x01 .. 0xFE 1 BYTE | ||
58 | * DataLen := 0x00 .. 0xFF 1 BYTE | ||
59 | * Data := DataLen bytes | ||
60 | * EndToken := 0x00 | ||
61 | * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes | ||
62 | * s. RotlCRC algorithm | ||
63 | * | ||
64 | * RotlCRC algorithm: | ||
65 | * ucSum= 0 1 uchar | ||
66 | * for all NonEndTokenChunk bytes: | ||
67 | * ROTL(ucSum,1) rotate left by 1 | ||
68 | * ucSum += Char; add current byte with swap around | ||
69 | * RotlCRC= ~ucSum; invert all bits for result | ||
70 | * | ||
71 | * note: | ||
72 | * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! | ||
73 | */ | ||
74 | |||
75 | /*--------------------------------------error logger------------------------*/ | ||
76 | /* note: pof needs final 0 ! */ | ||
77 | #define ERRLOG_CMD_REQ "ERRLOG ON" | ||
78 | #define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ | ||
79 | #define ERRLOG_CMD_STOP "ERRLOG OFF" | ||
80 | #define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ | ||
81 | |||
82 | #define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ | ||
83 | /* remaining text size = 55 */ | ||
84 | #define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) | ||
85 | |||
86 | typedef struct ErrLogEntry_tag { | ||
87 | |||
88 | /*00 */ ulong ulErrType; | ||
89 | |||
90 | /*04 */ ulong ulErrSubtype; | ||
91 | |||
92 | /*08 */ uchar ucTextSize; | ||
93 | |||
94 | /*09 */ uchar ucText[ERRLOG_TEXT_SIZE]; | ||
95 | /* ASCIIZ of len ucTextSize-1 */ | ||
96 | |||
97 | /*40 */ | ||
98 | } tErrLogEntry; | ||
99 | |||
100 | |||
101 | #if defined(__TURBOC__) | ||
102 | #if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE | ||
103 | #error size of tErrLogEntry != ERRLOG_ENTRY_SIZE | ||
104 | #endif /* */ | ||
105 | #endif /* */ | ||
106 | |||
107 | /*--------------------------------------DPRAM boot spooler------------------*/ | ||
108 | /* this is the struture used between pc and | ||
109 | * hyperstone to exchange boot data | ||
110 | */ | ||
111 | #define DPRAM_SPOOLER_DATA_SIZE 0x20 | ||
112 | typedef struct DpramBootSpooler_tag { | ||
113 | |||
114 | /*00 */ uchar Len; | ||
115 | |||
116 | /*01 */ volatile uchar RdPtr; | ||
117 | |||
118 | /*02 */ uchar WrPtr; | ||
119 | |||
120 | /*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE]; | ||
121 | |||
122 | /*23 */ | ||
123 | } tDpramBootSpooler; | ||
124 | |||
125 | |||
126 | #define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ | ||
127 | #define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ | ||
128 | |||
129 | /*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ | ||
130 | /* at DPRAM offset 0x1C00: */ | ||
131 | #define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ | ||
132 | |||
133 | |||
134 | #endif /* __INCE1PC_H__ */ | ||