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/hisax/elsa_ser.c |
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/hisax/elsa_ser.c')
-rw-r--r-- | drivers/isdn/hisax/elsa_ser.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c new file mode 100644 index 000000000000..689c83395693 --- /dev/null +++ b/drivers/isdn/hisax/elsa_ser.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $ | ||
2 | * | ||
3 | * stuff for the serial modem on ELSA cards | ||
4 | * | ||
5 | * This software may be used and distributed according to the terms | ||
6 | * of the GNU General Public License, incorporated herein by reference. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/serial.h> | ||
12 | #include <linux/serial_reg.h> | ||
13 | |||
14 | #define MAX_MODEM_BUF 256 | ||
15 | #define WAKEUP_CHARS (MAX_MODEM_BUF/2) | ||
16 | #define RS_ISR_PASS_LIMIT 256 | ||
17 | #define BASE_BAUD ( 1843200 / 16 ) | ||
18 | |||
19 | //#define SERIAL_DEBUG_OPEN 1 | ||
20 | //#define SERIAL_DEBUG_INTR 1 | ||
21 | //#define SERIAL_DEBUG_FLOW 1 | ||
22 | #undef SERIAL_DEBUG_OPEN | ||
23 | #undef SERIAL_DEBUG_INTR | ||
24 | #undef SERIAL_DEBUG_FLOW | ||
25 | #undef SERIAL_DEBUG_REG | ||
26 | //#define SERIAL_DEBUG_REG 1 | ||
27 | |||
28 | #ifdef SERIAL_DEBUG_REG | ||
29 | static u_char deb[32]; | ||
30 | const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"}; | ||
31 | const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"}; | ||
32 | #endif | ||
33 | |||
34 | static char *MInit_1 = "AT&F&C1E0&D2\r\0"; | ||
35 | static char *MInit_2 = "ATL2M1S64=13\r\0"; | ||
36 | static char *MInit_3 = "AT+FCLASS=0\r\0"; | ||
37 | static char *MInit_4 = "ATV1S2=128X1\r\0"; | ||
38 | static char *MInit_5 = "AT\\V8\\N3\r\0"; | ||
39 | static char *MInit_6 = "ATL0M0&G0%E1\r\0"; | ||
40 | static char *MInit_7 = "AT%L1%M0%C3\r\0"; | ||
41 | |||
42 | static char *MInit_speed28800 = "AT%G0%B28800\r\0"; | ||
43 | |||
44 | static char *MInit_dialout = "ATs7=60 x1 d\r\0"; | ||
45 | static char *MInit_dialin = "ATs7=60 x1 a\r\0"; | ||
46 | |||
47 | |||
48 | static inline unsigned int serial_in(struct IsdnCardState *cs, int offset) | ||
49 | { | ||
50 | #ifdef SERIAL_DEBUG_REG | ||
51 | u_int val = inb(cs->hw.elsa.base + 8 + offset); | ||
52 | debugl1(cs,"in %s %02x",ModemIn[offset], val); | ||
53 | return(val); | ||
54 | #else | ||
55 | return inb(cs->hw.elsa.base + 8 + offset); | ||
56 | #endif | ||
57 | } | ||
58 | |||
59 | static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset) | ||
60 | { | ||
61 | #ifdef SERIAL_DEBUG_REG | ||
62 | #ifdef CONFIG_SERIAL_NOPAUSE_IO | ||
63 | u_int val = inb(cs->hw.elsa.base + 8 + offset); | ||
64 | debugl1(cs,"inp %s %02x",ModemIn[offset], val); | ||
65 | #else | ||
66 | u_int val = inb_p(cs->hw.elsa.base + 8 + offset); | ||
67 | debugl1(cs,"inP %s %02x",ModemIn[offset], val); | ||
68 | #endif | ||
69 | return(val); | ||
70 | #else | ||
71 | #ifdef CONFIG_SERIAL_NOPAUSE_IO | ||
72 | return inb(cs->hw.elsa.base + 8 + offset); | ||
73 | #else | ||
74 | return inb_p(cs->hw.elsa.base + 8 + offset); | ||
75 | #endif | ||
76 | #endif | ||
77 | } | ||
78 | |||
79 | static inline void serial_out(struct IsdnCardState *cs, int offset, int value) | ||
80 | { | ||
81 | #ifdef SERIAL_DEBUG_REG | ||
82 | debugl1(cs,"out %s %02x",ModemOut[offset], value); | ||
83 | #endif | ||
84 | outb(value, cs->hw.elsa.base + 8 + offset); | ||
85 | } | ||
86 | |||
87 | static inline void serial_outp(struct IsdnCardState *cs, int offset, | ||
88 | int value) | ||
89 | { | ||
90 | #ifdef SERIAL_DEBUG_REG | ||
91 | #ifdef CONFIG_SERIAL_NOPAUSE_IO | ||
92 | debugl1(cs,"outp %s %02x",ModemOut[offset], value); | ||
93 | #else | ||
94 | debugl1(cs,"outP %s %02x",ModemOut[offset], value); | ||
95 | #endif | ||
96 | #endif | ||
97 | #ifdef CONFIG_SERIAL_NOPAUSE_IO | ||
98 | outb(value, cs->hw.elsa.base + 8 + offset); | ||
99 | #else | ||
100 | outb_p(value, cs->hw.elsa.base + 8 + offset); | ||
101 | #endif | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * This routine is called to set the UART divisor registers to match | ||
106 | * the specified baud rate for a serial port. | ||
107 | */ | ||
108 | static void change_speed(struct IsdnCardState *cs, int baud) | ||
109 | { | ||
110 | int quot = 0, baud_base; | ||
111 | unsigned cval, fcr = 0; | ||
112 | int bits; | ||
113 | |||
114 | |||
115 | /* byte size and parity */ | ||
116 | cval = 0x03; bits = 10; | ||
117 | /* Determine divisor based on baud rate */ | ||
118 | baud_base = BASE_BAUD; | ||
119 | quot = baud_base / baud; | ||
120 | /* If the quotient is ever zero, default to 9600 bps */ | ||
121 | if (!quot) | ||
122 | quot = baud_base / 9600; | ||
123 | |||
124 | /* Set up FIFO's */ | ||
125 | if ((baud_base / quot) < 2400) | ||
126 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; | ||
127 | else | ||
128 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; | ||
129 | serial_outp(cs, UART_FCR, fcr); | ||
130 | /* CTS flow control flag and modem status interrupts */ | ||
131 | cs->hw.elsa.IER &= ~UART_IER_MSI; | ||
132 | cs->hw.elsa.IER |= UART_IER_MSI; | ||
133 | serial_outp(cs, UART_IER, cs->hw.elsa.IER); | ||
134 | |||
135 | debugl1(cs,"modem quot=0x%x", quot); | ||
136 | serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ | ||
137 | serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */ | ||
138 | serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */ | ||
139 | serial_outp(cs, UART_LCR, cval); /* reset DLAB */ | ||
140 | serial_inp(cs, UART_RX); | ||
141 | } | ||
142 | |||
143 | static int mstartup(struct IsdnCardState *cs) | ||
144 | { | ||
145 | int retval=0; | ||
146 | |||
147 | /* | ||
148 | * Clear the FIFO buffers and disable them | ||
149 | * (they will be reenabled in change_speed()) | ||
150 | */ | ||
151 | serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); | ||
152 | |||
153 | /* | ||
154 | * At this point there's no way the LSR could still be 0xFF; | ||
155 | * if it is, then bail out, because there's likely no UART | ||
156 | * here. | ||
157 | */ | ||
158 | if (serial_inp(cs, UART_LSR) == 0xff) { | ||
159 | retval = -ENODEV; | ||
160 | goto errout; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Clear the interrupt registers. | ||
165 | */ | ||
166 | (void) serial_inp(cs, UART_RX); | ||
167 | (void) serial_inp(cs, UART_IIR); | ||
168 | (void) serial_inp(cs, UART_MSR); | ||
169 | |||
170 | /* | ||
171 | * Now, initialize the UART | ||
172 | */ | ||
173 | serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ | ||
174 | |||
175 | cs->hw.elsa.MCR = 0; | ||
176 | cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; | ||
177 | serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); | ||
178 | |||
179 | /* | ||
180 | * Finally, enable interrupts | ||
181 | */ | ||
182 | cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; | ||
183 | serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */ | ||
184 | |||
185 | /* | ||
186 | * And clear the interrupt registers again for luck. | ||
187 | */ | ||
188 | (void)serial_inp(cs, UART_LSR); | ||
189 | (void)serial_inp(cs, UART_RX); | ||
190 | (void)serial_inp(cs, UART_IIR); | ||
191 | (void)serial_inp(cs, UART_MSR); | ||
192 | |||
193 | cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0; | ||
194 | cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp =0; | ||
195 | |||
196 | /* | ||
197 | * and set the speed of the serial port | ||
198 | */ | ||
199 | change_speed(cs, BASE_BAUD); | ||
200 | cs->hw.elsa.MFlag = 1; | ||
201 | errout: | ||
202 | return retval; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * This routine will shutdown a serial port; interrupts are disabled, and | ||
207 | * DTR is dropped if the hangup on close termio flag is on. | ||
208 | */ | ||
209 | static void mshutdown(struct IsdnCardState *cs) | ||
210 | { | ||
211 | |||
212 | #ifdef SERIAL_DEBUG_OPEN | ||
213 | printk(KERN_DEBUG"Shutting down serial ...."); | ||
214 | #endif | ||
215 | |||
216 | /* | ||
217 | * clear delta_msr_wait queue to avoid mem leaks: we may free the irq | ||
218 | * here so the queue might never be waken up | ||
219 | */ | ||
220 | |||
221 | cs->hw.elsa.IER = 0; | ||
222 | serial_outp(cs, UART_IER, 0x00); /* disable all intrs */ | ||
223 | cs->hw.elsa.MCR &= ~UART_MCR_OUT2; | ||
224 | |||
225 | /* disable break condition */ | ||
226 | serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC); | ||
227 | |||
228 | cs->hw.elsa.MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); | ||
229 | serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); | ||
230 | |||
231 | /* disable FIFO's */ | ||
232 | serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); | ||
233 | serial_inp(cs, UART_RX); /* read data port to reset things */ | ||
234 | |||
235 | #ifdef SERIAL_DEBUG_OPEN | ||
236 | printk(" done\n"); | ||
237 | #endif | ||
238 | } | ||
239 | |||
240 | inline int | ||
241 | write_modem(struct BCState *bcs) { | ||
242 | int ret=0; | ||
243 | struct IsdnCardState *cs = bcs->cs; | ||
244 | int count, len, fp; | ||
245 | |||
246 | if (!bcs->tx_skb) | ||
247 | return 0; | ||
248 | if (bcs->tx_skb->len <= 0) | ||
249 | return 0; | ||
250 | len = bcs->tx_skb->len; | ||
251 | if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt) | ||
252 | len = MAX_MODEM_BUF - cs->hw.elsa.transcnt; | ||
253 | fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; | ||
254 | fp &= (MAX_MODEM_BUF -1); | ||
255 | count = len; | ||
256 | if (count > MAX_MODEM_BUF - fp) { | ||
257 | count = MAX_MODEM_BUF - fp; | ||
258 | memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count); | ||
259 | skb_pull(bcs->tx_skb, count); | ||
260 | cs->hw.elsa.transcnt += count; | ||
261 | ret = count; | ||
262 | count = len - count; | ||
263 | fp = 0; | ||
264 | } | ||
265 | memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count); | ||
266 | skb_pull(bcs->tx_skb, count); | ||
267 | cs->hw.elsa.transcnt += count; | ||
268 | ret += count; | ||
269 | |||
270 | if (cs->hw.elsa.transcnt && | ||
271 | !(cs->hw.elsa.IER & UART_IER_THRI)) { | ||
272 | cs->hw.elsa.IER |= UART_IER_THRI; | ||
273 | serial_outp(cs, UART_IER, cs->hw.elsa.IER); | ||
274 | } | ||
275 | return(ret); | ||
276 | } | ||
277 | |||
278 | inline void | ||
279 | modem_fill(struct BCState *bcs) { | ||
280 | |||
281 | if (bcs->tx_skb) { | ||
282 | if (bcs->tx_skb->len) { | ||
283 | write_modem(bcs); | ||
284 | return; | ||
285 | } else { | ||
286 | if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && | ||
287 | (PACKET_NOACK != bcs->tx_skb->pkt_type)) { | ||
288 | u_long flags; | ||
289 | spin_lock_irqsave(&bcs->aclock, flags); | ||
290 | bcs->ackcnt += bcs->hw.hscx.count; | ||
291 | spin_unlock_irqrestore(&bcs->aclock, flags); | ||
292 | schedule_event(bcs, B_ACKPENDING); | ||
293 | } | ||
294 | dev_kfree_skb_any(bcs->tx_skb); | ||
295 | bcs->tx_skb = NULL; | ||
296 | } | ||
297 | } | ||
298 | if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | ||
299 | bcs->hw.hscx.count = 0; | ||
300 | test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | ||
301 | write_modem(bcs); | ||
302 | } else { | ||
303 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
304 | schedule_event(bcs, B_XMTBUFREADY); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static inline void receive_chars(struct IsdnCardState *cs, | ||
309 | int *status) | ||
310 | { | ||
311 | unsigned char ch; | ||
312 | struct sk_buff *skb; | ||
313 | |||
314 | do { | ||
315 | ch = serial_in(cs, UART_RX); | ||
316 | if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF) | ||
317 | break; | ||
318 | cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch; | ||
319 | #ifdef SERIAL_DEBUG_INTR | ||
320 | printk("DR%02x:%02x...", ch, *status); | ||
321 | #endif | ||
322 | if (*status & (UART_LSR_BI | UART_LSR_PE | | ||
323 | UART_LSR_FE | UART_LSR_OE)) { | ||
324 | |||
325 | #ifdef SERIAL_DEBUG_INTR | ||
326 | printk("handling exept...."); | ||
327 | #endif | ||
328 | } | ||
329 | *status = serial_inp(cs, UART_LSR); | ||
330 | } while (*status & UART_LSR_DR); | ||
331 | if (cs->hw.elsa.MFlag == 2) { | ||
332 | if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt))) | ||
333 | printk(KERN_WARNING "ElsaSER: receive out of memory\n"); | ||
334 | else { | ||
335 | memcpy(skb_put(skb, cs->hw.elsa.rcvcnt), cs->hw.elsa.rcvbuf, | ||
336 | cs->hw.elsa.rcvcnt); | ||
337 | skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb); | ||
338 | } | ||
339 | schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY); | ||
340 | } else { | ||
341 | char tmp[128]; | ||
342 | char *t = tmp; | ||
343 | |||
344 | t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt); | ||
345 | QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt); | ||
346 | debugl1(cs, tmp); | ||
347 | } | ||
348 | cs->hw.elsa.rcvcnt = 0; | ||
349 | } | ||
350 | |||
351 | static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done) | ||
352 | { | ||
353 | int count; | ||
354 | |||
355 | debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp, | ||
356 | cs->hw.elsa.transcnt); | ||
357 | |||
358 | if (cs->hw.elsa.transcnt <= 0) { | ||
359 | cs->hw.elsa.IER &= ~UART_IER_THRI; | ||
360 | serial_out(cs, UART_IER, cs->hw.elsa.IER); | ||
361 | return; | ||
362 | } | ||
363 | count = 16; | ||
364 | do { | ||
365 | serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]); | ||
366 | if (cs->hw.elsa.transp >= MAX_MODEM_BUF) | ||
367 | cs->hw.elsa.transp=0; | ||
368 | if (--cs->hw.elsa.transcnt <= 0) | ||
369 | break; | ||
370 | } while (--count > 0); | ||
371 | if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag==2)) | ||
372 | modem_fill(cs->hw.elsa.bcs); | ||
373 | |||
374 | #ifdef SERIAL_DEBUG_INTR | ||
375 | printk("THRE..."); | ||
376 | #endif | ||
377 | if (intr_done) | ||
378 | *intr_done = 0; | ||
379 | if (cs->hw.elsa.transcnt <= 0) { | ||
380 | cs->hw.elsa.IER &= ~UART_IER_THRI; | ||
381 | serial_outp(cs, UART_IER, cs->hw.elsa.IER); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | |||
386 | static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs) | ||
387 | { | ||
388 | int status, iir, msr; | ||
389 | int pass_counter = 0; | ||
390 | |||
391 | #ifdef SERIAL_DEBUG_INTR | ||
392 | printk("rs_interrupt_single(%d)...", irq); | ||
393 | #endif | ||
394 | |||
395 | do { | ||
396 | status = serial_inp(cs, UART_LSR); | ||
397 | debugl1(cs,"rs LSR %02x", status); | ||
398 | #ifdef SERIAL_DEBUG_INTR | ||
399 | printk("status = %x...", status); | ||
400 | #endif | ||
401 | if (status & UART_LSR_DR) | ||
402 | receive_chars(cs, &status); | ||
403 | if (status & UART_LSR_THRE) | ||
404 | transmit_chars(cs, NULL); | ||
405 | if (pass_counter++ > RS_ISR_PASS_LIMIT) { | ||
406 | printk("rs_single loop break.\n"); | ||
407 | break; | ||
408 | } | ||
409 | iir = serial_inp(cs, UART_IIR); | ||
410 | debugl1(cs,"rs IIR %02x", iir); | ||
411 | if ((iir & 0xf) == 0) { | ||
412 | msr = serial_inp(cs, UART_MSR); | ||
413 | debugl1(cs,"rs MSR %02x", msr); | ||
414 | } | ||
415 | } while (!(iir & UART_IIR_NO_INT)); | ||
416 | #ifdef SERIAL_DEBUG_INTR | ||
417 | printk("end.\n"); | ||
418 | #endif | ||
419 | } | ||
420 | |||
421 | extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs); | ||
422 | extern void modehscx(struct BCState *bcs, int mode, int bc); | ||
423 | extern void hscx_l2l1(struct PStack *st, int pr, void *arg); | ||
424 | |||
425 | void | ||
426 | close_elsastate(struct BCState *bcs) | ||
427 | { | ||
428 | modehscx(bcs, 0, bcs->channel); | ||
429 | if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { | ||
430 | if (bcs->hw.hscx.rcvbuf) { | ||
431 | if (bcs->mode != L1_MODE_MODEM) | ||
432 | kfree(bcs->hw.hscx.rcvbuf); | ||
433 | bcs->hw.hscx.rcvbuf = NULL; | ||
434 | } | ||
435 | skb_queue_purge(&bcs->rqueue); | ||
436 | skb_queue_purge(&bcs->squeue); | ||
437 | if (bcs->tx_skb) { | ||
438 | dev_kfree_skb_any(bcs->tx_skb); | ||
439 | bcs->tx_skb = NULL; | ||
440 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | void | ||
446 | modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { | ||
447 | int count, fp; | ||
448 | u_char *msg = buf; | ||
449 | |||
450 | if (!len) | ||
451 | return; | ||
452 | if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) { | ||
453 | return; | ||
454 | } | ||
455 | fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; | ||
456 | fp &= (MAX_MODEM_BUF -1); | ||
457 | count = len; | ||
458 | if (count > MAX_MODEM_BUF - fp) { | ||
459 | count = MAX_MODEM_BUF - fp; | ||
460 | memcpy(cs->hw.elsa.transbuf + fp, msg, count); | ||
461 | cs->hw.elsa.transcnt += count; | ||
462 | msg += count; | ||
463 | count = len - count; | ||
464 | fp = 0; | ||
465 | } | ||
466 | memcpy(cs->hw.elsa.transbuf + fp, msg, count); | ||
467 | cs->hw.elsa.transcnt += count; | ||
468 | if (cs->hw.elsa.transcnt && | ||
469 | !(cs->hw.elsa.IER & UART_IER_THRI)) { | ||
470 | cs->hw.elsa.IER |= UART_IER_THRI; | ||
471 | serial_outp(cs, UART_IER, cs->hw.elsa.IER); | ||
472 | } | ||
473 | } | ||
474 | |||
475 | void | ||
476 | modem_set_init(struct IsdnCardState *cs) { | ||
477 | int timeout; | ||
478 | |||
479 | #define RCV_DELAY 20000 | ||
480 | modem_write_cmd(cs, MInit_1, strlen(MInit_1)); | ||
481 | timeout = 1000; | ||
482 | while(timeout-- && cs->hw.elsa.transcnt) | ||
483 | udelay(1000); | ||
484 | debugl1(cs, "msi tout=%d", timeout); | ||
485 | udelay(RCV_DELAY); | ||
486 | modem_write_cmd(cs, MInit_2, strlen(MInit_2)); | ||
487 | timeout = 1000; | ||
488 | while(timeout-- && cs->hw.elsa.transcnt) | ||
489 | udelay(1000); | ||
490 | debugl1(cs, "msi tout=%d", timeout); | ||
491 | udelay(RCV_DELAY); | ||
492 | modem_write_cmd(cs, MInit_3, strlen(MInit_3)); | ||
493 | timeout = 1000; | ||
494 | while(timeout-- && cs->hw.elsa.transcnt) | ||
495 | udelay(1000); | ||
496 | debugl1(cs, "msi tout=%d", timeout); | ||
497 | udelay(RCV_DELAY); | ||
498 | modem_write_cmd(cs, MInit_4, strlen(MInit_4)); | ||
499 | timeout = 1000; | ||
500 | while(timeout-- && cs->hw.elsa.transcnt) | ||
501 | udelay(1000); | ||
502 | debugl1(cs, "msi tout=%d", timeout); | ||
503 | udelay(RCV_DELAY ); | ||
504 | modem_write_cmd(cs, MInit_5, strlen(MInit_5)); | ||
505 | timeout = 1000; | ||
506 | while(timeout-- && cs->hw.elsa.transcnt) | ||
507 | udelay(1000); | ||
508 | debugl1(cs, "msi tout=%d", timeout); | ||
509 | udelay(RCV_DELAY); | ||
510 | modem_write_cmd(cs, MInit_6, strlen(MInit_6)); | ||
511 | timeout = 1000; | ||
512 | while(timeout-- && cs->hw.elsa.transcnt) | ||
513 | udelay(1000); | ||
514 | debugl1(cs, "msi tout=%d", timeout); | ||
515 | udelay(RCV_DELAY); | ||
516 | modem_write_cmd(cs, MInit_7, strlen(MInit_7)); | ||
517 | timeout = 1000; | ||
518 | while(timeout-- && cs->hw.elsa.transcnt) | ||
519 | udelay(1000); | ||
520 | debugl1(cs, "msi tout=%d", timeout); | ||
521 | udelay(RCV_DELAY); | ||
522 | } | ||
523 | |||
524 | void | ||
525 | modem_set_dial(struct IsdnCardState *cs, int outgoing) { | ||
526 | int timeout; | ||
527 | #define RCV_DELAY 20000 | ||
528 | |||
529 | modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800)); | ||
530 | timeout = 1000; | ||
531 | while(timeout-- && cs->hw.elsa.transcnt) | ||
532 | udelay(1000); | ||
533 | debugl1(cs, "msi tout=%d", timeout); | ||
534 | udelay(RCV_DELAY); | ||
535 | if (outgoing) | ||
536 | modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout)); | ||
537 | else | ||
538 | modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin)); | ||
539 | timeout = 1000; | ||
540 | while(timeout-- && cs->hw.elsa.transcnt) | ||
541 | udelay(1000); | ||
542 | debugl1(cs, "msi tout=%d", timeout); | ||
543 | udelay(RCV_DELAY); | ||
544 | } | ||
545 | |||
546 | void | ||
547 | modem_l2l1(struct PStack *st, int pr, void *arg) | ||
548 | { | ||
549 | struct BCState *bcs = st->l1.bcs; | ||
550 | struct sk_buff *skb = arg; | ||
551 | u_long flags; | ||
552 | |||
553 | if (pr == (PH_DATA | REQUEST)) { | ||
554 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
555 | if (bcs->tx_skb) { | ||
556 | skb_queue_tail(&bcs->squeue, skb); | ||
557 | } else { | ||
558 | bcs->tx_skb = skb; | ||
559 | test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | ||
560 | bcs->hw.hscx.count = 0; | ||
561 | write_modem(bcs); | ||
562 | } | ||
563 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
564 | } else if (pr == (PH_ACTIVATE | REQUEST)) { | ||
565 | test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); | ||
566 | st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); | ||
567 | set_arcofi(bcs->cs, st->l1.bc); | ||
568 | mstartup(bcs->cs); | ||
569 | modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag)); | ||
570 | bcs->cs->hw.elsa.MFlag=2; | ||
571 | } else if (pr == (PH_DEACTIVATE | REQUEST)) { | ||
572 | test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); | ||
573 | bcs->cs->dc.isac.arcofi_bc = st->l1.bc; | ||
574 | arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); | ||
575 | interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait); | ||
576 | bcs->cs->hw.elsa.MFlag=1; | ||
577 | } else { | ||
578 | printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | int | ||
583 | setstack_elsa(struct PStack *st, struct BCState *bcs) | ||
584 | { | ||
585 | |||
586 | bcs->channel = st->l1.bc; | ||
587 | switch (st->l1.mode) { | ||
588 | case L1_MODE_HDLC: | ||
589 | case L1_MODE_TRANS: | ||
590 | if (open_hscxstate(st->l1.hardware, bcs)) | ||
591 | return (-1); | ||
592 | st->l2.l2l1 = hscx_l2l1; | ||
593 | break; | ||
594 | case L1_MODE_MODEM: | ||
595 | bcs->mode = L1_MODE_MODEM; | ||
596 | if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { | ||
597 | bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf; | ||
598 | skb_queue_head_init(&bcs->rqueue); | ||
599 | skb_queue_head_init(&bcs->squeue); | ||
600 | } | ||
601 | bcs->tx_skb = NULL; | ||
602 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
603 | bcs->event = 0; | ||
604 | bcs->hw.hscx.rcvidx = 0; | ||
605 | bcs->tx_cnt = 0; | ||
606 | bcs->cs->hw.elsa.bcs = bcs; | ||
607 | st->l2.l2l1 = modem_l2l1; | ||
608 | break; | ||
609 | } | ||
610 | st->l1.bcs = bcs; | ||
611 | setstack_manager(st); | ||
612 | bcs->st = st; | ||
613 | setstack_l1_B(st); | ||
614 | return (0); | ||
615 | } | ||
616 | |||
617 | void | ||
618 | init_modem(struct IsdnCardState *cs) { | ||
619 | |||
620 | cs->bcs[0].BC_SetStack = setstack_elsa; | ||
621 | cs->bcs[1].BC_SetStack = setstack_elsa; | ||
622 | cs->bcs[0].BC_Close = close_elsastate; | ||
623 | cs->bcs[1].BC_Close = close_elsastate; | ||
624 | if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF, | ||
625 | GFP_ATOMIC))) { | ||
626 | printk(KERN_WARNING | ||
627 | "Elsa: No modem mem hw.elsa.rcvbuf\n"); | ||
628 | return; | ||
629 | } | ||
630 | if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF, | ||
631 | GFP_ATOMIC))) { | ||
632 | printk(KERN_WARNING | ||
633 | "Elsa: No modem mem hw.elsa.transbuf\n"); | ||
634 | kfree(cs->hw.elsa.rcvbuf); | ||
635 | cs->hw.elsa.rcvbuf = NULL; | ||
636 | return; | ||
637 | } | ||
638 | if (mstartup(cs)) { | ||
639 | printk(KERN_WARNING "Elsa: problem startup modem\n"); | ||
640 | } | ||
641 | modem_set_init(cs); | ||
642 | } | ||
643 | |||
644 | void | ||
645 | release_modem(struct IsdnCardState *cs) { | ||
646 | |||
647 | cs->hw.elsa.MFlag = 0; | ||
648 | if (cs->hw.elsa.transbuf) { | ||
649 | if (cs->hw.elsa.rcvbuf) { | ||
650 | mshutdown(cs); | ||
651 | kfree(cs->hw.elsa.rcvbuf); | ||
652 | cs->hw.elsa.rcvbuf = NULL; | ||
653 | } | ||
654 | kfree(cs->hw.elsa.transbuf); | ||
655 | cs->hw.elsa.transbuf = NULL; | ||
656 | } | ||
657 | } | ||