diff options
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/Makefile | 1 | ||||
-rw-r--r-- | drivers/isdn/gigaset/Kconfig | 42 | ||||
-rw-r--r-- | drivers/isdn/gigaset/Makefile | 6 | ||||
-rw-r--r-- | drivers/isdn/gigaset/asyncdata.c | 597 | ||||
-rw-r--r-- | drivers/isdn/gigaset/bas-gigaset.c | 2365 | ||||
-rw-r--r-- | drivers/isdn/gigaset/common.c | 1203 | ||||
-rw-r--r-- | drivers/isdn/gigaset/ev-layer.c | 1983 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 938 | ||||
-rw-r--r-- | drivers/isdn/gigaset/i4l.c | 567 | ||||
-rw-r--r-- | drivers/isdn/gigaset/interface.c | 718 | ||||
-rw-r--r-- | drivers/isdn/gigaset/isocdata.c | 1009 | ||||
-rw-r--r-- | drivers/isdn/gigaset/proc.c | 81 | ||||
-rw-r--r-- | drivers/isdn/gigaset/usb-gigaset.c | 1008 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/avmcard.h | 4 | ||||
-rw-r--r-- | drivers/isdn/i4l/Kconfig | 1 |
15 files changed, 10520 insertions, 3 deletions
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 03d8ccd51955..988142c30a6d 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile | |||
@@ -13,3 +13,4 @@ obj-$(CONFIG_ISDN_DRV_SC) += sc/ | |||
13 | obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/ | 13 | obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/ |
14 | obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000/ | 14 | obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000/ |
15 | obj-$(CONFIG_HYSDN) += hysdn/ | 15 | obj-$(CONFIG_HYSDN) += hysdn/ |
16 | obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/ | ||
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig new file mode 100644 index 000000000000..53c4fb62ed85 --- /dev/null +++ b/drivers/isdn/gigaset/Kconfig | |||
@@ -0,0 +1,42 @@ | |||
1 | menu "Siemens Gigaset" | ||
2 | depends on ISDN_I4L | ||
3 | |||
4 | config ISDN_DRV_GIGASET | ||
5 | tristate "Siemens Gigaset support (isdn)" | ||
6 | depends on ISDN_I4L && m | ||
7 | # depends on ISDN_I4L && MODULES | ||
8 | help | ||
9 | Say m here if you have a Gigaset or Sinus isdn device. | ||
10 | |||
11 | if ISDN_DRV_GIGASET!=n | ||
12 | |||
13 | config GIGASET_BASE | ||
14 | tristate "Gigaset base station support" | ||
15 | depends on ISDN_DRV_GIGASET && USB | ||
16 | help | ||
17 | Say m here if you need to communicate with the base | ||
18 | directly via USB. | ||
19 | |||
20 | config GIGASET_M105 | ||
21 | tristate "Gigaset M105 support" | ||
22 | depends on ISDN_DRV_GIGASET && USB | ||
23 | help | ||
24 | Say m here if you need the driver for the Gigaset M105 device. | ||
25 | |||
26 | config GIGASET_DEBUG | ||
27 | bool "Gigaset debugging" | ||
28 | help | ||
29 | This enables debugging code in the Gigaset drivers. | ||
30 | If in doubt, say yes. | ||
31 | |||
32 | config GIGASET_UNDOCREQ | ||
33 | bool "Support for undocumented USB requests" | ||
34 | help | ||
35 | This enables support for USB requests we only know from | ||
36 | reverse engineering (currently M105 only). If you need | ||
37 | features like configuration mode of M105, say yes. If you | ||
38 | care about your device, say no. | ||
39 | |||
40 | endif | ||
41 | |||
42 | endmenu | ||
diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile new file mode 100644 index 000000000000..9b9acf1a21ad --- /dev/null +++ b/drivers/isdn/gigaset/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o | ||
2 | usb_gigaset-y := usb-gigaset.o asyncdata.o | ||
3 | bas_gigaset-y := bas-gigaset.o isocdata.o | ||
4 | |||
5 | obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o | ||
6 | obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o | ||
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c new file mode 100644 index 000000000000..171f8b703d61 --- /dev/null +++ b/drivers/isdn/gigaset/asyncdata.c | |||
@@ -0,0 +1,597 @@ | |||
1 | /* | ||
2 | * Common data handling layer for ser_gigaset and usb_gigaset | ||
3 | * | ||
4 | * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>, | ||
5 | * Hansjoerg Lipp <hjlipp@web.de>, | ||
6 | * Stefan Eilers <Eilers.Stefan@epost.de>. | ||
7 | * | ||
8 | * ===================================================================== | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of | ||
12 | * the License, or (at your option) any later version. | ||
13 | * ===================================================================== | ||
14 | * ToDo: ... | ||
15 | * ===================================================================== | ||
16 | * Version: $Id: asyncdata.c,v 1.2.2.7 2005/11/13 23:05:18 hjlipp Exp $ | ||
17 | * ===================================================================== | ||
18 | */ | ||
19 | |||
20 | #include "gigaset.h" | ||
21 | #include <linux/crc-ccitt.h> | ||
22 | |||
23 | //#define GIG_M10x_STUFF_VOICE_DATA | ||
24 | |||
25 | /* check if byte must be stuffed/escaped | ||
26 | * I'm not sure which data should be encoded. | ||
27 | * Therefore I will go the hard way and decode every value | ||
28 | * less than 0x20, the flag sequence and the control escape char. | ||
29 | */ | ||
30 | static inline int muststuff(unsigned char c) | ||
31 | { | ||
32 | if (c < PPP_TRANS) return 1; | ||
33 | if (c == PPP_FLAG) return 1; | ||
34 | if (c == PPP_ESCAPE) return 1; | ||
35 | /* other possible candidates: */ | ||
36 | /* 0x91: XON with parity set */ | ||
37 | /* 0x93: XOFF with parity set */ | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | /* == data input =========================================================== */ | ||
42 | |||
43 | /* process a block of received bytes in command mode (modem response) | ||
44 | * Return value: | ||
45 | * number of processed bytes | ||
46 | */ | ||
47 | static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, | ||
48 | struct inbuf_t *inbuf) | ||
49 | { | ||
50 | struct cardstate *cs = inbuf->cs; | ||
51 | unsigned cbytes = cs->cbytes; | ||
52 | int inputstate = inbuf->inputstate; | ||
53 | int startbytes = numbytes; | ||
54 | |||
55 | for (;;) { | ||
56 | cs->respdata[cbytes] = c; | ||
57 | if (c == 10 || c == 13) { | ||
58 | dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", | ||
59 | __func__, cbytes); | ||
60 | cs->cbytes = cbytes; | ||
61 | gigaset_handle_modem_response(cs); /* can change cs->dle */ | ||
62 | cbytes = 0; | ||
63 | |||
64 | if (cs->dle && | ||
65 | !(inputstate & INS_DLE_command)) { | ||
66 | inputstate &= ~INS_command; | ||
67 | break; | ||
68 | } | ||
69 | } else { | ||
70 | /* advance in line buffer, checking for overflow */ | ||
71 | if (cbytes < MAX_RESP_SIZE - 1) | ||
72 | cbytes++; | ||
73 | else | ||
74 | warn("response too large"); | ||
75 | } | ||
76 | |||
77 | if (!numbytes) | ||
78 | break; | ||
79 | c = *src++; | ||
80 | --numbytes; | ||
81 | if (c == DLE_FLAG && | ||
82 | (cs->dle || inputstate & INS_DLE_command)) { | ||
83 | inputstate |= INS_DLE_char; | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | cs->cbytes = cbytes; | ||
89 | inbuf->inputstate = inputstate; | ||
90 | |||
91 | return startbytes - numbytes; | ||
92 | } | ||
93 | |||
94 | /* process a block of received bytes in lock mode (tty i/f) | ||
95 | * Return value: | ||
96 | * number of processed bytes | ||
97 | */ | ||
98 | static inline int lock_loop(unsigned char *src, int numbytes, | ||
99 | struct inbuf_t *inbuf) | ||
100 | { | ||
101 | struct cardstate *cs = inbuf->cs; | ||
102 | |||
103 | gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src, 0); | ||
104 | gigaset_if_receive(cs, src, numbytes); | ||
105 | |||
106 | return numbytes; | ||
107 | } | ||
108 | |||
109 | /* process a block of received bytes in HDLC data mode | ||
110 | * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. | ||
111 | * When a frame is complete, check the FCS and pass valid frames to the LL. | ||
112 | * If DLE is encountered, return immediately to let the caller handle it. | ||
113 | * Return value: | ||
114 | * number of processed bytes | ||
115 | * numbytes (all bytes processed) on error --FIXME | ||
116 | */ | ||
117 | static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, | ||
118 | struct inbuf_t *inbuf) | ||
119 | { | ||
120 | struct cardstate *cs = inbuf->cs; | ||
121 | struct bc_state *bcs = inbuf->bcs; | ||
122 | int inputstate; | ||
123 | __u16 fcs; | ||
124 | struct sk_buff *skb; | ||
125 | unsigned char error; | ||
126 | struct sk_buff *compskb; | ||
127 | int startbytes = numbytes; | ||
128 | int l; | ||
129 | |||
130 | IFNULLRETVAL(bcs, numbytes); | ||
131 | inputstate = bcs->inputstate; | ||
132 | fcs = bcs->fcs; | ||
133 | skb = bcs->skb; | ||
134 | IFNULLRETVAL(skb, numbytes); | ||
135 | |||
136 | if (unlikely(inputstate & INS_byte_stuff)) { | ||
137 | inputstate &= ~INS_byte_stuff; | ||
138 | goto byte_stuff; | ||
139 | } | ||
140 | for (;;) { | ||
141 | if (unlikely(c == PPP_ESCAPE)) { | ||
142 | if (unlikely(!numbytes)) { | ||
143 | inputstate |= INS_byte_stuff; | ||
144 | break; | ||
145 | } | ||
146 | c = *src++; | ||
147 | --numbytes; | ||
148 | if (unlikely(c == DLE_FLAG && | ||
149 | (cs->dle || | ||
150 | inbuf->inputstate & INS_DLE_command))) { | ||
151 | inbuf->inputstate |= INS_DLE_char; | ||
152 | inputstate |= INS_byte_stuff; | ||
153 | break; | ||
154 | } | ||
155 | byte_stuff: | ||
156 | c ^= PPP_TRANS; | ||
157 | #ifdef CONFIG_GIGASET_DEBUG | ||
158 | if (unlikely(!muststuff(c))) | ||
159 | dbg(DEBUG_HDLC, | ||
160 | "byte stuffed: 0x%02x", c); | ||
161 | #endif | ||
162 | } else if (unlikely(c == PPP_FLAG)) { | ||
163 | if (unlikely(inputstate & INS_skip_frame)) { | ||
164 | if (!(inputstate & INS_have_data)) { /* 7E 7E */ | ||
165 | //dbg(DEBUG_HDLC, "(7e)7e------------------------"); | ||
166 | #ifdef CONFIG_GIGASET_DEBUG | ||
167 | ++bcs->emptycount; | ||
168 | #endif | ||
169 | } else | ||
170 | dbg(DEBUG_HDLC, | ||
171 | "7e----------------------------"); | ||
172 | |||
173 | /* end of frame */ | ||
174 | error = 1; | ||
175 | gigaset_rcv_error(NULL, cs, bcs); | ||
176 | } else if (!(inputstate & INS_have_data)) { /* 7E 7E */ | ||
177 | //dbg(DEBUG_HDLC, "(7e)7e------------------------"); | ||
178 | #ifdef CONFIG_GIGASET_DEBUG | ||
179 | ++bcs->emptycount; | ||
180 | #endif | ||
181 | break; | ||
182 | } else { | ||
183 | dbg(DEBUG_HDLC, | ||
184 | "7e----------------------------"); | ||
185 | |||
186 | /* end of frame */ | ||
187 | error = 0; | ||
188 | |||
189 | if (unlikely(fcs != PPP_GOODFCS)) { | ||
190 | err("Packet checksum at %lu failed, " | ||
191 | "packet is corrupted (%u bytes)!", | ||
192 | bcs->rcvbytes, skb->len); | ||
193 | compskb = NULL; | ||
194 | gigaset_rcv_error(compskb, cs, bcs); | ||
195 | error = 1; | ||
196 | } else { | ||
197 | if (likely((l = skb->len) > 2)) { | ||
198 | skb->tail -= 2; | ||
199 | skb->len -= 2; | ||
200 | } else { | ||
201 | dev_kfree_skb(skb); | ||
202 | skb = NULL; | ||
203 | inputstate |= INS_skip_frame; | ||
204 | if (l == 1) { | ||
205 | err("invalid packet size (1)!"); | ||
206 | error = 1; | ||
207 | gigaset_rcv_error(NULL, cs, bcs); | ||
208 | } | ||
209 | } | ||
210 | if (likely(!(error || | ||
211 | (inputstate & | ||
212 | INS_skip_frame)))) { | ||
213 | gigaset_rcv_skb(skb, cs, bcs); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | if (unlikely(error)) | ||
219 | if (skb) | ||
220 | dev_kfree_skb(skb); | ||
221 | |||
222 | fcs = PPP_INITFCS; | ||
223 | inputstate &= ~(INS_have_data | INS_skip_frame); | ||
224 | if (unlikely(bcs->ignore)) { | ||
225 | inputstate |= INS_skip_frame; | ||
226 | skb = NULL; | ||
227 | } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) { | ||
228 | skb_reserve(skb, HW_HDR_LEN); | ||
229 | } else { | ||
230 | warn("could not allocate new skb"); | ||
231 | inputstate |= INS_skip_frame; | ||
232 | } | ||
233 | |||
234 | break; | ||
235 | #ifdef CONFIG_GIGASET_DEBUG | ||
236 | } else if (unlikely(muststuff(c))) { | ||
237 | /* Should not happen. Possible after ZDLE=1<CR><LF>. */ | ||
238 | dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); | ||
239 | #endif | ||
240 | } | ||
241 | |||
242 | /* add character */ | ||
243 | |||
244 | #ifdef CONFIG_GIGASET_DEBUG | ||
245 | if (unlikely(!(inputstate & INS_have_data))) { | ||
246 | dbg(DEBUG_HDLC, | ||
247 | "7e (%d x) ================", bcs->emptycount); | ||
248 | bcs->emptycount = 0; | ||
249 | } | ||
250 | #endif | ||
251 | |||
252 | inputstate |= INS_have_data; | ||
253 | |||
254 | if (likely(!(inputstate & INS_skip_frame))) { | ||
255 | if (unlikely(skb->len == SBUFSIZE)) { | ||
256 | warn("received packet too long"); | ||
257 | dev_kfree_skb_any(skb); | ||
258 | skb = NULL; | ||
259 | inputstate |= INS_skip_frame; | ||
260 | break; | ||
261 | } | ||
262 | *gigaset_skb_put_quick(skb, 1) = c; | ||
263 | /* *__skb_put (skb, 1) = c; */ | ||
264 | fcs = crc_ccitt_byte(fcs, c); | ||
265 | } | ||
266 | |||
267 | if (unlikely(!numbytes)) | ||
268 | break; | ||
269 | c = *src++; | ||
270 | --numbytes; | ||
271 | if (unlikely(c == DLE_FLAG && | ||
272 | (cs->dle || | ||
273 | inbuf->inputstate & INS_DLE_command))) { | ||
274 | inbuf->inputstate |= INS_DLE_char; | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | bcs->inputstate = inputstate; | ||
279 | bcs->fcs = fcs; | ||
280 | bcs->skb = skb; | ||
281 | return startbytes - numbytes; | ||
282 | } | ||
283 | |||
284 | /* process a block of received bytes in transparent data mode | ||
285 | * Invert bytes, undoing byte stuffing and watching for DLE escapes. | ||
286 | * If DLE is encountered, return immediately to let the caller handle it. | ||
287 | * Return value: | ||
288 | * number of processed bytes | ||
289 | * numbytes (all bytes processed) on error --FIXME | ||
290 | */ | ||
291 | static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, | ||
292 | struct inbuf_t *inbuf) | ||
293 | { | ||
294 | struct cardstate *cs = inbuf->cs; | ||
295 | struct bc_state *bcs = inbuf->bcs; | ||
296 | int inputstate; | ||
297 | struct sk_buff *skb; | ||
298 | int startbytes = numbytes; | ||
299 | |||
300 | IFNULLRETVAL(bcs, numbytes); | ||
301 | inputstate = bcs->inputstate; | ||
302 | skb = bcs->skb; | ||
303 | IFNULLRETVAL(skb, numbytes); | ||
304 | |||
305 | for (;;) { | ||
306 | /* add character */ | ||
307 | inputstate |= INS_have_data; | ||
308 | |||
309 | if (likely(!(inputstate & INS_skip_frame))) { | ||
310 | if (unlikely(skb->len == SBUFSIZE)) { | ||
311 | //FIXME just pass skb up and allocate a new one | ||
312 | warn("received packet too long"); | ||
313 | dev_kfree_skb_any(skb); | ||
314 | skb = NULL; | ||
315 | inputstate |= INS_skip_frame; | ||
316 | break; | ||
317 | } | ||
318 | *gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c]; | ||
319 | } | ||
320 | |||
321 | if (unlikely(!numbytes)) | ||
322 | break; | ||
323 | c = *src++; | ||
324 | --numbytes; | ||
325 | if (unlikely(c == DLE_FLAG && | ||
326 | (cs->dle || | ||
327 | inbuf->inputstate & INS_DLE_command))) { | ||
328 | inbuf->inputstate |= INS_DLE_char; | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /* pass data up */ | ||
334 | if (likely(inputstate & INS_have_data)) { | ||
335 | if (likely(!(inputstate & INS_skip_frame))) { | ||
336 | gigaset_rcv_skb(skb, cs, bcs); | ||
337 | } | ||
338 | inputstate &= ~(INS_have_data | INS_skip_frame); | ||
339 | if (unlikely(bcs->ignore)) { | ||
340 | inputstate |= INS_skip_frame; | ||
341 | skb = NULL; | ||
342 | } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) | ||
343 | != NULL)) { | ||
344 | skb_reserve(skb, HW_HDR_LEN); | ||
345 | } else { | ||
346 | warn("could not allocate new skb"); | ||
347 | inputstate |= INS_skip_frame; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | bcs->inputstate = inputstate; | ||
352 | bcs->skb = skb; | ||
353 | return startbytes - numbytes; | ||
354 | } | ||
355 | |||
356 | /* process a block of data received from the device | ||
357 | */ | ||
358 | void gigaset_m10x_input(struct inbuf_t *inbuf) | ||
359 | { | ||
360 | struct cardstate *cs; | ||
361 | unsigned tail, head, numbytes; | ||
362 | unsigned char *src, c; | ||
363 | int procbytes; | ||
364 | |||
365 | head = atomic_read(&inbuf->head); | ||
366 | tail = atomic_read(&inbuf->tail); | ||
367 | dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); | ||
368 | |||
369 | if (head != tail) { | ||
370 | cs = inbuf->cs; | ||
371 | src = inbuf->data + head; | ||
372 | numbytes = (head > tail ? RBUFSIZE : tail) - head; | ||
373 | dbg(DEBUG_INTR, "processing %u bytes", numbytes); | ||
374 | |||
375 | while (numbytes) { | ||
376 | if (atomic_read(&cs->mstate) == MS_LOCKED) { | ||
377 | procbytes = lock_loop(src, numbytes, inbuf); | ||
378 | src += procbytes; | ||
379 | numbytes -= procbytes; | ||
380 | } else { | ||
381 | c = *src++; | ||
382 | --numbytes; | ||
383 | if (c == DLE_FLAG && (cs->dle || | ||
384 | inbuf->inputstate & INS_DLE_command)) { | ||
385 | if (!(inbuf->inputstate & INS_DLE_char)) { | ||
386 | inbuf->inputstate |= INS_DLE_char; | ||
387 | goto nextbyte; | ||
388 | } | ||
389 | /* <DLE> <DLE> => <DLE> in data stream */ | ||
390 | inbuf->inputstate &= ~INS_DLE_char; | ||
391 | } | ||
392 | |||
393 | if (!(inbuf->inputstate & INS_DLE_char)) { | ||
394 | |||
395 | /* FIXME Einfach je nach Modus Funktionszeiger in cs setzen [hier+hdlc_loop]? */ | ||
396 | /* FIXME Spart folgendes "if" und ermoeglicht andere Protokolle */ | ||
397 | if (inbuf->inputstate & INS_command) | ||
398 | procbytes = cmd_loop(c, src, numbytes, inbuf); | ||
399 | else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC) | ||
400 | procbytes = hdlc_loop(c, src, numbytes, inbuf); | ||
401 | else | ||
402 | procbytes = iraw_loop(c, src, numbytes, inbuf); | ||
403 | |||
404 | src += procbytes; | ||
405 | numbytes -= procbytes; | ||
406 | } else { /* DLE-char */ | ||
407 | inbuf->inputstate &= ~INS_DLE_char; | ||
408 | switch (c) { | ||
409 | case 'X': /*begin of command*/ | ||
410 | #ifdef CONFIG_GIGASET_DEBUG | ||
411 | if (inbuf->inputstate & INS_command) | ||
412 | err("received <DLE> 'X' in command mode"); | ||
413 | #endif | ||
414 | inbuf->inputstate |= | ||
415 | INS_command | INS_DLE_command; | ||
416 | break; | ||
417 | case '.': /*end of command*/ | ||
418 | #ifdef CONFIG_GIGASET_DEBUG | ||
419 | if (!(inbuf->inputstate & INS_command)) | ||
420 | err("received <DLE> '.' in hdlc mode"); | ||
421 | #endif | ||
422 | inbuf->inputstate &= cs->dle ? | ||
423 | ~(INS_DLE_command|INS_command) | ||
424 | : ~INS_DLE_command; | ||
425 | break; | ||
426 | //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */ | ||
427 | default: | ||
428 | err("received 0x10 0x%02x!", (int) c); | ||
429 | /* FIXME: reset driver?? */ | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | nextbyte: | ||
434 | if (!numbytes) { | ||
435 | /* end of buffer, check for wrap */ | ||
436 | if (head > tail) { | ||
437 | head = 0; | ||
438 | src = inbuf->data; | ||
439 | numbytes = tail; | ||
440 | } else { | ||
441 | head = tail; | ||
442 | break; | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
447 | dbg(DEBUG_INTR, "setting head to %u", head); | ||
448 | atomic_set(&inbuf->head, head); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | |||
453 | /* == data output ========================================================== */ | ||
454 | |||
455 | /* Encoding of a PPP packet into an octet stuffed HDLC frame | ||
456 | * with FCS, opening and closing flags. | ||
457 | * parameters: | ||
458 | * skb skb containing original packet (freed upon return) | ||
459 | * head number of headroom bytes to allocate in result skb | ||
460 | * tail number of tailroom bytes to allocate in result skb | ||
461 | * Return value: | ||
462 | * pointer to newly allocated skb containing the result frame | ||
463 | */ | ||
464 | static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) | ||
465 | { | ||
466 | struct sk_buff *hdlc_skb; | ||
467 | __u16 fcs; | ||
468 | unsigned char c; | ||
469 | unsigned char *cp; | ||
470 | int len; | ||
471 | unsigned int stuf_cnt; | ||
472 | |||
473 | stuf_cnt = 0; | ||
474 | fcs = PPP_INITFCS; | ||
475 | cp = skb->data; | ||
476 | len = skb->len; | ||
477 | while (len--) { | ||
478 | if (muststuff(*cp)) | ||
479 | stuf_cnt++; | ||
480 | fcs = crc_ccitt_byte(fcs, *cp++); | ||
481 | } | ||
482 | fcs ^= 0xffff; /* complement */ | ||
483 | |||
484 | /* size of new buffer: original size + number of stuffing bytes | ||
485 | * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes | ||
486 | */ | ||
487 | hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head); | ||
488 | if (!hdlc_skb) { | ||
489 | err("unable to allocate memory for HDLC encoding!"); | ||
490 | dev_kfree_skb(skb); | ||
491 | return NULL; | ||
492 | } | ||
493 | skb_reserve(hdlc_skb, head); | ||
494 | |||
495 | /* Copy acknowledge request into new skb */ | ||
496 | memcpy(hdlc_skb->head, skb->head, 2); | ||
497 | |||
498 | /* Add flag sequence in front of everything.. */ | ||
499 | *(skb_put(hdlc_skb, 1)) = PPP_FLAG; | ||
500 | |||
501 | /* Perform byte stuffing while copying data. */ | ||
502 | while (skb->len--) { | ||
503 | if (muststuff(*skb->data)) { | ||
504 | *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; | ||
505 | *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS; | ||
506 | } else | ||
507 | *(skb_put(hdlc_skb, 1)) = *skb->data++; | ||
508 | } | ||
509 | |||
510 | /* Finally add FCS (byte stuffed) and flag sequence */ | ||
511 | c = (fcs & 0x00ff); /* least significant byte first */ | ||
512 | if (muststuff(c)) { | ||
513 | *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; | ||
514 | c ^= PPP_TRANS; | ||
515 | } | ||
516 | *(skb_put(hdlc_skb, 1)) = c; | ||
517 | |||
518 | c = ((fcs >> 8) & 0x00ff); | ||
519 | if (muststuff(c)) { | ||
520 | *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; | ||
521 | c ^= PPP_TRANS; | ||
522 | } | ||
523 | *(skb_put(hdlc_skb, 1)) = c; | ||
524 | |||
525 | *(skb_put(hdlc_skb, 1)) = PPP_FLAG; | ||
526 | |||
527 | dev_kfree_skb(skb); | ||
528 | return hdlc_skb; | ||
529 | } | ||
530 | |||
531 | /* Encoding of a raw packet into an octet stuffed bit inverted frame | ||
532 | * parameters: | ||
533 | * skb skb containing original packet (freed upon return) | ||
534 | * head number of headroom bytes to allocate in result skb | ||
535 | * tail number of tailroom bytes to allocate in result skb | ||
536 | * Return value: | ||
537 | * pointer to newly allocated skb containing the result frame | ||
538 | */ | ||
539 | static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) | ||
540 | { | ||
541 | struct sk_buff *iraw_skb; | ||
542 | unsigned char c; | ||
543 | unsigned char *cp; | ||
544 | int len; | ||
545 | |||
546 | /* worst case: every byte must be stuffed */ | ||
547 | iraw_skb = dev_alloc_skb(2*skb->len + tail + head); | ||
548 | if (!iraw_skb) { | ||
549 | err("unable to allocate memory for HDLC encoding!"); | ||
550 | dev_kfree_skb(skb); | ||
551 | return NULL; | ||
552 | } | ||
553 | skb_reserve(iraw_skb, head); | ||
554 | |||
555 | cp = skb->data; | ||
556 | len = skb->len; | ||
557 | while (len--) { | ||
558 | c = gigaset_invtab[*cp++]; | ||
559 | if (c == DLE_FLAG) | ||
560 | *(skb_put(iraw_skb, 1)) = c; | ||
561 | *(skb_put(iraw_skb, 1)) = c; | ||
562 | } | ||
563 | dev_kfree_skb(skb); | ||
564 | return iraw_skb; | ||
565 | } | ||
566 | |||
567 | /* gigaset_send_skb | ||
568 | * called by common.c to queue an skb for sending | ||
569 | * and start transmission if necessary | ||
570 | * parameters: | ||
571 | * B Channel control structure | ||
572 | * skb | ||
573 | * Return value: | ||
574 | * number of bytes accepted for sending | ||
575 | * (skb->len if ok, 0 if out of buffer space) | ||
576 | * or error code (< 0, eg. -EINVAL) | ||
577 | */ | ||
578 | int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) | ||
579 | { | ||
580 | unsigned len; | ||
581 | |||
582 | IFNULLRETVAL(bcs, -EFAULT); | ||
583 | IFNULLRETVAL(skb, -EFAULT); | ||
584 | len = skb->len; | ||
585 | |||
586 | if (bcs->proto2 == ISDN_PROTO_L2_HDLC) | ||
587 | skb = HDLC_Encode(skb, HW_HDR_LEN, 0); | ||
588 | else | ||
589 | skb = iraw_encode(skb, HW_HDR_LEN, 0); | ||
590 | if (!skb) | ||
591 | return -ENOMEM; | ||
592 | |||
593 | skb_queue_tail(&bcs->squeue, skb); | ||
594 | tasklet_schedule(&bcs->cs->write_tasklet); | ||
595 | |||
596 | return len; /* ok so far */ | ||
597 | } | ||
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c new file mode 100644 index 000000000000..31f0f07832bc --- /dev/null +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -0,0 +1,2365 @@ | |||
1 | /* | ||
2 | * USB driver for Gigaset 307x base via direct USB connection. | ||
3 | * | ||
4 | * Copyright (c) 2001 by Hansjoerg Lipp <hjlipp@web.de>, | ||
5 | * Tilman Schmidt <tilman@imap.cc>, | ||
6 | * Stefan Eilers <Eilers.Stefan@epost.de>. | ||
7 | * | ||
8 | * Based on usb-gigaset.c. | ||
9 | * | ||
10 | * ===================================================================== | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; either version 2 of | ||
14 | * the License, or (at your option) any later version. | ||
15 | * ===================================================================== | ||
16 | * ToDo: ... | ||
17 | * ===================================================================== | ||
18 | * Version: $Id: bas-gigaset.c,v 1.52.4.19 2006/02/04 18:28:16 hjlipp Exp $ | ||
19 | * ===================================================================== | ||
20 | */ | ||
21 | |||
22 | #include "gigaset.h" | ||
23 | |||
24 | #include <linux/errno.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <linux/usb.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | |||
32 | /* Version Information */ | ||
33 | #define DRIVER_AUTHOR "Tilman Schmidt <tilman@imap.cc>, Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>" | ||
34 | #define DRIVER_DESC "USB Driver for Gigaset 307x" | ||
35 | |||
36 | |||
37 | /* Module parameters */ | ||
38 | |||
39 | static int startmode = SM_ISDN; | ||
40 | static int cidmode = 1; | ||
41 | |||
42 | module_param(startmode, int, S_IRUGO); | ||
43 | module_param(cidmode, int, S_IRUGO); | ||
44 | MODULE_PARM_DESC(startmode, "start in isdn4linux mode"); | ||
45 | MODULE_PARM_DESC(cidmode, "Call-ID mode"); | ||
46 | |||
47 | #define GIGASET_MINORS 1 | ||
48 | #define GIGASET_MINOR 16 | ||
49 | #define GIGASET_MODULENAME "bas_gigaset" | ||
50 | #define GIGASET_DEVFSNAME "gig/bas/" | ||
51 | #define GIGASET_DEVNAME "ttyGB" | ||
52 | |||
53 | #define IF_WRITEBUF 256 //FIXME | ||
54 | |||
55 | /* Values for the Gigaset 307x */ | ||
56 | #define USB_GIGA_VENDOR_ID 0x0681 | ||
57 | #define USB_GIGA_PRODUCT_ID 0x0001 | ||
58 | #define USB_4175_PRODUCT_ID 0x0002 | ||
59 | #define USB_SX303_PRODUCT_ID 0x0021 | ||
60 | #define USB_SX353_PRODUCT_ID 0x0022 | ||
61 | |||
62 | /* table of devices that work with this driver */ | ||
63 | static struct usb_device_id gigaset_table [] = { | ||
64 | { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_GIGA_PRODUCT_ID) }, | ||
65 | { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_4175_PRODUCT_ID) }, | ||
66 | { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) }, | ||
67 | { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) }, | ||
68 | { } /* Terminating entry */ | ||
69 | }; | ||
70 | |||
71 | MODULE_DEVICE_TABLE(usb, gigaset_table); | ||
72 | |||
73 | /* Get a minor range for your devices from the usb maintainer */ | ||
74 | #define USB_SKEL_MINOR_BASE 200 | ||
75 | |||
76 | /*======================= local function prototypes =============================*/ | ||
77 | |||
78 | /* This function is called if a new device is connected to the USB port. It | ||
79 | * checks whether this new device belongs to this driver. | ||
80 | */ | ||
81 | static int gigaset_probe(struct usb_interface *interface, | ||
82 | const struct usb_device_id *id); | ||
83 | |||
84 | /* Function will be called if the device is unplugged */ | ||
85 | static void gigaset_disconnect(struct usb_interface *interface); | ||
86 | |||
87 | |||
88 | /*==============================================================================*/ | ||
89 | |||
90 | struct bas_cardstate { | ||
91 | struct usb_device *udev; /* USB device pointer */ | ||
92 | struct usb_interface *interface; /* interface for this device */ | ||
93 | unsigned char minor; /* starting minor number */ | ||
94 | |||
95 | struct urb *urb_ctrl; /* control pipe default URB */ | ||
96 | struct usb_ctrlrequest dr_ctrl; | ||
97 | struct timer_list timer_ctrl; /* control request timeout */ | ||
98 | |||
99 | struct timer_list timer_atrdy; /* AT command ready timeout */ | ||
100 | struct urb *urb_cmd_out; /* for sending AT commands */ | ||
101 | struct usb_ctrlrequest dr_cmd_out; | ||
102 | int retry_cmd_out; | ||
103 | |||
104 | struct urb *urb_cmd_in; /* for receiving AT replies */ | ||
105 | struct usb_ctrlrequest dr_cmd_in; | ||
106 | struct timer_list timer_cmd_in; /* receive request timeout */ | ||
107 | unsigned char *rcvbuf; /* AT reply receive buffer */ | ||
108 | |||
109 | struct urb *urb_int_in; /* URB for interrupt pipe */ | ||
110 | unsigned char int_in_buf[3]; | ||
111 | |||
112 | spinlock_t lock; /* locks all following */ | ||
113 | atomic_t basstate; /* bitmap (BS_*) */ | ||
114 | int pending; /* uncompleted base request */ | ||
115 | int rcvbuf_size; /* size of AT receive buffer */ | ||
116 | /* 0: no receive in progress */ | ||
117 | int retry_cmd_in; /* receive req retry count */ | ||
118 | }; | ||
119 | |||
120 | /* status of direct USB connection to 307x base (bits in basstate) */ | ||
121 | #define BS_ATOPEN 0x001 | ||
122 | #define BS_B1OPEN 0x002 | ||
123 | #define BS_B2OPEN 0x004 | ||
124 | #define BS_ATREADY 0x008 | ||
125 | #define BS_INIT 0x010 | ||
126 | #define BS_ATTIMER 0x020 | ||
127 | |||
128 | |||
129 | static struct gigaset_driver *driver = NULL; | ||
130 | static struct cardstate *cardstate = NULL; | ||
131 | |||
132 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
133 | static struct usb_driver gigaset_usb_driver = { | ||
134 | .name = GIGASET_MODULENAME, | ||
135 | .probe = gigaset_probe, | ||
136 | .disconnect = gigaset_disconnect, | ||
137 | .id_table = gigaset_table, | ||
138 | }; | ||
139 | |||
140 | /* get message text for USB status code | ||
141 | */ | ||
142 | static char *get_usb_statmsg(int status) | ||
143 | { | ||
144 | static char unkmsg[28]; | ||
145 | |||
146 | switch (status) { | ||
147 | case 0: | ||
148 | return "success"; | ||
149 | case -ENOENT: | ||
150 | return "canceled"; | ||
151 | case -ECONNRESET: | ||
152 | return "canceled (async)"; | ||
153 | case -EINPROGRESS: | ||
154 | return "pending"; | ||
155 | case -EPROTO: | ||
156 | return "bit stuffing or unknown USB error"; | ||
157 | case -EILSEQ: | ||
158 | return "Illegal byte sequence (CRC mismatch)"; | ||
159 | case -EPIPE: | ||
160 | return "babble detect or endpoint stalled"; | ||
161 | case -ENOSR: | ||
162 | return "buffer error"; | ||
163 | case -ETIMEDOUT: | ||
164 | return "timed out"; | ||
165 | case -ENODEV: | ||
166 | return "device not present"; | ||
167 | case -EREMOTEIO: | ||
168 | return "short packet detected"; | ||
169 | case -EXDEV: | ||
170 | return "partial isochronous transfer"; | ||
171 | case -EINVAL: | ||
172 | return "invalid argument"; | ||
173 | case -ENXIO: | ||
174 | return "URB already queued"; | ||
175 | case -EAGAIN: | ||
176 | return "isochronous start frame too early or too much scheduled"; | ||
177 | case -EFBIG: | ||
178 | return "too many isochronous frames requested"; | ||
179 | case -EMSGSIZE: | ||
180 | return "endpoint message size zero"; | ||
181 | case -ESHUTDOWN: | ||
182 | return "endpoint shutdown"; | ||
183 | case -EBUSY: | ||
184 | return "another request pending"; | ||
185 | default: | ||
186 | snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", status); | ||
187 | return unkmsg; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | /* usb_pipetype_str | ||
192 | * retrieve string representation of USB pipe type | ||
193 | */ | ||
194 | static inline char *usb_pipetype_str(int pipe) | ||
195 | { | ||
196 | if (usb_pipeisoc(pipe)) | ||
197 | return "Isoc"; | ||
198 | if (usb_pipeint(pipe)) | ||
199 | return "Int"; | ||
200 | if (usb_pipecontrol(pipe)) | ||
201 | return "Ctrl"; | ||
202 | if (usb_pipebulk(pipe)) | ||
203 | return "Bulk"; | ||
204 | return "?"; | ||
205 | } | ||
206 | |||
207 | /* dump_urb | ||
208 | * write content of URB to syslog for debugging | ||
209 | */ | ||
210 | static inline void dump_urb(enum debuglevel level, const char *tag, | ||
211 | struct urb *urb) | ||
212 | { | ||
213 | #ifdef CONFIG_GIGASET_DEBUG | ||
214 | int i; | ||
215 | IFNULLRET(tag); | ||
216 | dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb); | ||
217 | if (urb) { | ||
218 | dbg(level, | ||
219 | " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, " | ||
220 | "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,", | ||
221 | (unsigned long) urb->dev, | ||
222 | usb_pipetype_str(urb->pipe), | ||
223 | usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe), | ||
224 | usb_pipein(urb->pipe) ? "in" : "out", | ||
225 | urb->status, (unsigned long) urb->hcpriv, | ||
226 | urb->transfer_flags); | ||
227 | dbg(level, | ||
228 | " transfer_buffer=0x%08lx[%d], actual_length=%d, " | ||
229 | "bandwidth=%d, setup_packet=0x%08lx,", | ||
230 | (unsigned long) urb->transfer_buffer, | ||
231 | urb->transfer_buffer_length, urb->actual_length, | ||
232 | urb->bandwidth, (unsigned long) urb->setup_packet); | ||
233 | dbg(level, | ||
234 | " start_frame=%d, number_of_packets=%d, interval=%d, " | ||
235 | "error_count=%d,", | ||
236 | urb->start_frame, urb->number_of_packets, urb->interval, | ||
237 | urb->error_count); | ||
238 | dbg(level, | ||
239 | " context=0x%08lx, complete=0x%08lx, iso_frame_desc[]={", | ||
240 | (unsigned long) urb->context, | ||
241 | (unsigned long) urb->complete); | ||
242 | for (i = 0; i < urb->number_of_packets; i++) { | ||
243 | struct usb_iso_packet_descriptor *pifd = &urb->iso_frame_desc[i]; | ||
244 | dbg(level, | ||
245 | " {offset=%u, length=%u, actual_length=%u, " | ||
246 | "status=%u}", | ||
247 | pifd->offset, pifd->length, pifd->actual_length, | ||
248 | pifd->status); | ||
249 | } | ||
250 | } | ||
251 | dbg(level, "}}"); | ||
252 | #endif | ||
253 | } | ||
254 | |||
255 | /* read/set modem control bits etc. (m10x only) */ | ||
256 | static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, | ||
257 | unsigned new_state) | ||
258 | { | ||
259 | return -EINVAL; | ||
260 | } | ||
261 | |||
262 | static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) | ||
263 | { | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) | ||
268 | { | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | /* error_hangup | ||
273 | * hang up any existing connection because of an unrecoverable error | ||
274 | * This function may be called from any context and takes care of scheduling | ||
275 | * the necessary actions for execution outside of interrupt context. | ||
276 | * argument: | ||
277 | * B channel control structure | ||
278 | */ | ||
279 | static inline void error_hangup(struct bc_state *bcs) | ||
280 | { | ||
281 | struct cardstate *cs = bcs->cs; | ||
282 | |||
283 | dbg(DEBUG_ANY, | ||
284 | "%s: scheduling HUP for channel %d", __func__, bcs->channel); | ||
285 | |||
286 | if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { | ||
287 | //FIXME what should we do? | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | gigaset_schedule_event(cs); | ||
292 | } | ||
293 | |||
294 | /* error_reset | ||
295 | * reset Gigaset device because of an unrecoverable error | ||
296 | * This function may be called from any context and takes care of scheduling | ||
297 | * the necessary actions for execution outside of interrupt context. | ||
298 | * argument: | ||
299 | * controller state structure | ||
300 | */ | ||
301 | static inline void error_reset(struct cardstate *cs) | ||
302 | { | ||
303 | //FIXME try to recover without bothering the user | ||
304 | err("unrecoverable error - please disconnect the Gigaset base to reset"); | ||
305 | } | ||
306 | |||
307 | /* check_pending | ||
308 | * check for completion of pending control request | ||
309 | * parameter: | ||
310 | * urb USB request block of completed request | ||
311 | * urb->context = hardware specific controller state structure | ||
312 | */ | ||
313 | static void check_pending(struct bas_cardstate *ucs) | ||
314 | { | ||
315 | unsigned long flags; | ||
316 | |||
317 | IFNULLRET(ucs); | ||
318 | IFNULLRET(cardstate); | ||
319 | |||
320 | spin_lock_irqsave(&ucs->lock, flags); | ||
321 | switch (ucs->pending) { | ||
322 | case 0: | ||
323 | break; | ||
324 | case HD_OPEN_ATCHANNEL: | ||
325 | if (atomic_read(&ucs->basstate) & BS_ATOPEN) | ||
326 | ucs->pending = 0; | ||
327 | break; | ||
328 | case HD_OPEN_B1CHANNEL: | ||
329 | if (atomic_read(&ucs->basstate) & BS_B1OPEN) | ||
330 | ucs->pending = 0; | ||
331 | break; | ||
332 | case HD_OPEN_B2CHANNEL: | ||
333 | if (atomic_read(&ucs->basstate) & BS_B2OPEN) | ||
334 | ucs->pending = 0; | ||
335 | break; | ||
336 | case HD_CLOSE_ATCHANNEL: | ||
337 | if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) | ||
338 | ucs->pending = 0; | ||
339 | //wake_up_interruptible(cs->initwait); | ||
340 | //FIXME need own wait queue? | ||
341 | break; | ||
342 | case HD_CLOSE_B1CHANNEL: | ||
343 | if (!(atomic_read(&ucs->basstate) & BS_B1OPEN)) | ||
344 | ucs->pending = 0; | ||
345 | break; | ||
346 | case HD_CLOSE_B2CHANNEL: | ||
347 | if (!(atomic_read(&ucs->basstate) & BS_B2OPEN)) | ||
348 | ucs->pending = 0; | ||
349 | break; | ||
350 | case HD_DEVICE_INIT_ACK: /* no reply expected */ | ||
351 | ucs->pending = 0; | ||
352 | break; | ||
353 | /* HD_READ_ATMESSAGE, HD_WRITE_ATMESSAGE, HD_RESET_INTERRUPTPIPE | ||
354 | * are handled separately and should never end up here | ||
355 | */ | ||
356 | default: | ||
357 | warn("unknown pending request 0x%02x cleared", ucs->pending); | ||
358 | ucs->pending = 0; | ||
359 | } | ||
360 | |||
361 | if (!ucs->pending) | ||
362 | del_timer(&ucs->timer_ctrl); | ||
363 | |||
364 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
365 | } | ||
366 | |||
367 | /* cmd_in_timeout | ||
368 | * timeout routine for command input request | ||
369 | * argument: | ||
370 | * controller state structure | ||
371 | */ | ||
372 | static void cmd_in_timeout(unsigned long data) | ||
373 | { | ||
374 | struct cardstate *cs = (struct cardstate *) data; | ||
375 | struct bas_cardstate *ucs; | ||
376 | unsigned long flags; | ||
377 | |||
378 | IFNULLRET(cs); | ||
379 | ucs = cs->hw.bas; | ||
380 | IFNULLRET(ucs); | ||
381 | |||
382 | spin_lock_irqsave(&cs->lock, flags); | ||
383 | if (!atomic_read(&cs->connected)) { | ||
384 | dbg(DEBUG_USBREQ, "%s: disconnected", __func__); | ||
385 | spin_unlock_irqrestore(&cs->lock, flags); | ||
386 | return; | ||
387 | } | ||
388 | if (!ucs->rcvbuf_size) { | ||
389 | dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); | ||
390 | spin_unlock_irqrestore(&cs->lock, flags); | ||
391 | return; | ||
392 | } | ||
393 | spin_unlock_irqrestore(&cs->lock, flags); | ||
394 | |||
395 | err("timeout reading AT response"); | ||
396 | error_reset(cs); //FIXME retry? | ||
397 | } | ||
398 | |||
399 | |||
400 | static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs); | ||
401 | |||
402 | /* atread_submit | ||
403 | * submit an HD_READ_ATMESSAGE command URB | ||
404 | * parameters: | ||
405 | * cs controller state structure | ||
406 | * timeout timeout in 1/10 sec., 0: none | ||
407 | * return value: | ||
408 | * 0 on success | ||
409 | * -EINVAL if a NULL pointer is encountered somewhere | ||
410 | * -EBUSY if another request is pending | ||
411 | * any URB submission error code | ||
412 | */ | ||
413 | static int atread_submit(struct cardstate *cs, int timeout) | ||
414 | { | ||
415 | struct bas_cardstate *ucs; | ||
416 | int ret; | ||
417 | |||
418 | IFNULLRETVAL(cs, -EINVAL); | ||
419 | ucs = cs->hw.bas; | ||
420 | IFNULLRETVAL(ucs, -EINVAL); | ||
421 | IFNULLRETVAL(ucs->urb_cmd_in, -EINVAL); | ||
422 | |||
423 | dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size); | ||
424 | |||
425 | if (ucs->urb_cmd_in->status == -EINPROGRESS) { | ||
426 | err("could not submit HD_READ_ATMESSAGE: URB busy"); | ||
427 | return -EBUSY; | ||
428 | } | ||
429 | |||
430 | ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ; | ||
431 | ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE; | ||
432 | ucs->dr_cmd_in.wValue = 0; | ||
433 | ucs->dr_cmd_in.wIndex = 0; | ||
434 | ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size); | ||
435 | usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev, | ||
436 | usb_rcvctrlpipe(ucs->udev, 0), | ||
437 | (unsigned char*) & ucs->dr_cmd_in, | ||
438 | ucs->rcvbuf, ucs->rcvbuf_size, | ||
439 | read_ctrl_callback, cs->inbuf); | ||
440 | |||
441 | if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { | ||
442 | err("could not submit HD_READ_ATMESSAGE: %s", | ||
443 | get_usb_statmsg(ret)); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | if (timeout > 0) { | ||
448 | dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); | ||
449 | ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10; | ||
450 | ucs->timer_cmd_in.data = (unsigned long) cs; | ||
451 | ucs->timer_cmd_in.function = cmd_in_timeout; | ||
452 | add_timer(&ucs->timer_cmd_in); | ||
453 | } | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static void stopurbs(struct bas_bc_state *); | ||
458 | static int start_cbsend(struct cardstate *); | ||
459 | |||
460 | /* set/clear bits in base connection state | ||
461 | */ | ||
462 | inline static void update_basstate(struct bas_cardstate *ucs, | ||
463 | int set, int clear) | ||
464 | { | ||
465 | unsigned long flags; | ||
466 | int state; | ||
467 | |||
468 | spin_lock_irqsave(&ucs->lock, flags); | ||
469 | state = atomic_read(&ucs->basstate); | ||
470 | state &= ~clear; | ||
471 | state |= set; | ||
472 | atomic_set(&ucs->basstate, state); | ||
473 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
474 | } | ||
475 | |||
476 | |||
477 | /* read_int_callback | ||
478 | * USB completion handler for interrupt pipe input | ||
479 | * called by the USB subsystem in interrupt context | ||
480 | * parameter: | ||
481 | * urb USB request block | ||
482 | * urb->context = controller state structure | ||
483 | */ | ||
484 | static void read_int_callback(struct urb *urb, struct pt_regs *regs) | ||
485 | { | ||
486 | struct cardstate *cs; | ||
487 | struct bas_cardstate *ucs; | ||
488 | struct bc_state *bcs; | ||
489 | unsigned long flags; | ||
490 | int status; | ||
491 | unsigned l; | ||
492 | int channel; | ||
493 | |||
494 | IFNULLRET(urb); | ||
495 | cs = (struct cardstate *) urb->context; | ||
496 | IFNULLRET(cs); | ||
497 | ucs = cs->hw.bas; | ||
498 | IFNULLRET(ucs); | ||
499 | |||
500 | if (unlikely(!atomic_read(&cs->connected))) { | ||
501 | warn("%s: disconnected", __func__); | ||
502 | return; | ||
503 | } | ||
504 | |||
505 | switch (urb->status) { | ||
506 | case 0: /* success */ | ||
507 | break; | ||
508 | case -ENOENT: /* canceled */ | ||
509 | case -ECONNRESET: /* canceled (async) */ | ||
510 | case -EINPROGRESS: /* pending */ | ||
511 | /* ignore silently */ | ||
512 | dbg(DEBUG_USBREQ, | ||
513 | "%s: %s", __func__, get_usb_statmsg(urb->status)); | ||
514 | return; | ||
515 | default: /* severe trouble */ | ||
516 | warn("interrupt read: %s", get_usb_statmsg(urb->status)); | ||
517 | //FIXME corrective action? resubmission always ok? | ||
518 | goto resubmit; | ||
519 | } | ||
520 | |||
521 | l = (unsigned) ucs->int_in_buf[1] + | ||
522 | (((unsigned) ucs->int_in_buf[2]) << 8); | ||
523 | |||
524 | dbg(DEBUG_USBREQ, | ||
525 | "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", urb->actual_length, | ||
526 | (int)ucs->int_in_buf[0], l, | ||
527 | (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]); | ||
528 | |||
529 | channel = 0; | ||
530 | |||
531 | switch (ucs->int_in_buf[0]) { | ||
532 | case HD_DEVICE_INIT_OK: | ||
533 | update_basstate(ucs, BS_INIT, 0); | ||
534 | break; | ||
535 | |||
536 | case HD_READY_SEND_ATDATA: | ||
537 | del_timer(&ucs->timer_atrdy); | ||
538 | update_basstate(ucs, BS_ATREADY, BS_ATTIMER); | ||
539 | start_cbsend(cs); | ||
540 | break; | ||
541 | |||
542 | case HD_OPEN_B2CHANNEL_ACK: | ||
543 | ++channel; | ||
544 | case HD_OPEN_B1CHANNEL_ACK: | ||
545 | bcs = cs->bcs + channel; | ||
546 | update_basstate(ucs, BS_B1OPEN << channel, 0); | ||
547 | gigaset_bchannel_up(bcs); | ||
548 | break; | ||
549 | |||
550 | case HD_OPEN_ATCHANNEL_ACK: | ||
551 | update_basstate(ucs, BS_ATOPEN, 0); | ||
552 | start_cbsend(cs); | ||
553 | break; | ||
554 | |||
555 | case HD_CLOSE_B2CHANNEL_ACK: | ||
556 | ++channel; | ||
557 | case HD_CLOSE_B1CHANNEL_ACK: | ||
558 | bcs = cs->bcs + channel; | ||
559 | update_basstate(ucs, 0, BS_B1OPEN << channel); | ||
560 | stopurbs(bcs->hw.bas); | ||
561 | gigaset_bchannel_down(bcs); | ||
562 | break; | ||
563 | |||
564 | case HD_CLOSE_ATCHANNEL_ACK: | ||
565 | update_basstate(ucs, 0, BS_ATOPEN); | ||
566 | break; | ||
567 | |||
568 | case HD_B2_FLOW_CONTROL: | ||
569 | ++channel; | ||
570 | case HD_B1_FLOW_CONTROL: | ||
571 | bcs = cs->bcs + channel; | ||
572 | atomic_add((l - BAS_NORMFRAME) * BAS_CORRFRAMES, | ||
573 | &bcs->hw.bas->corrbytes); | ||
574 | dbg(DEBUG_ISO, | ||
575 | "Flow control (channel %d, sub %d): 0x%02x => %d", | ||
576 | channel, bcs->hw.bas->numsub, l, | ||
577 | atomic_read(&bcs->hw.bas->corrbytes)); | ||
578 | break; | ||
579 | |||
580 | case HD_RECEIVEATDATA_ACK: /* AT response ready to be received */ | ||
581 | if (!l) { | ||
582 | warn("HD_RECEIVEATDATA_ACK with length 0 ignored"); | ||
583 | break; | ||
584 | } | ||
585 | spin_lock_irqsave(&cs->lock, flags); | ||
586 | if (ucs->rcvbuf_size) { | ||
587 | spin_unlock_irqrestore(&cs->lock, flags); | ||
588 | err("receive AT data overrun, %d bytes lost", l); | ||
589 | error_reset(cs); //FIXME reschedule | ||
590 | break; | ||
591 | } | ||
592 | if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) { | ||
593 | spin_unlock_irqrestore(&cs->lock, flags); | ||
594 | err("%s: out of memory, %d bytes lost", __func__, l); | ||
595 | error_reset(cs); //FIXME reschedule | ||
596 | break; | ||
597 | } | ||
598 | ucs->rcvbuf_size = l; | ||
599 | ucs->retry_cmd_in = 0; | ||
600 | if ((status = atread_submit(cs, BAS_TIMEOUT)) < 0) { | ||
601 | kfree(ucs->rcvbuf); | ||
602 | ucs->rcvbuf = NULL; | ||
603 | ucs->rcvbuf_size = 0; | ||
604 | error_reset(cs); //FIXME reschedule | ||
605 | } | ||
606 | spin_unlock_irqrestore(&cs->lock, flags); | ||
607 | break; | ||
608 | |||
609 | case HD_RESET_INTERRUPT_PIPE_ACK: | ||
610 | dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK"); | ||
611 | break; | ||
612 | |||
613 | case HD_SUSPEND_END: | ||
614 | dbg(DEBUG_USBREQ, "HD_SUSPEND_END"); | ||
615 | break; | ||
616 | |||
617 | default: | ||
618 | warn("unknown Gigaset signal 0x%02x (%u) ignored", | ||
619 | (int) ucs->int_in_buf[0], l); | ||
620 | } | ||
621 | |||
622 | check_pending(ucs); | ||
623 | |||
624 | resubmit: | ||
625 | status = usb_submit_urb(urb, SLAB_ATOMIC); | ||
626 | if (unlikely(status)) { | ||
627 | err("could not resubmit interrupt URB: %s", | ||
628 | get_usb_statmsg(status)); | ||
629 | error_reset(cs); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | /* read_ctrl_callback | ||
634 | * USB completion handler for control pipe input | ||
635 | * called by the USB subsystem in interrupt context | ||
636 | * parameter: | ||
637 | * urb USB request block | ||
638 | * urb->context = inbuf structure for controller state | ||
639 | */ | ||
640 | static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) | ||
641 | { | ||
642 | struct cardstate *cs; | ||
643 | struct bas_cardstate *ucs; | ||
644 | unsigned numbytes; | ||
645 | unsigned long flags; | ||
646 | struct inbuf_t *inbuf; | ||
647 | int have_data = 0; | ||
648 | |||
649 | IFNULLRET(urb); | ||
650 | inbuf = (struct inbuf_t *) urb->context; | ||
651 | IFNULLRET(inbuf); | ||
652 | cs = inbuf->cs; | ||
653 | IFNULLRET(cs); | ||
654 | ucs = cs->hw.bas; | ||
655 | IFNULLRET(ucs); | ||
656 | |||
657 | spin_lock_irqsave(&cs->lock, flags); | ||
658 | if (!atomic_read(&cs->connected)) { | ||
659 | warn("%s: disconnected", __func__); | ||
660 | spin_unlock_irqrestore(&cs->lock, flags); | ||
661 | return; | ||
662 | } | ||
663 | |||
664 | if (!ucs->rcvbuf_size) { | ||
665 | warn("%s: no receive in progress", __func__); | ||
666 | spin_unlock_irqrestore(&cs->lock, flags); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | del_timer(&ucs->timer_cmd_in); | ||
671 | |||
672 | switch (urb->status) { | ||
673 | case 0: /* normal completion */ | ||
674 | numbytes = urb->actual_length; | ||
675 | if (unlikely(numbytes == 0)) { | ||
676 | warn("control read: empty block received"); | ||
677 | goto retry; | ||
678 | } | ||
679 | if (unlikely(numbytes != ucs->rcvbuf_size)) { | ||
680 | warn("control read: received %d chars, expected %d", | ||
681 | numbytes, ucs->rcvbuf_size); | ||
682 | if (numbytes > ucs->rcvbuf_size) | ||
683 | numbytes = ucs->rcvbuf_size; | ||
684 | } | ||
685 | |||
686 | /* copy received bytes to inbuf */ | ||
687 | have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); | ||
688 | |||
689 | if (unlikely(numbytes < ucs->rcvbuf_size)) { | ||
690 | /* incomplete - resubmit for remaining bytes */ | ||
691 | ucs->rcvbuf_size -= numbytes; | ||
692 | ucs->retry_cmd_in = 0; | ||
693 | goto retry; | ||
694 | } | ||
695 | break; | ||
696 | |||
697 | case -ENOENT: /* canceled */ | ||
698 | case -ECONNRESET: /* canceled (async) */ | ||
699 | case -EINPROGRESS: /* pending */ | ||
700 | /* no action necessary */ | ||
701 | dbg(DEBUG_USBREQ, | ||
702 | "%s: %s", __func__, get_usb_statmsg(urb->status)); | ||
703 | break; | ||
704 | |||
705 | default: /* severe trouble */ | ||
706 | warn("control read: %s", get_usb_statmsg(urb->status)); | ||
707 | retry: | ||
708 | if (ucs->retry_cmd_in++ < BAS_RETRY) { | ||
709 | notice("control read: retry %d", ucs->retry_cmd_in); | ||
710 | if (atread_submit(cs, BAS_TIMEOUT) >= 0) { | ||
711 | /* resubmitted - bypass regular exit block */ | ||
712 | spin_unlock_irqrestore(&cs->lock, flags); | ||
713 | return; | ||
714 | } | ||
715 | } else { | ||
716 | err("control read: giving up after %d tries", | ||
717 | ucs->retry_cmd_in); | ||
718 | } | ||
719 | error_reset(cs); | ||
720 | } | ||
721 | |||
722 | kfree(ucs->rcvbuf); | ||
723 | ucs->rcvbuf = NULL; | ||
724 | ucs->rcvbuf_size = 0; | ||
725 | spin_unlock_irqrestore(&cs->lock, flags); | ||
726 | if (have_data) { | ||
727 | dbg(DEBUG_INTR, "%s-->BH", __func__); | ||
728 | gigaset_schedule_event(cs); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | /* read_iso_callback | ||
733 | * USB completion handler for B channel isochronous input | ||
734 | * called by the USB subsystem in interrupt context | ||
735 | * parameter: | ||
736 | * urb USB request block of completed request | ||
737 | * urb->context = bc_state structure | ||
738 | */ | ||
739 | static void read_iso_callback(struct urb *urb, struct pt_regs *regs) | ||
740 | { | ||
741 | struct bc_state *bcs; | ||
742 | struct bas_bc_state *ubc; | ||
743 | unsigned long flags; | ||
744 | int i, rc; | ||
745 | |||
746 | IFNULLRET(urb); | ||
747 | IFNULLRET(urb->context); | ||
748 | IFNULLRET(cardstate); | ||
749 | |||
750 | /* status codes not worth bothering the tasklet with */ | ||
751 | if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || | ||
752 | urb->status == -EINPROGRESS)) { | ||
753 | dbg(DEBUG_ISO, | ||
754 | "%s: %s", __func__, get_usb_statmsg(urb->status)); | ||
755 | return; | ||
756 | } | ||
757 | |||
758 | bcs = (struct bc_state *) urb->context; | ||
759 | ubc = bcs->hw.bas; | ||
760 | IFNULLRET(ubc); | ||
761 | |||
762 | spin_lock_irqsave(&ubc->isoinlock, flags); | ||
763 | if (likely(ubc->isoindone == NULL)) { | ||
764 | /* pass URB to tasklet */ | ||
765 | ubc->isoindone = urb; | ||
766 | tasklet_schedule(&ubc->rcvd_tasklet); | ||
767 | } else { | ||
768 | /* tasklet still busy, drop data and resubmit URB */ | ||
769 | ubc->loststatus = urb->status; | ||
770 | for (i = 0; i < BAS_NUMFRAMES; i++) { | ||
771 | ubc->isoinlost += urb->iso_frame_desc[i].actual_length; | ||
772 | if (unlikely(urb->iso_frame_desc[i].status != 0 && | ||
773 | urb->iso_frame_desc[i].status != -EINPROGRESS)) { | ||
774 | ubc->loststatus = urb->iso_frame_desc[i].status; | ||
775 | } | ||
776 | urb->iso_frame_desc[i].status = 0; | ||
777 | urb->iso_frame_desc[i].actual_length = 0; | ||
778 | } | ||
779 | if (likely(atomic_read(&ubc->running))) { | ||
780 | urb->dev = bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */ | ||
781 | urb->transfer_flags = URB_ISO_ASAP; | ||
782 | urb->number_of_packets = BAS_NUMFRAMES; | ||
783 | dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__); | ||
784 | rc = usb_submit_urb(urb, SLAB_ATOMIC); | ||
785 | if (unlikely(rc != 0)) { | ||
786 | err("could not resubmit isochronous read URB: %s", | ||
787 | get_usb_statmsg(rc)); | ||
788 | dump_urb(DEBUG_ISO, "isoc read", urb); | ||
789 | error_hangup(bcs); | ||
790 | } | ||
791 | } | ||
792 | } | ||
793 | spin_unlock_irqrestore(&ubc->isoinlock, flags); | ||
794 | } | ||
795 | |||
796 | /* write_iso_callback | ||
797 | * USB completion handler for B channel isochronous output | ||
798 | * called by the USB subsystem in interrupt context | ||
799 | * parameter: | ||
800 | * urb USB request block of completed request | ||
801 | * urb->context = isow_urbctx_t structure | ||
802 | */ | ||
803 | static void write_iso_callback(struct urb *urb, struct pt_regs *regs) | ||
804 | { | ||
805 | struct isow_urbctx_t *ucx; | ||
806 | struct bas_bc_state *ubc; | ||
807 | unsigned long flags; | ||
808 | |||
809 | IFNULLRET(urb); | ||
810 | IFNULLRET(urb->context); | ||
811 | IFNULLRET(cardstate); | ||
812 | |||
813 | /* status codes not worth bothering the tasklet with */ | ||
814 | if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || | ||
815 | urb->status == -EINPROGRESS)) { | ||
816 | dbg(DEBUG_ISO, | ||
817 | "%s: %s", __func__, get_usb_statmsg(urb->status)); | ||
818 | return; | ||
819 | } | ||
820 | |||
821 | /* pass URB context to tasklet */ | ||
822 | ucx = (struct isow_urbctx_t *) urb->context; | ||
823 | IFNULLRET(ucx->bcs); | ||
824 | ubc = ucx->bcs->hw.bas; | ||
825 | IFNULLRET(ubc); | ||
826 | |||
827 | spin_lock_irqsave(&ubc->isooutlock, flags); | ||
828 | ubc->isooutovfl = ubc->isooutdone; | ||
829 | ubc->isooutdone = ucx; | ||
830 | spin_unlock_irqrestore(&ubc->isooutlock, flags); | ||
831 | tasklet_schedule(&ubc->sent_tasklet); | ||
832 | } | ||
833 | |||
834 | /* starturbs | ||
835 | * prepare and submit USB request blocks for isochronous input and output | ||
836 | * argument: | ||
837 | * B channel control structure | ||
838 | * return value: | ||
839 | * 0 on success | ||
840 | * < 0 on error (no URBs submitted) | ||
841 | */ | ||
842 | static int starturbs(struct bc_state *bcs) | ||
843 | { | ||
844 | struct urb *urb; | ||
845 | struct bas_bc_state *ubc; | ||
846 | int j, k; | ||
847 | int rc; | ||
848 | |||
849 | IFNULLRETVAL(bcs, -EFAULT); | ||
850 | ubc = bcs->hw.bas; | ||
851 | IFNULLRETVAL(ubc, -EFAULT); | ||
852 | |||
853 | /* initialize L2 reception */ | ||
854 | if (bcs->proto2 == ISDN_PROTO_L2_HDLC) | ||
855 | bcs->inputstate |= INS_flag_hunt; | ||
856 | |||
857 | /* submit all isochronous input URBs */ | ||
858 | atomic_set(&ubc->running, 1); | ||
859 | for (k = 0; k < BAS_INURBS; k++) { | ||
860 | urb = ubc->isoinurbs[k]; | ||
861 | if (!urb) { | ||
862 | err("isoinurbs[%d]==NULL", k); | ||
863 | rc = -EFAULT; | ||
864 | goto error; | ||
865 | } | ||
866 | |||
867 | urb->dev = bcs->cs->hw.bas->udev; | ||
868 | urb->pipe = usb_rcvisocpipe(urb->dev, 3 + 2 * bcs->channel); | ||
869 | urb->transfer_flags = URB_ISO_ASAP; | ||
870 | urb->transfer_buffer = ubc->isoinbuf + k * BAS_INBUFSIZE; | ||
871 | urb->transfer_buffer_length = BAS_INBUFSIZE; | ||
872 | urb->number_of_packets = BAS_NUMFRAMES; | ||
873 | urb->interval = BAS_FRAMETIME; | ||
874 | urb->complete = read_iso_callback; | ||
875 | urb->context = bcs; | ||
876 | for (j = 0; j < BAS_NUMFRAMES; j++) { | ||
877 | urb->iso_frame_desc[j].offset = j * BAS_MAXFRAME; | ||
878 | urb->iso_frame_desc[j].length = BAS_MAXFRAME; | ||
879 | urb->iso_frame_desc[j].status = 0; | ||
880 | urb->iso_frame_desc[j].actual_length = 0; | ||
881 | } | ||
882 | |||
883 | dump_urb(DEBUG_ISO, "Initial isoc read", urb); | ||
884 | if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { | ||
885 | err("could not submit isochronous read URB %d: %s", | ||
886 | k, get_usb_statmsg(rc)); | ||
887 | goto error; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | /* initialize L2 transmission */ | ||
892 | gigaset_isowbuf_init(ubc->isooutbuf, PPP_FLAG); | ||
893 | |||
894 | /* set up isochronous output URBs for flag idling */ | ||
895 | for (k = 0; k < BAS_OUTURBS; ++k) { | ||
896 | urb = ubc->isoouturbs[k].urb; | ||
897 | if (!urb) { | ||
898 | err("isoouturbs[%d].urb==NULL", k); | ||
899 | rc = -EFAULT; | ||
900 | goto error; | ||
901 | } | ||
902 | urb->dev = bcs->cs->hw.bas->udev; | ||
903 | urb->pipe = usb_sndisocpipe(urb->dev, 4 + 2 * bcs->channel); | ||
904 | urb->transfer_flags = URB_ISO_ASAP; | ||
905 | urb->transfer_buffer = ubc->isooutbuf->data; | ||
906 | urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data); | ||
907 | urb->number_of_packets = BAS_NUMFRAMES; | ||
908 | urb->interval = BAS_FRAMETIME; | ||
909 | urb->complete = write_iso_callback; | ||
910 | urb->context = &ubc->isoouturbs[k]; | ||
911 | for (j = 0; j < BAS_NUMFRAMES; ++j) { | ||
912 | urb->iso_frame_desc[j].offset = BAS_OUTBUFSIZE; | ||
913 | urb->iso_frame_desc[j].length = BAS_NORMFRAME; | ||
914 | urb->iso_frame_desc[j].status = 0; | ||
915 | urb->iso_frame_desc[j].actual_length = 0; | ||
916 | } | ||
917 | ubc->isoouturbs[k].limit = -1; | ||
918 | } | ||
919 | |||
920 | /* submit two URBs, keep third one */ | ||
921 | for (k = 0; k < 2; ++k) { | ||
922 | dump_urb(DEBUG_ISO, "Initial isoc write", urb); | ||
923 | rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC); | ||
924 | if (rc != 0) { | ||
925 | err("could not submit isochronous write URB %d: %s", | ||
926 | k, get_usb_statmsg(rc)); | ||
927 | goto error; | ||
928 | } | ||
929 | } | ||
930 | dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb); | ||
931 | ubc->isooutfree = &ubc->isoouturbs[2]; | ||
932 | ubc->isooutdone = ubc->isooutovfl = NULL; | ||
933 | return 0; | ||
934 | error: | ||
935 | stopurbs(ubc); | ||
936 | return rc; | ||
937 | } | ||
938 | |||
939 | /* stopurbs | ||
940 | * cancel the USB request blocks for isochronous input and output | ||
941 | * errors are silently ignored | ||
942 | * argument: | ||
943 | * B channel control structure | ||
944 | */ | ||
945 | static void stopurbs(struct bas_bc_state *ubc) | ||
946 | { | ||
947 | int k, rc; | ||
948 | |||
949 | IFNULLRET(ubc); | ||
950 | |||
951 | atomic_set(&ubc->running, 0); | ||
952 | |||
953 | for (k = 0; k < BAS_INURBS; ++k) { | ||
954 | rc = usb_unlink_urb(ubc->isoinurbs[k]); | ||
955 | dbg(DEBUG_ISO, "%s: isoc input URB %d unlinked, result = %d", | ||
956 | __func__, k, rc); | ||
957 | } | ||
958 | |||
959 | for (k = 0; k < BAS_OUTURBS; ++k) { | ||
960 | rc = usb_unlink_urb(ubc->isoouturbs[k].urb); | ||
961 | dbg(DEBUG_ISO, "%s: isoc output URB %d unlinked, result = %d", | ||
962 | __func__, k, rc); | ||
963 | } | ||
964 | } | ||
965 | |||
966 | /* Isochronous Write - Bottom Half */ | ||
967 | /* =============================== */ | ||
968 | |||
969 | /* submit_iso_write_urb | ||
970 | * fill and submit the next isochronous write URB | ||
971 | * parameters: | ||
972 | * bcs B channel state structure | ||
973 | * return value: | ||
974 | * number of frames submitted in URB | ||
975 | * 0 if URB not submitted because no data available (isooutbuf busy) | ||
976 | * error code < 0 on error | ||
977 | */ | ||
978 | static int submit_iso_write_urb(struct isow_urbctx_t *ucx) | ||
979 | { | ||
980 | struct urb *urb; | ||
981 | struct bas_bc_state *ubc; | ||
982 | struct usb_iso_packet_descriptor *ifd; | ||
983 | int corrbytes, nframe, rc; | ||
984 | |||
985 | IFNULLRETVAL(ucx, -EFAULT); | ||
986 | urb = ucx->urb; | ||
987 | IFNULLRETVAL(urb, -EFAULT); | ||
988 | IFNULLRETVAL(ucx->bcs, -EFAULT); | ||
989 | ubc = ucx->bcs->hw.bas; | ||
990 | IFNULLRETVAL(ubc, -EFAULT); | ||
991 | |||
992 | urb->dev = ucx->bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */ | ||
993 | urb->transfer_flags = URB_ISO_ASAP; | ||
994 | urb->transfer_buffer = ubc->isooutbuf->data; | ||
995 | urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data); | ||
996 | |||
997 | for (nframe = 0; nframe < BAS_NUMFRAMES; nframe++) { | ||
998 | ifd = &urb->iso_frame_desc[nframe]; | ||
999 | |||
1000 | /* compute frame length according to flow control */ | ||
1001 | ifd->length = BAS_NORMFRAME; | ||
1002 | if ((corrbytes = atomic_read(&ubc->corrbytes)) != 0) { | ||
1003 | dbg(DEBUG_ISO, "%s: corrbytes=%d", __func__, corrbytes); | ||
1004 | if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME) | ||
1005 | corrbytes = BAS_HIGHFRAME - BAS_NORMFRAME; | ||
1006 | else if (corrbytes < BAS_LOWFRAME - BAS_NORMFRAME) | ||
1007 | corrbytes = BAS_LOWFRAME - BAS_NORMFRAME; | ||
1008 | ifd->length += corrbytes; | ||
1009 | atomic_add(-corrbytes, &ubc->corrbytes); | ||
1010 | } | ||
1011 | //dbg(DEBUG_ISO, "%s: frame %d length=%d", __func__, nframe, ifd->length); | ||
1012 | |||
1013 | /* retrieve block of data to send */ | ||
1014 | ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf, ifd->length); | ||
1015 | if (ifd->offset < 0) { | ||
1016 | if (ifd->offset == -EBUSY) { | ||
1017 | dbg(DEBUG_ISO, "%s: buffer busy at frame %d", | ||
1018 | __func__, nframe); | ||
1019 | /* tasklet will be restarted from gigaset_send_skb() */ | ||
1020 | } else { | ||
1021 | err("%s: buffer error %d at frame %d", | ||
1022 | __func__, ifd->offset, nframe); | ||
1023 | return ifd->offset; | ||
1024 | } | ||
1025 | break; | ||
1026 | } | ||
1027 | ucx->limit = atomic_read(&ubc->isooutbuf->nextread); | ||
1028 | ifd->status = 0; | ||
1029 | ifd->actual_length = 0; | ||
1030 | } | ||
1031 | if ((urb->number_of_packets = nframe) > 0) { | ||
1032 | if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { | ||
1033 | err("could not submit isochronous write URB: %s", | ||
1034 | get_usb_statmsg(rc)); | ||
1035 | dump_urb(DEBUG_ISO, "isoc write", urb); | ||
1036 | return rc; | ||
1037 | } | ||
1038 | ++ubc->numsub; | ||
1039 | } | ||
1040 | return nframe; | ||
1041 | } | ||
1042 | |||
1043 | /* write_iso_tasklet | ||
1044 | * tasklet scheduled when an isochronous output URB from the Gigaset device | ||
1045 | * has completed | ||
1046 | * parameter: | ||
1047 | * data B channel state structure | ||
1048 | */ | ||
1049 | static void write_iso_tasklet(unsigned long data) | ||
1050 | { | ||
1051 | struct bc_state *bcs; | ||
1052 | struct bas_bc_state *ubc; | ||
1053 | struct cardstate *cs; | ||
1054 | struct isow_urbctx_t *done, *next, *ovfl; | ||
1055 | struct urb *urb; | ||
1056 | struct usb_iso_packet_descriptor *ifd; | ||
1057 | int offset; | ||
1058 | unsigned long flags; | ||
1059 | int i; | ||
1060 | struct sk_buff *skb; | ||
1061 | int len; | ||
1062 | |||
1063 | bcs = (struct bc_state *) data; | ||
1064 | IFNULLRET(bcs); | ||
1065 | ubc = bcs->hw.bas; | ||
1066 | IFNULLRET(ubc); | ||
1067 | cs = bcs->cs; | ||
1068 | IFNULLRET(cs); | ||
1069 | |||
1070 | /* loop while completed URBs arrive in time */ | ||
1071 | for (;;) { | ||
1072 | if (unlikely(!atomic_read(&cs->connected))) { | ||
1073 | warn("%s: disconnected", __func__); | ||
1074 | return; | ||
1075 | } | ||
1076 | |||
1077 | if (unlikely(!(atomic_read(&ubc->running)))) { | ||
1078 | dbg(DEBUG_ISO, "%s: not running", __func__); | ||
1079 | return; | ||
1080 | } | ||
1081 | |||
1082 | /* retrieve completed URBs */ | ||
1083 | spin_lock_irqsave(&ubc->isooutlock, flags); | ||
1084 | done = ubc->isooutdone; | ||
1085 | ubc->isooutdone = NULL; | ||
1086 | ovfl = ubc->isooutovfl; | ||
1087 | ubc->isooutovfl = NULL; | ||
1088 | spin_unlock_irqrestore(&ubc->isooutlock, flags); | ||
1089 | if (ovfl) { | ||
1090 | err("isochronous write buffer underrun - buy a faster machine :-)"); | ||
1091 | error_hangup(bcs); | ||
1092 | break; | ||
1093 | } | ||
1094 | if (!done) | ||
1095 | break; | ||
1096 | |||
1097 | /* submit free URB if available */ | ||
1098 | spin_lock_irqsave(&ubc->isooutlock, flags); | ||
1099 | next = ubc->isooutfree; | ||
1100 | ubc->isooutfree = NULL; | ||
1101 | spin_unlock_irqrestore(&ubc->isooutlock, flags); | ||
1102 | if (next) { | ||
1103 | if (submit_iso_write_urb(next) <= 0) { | ||
1104 | /* could not submit URB, put it back */ | ||
1105 | spin_lock_irqsave(&ubc->isooutlock, flags); | ||
1106 | if (ubc->isooutfree == NULL) { | ||
1107 | ubc->isooutfree = next; | ||
1108 | next = NULL; | ||
1109 | } | ||
1110 | spin_unlock_irqrestore(&ubc->isooutlock, flags); | ||
1111 | if (next) { | ||
1112 | /* couldn't put it back */ | ||
1113 | err("losing isochronous write URB"); | ||
1114 | error_hangup(bcs); | ||
1115 | } | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | /* process completed URB */ | ||
1120 | urb = done->urb; | ||
1121 | switch (urb->status) { | ||
1122 | case 0: /* normal completion */ | ||
1123 | break; | ||
1124 | case -EXDEV: /* inspect individual frames */ | ||
1125 | /* assumptions (for lack of documentation): | ||
1126 | * - actual_length bytes of the frame in error are successfully sent | ||
1127 | * - all following frames are not sent at all | ||
1128 | */ | ||
1129 | dbg(DEBUG_ISO, "%s: URB partially completed", __func__); | ||
1130 | offset = done->limit; /* just in case */ | ||
1131 | for (i = 0; i < BAS_NUMFRAMES; i++) { | ||
1132 | ifd = &urb->iso_frame_desc[i]; | ||
1133 | if (ifd->status || | ||
1134 | ifd->actual_length != ifd->length) { | ||
1135 | warn("isochronous write: frame %d: %s, " | ||
1136 | "only %d of %d bytes sent", | ||
1137 | i, get_usb_statmsg(ifd->status), | ||
1138 | ifd->actual_length, ifd->length); | ||
1139 | offset = (ifd->offset + | ||
1140 | ifd->actual_length) | ||
1141 | % BAS_OUTBUFSIZE; | ||
1142 | break; | ||
1143 | } | ||
1144 | } | ||
1145 | #ifdef CONFIG_GIGASET_DEBUG | ||
1146 | /* check assumption on remaining frames */ | ||
1147 | for (; i < BAS_NUMFRAMES; i++) { | ||
1148 | ifd = &urb->iso_frame_desc[i]; | ||
1149 | if (ifd->status != -EINPROGRESS | ||
1150 | || ifd->actual_length != 0) { | ||
1151 | warn("isochronous write: frame %d: %s, " | ||
1152 | "%d of %d bytes sent", | ||
1153 | i, get_usb_statmsg(ifd->status), | ||
1154 | ifd->actual_length, ifd->length); | ||
1155 | offset = (ifd->offset + | ||
1156 | ifd->actual_length) | ||
1157 | % BAS_OUTBUFSIZE; | ||
1158 | break; | ||
1159 | } | ||
1160 | } | ||
1161 | #endif | ||
1162 | break; | ||
1163 | case -EPIPE: //FIXME is this the code for "underrun"? | ||
1164 | err("isochronous write stalled"); | ||
1165 | error_hangup(bcs); | ||
1166 | break; | ||
1167 | default: /* severe trouble */ | ||
1168 | warn("isochronous write: %s", | ||
1169 | get_usb_statmsg(urb->status)); | ||
1170 | } | ||
1171 | |||
1172 | /* mark the write buffer area covered by this URB as free */ | ||
1173 | if (done->limit >= 0) | ||
1174 | atomic_set(&ubc->isooutbuf->read, done->limit); | ||
1175 | |||
1176 | /* mark URB as free */ | ||
1177 | spin_lock_irqsave(&ubc->isooutlock, flags); | ||
1178 | next = ubc->isooutfree; | ||
1179 | ubc->isooutfree = done; | ||
1180 | spin_unlock_irqrestore(&ubc->isooutlock, flags); | ||
1181 | if (next) { | ||
1182 | /* only one URB still active - resubmit one */ | ||
1183 | if (submit_iso_write_urb(next) <= 0) { | ||
1184 | /* couldn't submit */ | ||
1185 | error_hangup(bcs); | ||
1186 | } | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | /* process queued SKBs */ | ||
1191 | while ((skb = skb_dequeue(&bcs->squeue))) { | ||
1192 | /* copy to output buffer, doing L2 encapsulation */ | ||
1193 | len = skb->len; | ||
1194 | if (gigaset_isoc_buildframe(bcs, skb->data, len) == -EAGAIN) { | ||
1195 | /* insufficient buffer space, push back onto queue */ | ||
1196 | skb_queue_head(&bcs->squeue, skb); | ||
1197 | dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d", | ||
1198 | __func__, skb_queue_len(&bcs->squeue)); | ||
1199 | break; | ||
1200 | } | ||
1201 | skb_pull(skb, len); | ||
1202 | gigaset_skb_sent(bcs, skb); | ||
1203 | dev_kfree_skb_any(skb); | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | /* Isochronous Read - Bottom Half */ | ||
1208 | /* ============================== */ | ||
1209 | |||
1210 | /* read_iso_tasklet | ||
1211 | * tasklet scheduled when an isochronous input URB from the Gigaset device | ||
1212 | * has completed | ||
1213 | * parameter: | ||
1214 | * data B channel state structure | ||
1215 | */ | ||
1216 | static void read_iso_tasklet(unsigned long data) | ||
1217 | { | ||
1218 | struct bc_state *bcs; | ||
1219 | struct bas_bc_state *ubc; | ||
1220 | struct cardstate *cs; | ||
1221 | struct urb *urb; | ||
1222 | char *rcvbuf; | ||
1223 | unsigned long flags; | ||
1224 | int totleft, numbytes, offset, frame, rc; | ||
1225 | |||
1226 | bcs = (struct bc_state *) data; | ||
1227 | IFNULLRET(bcs); | ||
1228 | ubc = bcs->hw.bas; | ||
1229 | IFNULLRET(ubc); | ||
1230 | cs = bcs->cs; | ||
1231 | IFNULLRET(cs); | ||
1232 | |||
1233 | /* loop while more completed URBs arrive in the meantime */ | ||
1234 | for (;;) { | ||
1235 | if (!atomic_read(&cs->connected)) { | ||
1236 | warn("%s: disconnected", __func__); | ||
1237 | return; | ||
1238 | } | ||
1239 | |||
1240 | /* retrieve URB */ | ||
1241 | spin_lock_irqsave(&ubc->isoinlock, flags); | ||
1242 | if (!(urb = ubc->isoindone)) { | ||
1243 | spin_unlock_irqrestore(&ubc->isoinlock, flags); | ||
1244 | return; | ||
1245 | } | ||
1246 | ubc->isoindone = NULL; | ||
1247 | if (unlikely(ubc->loststatus != -EINPROGRESS)) { | ||
1248 | warn("isochronous read overrun, dropped URB with status: %s, %d bytes lost", | ||
1249 | get_usb_statmsg(ubc->loststatus), ubc->isoinlost); | ||
1250 | ubc->loststatus = -EINPROGRESS; | ||
1251 | } | ||
1252 | spin_unlock_irqrestore(&ubc->isoinlock, flags); | ||
1253 | |||
1254 | if (unlikely(!(atomic_read(&ubc->running)))) { | ||
1255 | dbg(DEBUG_ISO, "%s: channel not running, dropped URB with status: %s", | ||
1256 | __func__, get_usb_statmsg(urb->status)); | ||
1257 | return; | ||
1258 | } | ||
1259 | |||
1260 | switch (urb->status) { | ||
1261 | case 0: /* normal completion */ | ||
1262 | break; | ||
1263 | case -EXDEV: /* inspect individual frames (we do that anyway) */ | ||
1264 | dbg(DEBUG_ISO, "%s: URB partially completed", __func__); | ||
1265 | break; | ||
1266 | case -ENOENT: | ||
1267 | case -ECONNRESET: | ||
1268 | dbg(DEBUG_ISO, "%s: URB canceled", __func__); | ||
1269 | continue; /* -> skip */ | ||
1270 | case -EINPROGRESS: /* huh? */ | ||
1271 | dbg(DEBUG_ISO, "%s: URB still pending", __func__); | ||
1272 | continue; /* -> skip */ | ||
1273 | case -EPIPE: | ||
1274 | err("isochronous read stalled"); | ||
1275 | error_hangup(bcs); | ||
1276 | continue; /* -> skip */ | ||
1277 | default: /* severe trouble */ | ||
1278 | warn("isochronous read: %s", | ||
1279 | get_usb_statmsg(urb->status)); | ||
1280 | goto error; | ||
1281 | } | ||
1282 | |||
1283 | rcvbuf = urb->transfer_buffer; | ||
1284 | totleft = urb->actual_length; | ||
1285 | for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) { | ||
1286 | if (unlikely(urb->iso_frame_desc[frame].status)) { | ||
1287 | warn("isochronous read: frame %d: %s", | ||
1288 | frame, get_usb_statmsg(urb->iso_frame_desc[frame].status)); | ||
1289 | break; | ||
1290 | } | ||
1291 | numbytes = urb->iso_frame_desc[frame].actual_length; | ||
1292 | if (unlikely(numbytes > BAS_MAXFRAME)) { | ||
1293 | warn("isochronous read: frame %d: numbytes (%d) > BAS_MAXFRAME", | ||
1294 | frame, numbytes); | ||
1295 | break; | ||
1296 | } | ||
1297 | if (unlikely(numbytes > totleft)) { | ||
1298 | warn("isochronous read: frame %d: numbytes (%d) > totleft (%d)", | ||
1299 | frame, numbytes, totleft); | ||
1300 | break; | ||
1301 | } | ||
1302 | offset = urb->iso_frame_desc[frame].offset; | ||
1303 | if (unlikely(offset + numbytes > BAS_INBUFSIZE)) { | ||
1304 | warn("isochronous read: frame %d: offset (%d) + numbytes (%d) > BAS_INBUFSIZE", | ||
1305 | frame, offset, numbytes); | ||
1306 | break; | ||
1307 | } | ||
1308 | gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs); | ||
1309 | totleft -= numbytes; | ||
1310 | } | ||
1311 | if (unlikely(totleft > 0)) | ||
1312 | warn("isochronous read: %d data bytes missing", | ||
1313 | totleft); | ||
1314 | |||
1315 | error: | ||
1316 | /* URB processed, resubmit */ | ||
1317 | for (frame = 0; frame < BAS_NUMFRAMES; frame++) { | ||
1318 | urb->iso_frame_desc[frame].status = 0; | ||
1319 | urb->iso_frame_desc[frame].actual_length = 0; | ||
1320 | } | ||
1321 | urb->dev = bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */ | ||
1322 | urb->transfer_flags = URB_ISO_ASAP; | ||
1323 | urb->number_of_packets = BAS_NUMFRAMES; | ||
1324 | if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { | ||
1325 | err("could not resubmit isochronous read URB: %s", | ||
1326 | get_usb_statmsg(rc)); | ||
1327 | dump_urb(DEBUG_ISO, "resubmit iso read", urb); | ||
1328 | error_hangup(bcs); | ||
1329 | } | ||
1330 | } | ||
1331 | } | ||
1332 | |||
1333 | /* Channel Operations */ | ||
1334 | /* ================== */ | ||
1335 | |||
1336 | /* req_timeout | ||
1337 | * timeout routine for control output request | ||
1338 | * argument: | ||
1339 | * B channel control structure | ||
1340 | */ | ||
1341 | static void req_timeout(unsigned long data) | ||
1342 | { | ||
1343 | struct bc_state *bcs = (struct bc_state *) data; | ||
1344 | struct bas_cardstate *ucs; | ||
1345 | int pending; | ||
1346 | unsigned long flags; | ||
1347 | |||
1348 | IFNULLRET(bcs); | ||
1349 | IFNULLRET(bcs->cs); | ||
1350 | ucs = bcs->cs->hw.bas; | ||
1351 | IFNULLRET(ucs); | ||
1352 | |||
1353 | check_pending(ucs); | ||
1354 | |||
1355 | spin_lock_irqsave(&ucs->lock, flags); | ||
1356 | pending = ucs->pending; | ||
1357 | ucs->pending = 0; | ||
1358 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
1359 | |||
1360 | switch (pending) { | ||
1361 | case 0: /* no pending request */ | ||
1362 | dbg(DEBUG_USBREQ, "%s: no request pending", __func__); | ||
1363 | break; | ||
1364 | |||
1365 | case HD_OPEN_ATCHANNEL: | ||
1366 | err("timeout opening AT channel"); | ||
1367 | error_reset(bcs->cs); | ||
1368 | break; | ||
1369 | |||
1370 | case HD_OPEN_B2CHANNEL: | ||
1371 | case HD_OPEN_B1CHANNEL: | ||
1372 | err("timeout opening channel %d", bcs->channel + 1); | ||
1373 | error_hangup(bcs); | ||
1374 | break; | ||
1375 | |||
1376 | case HD_CLOSE_ATCHANNEL: | ||
1377 | err("timeout closing AT channel"); | ||
1378 | //wake_up_interruptible(cs->initwait); | ||
1379 | //FIXME need own wait queue? | ||
1380 | break; | ||
1381 | |||
1382 | case HD_CLOSE_B2CHANNEL: | ||
1383 | case HD_CLOSE_B1CHANNEL: | ||
1384 | err("timeout closing channel %d", bcs->channel + 1); | ||
1385 | break; | ||
1386 | |||
1387 | default: | ||
1388 | warn("request 0x%02x timed out, clearing", pending); | ||
1389 | } | ||
1390 | } | ||
1391 | |||
1392 | /* write_ctrl_callback | ||
1393 | * USB completion handler for control pipe output | ||
1394 | * called by the USB subsystem in interrupt context | ||
1395 | * parameter: | ||
1396 | * urb USB request block of completed request | ||
1397 | * urb->context = hardware specific controller state structure | ||
1398 | */ | ||
1399 | static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) | ||
1400 | { | ||
1401 | struct bas_cardstate *ucs; | ||
1402 | unsigned long flags; | ||
1403 | |||
1404 | IFNULLRET(urb); | ||
1405 | IFNULLRET(urb->context); | ||
1406 | IFNULLRET(cardstate); | ||
1407 | |||
1408 | ucs = (struct bas_cardstate *) urb->context; | ||
1409 | spin_lock_irqsave(&ucs->lock, flags); | ||
1410 | if (urb->status && ucs->pending) { | ||
1411 | err("control request 0x%02x failed: %s", | ||
1412 | ucs->pending, get_usb_statmsg(urb->status)); | ||
1413 | del_timer(&ucs->timer_ctrl); | ||
1414 | ucs->pending = 0; | ||
1415 | } | ||
1416 | /* individual handling of specific request types */ | ||
1417 | switch (ucs->pending) { | ||
1418 | case HD_DEVICE_INIT_ACK: /* no reply expected */ | ||
1419 | ucs->pending = 0; | ||
1420 | break; | ||
1421 | } | ||
1422 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
1423 | } | ||
1424 | |||
1425 | /* req_submit | ||
1426 | * submit a control output request without message buffer to the Gigaset base | ||
1427 | * and optionally start a timeout | ||
1428 | * parameters: | ||
1429 | * bcs B channel control structure | ||
1430 | * req control request code (HD_*) | ||
1431 | * val control request parameter value (set to 0 if unused) | ||
1432 | * timeout timeout in seconds (0: no timeout) | ||
1433 | * return value: | ||
1434 | * 0 on success | ||
1435 | * -EINVAL if a NULL pointer is encountered somewhere | ||
1436 | * -EBUSY if another request is pending | ||
1437 | * any URB submission error code | ||
1438 | */ | ||
1439 | static int req_submit(struct bc_state *bcs, int req, int val, int timeout) | ||
1440 | { | ||
1441 | struct bas_cardstate *ucs; | ||
1442 | int ret; | ||
1443 | unsigned long flags; | ||
1444 | |||
1445 | IFNULLRETVAL(bcs, -EINVAL); | ||
1446 | IFNULLRETVAL(bcs->cs, -EINVAL); | ||
1447 | ucs = bcs->cs->hw.bas; | ||
1448 | IFNULLRETVAL(ucs, -EINVAL); | ||
1449 | IFNULLRETVAL(ucs->urb_ctrl, -EINVAL); | ||
1450 | |||
1451 | dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val); | ||
1452 | |||
1453 | spin_lock_irqsave(&ucs->lock, flags); | ||
1454 | if (ucs->pending) { | ||
1455 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
1456 | err("submission of request 0x%02x failed: request 0x%02x still pending", | ||
1457 | req, ucs->pending); | ||
1458 | return -EBUSY; | ||
1459 | } | ||
1460 | if (ucs->urb_ctrl->status == -EINPROGRESS) { | ||
1461 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
1462 | err("could not submit request 0x%02x: URB busy", req); | ||
1463 | return -EBUSY; | ||
1464 | } | ||
1465 | |||
1466 | ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ; | ||
1467 | ucs->dr_ctrl.bRequest = req; | ||
1468 | ucs->dr_ctrl.wValue = cpu_to_le16(val); | ||
1469 | ucs->dr_ctrl.wIndex = 0; | ||
1470 | ucs->dr_ctrl.wLength = 0; | ||
1471 | usb_fill_control_urb(ucs->urb_ctrl, ucs->udev, | ||
1472 | usb_sndctrlpipe(ucs->udev, 0), | ||
1473 | (unsigned char*) &ucs->dr_ctrl, NULL, 0, | ||
1474 | write_ctrl_callback, ucs); | ||
1475 | if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) { | ||
1476 | err("could not submit request 0x%02x: %s", | ||
1477 | req, get_usb_statmsg(ret)); | ||
1478 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
1479 | return ret; | ||
1480 | } | ||
1481 | ucs->pending = req; | ||
1482 | |||
1483 | if (timeout > 0) { | ||
1484 | dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); | ||
1485 | ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10; | ||
1486 | ucs->timer_ctrl.data = (unsigned long) bcs; | ||
1487 | ucs->timer_ctrl.function = req_timeout; | ||
1488 | add_timer(&ucs->timer_ctrl); | ||
1489 | } | ||
1490 | |||
1491 | spin_unlock_irqrestore(&ucs->lock, flags); | ||
1492 | return 0; | ||
1493 | } | ||
1494 | |||
1495 | /* gigaset_init_bchannel | ||
1496 | * called by common.c to connect a B channel | ||
1497 | * initialize isochronous I/O and tell the Gigaset base to open the channel | ||
1498 | * argument: | ||
1499 | * B channel control structure | ||
1500 | * return value: | ||
1501 | * 0 on success, error code < 0 on error | ||
1502 | */ | ||
1503 | static int gigaset_init_bchannel(struct bc_state *bcs) | ||
1504 | { | ||
1505 | int req, ret; | ||
1506 | |||
1507 | IFNULLRETVAL(bcs, -EINVAL); | ||
1508 | |||
1509 | if ((ret = starturbs(bcs)) < 0) { | ||
1510 | err("could not start isochronous I/O for channel %d", | ||
1511 | bcs->channel + 1); | ||
1512 | error_hangup(bcs); | ||
1513 | return ret; | ||
1514 | } | ||
1515 | |||
1516 | req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; | ||
1517 | if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { | ||
1518 | err("could not open channel %d: %s", | ||
1519 | bcs->channel + 1, get_usb_statmsg(ret)); | ||
1520 | stopurbs(bcs->hw.bas); | ||
1521 | error_hangup(bcs); | ||
1522 | } | ||
1523 | return ret; | ||
1524 | } | ||
1525 | |||
1526 | /* gigaset_close_bchannel | ||
1527 | * called by common.c to disconnect a B channel | ||
1528 | * tell the Gigaset base to close the channel | ||
1529 | * stopping isochronous I/O and LL notification will be done when the | ||
1530 | * acknowledgement for the close arrives | ||
1531 | * argument: | ||
1532 | * B channel control structure | ||
1533 | * return value: | ||
1534 | * 0 on success, error code < 0 on error | ||
1535 | */ | ||
1536 | static int gigaset_close_bchannel(struct bc_state *bcs) | ||
1537 | { | ||
1538 | int req, ret; | ||
1539 | |||
1540 | IFNULLRETVAL(bcs, -EINVAL); | ||
1541 | |||
1542 | if (!(atomic_read(&bcs->cs->hw.bas->basstate) & | ||
1543 | (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { | ||
1544 | /* channel not running: just signal common.c */ | ||
1545 | gigaset_bchannel_down(bcs); | ||
1546 | return 0; | ||
1547 | } | ||
1548 | |||
1549 | req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; | ||
1550 | if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) | ||
1551 | err("could not submit HD_CLOSE_BxCHANNEL request: %s", | ||
1552 | get_usb_statmsg(ret)); | ||
1553 | return ret; | ||
1554 | } | ||
1555 | |||
1556 | /* Device Operations */ | ||
1557 | /* ================= */ | ||
1558 | |||
1559 | /* complete_cb | ||
1560 | * unqueue first command buffer from queue, waking any sleepers | ||
1561 | * must be called with cs->cmdlock held | ||
1562 | * parameter: | ||
1563 | * cs controller state structure | ||
1564 | */ | ||
1565 | static void complete_cb(struct cardstate *cs) | ||
1566 | { | ||
1567 | struct cmdbuf_t *cb; | ||
1568 | |||
1569 | IFNULLRET(cs); | ||
1570 | cb = cs->cmdbuf; | ||
1571 | IFNULLRET(cb); | ||
1572 | |||
1573 | /* unqueue completed buffer */ | ||
1574 | cs->cmdbytes -= cs->curlen; | ||
1575 | dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, | ||
1576 | "write_command: sent %u bytes, %u left", | ||
1577 | cs->curlen, cs->cmdbytes); | ||
1578 | if ((cs->cmdbuf = cb->next) != NULL) { | ||
1579 | cs->cmdbuf->prev = NULL; | ||
1580 | cs->curlen = cs->cmdbuf->len; | ||
1581 | } else { | ||
1582 | cs->lastcmdbuf = NULL; | ||
1583 | cs->curlen = 0; | ||
1584 | } | ||
1585 | |||
1586 | if (cb->wake_tasklet) | ||
1587 | tasklet_schedule(cb->wake_tasklet); | ||
1588 | |||
1589 | kfree(cb); | ||
1590 | } | ||
1591 | |||
1592 | static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len); | ||
1593 | |||
1594 | /* write_command_callback | ||
1595 | * USB completion handler for AT command transmission | ||
1596 | * called by the USB subsystem in interrupt context | ||
1597 | * parameter: | ||
1598 | * urb USB request block of completed request | ||
1599 | * urb->context = controller state structure | ||
1600 | */ | ||
1601 | static void write_command_callback(struct urb *urb, struct pt_regs *regs) | ||
1602 | { | ||
1603 | struct cardstate *cs; | ||
1604 | unsigned long flags; | ||
1605 | struct bas_cardstate *ucs; | ||
1606 | |||
1607 | IFNULLRET(urb); | ||
1608 | cs = (struct cardstate *) urb->context; | ||
1609 | IFNULLRET(cs); | ||
1610 | ucs = cs->hw.bas; | ||
1611 | IFNULLRET(ucs); | ||
1612 | |||
1613 | /* check status */ | ||
1614 | switch (urb->status) { | ||
1615 | case 0: /* normal completion */ | ||
1616 | break; | ||
1617 | case -ENOENT: /* canceled */ | ||
1618 | case -ECONNRESET: /* canceled (async) */ | ||
1619 | case -EINPROGRESS: /* pending */ | ||
1620 | /* ignore silently */ | ||
1621 | dbg(DEBUG_USBREQ, | ||
1622 | "%s: %s", __func__, get_usb_statmsg(urb->status)); | ||
1623 | return; | ||
1624 | default: /* any failure */ | ||
1625 | if (++ucs->retry_cmd_out > BAS_RETRY) { | ||
1626 | warn("command write: %s, giving up after %d retries", | ||
1627 | get_usb_statmsg(urb->status), ucs->retry_cmd_out); | ||
1628 | break; | ||
1629 | } | ||
1630 | if (cs->cmdbuf == NULL) { | ||
1631 | warn("command write: %s, cannot retry - cmdbuf gone", | ||
1632 | get_usb_statmsg(urb->status)); | ||
1633 | break; | ||
1634 | } | ||
1635 | notice("command write: %s, retry %d", | ||
1636 | get_usb_statmsg(urb->status), ucs->retry_cmd_out); | ||
1637 | if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0) | ||
1638 | /* resubmitted - bypass regular exit block */ | ||
1639 | return; | ||
1640 | /* command send failed, assume base still waiting */ | ||
1641 | update_basstate(ucs, BS_ATREADY, 0); | ||
1642 | } | ||
1643 | |||
1644 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
1645 | if (cs->cmdbuf != NULL) | ||
1646 | complete_cb(cs); | ||
1647 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
1648 | } | ||
1649 | |||
1650 | /* atrdy_timeout | ||
1651 | * timeout routine for AT command transmission | ||
1652 | * argument: | ||
1653 | * controller state structure | ||
1654 | */ | ||
1655 | static void atrdy_timeout(unsigned long data) | ||
1656 | { | ||
1657 | struct cardstate *cs = (struct cardstate *) data; | ||
1658 | struct bas_cardstate *ucs; | ||
1659 | |||
1660 | IFNULLRET(cs); | ||
1661 | ucs = cs->hw.bas; | ||
1662 | IFNULLRET(ucs); | ||
1663 | |||
1664 | warn("timeout waiting for HD_READY_SEND_ATDATA"); | ||
1665 | |||
1666 | /* fake the missing signal - what else can I do? */ | ||
1667 | update_basstate(ucs, BS_ATREADY, BS_ATTIMER); | ||
1668 | start_cbsend(cs); | ||
1669 | } | ||
1670 | |||
1671 | /* atwrite_submit | ||
1672 | * submit an HD_WRITE_ATMESSAGE command URB | ||
1673 | * parameters: | ||
1674 | * cs controller state structure | ||
1675 | * buf buffer containing command to send | ||
1676 | * len length of command to send | ||
1677 | * return value: | ||
1678 | * 0 on success | ||
1679 | * -EFAULT if a NULL pointer is encountered somewhere | ||
1680 | * -EBUSY if another request is pending | ||
1681 | * any URB submission error code | ||
1682 | */ | ||
1683 | static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) | ||
1684 | { | ||
1685 | struct bas_cardstate *ucs; | ||
1686 | int ret; | ||
1687 | |||
1688 | IFNULLRETVAL(cs, -EFAULT); | ||
1689 | ucs = cs->hw.bas; | ||
1690 | IFNULLRETVAL(ucs, -EFAULT); | ||
1691 | IFNULLRETVAL(ucs->urb_cmd_out, -EFAULT); | ||
1692 | |||
1693 | dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); | ||
1694 | |||
1695 | if (ucs->urb_cmd_out->status == -EINPROGRESS) { | ||
1696 | err("could not submit HD_WRITE_ATMESSAGE: URB busy"); | ||
1697 | return -EBUSY; | ||
1698 | } | ||
1699 | |||
1700 | ucs->dr_cmd_out.bRequestType = OUT_VENDOR_REQ; | ||
1701 | ucs->dr_cmd_out.bRequest = HD_WRITE_ATMESSAGE; | ||
1702 | ucs->dr_cmd_out.wValue = 0; | ||
1703 | ucs->dr_cmd_out.wIndex = 0; | ||
1704 | ucs->dr_cmd_out.wLength = cpu_to_le16(len); | ||
1705 | usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev, | ||
1706 | usb_sndctrlpipe(ucs->udev, 0), | ||
1707 | (unsigned char*) &ucs->dr_cmd_out, buf, len, | ||
1708 | write_command_callback, cs); | ||
1709 | |||
1710 | if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) { | ||
1711 | err("could not submit HD_WRITE_ATMESSAGE: %s", | ||
1712 | get_usb_statmsg(ret)); | ||
1713 | return ret; | ||
1714 | } | ||
1715 | |||
1716 | /* submitted successfully */ | ||
1717 | update_basstate(ucs, 0, BS_ATREADY); | ||
1718 | |||
1719 | /* start timeout if necessary */ | ||
1720 | if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) { | ||
1721 | dbg(DEBUG_OUTPUT, | ||
1722 | "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT); | ||
1723 | ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10; | ||
1724 | ucs->timer_atrdy.data = (unsigned long) cs; | ||
1725 | ucs->timer_atrdy.function = atrdy_timeout; | ||
1726 | add_timer(&ucs->timer_atrdy); | ||
1727 | update_basstate(ucs, BS_ATTIMER, 0); | ||
1728 | } | ||
1729 | return 0; | ||
1730 | } | ||
1731 | |||
1732 | /* start_cbsend | ||
1733 | * start transmission of AT command queue if necessary | ||
1734 | * parameter: | ||
1735 | * cs controller state structure | ||
1736 | * return value: | ||
1737 | * 0 on success | ||
1738 | * error code < 0 on error | ||
1739 | */ | ||
1740 | static int start_cbsend(struct cardstate *cs) | ||
1741 | { | ||
1742 | struct cmdbuf_t *cb; | ||
1743 | struct bas_cardstate *ucs; | ||
1744 | unsigned long flags; | ||
1745 | int rc; | ||
1746 | int retval = 0; | ||
1747 | |||
1748 | IFNULLRETVAL(cs, -EFAULT); | ||
1749 | ucs = cs->hw.bas; | ||
1750 | IFNULLRETVAL(ucs, -EFAULT); | ||
1751 | |||
1752 | /* check if AT channel is open */ | ||
1753 | if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) { | ||
1754 | dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, "AT channel not open"); | ||
1755 | rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); | ||
1756 | if (rc < 0) { | ||
1757 | err("could not open AT channel"); | ||
1758 | /* flush command queue */ | ||
1759 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
1760 | while (cs->cmdbuf != NULL) | ||
1761 | complete_cb(cs); | ||
1762 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
1763 | } | ||
1764 | return rc; | ||
1765 | } | ||
1766 | |||
1767 | /* try to send first command in queue */ | ||
1768 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
1769 | |||
1770 | while ((cb = cs->cmdbuf) != NULL && | ||
1771 | atomic_read(&ucs->basstate) & BS_ATREADY) { | ||
1772 | ucs->retry_cmd_out = 0; | ||
1773 | rc = atwrite_submit(cs, cb->buf, cb->len); | ||
1774 | if (unlikely(rc)) { | ||
1775 | retval = rc; | ||
1776 | complete_cb(cs); | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
1781 | return retval; | ||
1782 | } | ||
1783 | |||
1784 | /* gigaset_write_cmd | ||
1785 | * This function is called by the device independent part of the driver | ||
1786 | * to transmit an AT command string to the Gigaset device. | ||
1787 | * It encapsulates the device specific method for transmission over the | ||
1788 | * direct USB connection to the base. | ||
1789 | * The command string is added to the queue of commands to send, and | ||
1790 | * USB transmission is started if necessary. | ||
1791 | * parameters: | ||
1792 | * cs controller state structure | ||
1793 | * buf command string to send | ||
1794 | * len number of bytes to send (max. IF_WRITEBUF) | ||
1795 | * wake_tasklet tasklet to run when transmission is completed (NULL if none) | ||
1796 | * return value: | ||
1797 | * number of bytes queued on success | ||
1798 | * error code < 0 on error | ||
1799 | */ | ||
1800 | static int gigaset_write_cmd(struct cardstate *cs, | ||
1801 | const unsigned char *buf, int len, | ||
1802 | struct tasklet_struct *wake_tasklet) | ||
1803 | { | ||
1804 | struct cmdbuf_t *cb; | ||
1805 | unsigned long flags; | ||
1806 | int status; | ||
1807 | |||
1808 | gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? | ||
1809 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | ||
1810 | "CMD Transmit", len, buf, 0); | ||
1811 | |||
1812 | if (!atomic_read(&cs->connected)) { | ||
1813 | err("%s: not connected", __func__); | ||
1814 | return -ENODEV; | ||
1815 | } | ||
1816 | |||
1817 | if (len <= 0) | ||
1818 | return 0; /* nothing to do */ | ||
1819 | |||
1820 | if (len > IF_WRITEBUF) | ||
1821 | len = IF_WRITEBUF; | ||
1822 | if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { | ||
1823 | err("%s: out of memory", __func__); | ||
1824 | return -ENOMEM; | ||
1825 | } | ||
1826 | |||
1827 | memcpy(cb->buf, buf, len); | ||
1828 | cb->len = len; | ||
1829 | cb->offset = 0; | ||
1830 | cb->next = NULL; | ||
1831 | cb->wake_tasklet = wake_tasklet; | ||
1832 | |||
1833 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
1834 | cb->prev = cs->lastcmdbuf; | ||
1835 | if (cs->lastcmdbuf) | ||
1836 | cs->lastcmdbuf->next = cb; | ||
1837 | else { | ||
1838 | cs->cmdbuf = cb; | ||
1839 | cs->curlen = len; | ||
1840 | } | ||
1841 | cs->cmdbytes += len; | ||
1842 | cs->lastcmdbuf = cb; | ||
1843 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
1844 | |||
1845 | status = start_cbsend(cs); | ||
1846 | |||
1847 | return status < 0 ? status : len; | ||
1848 | } | ||
1849 | |||
1850 | /* gigaset_write_room | ||
1851 | * tty_driver.write_room interface routine | ||
1852 | * return number of characters the driver will accept to be written via gigaset_write_cmd | ||
1853 | * parameter: | ||
1854 | * controller state structure | ||
1855 | * return value: | ||
1856 | * number of characters | ||
1857 | */ | ||
1858 | static int gigaset_write_room(struct cardstate *cs) | ||
1859 | { | ||
1860 | return IF_WRITEBUF; | ||
1861 | } | ||
1862 | |||
1863 | /* gigaset_chars_in_buffer | ||
1864 | * tty_driver.chars_in_buffer interface routine | ||
1865 | * return number of characters waiting to be sent | ||
1866 | * parameter: | ||
1867 | * controller state structure | ||
1868 | * return value: | ||
1869 | * number of characters | ||
1870 | */ | ||
1871 | static int gigaset_chars_in_buffer(struct cardstate *cs) | ||
1872 | { | ||
1873 | unsigned long flags; | ||
1874 | unsigned bytes; | ||
1875 | |||
1876 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
1877 | bytes = cs->cmdbytes; | ||
1878 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
1879 | |||
1880 | return bytes; | ||
1881 | } | ||
1882 | |||
1883 | /* gigaset_brkchars | ||
1884 | * implementation of ioctl(GIGASET_BRKCHARS) | ||
1885 | * parameter: | ||
1886 | * controller state structure | ||
1887 | * return value: | ||
1888 | * -EINVAL (unimplemented function) | ||
1889 | */ | ||
1890 | static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) | ||
1891 | { | ||
1892 | return -EINVAL; | ||
1893 | } | ||
1894 | |||
1895 | |||
1896 | /* Device Initialization/Shutdown */ | ||
1897 | /* ============================== */ | ||
1898 | |||
1899 | /* Free hardware dependent part of the B channel structure | ||
1900 | * parameter: | ||
1901 | * bcs B channel structure | ||
1902 | * return value: | ||
1903 | * !=0 on success | ||
1904 | */ | ||
1905 | static int gigaset_freebcshw(struct bc_state *bcs) | ||
1906 | { | ||
1907 | if (!bcs->hw.bas) | ||
1908 | return 0; | ||
1909 | |||
1910 | if (bcs->hw.bas->isooutbuf) | ||
1911 | kfree(bcs->hw.bas->isooutbuf); | ||
1912 | kfree(bcs->hw.bas); | ||
1913 | bcs->hw.bas = NULL; | ||
1914 | return 1; | ||
1915 | } | ||
1916 | |||
1917 | /* Initialize hardware dependent part of the B channel structure | ||
1918 | * parameter: | ||
1919 | * bcs B channel structure | ||
1920 | * return value: | ||
1921 | * !=0 on success | ||
1922 | */ | ||
1923 | static int gigaset_initbcshw(struct bc_state *bcs) | ||
1924 | { | ||
1925 | int i; | ||
1926 | struct bas_bc_state *ubc; | ||
1927 | |||
1928 | bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL); | ||
1929 | if (!ubc) { | ||
1930 | err("could not allocate bas_bc_state"); | ||
1931 | return 0; | ||
1932 | } | ||
1933 | |||
1934 | atomic_set(&ubc->running, 0); | ||
1935 | atomic_set(&ubc->corrbytes, 0); | ||
1936 | spin_lock_init(&ubc->isooutlock); | ||
1937 | for (i = 0; i < BAS_OUTURBS; ++i) { | ||
1938 | ubc->isoouturbs[i].urb = NULL; | ||
1939 | ubc->isoouturbs[i].bcs = bcs; | ||
1940 | } | ||
1941 | ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL; | ||
1942 | ubc->numsub = 0; | ||
1943 | if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) { | ||
1944 | err("could not allocate isochronous output buffer"); | ||
1945 | kfree(ubc); | ||
1946 | bcs->hw.bas = NULL; | ||
1947 | return 0; | ||
1948 | } | ||
1949 | tasklet_init(&ubc->sent_tasklet, | ||
1950 | &write_iso_tasklet, (unsigned long) bcs); | ||
1951 | |||
1952 | spin_lock_init(&ubc->isoinlock); | ||
1953 | for (i = 0; i < BAS_INURBS; ++i) | ||
1954 | ubc->isoinurbs[i] = NULL; | ||
1955 | ubc->isoindone = NULL; | ||
1956 | ubc->loststatus = -EINPROGRESS; | ||
1957 | ubc->isoinlost = 0; | ||
1958 | ubc->seqlen = 0; | ||
1959 | ubc->inbyte = 0; | ||
1960 | ubc->inbits = 0; | ||
1961 | ubc->goodbytes = 0; | ||
1962 | ubc->alignerrs = 0; | ||
1963 | ubc->fcserrs = 0; | ||
1964 | ubc->frameerrs = 0; | ||
1965 | ubc->giants = 0; | ||
1966 | ubc->runts = 0; | ||
1967 | ubc->aborts = 0; | ||
1968 | ubc->shared0s = 0; | ||
1969 | ubc->stolen0s = 0; | ||
1970 | tasklet_init(&ubc->rcvd_tasklet, | ||
1971 | &read_iso_tasklet, (unsigned long) bcs); | ||
1972 | return 1; | ||
1973 | } | ||
1974 | |||
1975 | static void gigaset_reinitbcshw(struct bc_state *bcs) | ||
1976 | { | ||
1977 | struct bas_bc_state *ubc = bcs->hw.bas; | ||
1978 | |||
1979 | atomic_set(&bcs->hw.bas->running, 0); | ||
1980 | atomic_set(&bcs->hw.bas->corrbytes, 0); | ||
1981 | bcs->hw.bas->numsub = 0; | ||
1982 | spin_lock_init(&ubc->isooutlock); | ||
1983 | spin_lock_init(&ubc->isoinlock); | ||
1984 | ubc->loststatus = -EINPROGRESS; | ||
1985 | } | ||
1986 | |||
1987 | static void gigaset_freecshw(struct cardstate *cs) | ||
1988 | { | ||
1989 | struct bas_cardstate *ucs = cs->hw.bas; | ||
1990 | |||
1991 | del_timer(&ucs->timer_ctrl); | ||
1992 | del_timer(&ucs->timer_atrdy); | ||
1993 | del_timer(&ucs->timer_cmd_in); | ||
1994 | |||
1995 | kfree(cs->hw.bas); | ||
1996 | } | ||
1997 | |||
1998 | static int gigaset_initcshw(struct cardstate *cs) | ||
1999 | { | ||
2000 | struct bas_cardstate *ucs; | ||
2001 | |||
2002 | cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL); | ||
2003 | if (!ucs) | ||
2004 | return 0; | ||
2005 | |||
2006 | ucs->urb_cmd_in = NULL; | ||
2007 | ucs->urb_cmd_out = NULL; | ||
2008 | ucs->rcvbuf = NULL; | ||
2009 | ucs->rcvbuf_size = 0; | ||
2010 | |||
2011 | spin_lock_init(&ucs->lock); | ||
2012 | ucs->pending = 0; | ||
2013 | |||
2014 | atomic_set(&ucs->basstate, 0); | ||
2015 | init_timer(&ucs->timer_ctrl); | ||
2016 | init_timer(&ucs->timer_atrdy); | ||
2017 | init_timer(&ucs->timer_cmd_in); | ||
2018 | |||
2019 | return 1; | ||
2020 | } | ||
2021 | |||
2022 | /* freeurbs | ||
2023 | * unlink and deallocate all URBs unconditionally | ||
2024 | * caller must make sure that no commands are still in progress | ||
2025 | * parameter: | ||
2026 | * cs controller state structure | ||
2027 | */ | ||
2028 | static void freeurbs(struct cardstate *cs) | ||
2029 | { | ||
2030 | struct bas_cardstate *ucs; | ||
2031 | struct bas_bc_state *ubc; | ||
2032 | int i, j; | ||
2033 | |||
2034 | IFNULLRET(cs); | ||
2035 | ucs = cs->hw.bas; | ||
2036 | IFNULLRET(ucs); | ||
2037 | |||
2038 | for (j = 0; j < 2; ++j) { | ||
2039 | ubc = cs->bcs[j].hw.bas; | ||
2040 | IFNULLCONT(ubc); | ||
2041 | for (i = 0; i < BAS_OUTURBS; ++i) | ||
2042 | if (ubc->isoouturbs[i].urb) { | ||
2043 | usb_kill_urb(ubc->isoouturbs[i].urb); | ||
2044 | dbg(DEBUG_INIT, | ||
2045 | "%s: isoc output URB %d/%d unlinked", | ||
2046 | __func__, j, i); | ||
2047 | usb_free_urb(ubc->isoouturbs[i].urb); | ||
2048 | ubc->isoouturbs[i].urb = NULL; | ||
2049 | } | ||
2050 | for (i = 0; i < BAS_INURBS; ++i) | ||
2051 | if (ubc->isoinurbs[i]) { | ||
2052 | usb_kill_urb(ubc->isoinurbs[i]); | ||
2053 | dbg(DEBUG_INIT, | ||
2054 | "%s: isoc input URB %d/%d unlinked", | ||
2055 | __func__, j, i); | ||
2056 | usb_free_urb(ubc->isoinurbs[i]); | ||
2057 | ubc->isoinurbs[i] = NULL; | ||
2058 | } | ||
2059 | } | ||
2060 | if (ucs->urb_int_in) { | ||
2061 | usb_kill_urb(ucs->urb_int_in); | ||
2062 | dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", __func__); | ||
2063 | usb_free_urb(ucs->urb_int_in); | ||
2064 | ucs->urb_int_in = NULL; | ||
2065 | } | ||
2066 | if (ucs->urb_cmd_out) { | ||
2067 | usb_kill_urb(ucs->urb_cmd_out); | ||
2068 | dbg(DEBUG_INIT, "%s: command output URB unlinked", __func__); | ||
2069 | usb_free_urb(ucs->urb_cmd_out); | ||
2070 | ucs->urb_cmd_out = NULL; | ||
2071 | } | ||
2072 | if (ucs->urb_cmd_in) { | ||
2073 | usb_kill_urb(ucs->urb_cmd_in); | ||
2074 | dbg(DEBUG_INIT, "%s: command input URB unlinked", __func__); | ||
2075 | usb_free_urb(ucs->urb_cmd_in); | ||
2076 | ucs->urb_cmd_in = NULL; | ||
2077 | } | ||
2078 | if (ucs->urb_ctrl) { | ||
2079 | usb_kill_urb(ucs->urb_ctrl); | ||
2080 | dbg(DEBUG_INIT, "%s: control output URB unlinked", __func__); | ||
2081 | usb_free_urb(ucs->urb_ctrl); | ||
2082 | ucs->urb_ctrl = NULL; | ||
2083 | } | ||
2084 | } | ||
2085 | |||
2086 | /* gigaset_probe | ||
2087 | * This function is called when a new USB device is connected. | ||
2088 | * It checks whether the new device is handled by this driver. | ||
2089 | */ | ||
2090 | static int gigaset_probe(struct usb_interface *interface, | ||
2091 | const struct usb_device_id *id) | ||
2092 | { | ||
2093 | struct usb_host_interface *hostif; | ||
2094 | struct usb_device *udev = interface_to_usbdev(interface); | ||
2095 | struct cardstate *cs = NULL; | ||
2096 | struct bas_cardstate *ucs = NULL; | ||
2097 | struct bas_bc_state *ubc; | ||
2098 | struct usb_endpoint_descriptor *endpoint; | ||
2099 | int i, j; | ||
2100 | int ret; | ||
2101 | |||
2102 | IFNULLRETVAL(udev, -ENODEV); | ||
2103 | |||
2104 | dbg(DEBUG_ANY, | ||
2105 | "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", | ||
2106 | __func__, le16_to_cpu(udev->descriptor.idVendor), | ||
2107 | le16_to_cpu(udev->descriptor.idProduct)); | ||
2108 | |||
2109 | /* See if the device offered us matches what we can accept */ | ||
2110 | if ((le16_to_cpu(udev->descriptor.idVendor) != USB_GIGA_VENDOR_ID) || | ||
2111 | (le16_to_cpu(udev->descriptor.idProduct) != USB_GIGA_PRODUCT_ID && | ||
2112 | le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID && | ||
2113 | le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID && | ||
2114 | le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) { | ||
2115 | dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__); | ||
2116 | return -ENODEV; | ||
2117 | } | ||
2118 | |||
2119 | /* set required alternate setting */ | ||
2120 | hostif = interface->cur_altsetting; | ||
2121 | if (hostif->desc.bAlternateSetting != 3) { | ||
2122 | dbg(DEBUG_ANY, | ||
2123 | "%s: wrong alternate setting %d - trying to switch", | ||
2124 | __func__, hostif->desc.bAlternateSetting); | ||
2125 | if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) { | ||
2126 | warn("usb_set_interface failed, device %d interface %d altsetting %d", | ||
2127 | udev->devnum, hostif->desc.bInterfaceNumber, | ||
2128 | hostif->desc.bAlternateSetting); | ||
2129 | return -ENODEV; | ||
2130 | } | ||
2131 | hostif = interface->cur_altsetting; | ||
2132 | } | ||
2133 | |||
2134 | /* Reject application specific interfaces | ||
2135 | */ | ||
2136 | if (hostif->desc.bInterfaceClass != 255) { | ||
2137 | warn("%s: bInterfaceClass == %d", | ||
2138 | __func__, hostif->desc.bInterfaceClass); | ||
2139 | return -ENODEV; | ||
2140 | } | ||
2141 | |||
2142 | info("%s: Device matched (Vendor: 0x%x, Product: 0x%x)", | ||
2143 | __func__, le16_to_cpu(udev->descriptor.idVendor), | ||
2144 | le16_to_cpu(udev->descriptor.idProduct)); | ||
2145 | |||
2146 | cs = gigaset_getunassignedcs(driver); | ||
2147 | if (!cs) { | ||
2148 | err("%s: no free cardstate", __func__); | ||
2149 | return -ENODEV; | ||
2150 | } | ||
2151 | ucs = cs->hw.bas; | ||
2152 | ucs->udev = udev; | ||
2153 | ucs->interface = interface; | ||
2154 | |||
2155 | /* allocate URBs: | ||
2156 | * - one for the interrupt pipe | ||
2157 | * - three for the different uses of the default control pipe | ||
2158 | * - three for each isochronous pipe | ||
2159 | */ | ||
2160 | ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL); | ||
2161 | if (!ucs->urb_int_in) { | ||
2162 | err("No free urbs available"); | ||
2163 | goto error; | ||
2164 | } | ||
2165 | ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL); | ||
2166 | if (!ucs->urb_cmd_in) { | ||
2167 | err("No free urbs available"); | ||
2168 | goto error; | ||
2169 | } | ||
2170 | ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL); | ||
2171 | if (!ucs->urb_cmd_out) { | ||
2172 | err("No free urbs available"); | ||
2173 | goto error; | ||
2174 | } | ||
2175 | ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL); | ||
2176 | if (!ucs->urb_ctrl) { | ||
2177 | err("No free urbs available"); | ||
2178 | goto error; | ||
2179 | } | ||
2180 | |||
2181 | for (j = 0; j < 2; ++j) { | ||
2182 | ubc = cs->bcs[j].hw.bas; | ||
2183 | for (i = 0; i < BAS_OUTURBS; ++i) { | ||
2184 | ubc->isoouturbs[i].urb = | ||
2185 | usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); | ||
2186 | if (!ubc->isoouturbs[i].urb) { | ||
2187 | err("No free urbs available"); | ||
2188 | goto error; | ||
2189 | } | ||
2190 | } | ||
2191 | for (i = 0; i < BAS_INURBS; ++i) { | ||
2192 | ubc->isoinurbs[i] = | ||
2193 | usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); | ||
2194 | if (!ubc->isoinurbs[i]) { | ||
2195 | err("No free urbs available"); | ||
2196 | goto error; | ||
2197 | } | ||
2198 | } | ||
2199 | } | ||
2200 | |||
2201 | ucs->rcvbuf = NULL; | ||
2202 | ucs->rcvbuf_size = 0; | ||
2203 | |||
2204 | /* Fill the interrupt urb and send it to the core */ | ||
2205 | endpoint = &hostif->endpoint[0].desc; | ||
2206 | usb_fill_int_urb(ucs->urb_int_in, udev, | ||
2207 | usb_rcvintpipe(udev, | ||
2208 | (endpoint->bEndpointAddress) & 0x0f), | ||
2209 | ucs->int_in_buf, 3, read_int_callback, cs, | ||
2210 | endpoint->bInterval); | ||
2211 | ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL); | ||
2212 | if (ret) { | ||
2213 | err("could not submit interrupt URB: %s", get_usb_statmsg(ret)); | ||
2214 | goto error; | ||
2215 | } | ||
2216 | |||
2217 | /* tell the device that the driver is ready */ | ||
2218 | if ((ret = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) | ||
2219 | goto error; | ||
2220 | |||
2221 | /* tell common part that the device is ready */ | ||
2222 | if (startmode == SM_LOCKED) | ||
2223 | atomic_set(&cs->mstate, MS_LOCKED); | ||
2224 | if (!gigaset_start(cs)) | ||
2225 | goto error; | ||
2226 | |||
2227 | /* save address of controller structure */ | ||
2228 | usb_set_intfdata(interface, cs); | ||
2229 | |||
2230 | /* set up device sysfs */ | ||
2231 | gigaset_init_dev_sysfs(interface); | ||
2232 | return 0; | ||
2233 | |||
2234 | error: | ||
2235 | freeurbs(cs); | ||
2236 | gigaset_unassign(cs); | ||
2237 | return -ENODEV; | ||
2238 | } | ||
2239 | |||
2240 | /* gigaset_disconnect | ||
2241 | * This function is called when the Gigaset base is unplugged. | ||
2242 | */ | ||
2243 | static void gigaset_disconnect(struct usb_interface *interface) | ||
2244 | { | ||
2245 | struct cardstate *cs; | ||
2246 | struct bas_cardstate *ucs; | ||
2247 | |||
2248 | /* clear device sysfs */ | ||
2249 | gigaset_free_dev_sysfs(interface); | ||
2250 | |||
2251 | cs = usb_get_intfdata(interface); | ||
2252 | usb_set_intfdata(interface, NULL); | ||
2253 | |||
2254 | IFNULLRET(cs); | ||
2255 | ucs = cs->hw.bas; | ||
2256 | IFNULLRET(ucs); | ||
2257 | |||
2258 | info("disconnecting GigaSet base"); | ||
2259 | gigaset_stop(cs); | ||
2260 | freeurbs(cs); | ||
2261 | kfree(ucs->rcvbuf); | ||
2262 | ucs->rcvbuf = NULL; | ||
2263 | ucs->rcvbuf_size = 0; | ||
2264 | atomic_set(&ucs->basstate, 0); | ||
2265 | gigaset_unassign(cs); | ||
2266 | } | ||
2267 | |||
2268 | static struct gigaset_ops gigops = { | ||
2269 | gigaset_write_cmd, | ||
2270 | gigaset_write_room, | ||
2271 | gigaset_chars_in_buffer, | ||
2272 | gigaset_brkchars, | ||
2273 | gigaset_init_bchannel, | ||
2274 | gigaset_close_bchannel, | ||
2275 | gigaset_initbcshw, | ||
2276 | gigaset_freebcshw, | ||
2277 | gigaset_reinitbcshw, | ||
2278 | gigaset_initcshw, | ||
2279 | gigaset_freecshw, | ||
2280 | gigaset_set_modem_ctrl, | ||
2281 | gigaset_baud_rate, | ||
2282 | gigaset_set_line_ctrl, | ||
2283 | gigaset_isoc_send_skb, | ||
2284 | gigaset_isoc_input, | ||
2285 | }; | ||
2286 | |||
2287 | /* bas_gigaset_init | ||
2288 | * This function is called after the kernel module is loaded. | ||
2289 | */ | ||
2290 | static int __init bas_gigaset_init(void) | ||
2291 | { | ||
2292 | int result; | ||
2293 | |||
2294 | /* allocate memory for our driver state and intialize it */ | ||
2295 | if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, | ||
2296 | GIGASET_MODULENAME, GIGASET_DEVNAME, | ||
2297 | GIGASET_DEVFSNAME, &gigops, | ||
2298 | THIS_MODULE)) == NULL) | ||
2299 | goto error; | ||
2300 | |||
2301 | /* allocate memory for our device state and intialize it */ | ||
2302 | cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, GIGASET_MODULENAME); | ||
2303 | if (!cardstate) | ||
2304 | goto error; | ||
2305 | |||
2306 | /* register this driver with the USB subsystem */ | ||
2307 | result = usb_register(&gigaset_usb_driver); | ||
2308 | if (result < 0) { | ||
2309 | err("usb_register failed (error %d)", -result); | ||
2310 | goto error; | ||
2311 | } | ||
2312 | |||
2313 | info(DRIVER_AUTHOR); | ||
2314 | info(DRIVER_DESC); | ||
2315 | return 0; | ||
2316 | |||
2317 | error: if (cardstate) | ||
2318 | gigaset_freecs(cardstate); | ||
2319 | cardstate = NULL; | ||
2320 | if (driver) | ||
2321 | gigaset_freedriver(driver); | ||
2322 | driver = NULL; | ||
2323 | return -1; | ||
2324 | } | ||
2325 | |||
2326 | /* bas_gigaset_exit | ||
2327 | * This function is called before the kernel module is unloaded. | ||
2328 | */ | ||
2329 | static void __exit bas_gigaset_exit(void) | ||
2330 | { | ||
2331 | gigaset_blockdriver(driver); /* => probe will fail | ||
2332 | * => no gigaset_start any more | ||
2333 | */ | ||
2334 | |||
2335 | gigaset_shutdown(cardstate); | ||
2336 | /* from now on, no isdn callback should be possible */ | ||
2337 | |||
2338 | if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) { | ||
2339 | dbg(DEBUG_ANY, "closing AT channel"); | ||
2340 | if (req_submit(cardstate->bcs, | ||
2341 | HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) { | ||
2342 | /* successfully submitted - wait for completion */ | ||
2343 | //wait_event_interruptible(cs->initwait, !cs->hw.bas->pending); | ||
2344 | //FIXME need own wait queue? wakeup? | ||
2345 | } | ||
2346 | } | ||
2347 | |||
2348 | /* deregister this driver with the USB subsystem */ | ||
2349 | usb_deregister(&gigaset_usb_driver); | ||
2350 | /* this will call the disconnect-callback */ | ||
2351 | /* from now on, no disconnect/probe callback should be running */ | ||
2352 | |||
2353 | gigaset_freecs(cardstate); | ||
2354 | cardstate = NULL; | ||
2355 | gigaset_freedriver(driver); | ||
2356 | driver = NULL; | ||
2357 | } | ||
2358 | |||
2359 | |||
2360 | module_init(bas_gigaset_init); | ||
2361 | module_exit(bas_gigaset_exit); | ||
2362 | |||
2363 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
2364 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
2365 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c new file mode 100644 index 000000000000..64371995c1a9 --- /dev/null +++ b/drivers/isdn/gigaset/common.c | |||
@@ -0,0 +1,1203 @@ | |||
1 | /* | ||
2 | * Stuff used by all variants of the driver | ||
3 | * | ||
4 | * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>, | ||
5 | * Hansjoerg Lipp <hjlipp@web.de>, | ||
6 | * Tilman Schmidt <tilman@imap.cc>. | ||
7 | * | ||
8 | * ===================================================================== | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of | ||
12 | * the License, or (at your option) any later version. | ||
13 | * ===================================================================== | ||
14 | * ToDo: ... | ||
15 | * ===================================================================== | ||
16 | * Version: $Id: common.c,v 1.104.4.22 2006/02/04 18:28:16 hjlipp Exp $ | ||
17 | * ===================================================================== | ||
18 | */ | ||
19 | |||
20 | #include "gigaset.h" | ||
21 | #include <linux/ctype.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | |||
25 | /* Version Information */ | ||
26 | #define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers <Eilers.Stefan@epost.de>" | ||
27 | #define DRIVER_DESC "Driver for Gigaset 307x" | ||
28 | |||
29 | /* Module parameters */ | ||
30 | int gigaset_debuglevel = DEBUG_DEFAULT; | ||
31 | EXPORT_SYMBOL_GPL(gigaset_debuglevel); | ||
32 | module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR); | ||
33 | MODULE_PARM_DESC(debug, "debug level"); | ||
34 | |||
35 | /*====================================================================== | ||
36 | Prototypes of internal functions | ||
37 | */ | ||
38 | |||
39 | //static void gigaset_process_response(int resp_code, int parameter, | ||
40 | // struct at_state_t *at_state, | ||
41 | // unsigned char ** pstring); | ||
42 | static struct cardstate *alloc_cs(struct gigaset_driver *drv); | ||
43 | static void free_cs(struct cardstate *cs); | ||
44 | static void make_valid(struct cardstate *cs, unsigned mask); | ||
45 | static void make_invalid(struct cardstate *cs, unsigned mask); | ||
46 | |||
47 | #define VALID_MINOR 0x01 | ||
48 | #define VALID_ID 0x02 | ||
49 | #define ASSIGNED 0x04 | ||
50 | |||
51 | /* bitwise byte inversion table */ | ||
52 | __u8 gigaset_invtab[256] = { | ||
53 | 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, | ||
54 | 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, | ||
55 | 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, | ||
56 | 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, | ||
57 | 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, | ||
58 | 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, | ||
59 | 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, | ||
60 | 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, | ||
61 | 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, | ||
62 | 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, | ||
63 | 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, | ||
64 | 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, | ||
65 | 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, | ||
66 | 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, | ||
67 | 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, | ||
68 | 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, | ||
69 | 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, | ||
70 | 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, | ||
71 | 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, | ||
72 | 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, | ||
73 | 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, | ||
74 | 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, | ||
75 | 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, | ||
76 | 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, | ||
77 | 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, | ||
78 | 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, | ||
79 | 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, | ||
80 | 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, | ||
81 | 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, | ||
82 | 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, | ||
83 | 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, | ||
84 | 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff | ||
85 | }; | ||
86 | EXPORT_SYMBOL_GPL(gigaset_invtab); | ||
87 | |||
88 | void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, | ||
89 | size_t len, const unsigned char *buf, int from_user) | ||
90 | { | ||
91 | unsigned char outbuf[80]; | ||
92 | unsigned char inbuf[80 - 1]; | ||
93 | size_t numin; | ||
94 | const unsigned char *in; | ||
95 | size_t space = sizeof outbuf - 1; | ||
96 | unsigned char *out = outbuf; | ||
97 | |||
98 | if (!from_user) { | ||
99 | in = buf; | ||
100 | numin = len; | ||
101 | } else { | ||
102 | numin = len < sizeof inbuf ? len : sizeof inbuf; | ||
103 | in = inbuf; | ||
104 | if (copy_from_user(inbuf, (const unsigned char __user *) buf, numin)) { | ||
105 | strncpy(inbuf, "<FAULT>", sizeof inbuf); | ||
106 | numin = sizeof "<FAULT>" - 1; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | for (; numin && space; --numin, ++in) { | ||
111 | --space; | ||
112 | if (*in >= 32) | ||
113 | *out++ = *in; | ||
114 | else { | ||
115 | *out++ = '^'; | ||
116 | if (space) { | ||
117 | *out++ = '@' + *in; | ||
118 | --space; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | *out = 0; | ||
123 | |||
124 | dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf); | ||
125 | } | ||
126 | EXPORT_SYMBOL_GPL(gigaset_dbg_buffer); | ||
127 | |||
128 | static int setflags(struct cardstate *cs, unsigned flags, unsigned delay) | ||
129 | { | ||
130 | int r; | ||
131 | |||
132 | r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags); | ||
133 | cs->control_state = flags; | ||
134 | if (r < 0) | ||
135 | return r; | ||
136 | |||
137 | if (delay) { | ||
138 | set_current_state(TASK_INTERRUPTIBLE); | ||
139 | schedule_timeout(delay * HZ / 1000); | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | int gigaset_enterconfigmode(struct cardstate *cs) | ||
146 | { | ||
147 | int i, r; | ||
148 | |||
149 | if (!atomic_read(&cs->connected)) { | ||
150 | err("not connected!"); | ||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | cs->control_state = TIOCM_RTS; //FIXME | ||
155 | |||
156 | r = setflags(cs, TIOCM_DTR, 200); | ||
157 | if (r < 0) | ||
158 | goto error; | ||
159 | r = setflags(cs, 0, 200); | ||
160 | if (r < 0) | ||
161 | goto error; | ||
162 | for (i = 0; i < 5; ++i) { | ||
163 | r = setflags(cs, TIOCM_RTS, 100); | ||
164 | if (r < 0) | ||
165 | goto error; | ||
166 | r = setflags(cs, 0, 100); | ||
167 | if (r < 0) | ||
168 | goto error; | ||
169 | } | ||
170 | r = setflags(cs, TIOCM_RTS|TIOCM_DTR, 800); | ||
171 | if (r < 0) | ||
172 | goto error; | ||
173 | |||
174 | return 0; | ||
175 | |||
176 | error: | ||
177 | err("error %d on setuartbits!\n", -r); | ||
178 | cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value? | ||
179 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR); | ||
180 | |||
181 | return -1; //r | ||
182 | } | ||
183 | |||
184 | static int test_timeout(struct at_state_t *at_state) | ||
185 | { | ||
186 | if (!at_state->timer_expires) | ||
187 | return 0; | ||
188 | |||
189 | if (--at_state->timer_expires) { | ||
190 | dbg(DEBUG_MCMD, "decreased timer of %p to %lu", | ||
191 | at_state, at_state->timer_expires); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL, | ||
196 | atomic_read(&at_state->timer_index), NULL)) { | ||
197 | //FIXME what should we do? | ||
198 | } | ||
199 | |||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | static void timer_tick(unsigned long data) | ||
204 | { | ||
205 | struct cardstate *cs = (struct cardstate *) data; | ||
206 | unsigned long flags; | ||
207 | unsigned channel; | ||
208 | struct at_state_t *at_state; | ||
209 | int timeout = 0; | ||
210 | |||
211 | spin_lock_irqsave(&cs->lock, flags); | ||
212 | |||
213 | for (channel = 0; channel < cs->channels; ++channel) | ||
214 | if (test_timeout(&cs->bcs[channel].at_state)) | ||
215 | timeout = 1; | ||
216 | |||
217 | if (test_timeout(&cs->at_state)) | ||
218 | timeout = 1; | ||
219 | |||
220 | list_for_each_entry(at_state, &cs->temp_at_states, list) | ||
221 | if (test_timeout(at_state)) | ||
222 | timeout = 1; | ||
223 | |||
224 | if (atomic_read(&cs->running)) { | ||
225 | mod_timer(&cs->timer, jiffies + GIG_TICK); | ||
226 | if (timeout) { | ||
227 | dbg(DEBUG_CMD, "scheduling timeout"); | ||
228 | tasklet_schedule(&cs->event_tasklet); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | spin_unlock_irqrestore(&cs->lock, flags); | ||
233 | } | ||
234 | |||
235 | int gigaset_get_channel(struct bc_state *bcs) | ||
236 | { | ||
237 | unsigned long flags; | ||
238 | |||
239 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
240 | if (bcs->use_count) { | ||
241 | dbg(DEBUG_ANY, "could not allocate channel %d", bcs->channel); | ||
242 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
243 | return 0; | ||
244 | } | ||
245 | ++bcs->use_count; | ||
246 | bcs->busy = 1; | ||
247 | dbg(DEBUG_ANY, "allocated channel %d", bcs->channel); | ||
248 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
249 | return 1; | ||
250 | } | ||
251 | |||
252 | void gigaset_free_channel(struct bc_state *bcs) | ||
253 | { | ||
254 | unsigned long flags; | ||
255 | |||
256 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
257 | if (!bcs->busy) { | ||
258 | dbg(DEBUG_ANY, "could not free channel %d", bcs->channel); | ||
259 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
260 | return; | ||
261 | } | ||
262 | --bcs->use_count; | ||
263 | bcs->busy = 0; | ||
264 | dbg(DEBUG_ANY, "freed channel %d", bcs->channel); | ||
265 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
266 | } | ||
267 | |||
268 | int gigaset_get_channels(struct cardstate *cs) | ||
269 | { | ||
270 | unsigned long flags; | ||
271 | int i; | ||
272 | |||
273 | spin_lock_irqsave(&cs->lock, flags); | ||
274 | for (i = 0; i < cs->channels; ++i) | ||
275 | if (cs->bcs[i].use_count) { | ||
276 | spin_unlock_irqrestore(&cs->lock, flags); | ||
277 | dbg(DEBUG_ANY, "could not allocated all channels"); | ||
278 | return 0; | ||
279 | } | ||
280 | for (i = 0; i < cs->channels; ++i) | ||
281 | ++cs->bcs[i].use_count; | ||
282 | spin_unlock_irqrestore(&cs->lock, flags); | ||
283 | |||
284 | dbg(DEBUG_ANY, "allocated all channels"); | ||
285 | |||
286 | return 1; | ||
287 | } | ||
288 | |||
289 | void gigaset_free_channels(struct cardstate *cs) | ||
290 | { | ||
291 | unsigned long flags; | ||
292 | int i; | ||
293 | |||
294 | dbg(DEBUG_ANY, "unblocking all channels"); | ||
295 | spin_lock_irqsave(&cs->lock, flags); | ||
296 | for (i = 0; i < cs->channels; ++i) | ||
297 | --cs->bcs[i].use_count; | ||
298 | spin_unlock_irqrestore(&cs->lock, flags); | ||
299 | } | ||
300 | |||
301 | void gigaset_block_channels(struct cardstate *cs) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | int i; | ||
305 | |||
306 | dbg(DEBUG_ANY, "blocking all channels"); | ||
307 | spin_lock_irqsave(&cs->lock, flags); | ||
308 | for (i = 0; i < cs->channels; ++i) | ||
309 | ++cs->bcs[i].use_count; | ||
310 | spin_unlock_irqrestore(&cs->lock, flags); | ||
311 | } | ||
312 | |||
313 | static void clear_events(struct cardstate *cs) | ||
314 | { | ||
315 | struct event_t *ev; | ||
316 | unsigned head, tail; | ||
317 | |||
318 | /* no locking needed (no reader/writer allowed) */ | ||
319 | |||
320 | head = atomic_read(&cs->ev_head); | ||
321 | tail = atomic_read(&cs->ev_tail); | ||
322 | |||
323 | while (tail != head) { | ||
324 | ev = cs->events + head; | ||
325 | kfree(ev->ptr); | ||
326 | |||
327 | head = (head + 1) % MAX_EVENTS; | ||
328 | } | ||
329 | |||
330 | atomic_set(&cs->ev_head, tail); | ||
331 | } | ||
332 | |||
333 | struct event_t *gigaset_add_event(struct cardstate *cs, | ||
334 | struct at_state_t *at_state, int type, | ||
335 | void *ptr, int parameter, void *arg) | ||
336 | { | ||
337 | unsigned long flags; | ||
338 | unsigned next, tail; | ||
339 | struct event_t *event = NULL; | ||
340 | |||
341 | spin_lock_irqsave(&cs->ev_lock, flags); | ||
342 | |||
343 | tail = atomic_read(&cs->ev_tail); | ||
344 | next = (tail + 1) % MAX_EVENTS; | ||
345 | if (unlikely(next == atomic_read(&cs->ev_head))) | ||
346 | err("event queue full"); | ||
347 | else { | ||
348 | event = cs->events + tail; | ||
349 | event->type = type; | ||
350 | event->at_state = at_state; | ||
351 | event->cid = -1; | ||
352 | event->ptr = ptr; | ||
353 | event->arg = arg; | ||
354 | event->parameter = parameter; | ||
355 | atomic_set(&cs->ev_tail, next); | ||
356 | } | ||
357 | |||
358 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
359 | |||
360 | return event; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(gigaset_add_event); | ||
363 | |||
364 | static void free_strings(struct at_state_t *at_state) | ||
365 | { | ||
366 | int i; | ||
367 | |||
368 | for (i = 0; i < STR_NUM; ++i) { | ||
369 | kfree(at_state->str_var[i]); | ||
370 | at_state->str_var[i] = NULL; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | static void clear_at_state(struct at_state_t *at_state) | ||
375 | { | ||
376 | free_strings(at_state); | ||
377 | } | ||
378 | |||
379 | static void dealloc_at_states(struct cardstate *cs) | ||
380 | { | ||
381 | struct at_state_t *cur, *next; | ||
382 | |||
383 | list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) { | ||
384 | list_del(&cur->list); | ||
385 | free_strings(cur); | ||
386 | kfree(cur); | ||
387 | } | ||
388 | } | ||
389 | |||
390 | static void gigaset_freebcs(struct bc_state *bcs) | ||
391 | { | ||
392 | int i; | ||
393 | |||
394 | dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel); | ||
395 | if (!bcs->cs->ops->freebcshw(bcs)) { | ||
396 | dbg(DEBUG_INIT, "failed"); | ||
397 | } | ||
398 | |||
399 | dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); | ||
400 | clear_at_state(&bcs->at_state); | ||
401 | dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); | ||
402 | |||
403 | if (bcs->skb) | ||
404 | dev_kfree_skb(bcs->skb); | ||
405 | for (i = 0; i < AT_NUM; ++i) { | ||
406 | kfree(bcs->commands[i]); | ||
407 | bcs->commands[i] = NULL; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | void gigaset_freecs(struct cardstate *cs) | ||
412 | { | ||
413 | int i; | ||
414 | unsigned long flags; | ||
415 | |||
416 | if (!cs) | ||
417 | return; | ||
418 | |||
419 | down(&cs->sem); | ||
420 | |||
421 | if (!cs->bcs) | ||
422 | goto f_cs; | ||
423 | if (!cs->inbuf) | ||
424 | goto f_bcs; | ||
425 | |||
426 | spin_lock_irqsave(&cs->lock, flags); | ||
427 | atomic_set(&cs->running, 0); | ||
428 | spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are not rescheduled below */ | ||
429 | |||
430 | tasklet_kill(&cs->event_tasklet); | ||
431 | del_timer_sync(&cs->timer); | ||
432 | |||
433 | switch (cs->cs_init) { | ||
434 | default: | ||
435 | gigaset_if_free(cs); | ||
436 | |||
437 | dbg(DEBUG_INIT, "clearing hw"); | ||
438 | cs->ops->freecshw(cs); | ||
439 | |||
440 | //FIXME cmdbuf | ||
441 | |||
442 | /* fall through */ | ||
443 | case 2: /* error in initcshw */ | ||
444 | /* Deregister from LL */ | ||
445 | make_invalid(cs, VALID_ID); | ||
446 | dbg(DEBUG_INIT, "clearing iif"); | ||
447 | gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD); | ||
448 | |||
449 | /* fall through */ | ||
450 | case 1: /* error when regestering to LL */ | ||
451 | dbg(DEBUG_INIT, "clearing at_state"); | ||
452 | clear_at_state(&cs->at_state); | ||
453 | dealloc_at_states(cs); | ||
454 | |||
455 | /* fall through */ | ||
456 | case 0: /* error in one call to initbcs */ | ||
457 | for (i = 0; i < cs->channels; ++i) { | ||
458 | dbg(DEBUG_INIT, "clearing bcs[%d]", i); | ||
459 | gigaset_freebcs(cs->bcs + i); | ||
460 | } | ||
461 | |||
462 | clear_events(cs); | ||
463 | dbg(DEBUG_INIT, "freeing inbuf"); | ||
464 | kfree(cs->inbuf); | ||
465 | } | ||
466 | f_bcs: dbg(DEBUG_INIT, "freeing bcs[]"); | ||
467 | kfree(cs->bcs); | ||
468 | f_cs: dbg(DEBUG_INIT, "freeing cs"); | ||
469 | up(&cs->sem); | ||
470 | free_cs(cs); | ||
471 | } | ||
472 | EXPORT_SYMBOL_GPL(gigaset_freecs); | ||
473 | |||
474 | void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, | ||
475 | struct cardstate *cs, int cid) | ||
476 | { | ||
477 | int i; | ||
478 | |||
479 | INIT_LIST_HEAD(&at_state->list); | ||
480 | at_state->waiting = 0; | ||
481 | at_state->getstring = 0; | ||
482 | at_state->pending_commands = 0; | ||
483 | at_state->timer_expires = 0; | ||
484 | at_state->timer_active = 0; | ||
485 | atomic_set(&at_state->timer_index, 0); | ||
486 | atomic_set(&at_state->seq_index, 0); | ||
487 | at_state->ConState = 0; | ||
488 | for (i = 0; i < STR_NUM; ++i) | ||
489 | at_state->str_var[i] = NULL; | ||
490 | at_state->int_var[VAR_ZDLE] = 0; | ||
491 | at_state->int_var[VAR_ZCTP] = -1; | ||
492 | at_state->int_var[VAR_ZSAU] = ZSAU_NULL; | ||
493 | at_state->cs = cs; | ||
494 | at_state->bcs = bcs; | ||
495 | at_state->cid = cid; | ||
496 | if (!cid) | ||
497 | at_state->replystruct = cs->tabnocid; | ||
498 | else | ||
499 | at_state->replystruct = cs->tabcid; | ||
500 | } | ||
501 | |||
502 | |||
503 | static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs, | ||
504 | struct cardstate *cs, int inputstate) | ||
505 | /* inbuf->read must be allocated before! */ | ||
506 | { | ||
507 | atomic_set(&inbuf->head, 0); | ||
508 | atomic_set(&inbuf->tail, 0); | ||
509 | inbuf->cs = cs; | ||
510 | inbuf->bcs = bcs; /*base driver: NULL*/ | ||
511 | inbuf->rcvbuf = NULL; //FIXME | ||
512 | inbuf->inputstate = inputstate; | ||
513 | } | ||
514 | |||
515 | /* Initialize the b-channel structure */ | ||
516 | static struct bc_state *gigaset_initbcs(struct bc_state *bcs, | ||
517 | struct cardstate *cs, int channel) | ||
518 | { | ||
519 | int i; | ||
520 | |||
521 | bcs->tx_skb = NULL; //FIXME -> hw part | ||
522 | |||
523 | skb_queue_head_init(&bcs->squeue); | ||
524 | |||
525 | bcs->corrupted = 0; | ||
526 | bcs->trans_down = 0; | ||
527 | bcs->trans_up = 0; | ||
528 | |||
529 | dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel); | ||
530 | gigaset_at_init(&bcs->at_state, bcs, cs, -1); | ||
531 | |||
532 | bcs->rcvbytes = 0; | ||
533 | |||
534 | #ifdef CONFIG_GIGASET_DEBUG | ||
535 | bcs->emptycount = 0; | ||
536 | #endif | ||
537 | |||
538 | dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); | ||
539 | bcs->fcs = PPP_INITFCS; | ||
540 | bcs->inputstate = 0; | ||
541 | if (cs->ignoreframes) { | ||
542 | bcs->inputstate |= INS_skip_frame; | ||
543 | bcs->skb = NULL; | ||
544 | } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) | ||
545 | skb_reserve(bcs->skb, HW_HDR_LEN); | ||
546 | else { | ||
547 | warn("could not allocate skb"); | ||
548 | bcs->inputstate |= INS_skip_frame; | ||
549 | } | ||
550 | |||
551 | bcs->channel = channel; | ||
552 | bcs->cs = cs; | ||
553 | |||
554 | bcs->chstate = 0; | ||
555 | bcs->use_count = 1; | ||
556 | bcs->busy = 0; | ||
557 | bcs->ignore = cs->ignoreframes; | ||
558 | |||
559 | for (i = 0; i < AT_NUM; ++i) | ||
560 | bcs->commands[i] = NULL; | ||
561 | |||
562 | dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); | ||
563 | if (cs->ops->initbcshw(bcs)) | ||
564 | return bcs; | ||
565 | |||
566 | //error: | ||
567 | dbg(DEBUG_INIT, " failed"); | ||
568 | |||
569 | dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); | ||
570 | if (bcs->skb) | ||
571 | dev_kfree_skb(bcs->skb); | ||
572 | |||
573 | return NULL; | ||
574 | } | ||
575 | |||
576 | /* gigaset_initcs | ||
577 | * Allocate and initialize cardstate structure for Gigaset driver | ||
578 | * Calls hardware dependent gigaset_initcshw() function | ||
579 | * Calls B channel initialization function gigaset_initbcs() for each B channel | ||
580 | * parameters: | ||
581 | * drv hardware driver the device belongs to | ||
582 | * channels number of B channels supported by device | ||
583 | * onechannel !=0: B channel data and AT commands share one communication channel | ||
584 | * ==0: B channels have separate communication channels | ||
585 | * ignoreframes number of frames to ignore after setting up B channel | ||
586 | * cidmode !=0: start in CallID mode | ||
587 | * modulename name of driver module (used for I4L registration) | ||
588 | * return value: | ||
589 | * pointer to cardstate structure | ||
590 | */ | ||
591 | struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | ||
592 | int onechannel, int ignoreframes, | ||
593 | int cidmode, const char *modulename) | ||
594 | { | ||
595 | struct cardstate *cs = NULL; | ||
596 | int i; | ||
597 | |||
598 | dbg(DEBUG_INIT, "allocating cs"); | ||
599 | cs = alloc_cs(drv); | ||
600 | if (!cs) | ||
601 | goto error; | ||
602 | dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); | ||
603 | cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); | ||
604 | if (!cs->bcs) | ||
605 | goto error; | ||
606 | dbg(DEBUG_INIT, "allocating inbuf"); | ||
607 | cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); | ||
608 | if (!cs->inbuf) | ||
609 | goto error; | ||
610 | |||
611 | cs->cs_init = 0; | ||
612 | cs->channels = channels; | ||
613 | cs->onechannel = onechannel; | ||
614 | cs->ignoreframes = ignoreframes; | ||
615 | INIT_LIST_HEAD(&cs->temp_at_states); | ||
616 | atomic_set(&cs->running, 0); | ||
617 | init_timer(&cs->timer); /* clear next & prev */ | ||
618 | spin_lock_init(&cs->ev_lock); | ||
619 | atomic_set(&cs->ev_tail, 0); | ||
620 | atomic_set(&cs->ev_head, 0); | ||
621 | init_MUTEX_LOCKED(&cs->sem); | ||
622 | tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs); | ||
623 | atomic_set(&cs->commands_pending, 0); | ||
624 | cs->cur_at_seq = 0; | ||
625 | cs->gotfwver = -1; | ||
626 | cs->open_count = 0; | ||
627 | cs->tty = NULL; | ||
628 | atomic_set(&cs->cidmode, cidmode != 0); | ||
629 | |||
630 | //if(onechannel) { //FIXME | ||
631 | cs->tabnocid = gigaset_tab_nocid_m10x; | ||
632 | cs->tabcid = gigaset_tab_cid_m10x; | ||
633 | //} else { | ||
634 | // cs->tabnocid = gigaset_tab_nocid; | ||
635 | // cs->tabcid = gigaset_tab_cid; | ||
636 | //} | ||
637 | |||
638 | init_waitqueue_head(&cs->waitqueue); | ||
639 | cs->waiting = 0; | ||
640 | |||
641 | atomic_set(&cs->mode, M_UNKNOWN); | ||
642 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | ||
643 | |||
644 | for (i = 0; i < channels; ++i) { | ||
645 | dbg(DEBUG_INIT, "setting up bcs[%d].read", i); | ||
646 | if (!gigaset_initbcs(cs->bcs + i, cs, i)) | ||
647 | goto error; | ||
648 | } | ||
649 | |||
650 | ++cs->cs_init; | ||
651 | |||
652 | dbg(DEBUG_INIT, "setting up at_state"); | ||
653 | spin_lock_init(&cs->lock); | ||
654 | gigaset_at_init(&cs->at_state, NULL, cs, 0); | ||
655 | cs->dle = 0; | ||
656 | cs->cbytes = 0; | ||
657 | |||
658 | dbg(DEBUG_INIT, "setting up inbuf"); | ||
659 | if (onechannel) { //FIXME distinction necessary? | ||
660 | gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command); | ||
661 | } else | ||
662 | gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command); | ||
663 | |||
664 | atomic_set(&cs->connected, 0); | ||
665 | |||
666 | dbg(DEBUG_INIT, "setting up cmdbuf"); | ||
667 | cs->cmdbuf = cs->lastcmdbuf = NULL; | ||
668 | spin_lock_init(&cs->cmdlock); | ||
669 | cs->curlen = 0; | ||
670 | cs->cmdbytes = 0; | ||
671 | |||
672 | /* | ||
673 | * Tell the ISDN4Linux subsystem (the LL) that | ||
674 | * a driver for a USB-Device is available ! | ||
675 | * If this is done, "isdnctrl" is able to bind a device for this driver even | ||
676 | * if no physical usb-device is currently connected. | ||
677 | * But this device will just be accessable if a physical USB device is connected | ||
678 | * (via "gigaset_probe") . | ||
679 | */ | ||
680 | dbg(DEBUG_INIT, "setting up iif"); | ||
681 | if (!gigaset_register_to_LL(cs, modulename)) { | ||
682 | err("register_isdn=>error"); | ||
683 | goto error; | ||
684 | } | ||
685 | |||
686 | make_valid(cs, VALID_ID); | ||
687 | ++cs->cs_init; | ||
688 | dbg(DEBUG_INIT, "setting up hw"); | ||
689 | if (!cs->ops->initcshw(cs)) | ||
690 | goto error; | ||
691 | |||
692 | ++cs->cs_init; | ||
693 | |||
694 | gigaset_if_init(cs); | ||
695 | |||
696 | atomic_set(&cs->running, 1); | ||
697 | cs->timer.data = (unsigned long) cs; | ||
698 | cs->timer.function = timer_tick; | ||
699 | cs->timer.expires = jiffies + GIG_TICK; | ||
700 | /* FIXME: can jiffies increase too much until the timer is added? | ||
701 | * Same problem(?) with mod_timer() in timer_tick(). */ | ||
702 | add_timer(&cs->timer); | ||
703 | |||
704 | dbg(DEBUG_INIT, "cs initialized!"); | ||
705 | up(&cs->sem); | ||
706 | return cs; | ||
707 | |||
708 | error: if (cs) | ||
709 | up(&cs->sem); | ||
710 | dbg(DEBUG_INIT, "failed"); | ||
711 | gigaset_freecs(cs); | ||
712 | return NULL; | ||
713 | } | ||
714 | EXPORT_SYMBOL_GPL(gigaset_initcs); | ||
715 | |||
716 | /* ReInitialize the b-channel structure */ /* e.g. called on hangup, disconnect */ | ||
717 | void gigaset_bcs_reinit(struct bc_state *bcs) | ||
718 | { | ||
719 | struct sk_buff *skb; | ||
720 | struct cardstate *cs = bcs->cs; | ||
721 | unsigned long flags; | ||
722 | |||
723 | while ((skb = skb_dequeue(&bcs->squeue)) != NULL) | ||
724 | dev_kfree_skb(skb); | ||
725 | |||
726 | spin_lock_irqsave(&cs->lock, flags); //FIXME | ||
727 | clear_at_state(&bcs->at_state); | ||
728 | bcs->at_state.ConState = 0; | ||
729 | bcs->at_state.timer_active = 0; | ||
730 | bcs->at_state.timer_expires = 0; | ||
731 | bcs->at_state.cid = -1; /* No CID defined */ | ||
732 | spin_unlock_irqrestore(&cs->lock, flags); | ||
733 | |||
734 | bcs->inputstate = 0; | ||
735 | |||
736 | #ifdef CONFIG_GIGASET_DEBUG | ||
737 | bcs->emptycount = 0; | ||
738 | #endif | ||
739 | |||
740 | bcs->fcs = PPP_INITFCS; | ||
741 | bcs->chstate = 0; | ||
742 | |||
743 | bcs->ignore = cs->ignoreframes; | ||
744 | if (bcs->ignore) | ||
745 | bcs->inputstate |= INS_skip_frame; | ||
746 | |||
747 | |||
748 | cs->ops->reinitbcshw(bcs); | ||
749 | } | ||
750 | |||
751 | static void cleanup_cs(struct cardstate *cs) | ||
752 | { | ||
753 | struct cmdbuf_t *cb, *tcb; | ||
754 | int i; | ||
755 | unsigned long flags; | ||
756 | |||
757 | spin_lock_irqsave(&cs->lock, flags); | ||
758 | |||
759 | atomic_set(&cs->mode, M_UNKNOWN); | ||
760 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | ||
761 | |||
762 | clear_at_state(&cs->at_state); | ||
763 | dealloc_at_states(cs); | ||
764 | free_strings(&cs->at_state); | ||
765 | gigaset_at_init(&cs->at_state, NULL, cs, 0); | ||
766 | |||
767 | kfree(cs->inbuf->rcvbuf); | ||
768 | cs->inbuf->rcvbuf = NULL; | ||
769 | cs->inbuf->inputstate = INS_command; | ||
770 | atomic_set(&cs->inbuf->head, 0); | ||
771 | atomic_set(&cs->inbuf->tail, 0); | ||
772 | |||
773 | cb = cs->cmdbuf; | ||
774 | while (cb) { | ||
775 | tcb = cb; | ||
776 | cb = cb->next; | ||
777 | kfree(tcb); | ||
778 | } | ||
779 | cs->cmdbuf = cs->lastcmdbuf = NULL; | ||
780 | cs->curlen = 0; | ||
781 | cs->cmdbytes = 0; | ||
782 | cs->gotfwver = -1; | ||
783 | cs->dle = 0; | ||
784 | cs->cur_at_seq = 0; | ||
785 | atomic_set(&cs->commands_pending, 0); | ||
786 | cs->cbytes = 0; | ||
787 | |||
788 | spin_unlock_irqrestore(&cs->lock, flags); | ||
789 | |||
790 | for (i = 0; i < cs->channels; ++i) { | ||
791 | gigaset_freebcs(cs->bcs + i); | ||
792 | if (!gigaset_initbcs(cs->bcs + i, cs, i)) | ||
793 | break; //FIXME error handling | ||
794 | } | ||
795 | |||
796 | if (cs->waiting) { | ||
797 | cs->cmd_result = -ENODEV; | ||
798 | cs->waiting = 0; | ||
799 | wake_up_interruptible(&cs->waitqueue); | ||
800 | } | ||
801 | } | ||
802 | |||
803 | |||
804 | int gigaset_start(struct cardstate *cs) | ||
805 | { | ||
806 | if (down_interruptible(&cs->sem)) | ||
807 | return 0; | ||
808 | //info("USB device for Gigaset 307x now attached to Dev %d", ucs->minor); | ||
809 | |||
810 | atomic_set(&cs->connected, 1); | ||
811 | |||
812 | if (atomic_read(&cs->mstate) != MS_LOCKED) { | ||
813 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); | ||
814 | cs->ops->baud_rate(cs, B115200); | ||
815 | cs->ops->set_line_ctrl(cs, CS8); | ||
816 | cs->control_state = TIOCM_DTR|TIOCM_RTS; | ||
817 | } else { | ||
818 | //FIXME use some saved values? | ||
819 | } | ||
820 | |||
821 | cs->waiting = 1; | ||
822 | |||
823 | if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) { | ||
824 | cs->waiting = 0; | ||
825 | //FIXME what should we do? | ||
826 | goto error; | ||
827 | } | ||
828 | |||
829 | dbg(DEBUG_CMD, "scheduling START"); | ||
830 | gigaset_schedule_event(cs); | ||
831 | |||
832 | wait_event(cs->waitqueue, !cs->waiting); | ||
833 | |||
834 | up(&cs->sem); | ||
835 | return 1; | ||
836 | |||
837 | error: | ||
838 | up(&cs->sem); | ||
839 | return 0; | ||
840 | } | ||
841 | EXPORT_SYMBOL_GPL(gigaset_start); | ||
842 | |||
843 | void gigaset_shutdown(struct cardstate *cs) | ||
844 | { | ||
845 | down(&cs->sem); | ||
846 | |||
847 | cs->waiting = 1; | ||
848 | |||
849 | if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) { | ||
850 | //FIXME what should we do? | ||
851 | goto exit; | ||
852 | } | ||
853 | |||
854 | dbg(DEBUG_CMD, "scheduling SHUTDOWN"); | ||
855 | gigaset_schedule_event(cs); | ||
856 | |||
857 | if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) { | ||
858 | warn("aborted"); | ||
859 | //FIXME | ||
860 | } | ||
861 | |||
862 | if (atomic_read(&cs->mstate) != MS_LOCKED) { | ||
863 | //FIXME? | ||
864 | //gigaset_baud_rate(cs, B115200); | ||
865 | //gigaset_set_line_ctrl(cs, CS8); | ||
866 | //gigaset_set_modem_ctrl(cs, TIOCM_DTR|TIOCM_RTS, 0); | ||
867 | //cs->control_state = 0; | ||
868 | } else { | ||
869 | //FIXME use some saved values? | ||
870 | } | ||
871 | |||
872 | cleanup_cs(cs); | ||
873 | |||
874 | exit: | ||
875 | up(&cs->sem); | ||
876 | } | ||
877 | EXPORT_SYMBOL_GPL(gigaset_shutdown); | ||
878 | |||
879 | void gigaset_stop(struct cardstate *cs) | ||
880 | { | ||
881 | down(&cs->sem); | ||
882 | |||
883 | atomic_set(&cs->connected, 0); | ||
884 | |||
885 | cs->waiting = 1; | ||
886 | |||
887 | if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) { | ||
888 | //FIXME what should we do? | ||
889 | goto exit; | ||
890 | } | ||
891 | |||
892 | dbg(DEBUG_CMD, "scheduling STOP"); | ||
893 | gigaset_schedule_event(cs); | ||
894 | |||
895 | if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) { | ||
896 | warn("aborted"); | ||
897 | //FIXME | ||
898 | } | ||
899 | |||
900 | /* Tell the LL that the device is not available .. */ | ||
901 | gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer? | ||
902 | |||
903 | cleanup_cs(cs); | ||
904 | |||
905 | exit: | ||
906 | up(&cs->sem); | ||
907 | } | ||
908 | EXPORT_SYMBOL_GPL(gigaset_stop); | ||
909 | |||
910 | static LIST_HEAD(drivers); | ||
911 | static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; | ||
912 | |||
913 | struct cardstate *gigaset_get_cs_by_id(int id) | ||
914 | { | ||
915 | unsigned long flags; | ||
916 | static struct cardstate *ret = NULL; | ||
917 | static struct cardstate *cs; | ||
918 | struct gigaset_driver *drv; | ||
919 | unsigned i; | ||
920 | |||
921 | spin_lock_irqsave(&driver_lock, flags); | ||
922 | list_for_each_entry(drv, &drivers, list) { | ||
923 | spin_lock(&drv->lock); | ||
924 | for (i = 0; i < drv->minors; ++i) { | ||
925 | if (drv->flags[i] & VALID_ID) { | ||
926 | cs = drv->cs + i; | ||
927 | if (cs->myid == id) | ||
928 | ret = cs; | ||
929 | } | ||
930 | if (ret) | ||
931 | break; | ||
932 | } | ||
933 | spin_unlock(&drv->lock); | ||
934 | if (ret) | ||
935 | break; | ||
936 | } | ||
937 | spin_unlock_irqrestore(&driver_lock, flags); | ||
938 | return ret; | ||
939 | } | ||
940 | |||
941 | void gigaset_debugdrivers(void) | ||
942 | { | ||
943 | unsigned long flags; | ||
944 | static struct cardstate *cs; | ||
945 | struct gigaset_driver *drv; | ||
946 | unsigned i; | ||
947 | |||
948 | spin_lock_irqsave(&driver_lock, flags); | ||
949 | list_for_each_entry(drv, &drivers, list) { | ||
950 | dbg(DEBUG_DRIVER, "driver %p", drv); | ||
951 | spin_lock(&drv->lock); | ||
952 | for (i = 0; i < drv->minors; ++i) { | ||
953 | dbg(DEBUG_DRIVER, " index %u", i); | ||
954 | dbg(DEBUG_DRIVER, " flags 0x%02x", drv->flags[i]); | ||
955 | cs = drv->cs + i; | ||
956 | dbg(DEBUG_DRIVER, " cardstate %p", cs); | ||
957 | dbg(DEBUG_DRIVER, " minor_index %u", cs->minor_index); | ||
958 | dbg(DEBUG_DRIVER, " driver %p", cs->driver); | ||
959 | dbg(DEBUG_DRIVER, " i4l id %d", cs->myid); | ||
960 | } | ||
961 | spin_unlock(&drv->lock); | ||
962 | } | ||
963 | spin_unlock_irqrestore(&driver_lock, flags); | ||
964 | } | ||
965 | EXPORT_SYMBOL_GPL(gigaset_debugdrivers); | ||
966 | |||
967 | struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) | ||
968 | { | ||
969 | if (tty->index < 0 || tty->index >= tty->driver->num) | ||
970 | return NULL; | ||
971 | return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); | ||
972 | } | ||
973 | |||
974 | struct cardstate *gigaset_get_cs_by_minor(unsigned minor) | ||
975 | { | ||
976 | unsigned long flags; | ||
977 | static struct cardstate *ret = NULL; | ||
978 | struct gigaset_driver *drv; | ||
979 | unsigned index; | ||
980 | |||
981 | spin_lock_irqsave(&driver_lock, flags); | ||
982 | list_for_each_entry(drv, &drivers, list) { | ||
983 | if (minor < drv->minor || minor >= drv->minor + drv->minors) | ||
984 | continue; | ||
985 | index = minor - drv->minor; | ||
986 | spin_lock(&drv->lock); | ||
987 | if (drv->flags[index] & VALID_MINOR) | ||
988 | ret = drv->cs + index; | ||
989 | spin_unlock(&drv->lock); | ||
990 | if (ret) | ||
991 | break; | ||
992 | } | ||
993 | spin_unlock_irqrestore(&driver_lock, flags); | ||
994 | return ret; | ||
995 | } | ||
996 | |||
997 | void gigaset_freedriver(struct gigaset_driver *drv) | ||
998 | { | ||
999 | unsigned long flags; | ||
1000 | |||
1001 | spin_lock_irqsave(&driver_lock, flags); | ||
1002 | list_del(&drv->list); | ||
1003 | spin_unlock_irqrestore(&driver_lock, flags); | ||
1004 | |||
1005 | gigaset_if_freedriver(drv); | ||
1006 | module_put(drv->owner); | ||
1007 | |||
1008 | kfree(drv->cs); | ||
1009 | kfree(drv->flags); | ||
1010 | kfree(drv); | ||
1011 | } | ||
1012 | EXPORT_SYMBOL_GPL(gigaset_freedriver); | ||
1013 | |||
1014 | /* gigaset_initdriver | ||
1015 | * Allocate and initialize gigaset_driver structure. Initialize interface. | ||
1016 | * parameters: | ||
1017 | * minor First minor number | ||
1018 | * minors Number of minors this driver can handle | ||
1019 | * procname Name of the driver (e.g. for /proc/tty/drivers, path in /proc/driver) | ||
1020 | * devname Name of the device files (prefix without minor number) | ||
1021 | * devfsname Devfs name of the device files without %d | ||
1022 | * return value: | ||
1023 | * Pointer to the gigaset_driver structure on success, NULL on failure. | ||
1024 | */ | ||
1025 | struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, | ||
1026 | const char *procname, | ||
1027 | const char *devname, | ||
1028 | const char *devfsname, | ||
1029 | const struct gigaset_ops *ops, | ||
1030 | struct module *owner) | ||
1031 | { | ||
1032 | struct gigaset_driver *drv; | ||
1033 | unsigned long flags; | ||
1034 | unsigned i; | ||
1035 | |||
1036 | drv = kmalloc(sizeof *drv, GFP_KERNEL); | ||
1037 | if (!drv) | ||
1038 | return NULL; | ||
1039 | if (!try_module_get(owner)) | ||
1040 | return NULL; | ||
1041 | |||
1042 | drv->cs = NULL; | ||
1043 | drv->have_tty = 0; | ||
1044 | drv->minor = minor; | ||
1045 | drv->minors = minors; | ||
1046 | spin_lock_init(&drv->lock); | ||
1047 | drv->blocked = 0; | ||
1048 | drv->ops = ops; | ||
1049 | drv->owner = owner; | ||
1050 | INIT_LIST_HEAD(&drv->list); | ||
1051 | |||
1052 | drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL); | ||
1053 | if (!drv->cs) | ||
1054 | goto out1; | ||
1055 | drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); | ||
1056 | if (!drv->flags) | ||
1057 | goto out2; | ||
1058 | |||
1059 | for (i = 0; i < minors; ++i) { | ||
1060 | drv->flags[i] = 0; | ||
1061 | drv->cs[i].driver = drv; | ||
1062 | drv->cs[i].ops = drv->ops; | ||
1063 | drv->cs[i].minor_index = i; | ||
1064 | } | ||
1065 | |||
1066 | gigaset_if_initdriver(drv, procname, devname, devfsname); | ||
1067 | |||
1068 | spin_lock_irqsave(&driver_lock, flags); | ||
1069 | list_add(&drv->list, &drivers); | ||
1070 | spin_unlock_irqrestore(&driver_lock, flags); | ||
1071 | |||
1072 | return drv; | ||
1073 | |||
1074 | out2: | ||
1075 | kfree(drv->cs); | ||
1076 | out1: | ||
1077 | kfree(drv); | ||
1078 | module_put(owner); | ||
1079 | return NULL; | ||
1080 | } | ||
1081 | EXPORT_SYMBOL_GPL(gigaset_initdriver); | ||
1082 | |||
1083 | static struct cardstate *alloc_cs(struct gigaset_driver *drv) | ||
1084 | { | ||
1085 | unsigned long flags; | ||
1086 | unsigned i; | ||
1087 | static struct cardstate *ret = NULL; | ||
1088 | |||
1089 | spin_lock_irqsave(&drv->lock, flags); | ||
1090 | for (i = 0; i < drv->minors; ++i) { | ||
1091 | if (!(drv->flags[i] & VALID_MINOR)) { | ||
1092 | drv->flags[i] = VALID_MINOR; | ||
1093 | ret = drv->cs + i; | ||
1094 | } | ||
1095 | if (ret) | ||
1096 | break; | ||
1097 | } | ||
1098 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1099 | return ret; | ||
1100 | } | ||
1101 | |||
1102 | static void free_cs(struct cardstate *cs) | ||
1103 | { | ||
1104 | unsigned long flags; | ||
1105 | struct gigaset_driver *drv = cs->driver; | ||
1106 | spin_lock_irqsave(&drv->lock, flags); | ||
1107 | drv->flags[cs->minor_index] = 0; | ||
1108 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1109 | } | ||
1110 | |||
1111 | static void make_valid(struct cardstate *cs, unsigned mask) | ||
1112 | { | ||
1113 | unsigned long flags; | ||
1114 | struct gigaset_driver *drv = cs->driver; | ||
1115 | spin_lock_irqsave(&drv->lock, flags); | ||
1116 | drv->flags[cs->minor_index] |= mask; | ||
1117 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1118 | } | ||
1119 | |||
1120 | static void make_invalid(struct cardstate *cs, unsigned mask) | ||
1121 | { | ||
1122 | unsigned long flags; | ||
1123 | struct gigaset_driver *drv = cs->driver; | ||
1124 | spin_lock_irqsave(&drv->lock, flags); | ||
1125 | drv->flags[cs->minor_index] &= ~mask; | ||
1126 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1127 | } | ||
1128 | |||
1129 | /* For drivers without fixed assignment device<->cardstate (usb) */ | ||
1130 | struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv) | ||
1131 | { | ||
1132 | unsigned long flags; | ||
1133 | struct cardstate *cs = NULL; | ||
1134 | unsigned i; | ||
1135 | |||
1136 | spin_lock_irqsave(&drv->lock, flags); | ||
1137 | if (drv->blocked) | ||
1138 | goto exit; | ||
1139 | for (i = 0; i < drv->minors; ++i) { | ||
1140 | if ((drv->flags[i] & VALID_MINOR) && | ||
1141 | !(drv->flags[i] & ASSIGNED)) { | ||
1142 | drv->flags[i] |= ASSIGNED; | ||
1143 | cs = drv->cs + i; | ||
1144 | break; | ||
1145 | } | ||
1146 | } | ||
1147 | exit: | ||
1148 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1149 | return cs; | ||
1150 | } | ||
1151 | EXPORT_SYMBOL_GPL(gigaset_getunassignedcs); | ||
1152 | |||
1153 | void gigaset_unassign(struct cardstate *cs) | ||
1154 | { | ||
1155 | unsigned long flags; | ||
1156 | unsigned *minor_flags; | ||
1157 | struct gigaset_driver *drv; | ||
1158 | |||
1159 | if (!cs) | ||
1160 | return; | ||
1161 | drv = cs->driver; | ||
1162 | spin_lock_irqsave(&drv->lock, flags); | ||
1163 | minor_flags = drv->flags + cs->minor_index; | ||
1164 | if (*minor_flags & VALID_MINOR) | ||
1165 | *minor_flags &= ~ASSIGNED; | ||
1166 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1167 | } | ||
1168 | EXPORT_SYMBOL_GPL(gigaset_unassign); | ||
1169 | |||
1170 | void gigaset_blockdriver(struct gigaset_driver *drv) | ||
1171 | { | ||
1172 | unsigned long flags; | ||
1173 | spin_lock_irqsave(&drv->lock, flags); | ||
1174 | drv->blocked = 1; | ||
1175 | spin_unlock_irqrestore(&drv->lock, flags); | ||
1176 | } | ||
1177 | EXPORT_SYMBOL_GPL(gigaset_blockdriver); | ||
1178 | |||
1179 | static int __init gigaset_init_module(void) | ||
1180 | { | ||
1181 | /* in accordance with the principle of least astonishment, | ||
1182 | * setting the 'debug' parameter to 1 activates a sensible | ||
1183 | * set of default debug levels | ||
1184 | */ | ||
1185 | if (gigaset_debuglevel == 1) | ||
1186 | gigaset_debuglevel = DEBUG_DEFAULT; | ||
1187 | |||
1188 | info(DRIVER_AUTHOR); | ||
1189 | info(DRIVER_DESC); | ||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | static void __exit gigaset_exit_module(void) | ||
1194 | { | ||
1195 | } | ||
1196 | |||
1197 | module_init(gigaset_init_module); | ||
1198 | module_exit(gigaset_exit_module); | ||
1199 | |||
1200 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1201 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1202 | |||
1203 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c new file mode 100644 index 000000000000..fdcb80bb21c7 --- /dev/null +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -0,0 +1,1983 @@ | |||
1 | /* | ||
2 | * Stuff used by all variants of the driver | ||
3 | * | ||
4 | * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>, | ||
5 | * Hansjoerg Lipp <hjlipp@web.de>, | ||
6 | * Tilman Schmidt <tilman@imap.cc>. | ||
7 | * | ||
8 | * ===================================================================== | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of | ||
12 | * the License, or (at your option) any later version. | ||
13 | * ===================================================================== | ||
14 | * ToDo: ... | ||
15 | * ===================================================================== | ||
16 | * Version: $Id: ev-layer.c,v 1.4.2.18 2006/02/04 18:28:16 hjlipp Exp $ | ||
17 | * ===================================================================== | ||
18 | */ | ||
19 | |||
20 | #include "gigaset.h" | ||
21 | |||
22 | /* ========================================================== */ | ||
23 | /* bit masks for pending commands */ | ||
24 | #define PC_INIT 0x004 | ||
25 | #define PC_DLE0 0x008 | ||
26 | #define PC_DLE1 0x010 | ||
27 | #define PC_CID 0x080 | ||
28 | #define PC_NOCID 0x100 | ||
29 | #define PC_HUP 0x002 | ||
30 | #define PC_DIAL 0x001 | ||
31 | #define PC_ACCEPT 0x040 | ||
32 | #define PC_SHUTDOWN 0x020 | ||
33 | #define PC_CIDMODE 0x200 | ||
34 | #define PC_UMMODE 0x400 | ||
35 | |||
36 | /* types of modem responses */ | ||
37 | #define RT_NOTHING 0 | ||
38 | #define RT_ZSAU 1 | ||
39 | #define RT_RING 2 | ||
40 | #define RT_NUMBER 3 | ||
41 | #define RT_STRING 4 | ||
42 | #define RT_HEX 5 | ||
43 | #define RT_ZCAU 6 | ||
44 | |||
45 | /* Possible ASCII responses */ | ||
46 | #define RSP_OK 0 | ||
47 | //#define RSP_BUSY 1 | ||
48 | //#define RSP_CONNECT 2 | ||
49 | #define RSP_ZGCI 3 | ||
50 | #define RSP_RING 4 | ||
51 | #define RSP_ZAOC 5 | ||
52 | #define RSP_ZCSTR 6 | ||
53 | #define RSP_ZCFGT 7 | ||
54 | #define RSP_ZCFG 8 | ||
55 | #define RSP_ZCCR 9 | ||
56 | #define RSP_EMPTY 10 | ||
57 | #define RSP_ZLOG 11 | ||
58 | #define RSP_ZCAU 12 | ||
59 | #define RSP_ZMWI 13 | ||
60 | #define RSP_ZABINFO 14 | ||
61 | #define RSP_ZSMLSTCHG 15 | ||
62 | #define RSP_VAR 100 | ||
63 | #define RSP_ZSAU (RSP_VAR + VAR_ZSAU) | ||
64 | #define RSP_ZDLE (RSP_VAR + VAR_ZDLE) | ||
65 | #define RSP_ZVLS (RSP_VAR + VAR_ZVLS) | ||
66 | #define RSP_ZCTP (RSP_VAR + VAR_ZCTP) | ||
67 | #define RSP_STR (RSP_VAR + VAR_NUM) | ||
68 | #define RSP_NMBR (RSP_STR + STR_NMBR) | ||
69 | #define RSP_ZCPN (RSP_STR + STR_ZCPN) | ||
70 | #define RSP_ZCON (RSP_STR + STR_ZCON) | ||
71 | #define RSP_ZBC (RSP_STR + STR_ZBC) | ||
72 | #define RSP_ZHLC (RSP_STR + STR_ZHLC) | ||
73 | #define RSP_ERROR -1 /* ERROR */ | ||
74 | #define RSP_WRONG_CID -2 /* unknown cid in cmd */ | ||
75 | //#define RSP_EMPTY -3 | ||
76 | #define RSP_UNKNOWN -4 /* unknown response */ | ||
77 | #define RSP_FAIL -5 /* internal error */ | ||
78 | #define RSP_INVAL -6 /* invalid response */ | ||
79 | |||
80 | #define RSP_NONE -19 | ||
81 | #define RSP_STRING -20 | ||
82 | #define RSP_NULL -21 | ||
83 | //#define RSP_RETRYFAIL -22 | ||
84 | //#define RSP_RETRY -23 | ||
85 | //#define RSP_SKIP -24 | ||
86 | #define RSP_INIT -27 | ||
87 | #define RSP_ANY -26 | ||
88 | #define RSP_LAST -28 | ||
89 | #define RSP_NODEV -9 | ||
90 | |||
91 | /* actions for process_response */ | ||
92 | #define ACT_NOTHING 0 | ||
93 | #define ACT_SETDLE1 1 | ||
94 | #define ACT_SETDLE0 2 | ||
95 | #define ACT_FAILINIT 3 | ||
96 | #define ACT_HUPMODEM 4 | ||
97 | #define ACT_CONFIGMODE 5 | ||
98 | #define ACT_INIT 6 | ||
99 | #define ACT_DLE0 7 | ||
100 | #define ACT_DLE1 8 | ||
101 | #define ACT_FAILDLE0 9 | ||
102 | #define ACT_FAILDLE1 10 | ||
103 | #define ACT_RING 11 | ||
104 | #define ACT_CID 12 | ||
105 | #define ACT_FAILCID 13 | ||
106 | #define ACT_SDOWN 14 | ||
107 | #define ACT_FAILSDOWN 15 | ||
108 | #define ACT_DEBUG 16 | ||
109 | #define ACT_WARN 17 | ||
110 | #define ACT_DIALING 18 | ||
111 | #define ACT_ABORTDIAL 19 | ||
112 | #define ACT_DISCONNECT 20 | ||
113 | #define ACT_CONNECT 21 | ||
114 | #define ACT_REMOTEREJECT 22 | ||
115 | #define ACT_CONNTIMEOUT 23 | ||
116 | #define ACT_REMOTEHUP 24 | ||
117 | #define ACT_ABORTHUP 25 | ||
118 | #define ACT_ICALL 26 | ||
119 | #define ACT_ACCEPTED 27 | ||
120 | #define ACT_ABORTACCEPT 28 | ||
121 | #define ACT_TIMEOUT 29 | ||
122 | #define ACT_GETSTRING 30 | ||
123 | #define ACT_SETVER 31 | ||
124 | #define ACT_FAILVER 32 | ||
125 | #define ACT_GOTVER 33 | ||
126 | #define ACT_TEST 34 | ||
127 | #define ACT_ERROR 35 | ||
128 | #define ACT_ABORTCID 36 | ||
129 | #define ACT_ZCAU 37 | ||
130 | #define ACT_NOTIFY_BC_DOWN 38 | ||
131 | #define ACT_NOTIFY_BC_UP 39 | ||
132 | #define ACT_DIAL 40 | ||
133 | #define ACT_ACCEPT 41 | ||
134 | #define ACT_PROTO_L2 42 | ||
135 | #define ACT_HUP 43 | ||
136 | #define ACT_IF_LOCK 44 | ||
137 | #define ACT_START 45 | ||
138 | #define ACT_STOP 46 | ||
139 | #define ACT_FAKEDLE0 47 | ||
140 | #define ACT_FAKEHUP 48 | ||
141 | #define ACT_FAKESDOWN 49 | ||
142 | #define ACT_SHUTDOWN 50 | ||
143 | #define ACT_PROC_CIDMODE 51 | ||
144 | #define ACT_UMODESET 52 | ||
145 | #define ACT_FAILUMODE 53 | ||
146 | #define ACT_CMODESET 54 | ||
147 | #define ACT_FAILCMODE 55 | ||
148 | #define ACT_IF_VER 56 | ||
149 | #define ACT_CMD 100 | ||
150 | |||
151 | /* at command sequences */ | ||
152 | #define SEQ_NONE 0 | ||
153 | #define SEQ_INIT 100 | ||
154 | #define SEQ_DLE0 200 | ||
155 | #define SEQ_DLE1 250 | ||
156 | #define SEQ_CID 300 | ||
157 | #define SEQ_NOCID 350 | ||
158 | #define SEQ_HUP 400 | ||
159 | #define SEQ_DIAL 600 | ||
160 | #define SEQ_ACCEPT 720 | ||
161 | #define SEQ_SHUTDOWN 500 | ||
162 | #define SEQ_CIDMODE 10 | ||
163 | #define SEQ_UMMODE 11 | ||
164 | |||
165 | |||
166 | // 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring | ||
167 | struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ | ||
168 | { | ||
169 | /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ | ||
170 | |||
171 | /* initialize device, set cid mode if possible */ | ||
172 | //{RSP_INIT, -1, -1,100, 900, 0, {ACT_TEST}}, | ||
173 | //{RSP_ERROR, 900,900, -1, 0, 0, {ACT_FAILINIT}}, | ||
174 | //{RSP_OK, 900,900, -1, 100, INIT_TIMEOUT, | ||
175 | // {ACT_TIMEOUT}}, | ||
176 | |||
177 | {RSP_INIT, -1, -1,SEQ_INIT, 100, INIT_TIMEOUT, | ||
178 | {ACT_TIMEOUT}}, /* wait until device is ready */ | ||
179 | |||
180 | {EV_TIMEOUT, 100,100, -1, 101, 3, {0}, "Z\r"}, /* device in transparent mode? try to initialize it. */ | ||
181 | {RSP_OK, 101,103, -1, 120, 5, {ACT_GETSTRING}, "+GMR\r"}, /* get version */ | ||
182 | |||
183 | {EV_TIMEOUT, 101,101, -1, 102, 5, {0}, "Z\r"}, /* timeout => try once again. */ | ||
184 | {RSP_ERROR, 101,101, -1, 102, 5, {0}, "Z\r"}, /* error => try once again. */ | ||
185 | |||
186 | {EV_TIMEOUT, 102,102, -1, 108, 5, {ACT_SETDLE1}, "^SDLE=0\r"}, /* timeout => try again in DLE mode. */ | ||
187 | {RSP_OK, 108,108, -1, 104,-1}, | ||
188 | {RSP_ZDLE, 104,104, 0, 103, 5, {0}, "Z\r"}, | ||
189 | {EV_TIMEOUT, 104,104, -1, 0, 0, {ACT_FAILINIT}}, | ||
190 | {RSP_ERROR, 108,108, -1, 0, 0, {ACT_FAILINIT}}, | ||
191 | |||
192 | {EV_TIMEOUT, 108,108, -1, 105, 2, {ACT_SETDLE0, | ||
193 | ACT_HUPMODEM, | ||
194 | ACT_TIMEOUT}}, /* still timeout => connection in unimodem mode? */ | ||
195 | {EV_TIMEOUT, 105,105, -1, 103, 5, {0}, "Z\r"}, | ||
196 | |||
197 | {RSP_ERROR, 102,102, -1, 107, 5, {0}, "^GETPRE\r"}, /* ERROR on ATZ => maybe in config mode? */ | ||
198 | {RSP_OK, 107,107, -1, 0, 0, {ACT_CONFIGMODE}}, | ||
199 | {RSP_ERROR, 107,107, -1, 0, 0, {ACT_FAILINIT}}, | ||
200 | {EV_TIMEOUT, 107,107, -1, 0, 0, {ACT_FAILINIT}}, | ||
201 | |||
202 | {RSP_ERROR, 103,103, -1, 0, 0, {ACT_FAILINIT}}, | ||
203 | {EV_TIMEOUT, 103,103, -1, 0, 0, {ACT_FAILINIT}}, | ||
204 | |||
205 | {RSP_STRING, 120,120, -1, 121,-1, {ACT_SETVER}}, | ||
206 | |||
207 | {EV_TIMEOUT, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, | ||
208 | {RSP_ERROR, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, | ||
209 | {RSP_OK, 121,121, -1, 0, 0, {ACT_GOTVER, ACT_INIT}}, | ||
210 | #if 0 | ||
211 | {EV_TIMEOUT, 120,121, -1, 130, 5, {ACT_FAILVER}, "^SGCI=1\r"}, | ||
212 | {RSP_ERROR, 120,121, -1, 130, 5, {ACT_FAILVER}, "^SGCI=1\r"}, | ||
213 | {RSP_OK, 121,121, -1, 130, 5, {ACT_GOTVER}, "^SGCI=1\r"}, | ||
214 | |||
215 | {RSP_OK, 130,130, -1, 0, 0, {ACT_INIT}}, | ||
216 | {RSP_ERROR, 130,130, -1, 0, 0, {ACT_FAILINIT}}, | ||
217 | {EV_TIMEOUT, 130,130, -1, 0, 0, {ACT_FAILINIT}}, | ||
218 | #endif | ||
219 | |||
220 | /* leave dle mode */ | ||
221 | {RSP_INIT, 0, 0,SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, | ||
222 | {RSP_OK, 201,201, -1, 202,-1}, | ||
223 | //{RSP_ZDLE, 202,202, 0, 202, 0, {ACT_ERROR}},//DELETE | ||
224 | {RSP_ZDLE, 202,202, 0, 0, 0, {ACT_DLE0}}, | ||
225 | {RSP_NODEV, 200,249, -1, 0, 0, {ACT_FAKEDLE0}}, | ||
226 | {RSP_ERROR, 200,249, -1, 0, 0, {ACT_FAILDLE0}}, | ||
227 | {EV_TIMEOUT, 200,249, -1, 0, 0, {ACT_FAILDLE0}}, | ||
228 | |||
229 | /* enter dle mode */ | ||
230 | {RSP_INIT, 0, 0,SEQ_DLE1, 251, 5, {0}, "^SDLE=1\r"}, | ||
231 | {RSP_OK, 251,251, -1, 252,-1}, | ||
232 | {RSP_ZDLE, 252,252, 1, 0, 0, {ACT_DLE1}}, | ||
233 | {RSP_ERROR, 250,299, -1, 0, 0, {ACT_FAILDLE1}}, | ||
234 | {EV_TIMEOUT, 250,299, -1, 0, 0, {ACT_FAILDLE1}}, | ||
235 | |||
236 | /* incoming call */ | ||
237 | {RSP_RING, -1, -1, -1, -1,-1, {ACT_RING}}, | ||
238 | |||
239 | /* get cid */ | ||
240 | //{RSP_INIT, 0, 0,300, 901, 0, {ACT_TEST}}, | ||
241 | //{RSP_ERROR, 901,901, -1, 0, 0, {ACT_FAILCID}}, | ||
242 | //{RSP_OK, 901,901, -1, 301, 5, {0}, "^SGCI?\r"}, | ||
243 | |||
244 | {RSP_INIT, 0, 0,SEQ_CID, 301, 5, {0}, "^SGCI?\r"}, | ||
245 | {RSP_OK, 301,301, -1, 302,-1}, | ||
246 | {RSP_ZGCI, 302,302, -1, 0, 0, {ACT_CID}}, | ||
247 | {RSP_ERROR, 301,349, -1, 0, 0, {ACT_FAILCID}}, | ||
248 | {EV_TIMEOUT, 301,349, -1, 0, 0, {ACT_FAILCID}}, | ||
249 | |||
250 | /* enter cid mode */ | ||
251 | {RSP_INIT, 0, 0,SEQ_CIDMODE, 150, 5, {0}, "^SGCI=1\r"}, | ||
252 | {RSP_OK, 150,150, -1, 0, 0, {ACT_CMODESET}}, | ||
253 | {RSP_ERROR, 150,150, -1, 0, 0, {ACT_FAILCMODE}}, | ||
254 | {EV_TIMEOUT, 150,150, -1, 0, 0, {ACT_FAILCMODE}}, | ||
255 | |||
256 | /* leave cid mode */ | ||
257 | //{RSP_INIT, 0, 0,SEQ_UMMODE, 160, 5, {0}, "^SGCI=0\r"}, | ||
258 | {RSP_INIT, 0, 0,SEQ_UMMODE, 160, 5, {0}, "Z\r"}, | ||
259 | {RSP_OK, 160,160, -1, 0, 0, {ACT_UMODESET}}, | ||
260 | {RSP_ERROR, 160,160, -1, 0, 0, {ACT_FAILUMODE}}, | ||
261 | {EV_TIMEOUT, 160,160, -1, 0, 0, {ACT_FAILUMODE}}, | ||
262 | |||
263 | /* abort getting cid */ | ||
264 | {RSP_INIT, 0, 0,SEQ_NOCID, 0, 0, {ACT_ABORTCID}}, | ||
265 | |||
266 | /* reset */ | ||
267 | #if 0 | ||
268 | {RSP_INIT, 0, 0,SEQ_SHUTDOWN, 503, 5, {0}, "^SGCI=0\r"}, | ||
269 | {RSP_OK, 503,503, -1, 504, 5, {0}, "Z\r"}, | ||
270 | #endif | ||
271 | {RSP_INIT, 0, 0,SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, | ||
272 | {RSP_OK, 504,504, -1, 0, 0, {ACT_SDOWN}}, | ||
273 | {RSP_ERROR, 501,599, -1, 0, 0, {ACT_FAILSDOWN}}, | ||
274 | {EV_TIMEOUT, 501,599, -1, 0, 0, {ACT_FAILSDOWN}}, | ||
275 | {RSP_NODEV, 501,599, -1, 0, 0, {ACT_FAKESDOWN}}, | ||
276 | |||
277 | {EV_PROC_CIDMODE,-1, -1, -1, -1,-1, {ACT_PROC_CIDMODE}}, //FIXME | ||
278 | {EV_IF_LOCK, -1, -1, -1, -1,-1, {ACT_IF_LOCK}}, //FIXME | ||
279 | {EV_IF_VER, -1, -1, -1, -1,-1, {ACT_IF_VER}}, //FIXME | ||
280 | {EV_START, -1, -1, -1, -1,-1, {ACT_START}}, //FIXME | ||
281 | {EV_STOP, -1, -1, -1, -1,-1, {ACT_STOP}}, //FIXME | ||
282 | {EV_SHUTDOWN, -1, -1, -1, -1,-1, {ACT_SHUTDOWN}}, //FIXME | ||
283 | |||
284 | /* misc. */ | ||
285 | {RSP_EMPTY, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
286 | {RSP_ZCFGT, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
287 | {RSP_ZCFG, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
288 | {RSP_ZLOG, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
289 | {RSP_ZMWI, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
290 | {RSP_ZABINFO, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
291 | {RSP_ZSMLSTCHG,-1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
292 | |||
293 | {RSP_ZCAU, -1, -1, -1, -1,-1, {ACT_ZCAU}}, | ||
294 | {RSP_NONE, -1, -1, -1, -1,-1, {ACT_DEBUG}}, | ||
295 | {RSP_ANY, -1, -1, -1, -1,-1, {ACT_WARN}}, | ||
296 | {RSP_LAST} | ||
297 | }; | ||
298 | |||
299 | // 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall | ||
300 | struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ | ||
301 | { | ||
302 | /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ | ||
303 | |||
304 | /* dial */ | ||
305 | {EV_DIAL, -1, -1, -1, -1,-1, {ACT_DIAL}}, //FIXME | ||
306 | {RSP_INIT, 0, 0,SEQ_DIAL, 601, 5, {ACT_CMD+AT_BC}}, | ||
307 | {RSP_OK, 601,601, -1, 602, 5, {ACT_CMD+AT_HLC}}, | ||
308 | {RSP_NULL, 602,602, -1, 603, 5, {ACT_CMD+AT_PROTO}}, | ||
309 | {RSP_OK, 602,602, -1, 603, 5, {ACT_CMD+AT_PROTO}}, | ||
310 | {RSP_OK, 603,603, -1, 604, 5, {ACT_CMD+AT_TYPE}}, | ||
311 | {RSP_OK, 604,604, -1, 605, 5, {ACT_CMD+AT_MSN}}, | ||
312 | {RSP_OK, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, | ||
313 | {RSP_NULL, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, | ||
314 | {RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"}, /* set "Endgeraetemodus" */ | ||
315 | {RSP_OK, 607,607, -1, 608,-1}, | ||
316 | //{RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 608, 0, {ACT_ERROR}},//DELETE | ||
317 | {RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 609, 5, {ACT_CMD+AT_DIAL}}, | ||
318 | {RSP_OK, 609,609, -1, 650, 0, {ACT_DIALING}}, | ||
319 | |||
320 | {RSP_ZVLS, 608,608, 17, -1,-1, {ACT_DEBUG}}, | ||
321 | {RSP_ZCTP, 609,609, -1, -1,-1, {ACT_DEBUG}}, | ||
322 | {RSP_ZCPN, 609,609, -1, -1,-1, {ACT_DEBUG}}, | ||
323 | {RSP_ERROR, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, | ||
324 | {EV_TIMEOUT, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, | ||
325 | |||
326 | /* dialing */ | ||
327 | {RSP_ZCTP, 650,650, -1, -1,-1, {ACT_DEBUG}}, | ||
328 | {RSP_ZCPN, 650,650, -1, -1,-1, {ACT_DEBUG}}, | ||
329 | {RSP_ZSAU, 650,650,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, /* some devices don't send this */ | ||
330 | |||
331 | /* connection established */ | ||
332 | {RSP_ZSAU, 650,650,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, //FIXME -> DLE1 | ||
333 | {RSP_ZSAU, 750,750,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, //FIXME -> DLE1 | ||
334 | |||
335 | {EV_BC_OPEN, 800,800, -1, 800,-1, {ACT_NOTIFY_BC_UP}}, //FIXME new constate + timeout | ||
336 | |||
337 | /* remote hangup */ | ||
338 | {RSP_ZSAU, 650,650,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT}}, | ||
339 | {RSP_ZSAU, 750,750,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, | ||
340 | {RSP_ZSAU, 800,800,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, | ||
341 | |||
342 | /* hangup */ | ||
343 | {EV_HUP, -1, -1, -1, -1,-1, {ACT_HUP}}, //FIXME | ||
344 | {RSP_INIT, -1, -1,SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, /* hang up */ //-1,-1? | ||
345 | {RSP_OK, 401,401, -1, 402, 5}, | ||
346 | {RSP_ZVLS, 402,402, 0, 403, 5}, | ||
347 | {RSP_ZSAU, 403,403,ZSAU_DISCONNECT_REQ, -1,-1, {ACT_DEBUG}}, /* if not remote hup */ | ||
348 | //{RSP_ZSAU, 403,403,ZSAU_NULL, 401, 0, {ACT_ERROR}}, //DELETE//FIXME -> DLE0 // should we do this _before_ hanging up for base driver? | ||
349 | {RSP_ZSAU, 403,403,ZSAU_NULL, 0, 0, {ACT_DISCONNECT}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver? | ||
350 | {RSP_NODEV, 401,403, -1, 0, 0, {ACT_FAKEHUP}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver? | ||
351 | {RSP_ERROR, 401,401, -1, 0, 0, {ACT_ABORTHUP}}, | ||
352 | {EV_TIMEOUT, 401,403, -1, 0, 0, {ACT_ABORTHUP}}, | ||
353 | |||
354 | {EV_BC_CLOSED, 0, 0, -1, 0,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME new constate + timeout | ||
355 | |||
356 | /* ring */ | ||
357 | {RSP_ZBC, 700,700, -1, -1,-1, {0}}, | ||
358 | {RSP_ZHLC, 700,700, -1, -1,-1, {0}}, | ||
359 | {RSP_NMBR, 700,700, -1, -1,-1, {0}}, | ||
360 | {RSP_ZCPN, 700,700, -1, -1,-1, {0}}, | ||
361 | {RSP_ZCTP, 700,700, -1, -1,-1, {0}}, | ||
362 | {EV_TIMEOUT, 700,700, -1, 720,720, {ACT_ICALL}}, | ||
363 | {EV_BC_CLOSED,720,720, -1, 0,-1, {ACT_NOTIFY_BC_DOWN}}, | ||
364 | |||
365 | /*accept icall*/ | ||
366 | {EV_ACCEPT, -1, -1, -1, -1,-1, {ACT_ACCEPT}}, //FIXME | ||
367 | {RSP_INIT, 720,720,SEQ_ACCEPT, 721, 5, {ACT_CMD+AT_PROTO}}, | ||
368 | {RSP_OK, 721,721, -1, 722, 5, {ACT_CMD+AT_ISO}}, | ||
369 | {RSP_OK, 722,722, -1, 723, 5, {0}, "+VLS=17\r"}, /* set "Endgeraetemodus" */ | ||
370 | {RSP_OK, 723,723, -1, 724, 5, {0}}, | ||
371 | {RSP_ZVLS, 724,724, 17, 750,50, {ACT_ACCEPTED}}, | ||
372 | {RSP_ERROR, 721,729, -1, 0, 0, {ACT_ABORTACCEPT}}, | ||
373 | {EV_TIMEOUT, 721,729, -1, 0, 0, {ACT_ABORTACCEPT}}, | ||
374 | {RSP_ZSAU, 700,729,ZSAU_NULL, 0, 0, {ACT_ABORTACCEPT}}, | ||
375 | {RSP_ZSAU, 700,729,ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT}}, | ||
376 | {RSP_ZSAU, 700,729,ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT}}, | ||
377 | |||
378 | {EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}}, | ||
379 | |||
380 | /* misc. */ | ||
381 | {EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME | ||
382 | |||
383 | {RSP_ZCON, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
384 | {RSP_ZCCR, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
385 | {RSP_ZAOC, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
386 | {RSP_ZCSTR, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME | ||
387 | |||
388 | {RSP_ZCAU, -1, -1, -1, -1,-1, {ACT_ZCAU}}, | ||
389 | {RSP_NONE, -1, -1, -1, -1,-1, {ACT_DEBUG}}, | ||
390 | {RSP_ANY, -1, -1, -1, -1,-1, {ACT_WARN}}, | ||
391 | {RSP_LAST} | ||
392 | }; | ||
393 | |||
394 | |||
395 | #if 0 | ||
396 | static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen uebernehmen | ||
397 | { | ||
398 | /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ | ||
399 | |||
400 | {RSP_ANY, -1, -1, -1, -1,-1, ACT_WARN, NULL}, | ||
401 | {RSP_LAST,0,0,0,0,0,0} | ||
402 | }; | ||
403 | |||
404 | static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen uebernehmen | ||
405 | { | ||
406 | /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ | ||
407 | |||
408 | {RSP_ANY, -1, -1, -1, -1,-1, ACT_WARN, NULL}, | ||
409 | {RSP_LAST,0,0,0,0,0,0} | ||
410 | }; | ||
411 | #endif | ||
412 | |||
413 | static struct resp_type_t resp_type[]= | ||
414 | { | ||
415 | /*{"", RSP_EMPTY, RT_NOTHING},*/ | ||
416 | {"OK", RSP_OK, RT_NOTHING}, | ||
417 | {"ERROR", RSP_ERROR, RT_NOTHING}, | ||
418 | {"ZSAU", RSP_ZSAU, RT_ZSAU}, | ||
419 | {"ZCAU", RSP_ZCAU, RT_ZCAU}, | ||
420 | {"RING", RSP_RING, RT_RING}, | ||
421 | {"ZGCI", RSP_ZGCI, RT_NUMBER}, | ||
422 | {"ZVLS", RSP_ZVLS, RT_NUMBER}, | ||
423 | {"ZCTP", RSP_ZCTP, RT_NUMBER}, | ||
424 | {"ZDLE", RSP_ZDLE, RT_NUMBER}, | ||
425 | {"ZCFGT", RSP_ZCFGT, RT_NUMBER}, | ||
426 | {"ZCCR", RSP_ZCCR, RT_NUMBER}, | ||
427 | {"ZMWI", RSP_ZMWI, RT_NUMBER}, | ||
428 | {"ZHLC", RSP_ZHLC, RT_STRING}, | ||
429 | {"ZBC", RSP_ZBC, RT_STRING}, | ||
430 | {"NMBR", RSP_NMBR, RT_STRING}, | ||
431 | {"ZCPN", RSP_ZCPN, RT_STRING}, | ||
432 | {"ZCON", RSP_ZCON, RT_STRING}, | ||
433 | {"ZAOC", RSP_ZAOC, RT_STRING}, | ||
434 | {"ZCSTR", RSP_ZCSTR, RT_STRING}, | ||
435 | {"ZCFG", RSP_ZCFG, RT_HEX}, | ||
436 | {"ZLOG", RSP_ZLOG, RT_NOTHING}, | ||
437 | {"ZABINFO", RSP_ZABINFO, RT_NOTHING}, | ||
438 | {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING}, | ||
439 | {NULL,0,0} | ||
440 | }; | ||
441 | |||
442 | /* | ||
443 | * Get integer from char-pointer | ||
444 | */ | ||
445 | static int isdn_getnum(char *p) | ||
446 | { | ||
447 | int v = -1; | ||
448 | |||
449 | IFNULLRETVAL(p, -1); | ||
450 | |||
451 | dbg(DEBUG_TRANSCMD, "string: %s", p); | ||
452 | |||
453 | while (*p >= '0' && *p <= '9') | ||
454 | v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0'); | ||
455 | if (*p) | ||
456 | v = -1; /* invalid Character */ | ||
457 | return v; | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Get integer from char-pointer | ||
462 | */ | ||
463 | static int isdn_gethex(char *p) | ||
464 | { | ||
465 | int v = 0; | ||
466 | int c; | ||
467 | |||
468 | IFNULLRETVAL(p, -1); | ||
469 | |||
470 | dbg(DEBUG_TRANSCMD, "string: %s", p); | ||
471 | |||
472 | if (!*p) | ||
473 | return -1; | ||
474 | |||
475 | do { | ||
476 | if (v > (INT_MAX - 15) / 16) | ||
477 | return -1; | ||
478 | c = *p; | ||
479 | if (c >= '0' && c <= '9') | ||
480 | c -= '0'; | ||
481 | else if (c >= 'a' && c <= 'f') | ||
482 | c -= 'a' - 10; | ||
483 | else if (c >= 'A' && c <= 'F') | ||
484 | c -= 'A' - 10; | ||
485 | else | ||
486 | return -1; | ||
487 | v = v * 16 + c; | ||
488 | } while (*++p); | ||
489 | |||
490 | return v; | ||
491 | } | ||
492 | |||
493 | static inline void new_index(atomic_t *index, int max) | ||
494 | { | ||
495 | if (atomic_read(index) == max) //FIXME race? | ||
496 | atomic_set(index, 0); | ||
497 | else | ||
498 | atomic_inc(index); | ||
499 | } | ||
500 | |||
501 | /* retrieve CID from parsed response | ||
502 | * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535 | ||
503 | */ | ||
504 | static int cid_of_response(char *s) | ||
505 | { | ||
506 | int cid; | ||
507 | |||
508 | if (s[-1] != ';') | ||
509 | return 0; /* no CID separator */ | ||
510 | cid = isdn_getnum(s); | ||
511 | if (cid < 0) | ||
512 | return 0; /* CID not numeric */ | ||
513 | if (cid < 1 || cid > 65535) | ||
514 | return -1; /* CID out of range */ | ||
515 | return cid; | ||
516 | //FIXME is ;<digit>+ at end of non-CID response really impossible? | ||
517 | } | ||
518 | |||
519 | /* This function will be called via task queue from the callback handler. | ||
520 | * We received a modem response and have to handle it.. | ||
521 | */ | ||
522 | void gigaset_handle_modem_response(struct cardstate *cs) | ||
523 | { | ||
524 | unsigned char *argv[MAX_REC_PARAMS + 1]; | ||
525 | int params; | ||
526 | int i, j; | ||
527 | struct resp_type_t *rt; | ||
528 | int curarg; | ||
529 | unsigned long flags; | ||
530 | unsigned next, tail, head; | ||
531 | struct event_t *event; | ||
532 | int resp_code; | ||
533 | int param_type; | ||
534 | int abort; | ||
535 | size_t len; | ||
536 | int cid; | ||
537 | int rawstring; | ||
538 | |||
539 | IFNULLRET(cs); | ||
540 | |||
541 | len = cs->cbytes; | ||
542 | if (!len) { | ||
543 | /* ignore additional LFs/CRs (M10x config mode or cx100) */ | ||
544 | dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]); | ||
545 | return; | ||
546 | } | ||
547 | cs->respdata[len] = 0; | ||
548 | dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata); | ||
549 | argv[0] = cs->respdata; | ||
550 | params = 1; | ||
551 | if (cs->at_state.getstring) { | ||
552 | /* getstring only allowed without cid at the moment */ | ||
553 | cs->at_state.getstring = 0; | ||
554 | rawstring = 1; | ||
555 | cid = 0; | ||
556 | } else { | ||
557 | /* parse line */ | ||
558 | for (i = 0; i < len; i++) | ||
559 | switch (cs->respdata[i]) { | ||
560 | case ';': | ||
561 | case ',': | ||
562 | case '=': | ||
563 | if (params > MAX_REC_PARAMS) { | ||
564 | warn("too many parameters in response"); | ||
565 | /* need last parameter (might be CID) */ | ||
566 | params--; | ||
567 | } | ||
568 | argv[params++] = cs->respdata + i + 1; | ||
569 | } | ||
570 | |||
571 | rawstring = 0; | ||
572 | cid = params > 1 ? cid_of_response(argv[params-1]) : 0; | ||
573 | if (cid < 0) { | ||
574 | gigaset_add_event(cs, &cs->at_state, RSP_INVAL, | ||
575 | NULL, 0, NULL); | ||
576 | return; | ||
577 | } | ||
578 | |||
579 | for (j = 1; j < params; ++j) | ||
580 | argv[j][-1] = 0; | ||
581 | |||
582 | dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]); | ||
583 | if (cid) { | ||
584 | --params; | ||
585 | dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]); | ||
586 | } | ||
587 | dbg(DEBUG_TRANSCMD, "available params: %d", params - 1); | ||
588 | for (j = 1; j < params; j++) | ||
589 | dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]); | ||
590 | } | ||
591 | |||
592 | spin_lock_irqsave(&cs->ev_lock, flags); | ||
593 | head = atomic_read(&cs->ev_head); | ||
594 | tail = atomic_read(&cs->ev_tail); | ||
595 | |||
596 | abort = 1; | ||
597 | curarg = 0; | ||
598 | while (curarg < params) { | ||
599 | next = (tail + 1) % MAX_EVENTS; | ||
600 | if (unlikely(next == head)) { | ||
601 | err("event queue full"); | ||
602 | break; | ||
603 | } | ||
604 | |||
605 | event = cs->events + tail; | ||
606 | event->at_state = NULL; | ||
607 | event->cid = cid; | ||
608 | event->ptr = NULL; | ||
609 | event->arg = NULL; | ||
610 | tail = next; | ||
611 | |||
612 | if (rawstring) { | ||
613 | resp_code = RSP_STRING; | ||
614 | param_type = RT_STRING; | ||
615 | } else { | ||
616 | for (rt = resp_type; rt->response; ++rt) | ||
617 | if (!strcmp(argv[curarg], rt->response)) | ||
618 | break; | ||
619 | |||
620 | if (!rt->response) { | ||
621 | event->type = RSP_UNKNOWN; | ||
622 | warn("unknown modem response: %s", | ||
623 | argv[curarg]); | ||
624 | break; | ||
625 | } | ||
626 | |||
627 | resp_code = rt->resp_code; | ||
628 | param_type = rt->type; | ||
629 | ++curarg; | ||
630 | } | ||
631 | |||
632 | event->type = resp_code; | ||
633 | |||
634 | switch (param_type) { | ||
635 | case RT_NOTHING: | ||
636 | break; | ||
637 | case RT_RING: | ||
638 | if (!cid) { | ||
639 | err("received RING without CID!"); | ||
640 | event->type = RSP_INVAL; | ||
641 | abort = 1; | ||
642 | } else { | ||
643 | event->cid = 0; | ||
644 | event->parameter = cid; | ||
645 | abort = 0; | ||
646 | } | ||
647 | break; | ||
648 | case RT_ZSAU: | ||
649 | if (curarg >= params) { | ||
650 | event->parameter = ZSAU_NONE; | ||
651 | break; | ||
652 | } | ||
653 | if (!strcmp(argv[curarg], "OUTGOING_CALL_PROCEEDING")) | ||
654 | event->parameter = ZSAU_OUTGOING_CALL_PROCEEDING; | ||
655 | else if (!strcmp(argv[curarg], "CALL_DELIVERED")) | ||
656 | event->parameter = ZSAU_CALL_DELIVERED; | ||
657 | else if (!strcmp(argv[curarg], "ACTIVE")) | ||
658 | event->parameter = ZSAU_ACTIVE; | ||
659 | else if (!strcmp(argv[curarg], "DISCONNECT_IND")) | ||
660 | event->parameter = ZSAU_DISCONNECT_IND; | ||
661 | else if (!strcmp(argv[curarg], "NULL")) | ||
662 | event->parameter = ZSAU_NULL; | ||
663 | else if (!strcmp(argv[curarg], "DISCONNECT_REQ")) | ||
664 | event->parameter = ZSAU_DISCONNECT_REQ; | ||
665 | else { | ||
666 | event->parameter = ZSAU_UNKNOWN; | ||
667 | warn("%s: unknown parameter %s after ZSAU", | ||
668 | __func__, argv[curarg]); | ||
669 | } | ||
670 | ++curarg; | ||
671 | break; | ||
672 | case RT_STRING: | ||
673 | if (curarg < params) { | ||
674 | len = strlen(argv[curarg]) + 1; | ||
675 | event->ptr = kmalloc(len, GFP_ATOMIC); | ||
676 | if (event->ptr) | ||
677 | memcpy(event->ptr, argv[curarg], len); | ||
678 | else | ||
679 | err("no memory for string!"); | ||
680 | ++curarg; | ||
681 | } | ||
682 | #ifdef CONFIG_GIGASET_DEBUG | ||
683 | if (!event->ptr) | ||
684 | dbg(DEBUG_CMD, "string==NULL"); | ||
685 | else | ||
686 | dbg(DEBUG_CMD, | ||
687 | "string==%s", (char *) event->ptr); | ||
688 | #endif | ||
689 | break; | ||
690 | case RT_ZCAU: | ||
691 | event->parameter = -1; | ||
692 | if (curarg + 1 < params) { | ||
693 | i = isdn_gethex(argv[curarg]); | ||
694 | j = isdn_gethex(argv[curarg + 1]); | ||
695 | if (i >= 0 && i < 256 && j >= 0 && j < 256) | ||
696 | event->parameter = (unsigned) i << 8 | ||
697 | | j; | ||
698 | curarg += 2; | ||
699 | } else | ||
700 | curarg = params - 1; | ||
701 | break; | ||
702 | case RT_NUMBER: | ||
703 | case RT_HEX: | ||
704 | if (curarg < params) { | ||
705 | if (param_type == RT_HEX) | ||
706 | event->parameter = | ||
707 | isdn_gethex(argv[curarg]); | ||
708 | else | ||
709 | event->parameter = | ||
710 | isdn_getnum(argv[curarg]); | ||
711 | ++curarg; | ||
712 | } else | ||
713 | event->parameter = -1; | ||
714 | #ifdef CONFIG_GIGASET_DEBUG | ||
715 | dbg(DEBUG_CMD, "parameter==%d", event->parameter); | ||
716 | #endif | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | if (resp_code == RSP_ZDLE) | ||
721 | cs->dle = event->parameter; | ||
722 | |||
723 | if (abort) | ||
724 | break; | ||
725 | } | ||
726 | |||
727 | atomic_set(&cs->ev_tail, tail); | ||
728 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
729 | |||
730 | if (curarg != params) | ||
731 | dbg(DEBUG_ANY, "invalid number of processed parameters: %d/%d", | ||
732 | curarg, params); | ||
733 | } | ||
734 | EXPORT_SYMBOL_GPL(gigaset_handle_modem_response); | ||
735 | |||
736 | /* disconnect | ||
737 | * process closing of connection associated with given AT state structure | ||
738 | */ | ||
739 | static void disconnect(struct at_state_t **at_state_p) | ||
740 | { | ||
741 | unsigned long flags; | ||
742 | struct bc_state *bcs; | ||
743 | struct cardstate *cs; | ||
744 | |||
745 | IFNULLRET(at_state_p); | ||
746 | IFNULLRET(*at_state_p); | ||
747 | bcs = (*at_state_p)->bcs; | ||
748 | cs = (*at_state_p)->cs; | ||
749 | IFNULLRET(cs); | ||
750 | |||
751 | new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX); | ||
752 | |||
753 | /* revert to selected idle mode */ | ||
754 | if (!atomic_read(&cs->cidmode)) { | ||
755 | cs->at_state.pending_commands |= PC_UMMODE; | ||
756 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
757 | dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); | ||
758 | } | ||
759 | |||
760 | if (bcs) { | ||
761 | /* B channel assigned: invoke hardware specific handler */ | ||
762 | cs->ops->close_bchannel(bcs); | ||
763 | } else { | ||
764 | /* no B channel assigned: just deallocate */ | ||
765 | spin_lock_irqsave(&cs->lock, flags); | ||
766 | list_del(&(*at_state_p)->list); | ||
767 | kfree(*at_state_p); | ||
768 | *at_state_p = NULL; | ||
769 | spin_unlock_irqrestore(&cs->lock, flags); | ||
770 | } | ||
771 | } | ||
772 | |||
773 | /* get_free_channel | ||
774 | * get a free AT state structure: either one of those associated with the | ||
775 | * B channels of the Gigaset device, or if none of those is available, | ||
776 | * a newly allocated one with bcs=NULL | ||
777 | * The structure should be freed by calling disconnect() after use. | ||
778 | */ | ||
779 | static inline struct at_state_t *get_free_channel(struct cardstate *cs, | ||
780 | int cid) | ||
781 | /* cids: >0: siemens-cid | ||
782 | 0: without cid | ||
783 | -1: no cid assigned yet | ||
784 | */ | ||
785 | { | ||
786 | unsigned long flags; | ||
787 | int i; | ||
788 | struct at_state_t *ret; | ||
789 | |||
790 | for (i = 0; i < cs->channels; ++i) | ||
791 | if (gigaset_get_channel(cs->bcs + i)) { | ||
792 | ret = &cs->bcs[i].at_state; | ||
793 | ret->cid = cid; | ||
794 | return ret; | ||
795 | } | ||
796 | |||
797 | spin_lock_irqsave(&cs->lock, flags); | ||
798 | ret = kmalloc(sizeof(struct at_state_t), GFP_ATOMIC); | ||
799 | if (ret) { | ||
800 | gigaset_at_init(ret, NULL, cs, cid); | ||
801 | list_add(&ret->list, &cs->temp_at_states); | ||
802 | } | ||
803 | spin_unlock_irqrestore(&cs->lock, flags); | ||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | static void init_failed(struct cardstate *cs, int mode) | ||
808 | { | ||
809 | int i; | ||
810 | struct at_state_t *at_state; | ||
811 | |||
812 | cs->at_state.pending_commands &= ~PC_INIT; | ||
813 | atomic_set(&cs->mode, mode); | ||
814 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | ||
815 | gigaset_free_channels(cs); | ||
816 | for (i = 0; i < cs->channels; ++i) { | ||
817 | at_state = &cs->bcs[i].at_state; | ||
818 | if (at_state->pending_commands & PC_CID) { | ||
819 | at_state->pending_commands &= ~PC_CID; | ||
820 | at_state->pending_commands |= PC_NOCID; | ||
821 | atomic_set(&cs->commands_pending, 1); | ||
822 | } | ||
823 | } | ||
824 | } | ||
825 | |||
826 | static void schedule_init(struct cardstate *cs, int state) | ||
827 | { | ||
828 | if (cs->at_state.pending_commands & PC_INIT) { | ||
829 | dbg(DEBUG_CMD, "not scheduling PC_INIT again"); | ||
830 | return; | ||
831 | } | ||
832 | atomic_set(&cs->mstate, state); | ||
833 | atomic_set(&cs->mode, M_UNKNOWN); | ||
834 | gigaset_block_channels(cs); | ||
835 | cs->at_state.pending_commands |= PC_INIT; | ||
836 | atomic_set(&cs->commands_pending, 1); | ||
837 | dbg(DEBUG_CMD, "Scheduling PC_INIT"); | ||
838 | } | ||
839 | |||
840 | /* Add "AT" to a command, add the cid, dle encode it, send the result to the hardware. */ | ||
841 | static void send_command(struct cardstate *cs, const char *cmd, int cid, | ||
842 | int dle, gfp_t kmallocflags) | ||
843 | { | ||
844 | size_t cmdlen, buflen; | ||
845 | char *cmdpos, *cmdbuf, *cmdtail; | ||
846 | |||
847 | cmdlen = strlen(cmd); | ||
848 | buflen = 11 + cmdlen; | ||
849 | |||
850 | if (likely(buflen > cmdlen)) { | ||
851 | cmdbuf = kmalloc(buflen, kmallocflags); | ||
852 | if (likely(cmdbuf != NULL)) { | ||
853 | cmdpos = cmdbuf + 9; | ||
854 | cmdtail = cmdpos + cmdlen; | ||
855 | memcpy(cmdpos, cmd, cmdlen); | ||
856 | |||
857 | if (cid > 0 && cid <= 65535) { | ||
858 | do { | ||
859 | *--cmdpos = '0' + cid % 10; | ||
860 | cid /= 10; | ||
861 | ++cmdlen; | ||
862 | } while (cid); | ||
863 | } | ||
864 | |||
865 | cmdlen += 2; | ||
866 | *--cmdpos = 'T'; | ||
867 | *--cmdpos = 'A'; | ||
868 | |||
869 | if (dle) { | ||
870 | cmdlen += 4; | ||
871 | *--cmdpos = '('; | ||
872 | *--cmdpos = 0x10; | ||
873 | *cmdtail++ = 0x10; | ||
874 | *cmdtail++ = ')'; | ||
875 | } | ||
876 | |||
877 | cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL); | ||
878 | kfree(cmdbuf); | ||
879 | } else | ||
880 | err("no memory for command buffer"); | ||
881 | } else | ||
882 | err("overflow in buflen"); | ||
883 | } | ||
884 | |||
885 | static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid) | ||
886 | { | ||
887 | struct at_state_t *at_state; | ||
888 | int i; | ||
889 | unsigned long flags; | ||
890 | |||
891 | if (cid == 0) | ||
892 | return &cs->at_state; | ||
893 | |||
894 | for (i = 0; i < cs->channels; ++i) | ||
895 | if (cid == cs->bcs[i].at_state.cid) | ||
896 | return &cs->bcs[i].at_state; | ||
897 | |||
898 | spin_lock_irqsave(&cs->lock, flags); | ||
899 | |||
900 | list_for_each_entry(at_state, &cs->temp_at_states, list) | ||
901 | if (cid == at_state->cid) { | ||
902 | spin_unlock_irqrestore(&cs->lock, flags); | ||
903 | return at_state; | ||
904 | } | ||
905 | |||
906 | spin_unlock_irqrestore(&cs->lock, flags); | ||
907 | |||
908 | return NULL; | ||
909 | } | ||
910 | |||
911 | static void bchannel_down(struct bc_state *bcs) | ||
912 | { | ||
913 | IFNULLRET(bcs); | ||
914 | IFNULLRET(bcs->cs); | ||
915 | |||
916 | if (bcs->chstate & CHS_B_UP) { | ||
917 | bcs->chstate &= ~CHS_B_UP; | ||
918 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP); | ||
919 | } | ||
920 | |||
921 | if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { | ||
922 | bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); | ||
923 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP); | ||
924 | } | ||
925 | |||
926 | gigaset_free_channel(bcs); | ||
927 | |||
928 | gigaset_bcs_reinit(bcs); | ||
929 | } | ||
930 | |||
931 | static void bchannel_up(struct bc_state *bcs) | ||
932 | { | ||
933 | IFNULLRET(bcs); | ||
934 | |||
935 | if (!(bcs->chstate & CHS_D_UP)) { | ||
936 | notice("%s: D channel not up", __func__); | ||
937 | bcs->chstate |= CHS_D_UP; | ||
938 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); | ||
939 | } | ||
940 | |||
941 | if (bcs->chstate & CHS_B_UP) { | ||
942 | notice("%s: B channel already up", __func__); | ||
943 | return; | ||
944 | } | ||
945 | |||
946 | bcs->chstate |= CHS_B_UP; | ||
947 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); | ||
948 | } | ||
949 | |||
950 | static void start_dial(struct at_state_t *at_state, void *data, int seq_index) | ||
951 | { | ||
952 | struct bc_state *bcs = at_state->bcs; | ||
953 | struct cardstate *cs = at_state->cs; | ||
954 | int retval; | ||
955 | |||
956 | bcs->chstate |= CHS_NOTIFY_LL; | ||
957 | //atomic_set(&bcs->status, BCS_INIT); | ||
958 | |||
959 | if (atomic_read(&at_state->seq_index) != seq_index) | ||
960 | goto error; | ||
961 | |||
962 | retval = gigaset_isdn_setup_dial(at_state, data); | ||
963 | if (retval != 0) | ||
964 | goto error; | ||
965 | |||
966 | |||
967 | at_state->pending_commands |= PC_CID; | ||
968 | dbg(DEBUG_CMD, "Scheduling PC_CID"); | ||
969 | //#ifdef GIG_MAYINITONDIAL | ||
970 | // if (atomic_read(&cs->MState) == MS_UNKNOWN) { | ||
971 | // cs->at_state.pending_commands |= PC_INIT; | ||
972 | // dbg(DEBUG_CMD, "Scheduling PC_INIT"); | ||
973 | // } | ||
974 | //#endif | ||
975 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
976 | return; | ||
977 | |||
978 | error: | ||
979 | at_state->pending_commands |= PC_NOCID; | ||
980 | dbg(DEBUG_CMD, "Scheduling PC_NOCID"); | ||
981 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
982 | return; | ||
983 | } | ||
984 | |||
985 | static void start_accept(struct at_state_t *at_state) | ||
986 | { | ||
987 | struct cardstate *cs = at_state->cs; | ||
988 | int retval; | ||
989 | |||
990 | retval = gigaset_isdn_setup_accept(at_state); | ||
991 | |||
992 | if (retval == 0) { | ||
993 | at_state->pending_commands |= PC_ACCEPT; | ||
994 | dbg(DEBUG_CMD, "Scheduling PC_ACCEPT"); | ||
995 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
996 | } else { | ||
997 | //FIXME | ||
998 | at_state->pending_commands |= PC_HUP; | ||
999 | dbg(DEBUG_CMD, "Scheduling PC_HUP"); | ||
1000 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | static void do_start(struct cardstate *cs) | ||
1005 | { | ||
1006 | gigaset_free_channels(cs); | ||
1007 | |||
1008 | if (atomic_read(&cs->mstate) != MS_LOCKED) | ||
1009 | schedule_init(cs, MS_INIT); | ||
1010 | |||
1011 | gigaset_i4l_cmd(cs, ISDN_STAT_RUN); | ||
1012 | // FIXME: not in locked mode | ||
1013 | // FIXME 2: only after init sequence | ||
1014 | |||
1015 | cs->waiting = 0; | ||
1016 | wake_up(&cs->waitqueue); | ||
1017 | } | ||
1018 | |||
1019 | static void finish_shutdown(struct cardstate *cs) | ||
1020 | { | ||
1021 | if (atomic_read(&cs->mstate) != MS_LOCKED) { | ||
1022 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | ||
1023 | atomic_set(&cs->mode, M_UNKNOWN); | ||
1024 | } | ||
1025 | |||
1026 | /* The rest is done by cleanup_cs () in user mode. */ | ||
1027 | |||
1028 | cs->cmd_result = -ENODEV; | ||
1029 | cs->waiting = 0; | ||
1030 | wake_up_interruptible(&cs->waitqueue); | ||
1031 | } | ||
1032 | |||
1033 | static void do_shutdown(struct cardstate *cs) | ||
1034 | { | ||
1035 | gigaset_block_channels(cs); | ||
1036 | |||
1037 | if (atomic_read(&cs->mstate) == MS_READY) { | ||
1038 | atomic_set(&cs->mstate, MS_SHUTDOWN); | ||
1039 | cs->at_state.pending_commands |= PC_SHUTDOWN; | ||
1040 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
1041 | dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); //FIXME | ||
1042 | //gigaset_schedule_event(cs); //FIXME | ||
1043 | } else | ||
1044 | finish_shutdown(cs); | ||
1045 | } | ||
1046 | |||
1047 | static void do_stop(struct cardstate *cs) | ||
1048 | { | ||
1049 | do_shutdown(cs); | ||
1050 | } | ||
1051 | |||
1052 | /* Entering cid mode or getting a cid failed: | ||
1053 | * try to initialize the device and try again. | ||
1054 | * | ||
1055 | * channel >= 0: getting cid for the channel failed | ||
1056 | * channel < 0: entering cid mode failed | ||
1057 | * | ||
1058 | * returns 0 on failure | ||
1059 | */ | ||
1060 | static int reinit_and_retry(struct cardstate *cs, int channel) | ||
1061 | { | ||
1062 | int i; | ||
1063 | |||
1064 | if (--cs->retry_count <= 0) | ||
1065 | return 0; | ||
1066 | |||
1067 | for (i = 0; i < cs->channels; ++i) | ||
1068 | if (cs->bcs[i].at_state.cid > 0) | ||
1069 | return 0; | ||
1070 | |||
1071 | if (channel < 0) | ||
1072 | warn("Could not enter cid mode. Reinit device and try again."); | ||
1073 | else { | ||
1074 | warn("Could not get a call id. Reinit device and try again."); | ||
1075 | cs->bcs[channel].at_state.pending_commands |= PC_CID; | ||
1076 | } | ||
1077 | schedule_init(cs, MS_INIT); | ||
1078 | return 1; | ||
1079 | } | ||
1080 | |||
1081 | static int at_state_invalid(struct cardstate *cs, | ||
1082 | struct at_state_t *test_ptr) | ||
1083 | { | ||
1084 | unsigned long flags; | ||
1085 | unsigned channel; | ||
1086 | struct at_state_t *at_state; | ||
1087 | int retval = 0; | ||
1088 | |||
1089 | spin_lock_irqsave(&cs->lock, flags); | ||
1090 | |||
1091 | if (test_ptr == &cs->at_state) | ||
1092 | goto exit; | ||
1093 | |||
1094 | list_for_each_entry(at_state, &cs->temp_at_states, list) | ||
1095 | if (at_state == test_ptr) | ||
1096 | goto exit; | ||
1097 | |||
1098 | for (channel = 0; channel < cs->channels; ++channel) | ||
1099 | if (&cs->bcs[channel].at_state == test_ptr) | ||
1100 | goto exit; | ||
1101 | |||
1102 | retval = 1; | ||
1103 | exit: | ||
1104 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1105 | return retval; | ||
1106 | } | ||
1107 | |||
1108 | static void handle_icall(struct cardstate *cs, struct bc_state *bcs, | ||
1109 | struct at_state_t **p_at_state) | ||
1110 | { | ||
1111 | int retval; | ||
1112 | struct at_state_t *at_state = *p_at_state; | ||
1113 | |||
1114 | retval = gigaset_isdn_icall(at_state); | ||
1115 | switch (retval) { | ||
1116 | case ICALL_ACCEPT: | ||
1117 | break; | ||
1118 | default: | ||
1119 | err("internal error: disposition=%d", retval); | ||
1120 | /* --v-- fall through --v-- */ | ||
1121 | case ICALL_IGNORE: | ||
1122 | case ICALL_REJECT: | ||
1123 | /* hang up actively | ||
1124 | * Device doc says that would reject the call. | ||
1125 | * In fact it doesn't. | ||
1126 | */ | ||
1127 | at_state->pending_commands |= PC_HUP; | ||
1128 | atomic_set(&cs->commands_pending, 1); | ||
1129 | break; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | static int do_lock(struct cardstate *cs) | ||
1134 | { | ||
1135 | int mode; | ||
1136 | int i; | ||
1137 | |||
1138 | switch (atomic_read(&cs->mstate)) { | ||
1139 | case MS_UNINITIALIZED: | ||
1140 | case MS_READY: | ||
1141 | if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) || | ||
1142 | cs->at_state.pending_commands) | ||
1143 | return -EBUSY; | ||
1144 | |||
1145 | for (i = 0; i < cs->channels; ++i) | ||
1146 | if (cs->bcs[i].at_state.pending_commands) | ||
1147 | return -EBUSY; | ||
1148 | |||
1149 | if (!gigaset_get_channels(cs)) | ||
1150 | return -EBUSY; | ||
1151 | |||
1152 | break; | ||
1153 | case MS_LOCKED: | ||
1154 | //retval = -EACCES; | ||
1155 | break; | ||
1156 | default: | ||
1157 | return -EBUSY; | ||
1158 | } | ||
1159 | |||
1160 | mode = atomic_read(&cs->mode); | ||
1161 | atomic_set(&cs->mstate, MS_LOCKED); | ||
1162 | atomic_set(&cs->mode, M_UNKNOWN); | ||
1163 | //FIXME reset card state / at states / bcs states | ||
1164 | |||
1165 | return mode; | ||
1166 | } | ||
1167 | |||
1168 | static int do_unlock(struct cardstate *cs) | ||
1169 | { | ||
1170 | if (atomic_read(&cs->mstate) != MS_LOCKED) | ||
1171 | return -EINVAL; | ||
1172 | |||
1173 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | ||
1174 | atomic_set(&cs->mode, M_UNKNOWN); | ||
1175 | gigaset_free_channels(cs); | ||
1176 | //FIXME reset card state / at states / bcs states | ||
1177 | if (atomic_read(&cs->connected)) | ||
1178 | schedule_init(cs, MS_INIT); | ||
1179 | |||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | static void do_action(int action, struct cardstate *cs, | ||
1184 | struct bc_state *bcs, | ||
1185 | struct at_state_t **p_at_state, char **pp_command, | ||
1186 | int *p_genresp, int *p_resp_code, | ||
1187 | struct event_t *ev) | ||
1188 | { | ||
1189 | struct at_state_t *at_state = *p_at_state; | ||
1190 | struct at_state_t *at_state2; | ||
1191 | unsigned long flags; | ||
1192 | |||
1193 | int channel; | ||
1194 | |||
1195 | unsigned char *s, *e; | ||
1196 | int i; | ||
1197 | unsigned long val; | ||
1198 | |||
1199 | switch (action) { | ||
1200 | case ACT_NOTHING: | ||
1201 | break; | ||
1202 | case ACT_TIMEOUT: | ||
1203 | at_state->waiting = 1; | ||
1204 | break; | ||
1205 | case ACT_INIT: | ||
1206 | //FIXME setup everything | ||
1207 | cs->at_state.pending_commands &= ~PC_INIT; | ||
1208 | cs->cur_at_seq = SEQ_NONE; | ||
1209 | atomic_set(&cs->mode, M_UNIMODEM); | ||
1210 | if (!atomic_read(&cs->cidmode)) { | ||
1211 | gigaset_free_channels(cs); | ||
1212 | atomic_set(&cs->mstate, MS_READY); | ||
1213 | break; | ||
1214 | } | ||
1215 | cs->at_state.pending_commands |= PC_CIDMODE; | ||
1216 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
1217 | dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | ||
1218 | break; | ||
1219 | case ACT_FAILINIT: | ||
1220 | warn("Could not initialize the device."); | ||
1221 | cs->dle = 0; | ||
1222 | init_failed(cs, M_UNKNOWN); | ||
1223 | cs->cur_at_seq = SEQ_NONE; | ||
1224 | break; | ||
1225 | case ACT_CONFIGMODE: | ||
1226 | init_failed(cs, M_CONFIG); | ||
1227 | cs->cur_at_seq = SEQ_NONE; | ||
1228 | break; | ||
1229 | case ACT_SETDLE1: | ||
1230 | cs->dle = 1; | ||
1231 | /* cs->inbuf[0].inputstate |= INS_command | INS_DLE_command; */ | ||
1232 | cs->inbuf[0].inputstate &= | ||
1233 | ~(INS_command | INS_DLE_command); | ||
1234 | break; | ||
1235 | case ACT_SETDLE0: | ||
1236 | cs->dle = 0; | ||
1237 | cs->inbuf[0].inputstate = | ||
1238 | (cs->inbuf[0].inputstate & ~INS_DLE_command) | ||
1239 | | INS_command; | ||
1240 | break; | ||
1241 | case ACT_CMODESET: | ||
1242 | if (atomic_read(&cs->mstate) == MS_INIT || | ||
1243 | atomic_read(&cs->mstate) == MS_RECOVER) { | ||
1244 | gigaset_free_channels(cs); | ||
1245 | atomic_set(&cs->mstate, MS_READY); | ||
1246 | } | ||
1247 | atomic_set(&cs->mode, M_CID); | ||
1248 | cs->cur_at_seq = SEQ_NONE; | ||
1249 | break; | ||
1250 | case ACT_UMODESET: | ||
1251 | atomic_set(&cs->mode, M_UNIMODEM); | ||
1252 | cs->cur_at_seq = SEQ_NONE; | ||
1253 | break; | ||
1254 | case ACT_FAILCMODE: | ||
1255 | cs->cur_at_seq = SEQ_NONE; | ||
1256 | if (atomic_read(&cs->mstate) == MS_INIT || | ||
1257 | atomic_read(&cs->mstate) == MS_RECOVER) { | ||
1258 | init_failed(cs, M_UNKNOWN); | ||
1259 | break; | ||
1260 | } | ||
1261 | if (!reinit_and_retry(cs, -1)) | ||
1262 | schedule_init(cs, MS_RECOVER); | ||
1263 | break; | ||
1264 | case ACT_FAILUMODE: | ||
1265 | cs->cur_at_seq = SEQ_NONE; | ||
1266 | schedule_init(cs, MS_RECOVER); | ||
1267 | break; | ||
1268 | case ACT_HUPMODEM: | ||
1269 | /* send "+++" (hangup in unimodem mode) */ | ||
1270 | cs->ops->write_cmd(cs, "+++", 3, NULL); | ||
1271 | break; | ||
1272 | case ACT_RING: | ||
1273 | /* get fresh AT state structure for new CID */ | ||
1274 | at_state2 = get_free_channel(cs, ev->parameter); | ||
1275 | if (!at_state2) { | ||
1276 | warn("RING ignored: " | ||
1277 | "could not allocate channel structure"); | ||
1278 | break; | ||
1279 | } | ||
1280 | |||
1281 | /* initialize AT state structure | ||
1282 | * note that bcs may be NULL if no B channel is free | ||
1283 | */ | ||
1284 | at_state2->ConState = 700; | ||
1285 | kfree(at_state2->str_var[STR_NMBR]); | ||
1286 | at_state2->str_var[STR_NMBR] = NULL; | ||
1287 | kfree(at_state2->str_var[STR_ZCPN]); | ||
1288 | at_state2->str_var[STR_ZCPN] = NULL; | ||
1289 | kfree(at_state2->str_var[STR_ZBC]); | ||
1290 | at_state2->str_var[STR_ZBC] = NULL; | ||
1291 | kfree(at_state2->str_var[STR_ZHLC]); | ||
1292 | at_state2->str_var[STR_ZHLC] = NULL; | ||
1293 | at_state2->int_var[VAR_ZCTP] = -1; | ||
1294 | |||
1295 | spin_lock_irqsave(&cs->lock, flags); | ||
1296 | at_state2->timer_expires = RING_TIMEOUT; | ||
1297 | at_state2->timer_active = 1; | ||
1298 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1299 | break; | ||
1300 | case ACT_ICALL: | ||
1301 | handle_icall(cs, bcs, p_at_state); | ||
1302 | at_state = *p_at_state; | ||
1303 | break; | ||
1304 | case ACT_FAILSDOWN: | ||
1305 | warn("Could not shut down the device."); | ||
1306 | /* fall through */ | ||
1307 | case ACT_FAKESDOWN: | ||
1308 | case ACT_SDOWN: | ||
1309 | cs->cur_at_seq = SEQ_NONE; | ||
1310 | finish_shutdown(cs); | ||
1311 | break; | ||
1312 | case ACT_CONNECT: | ||
1313 | if (cs->onechannel) { | ||
1314 | at_state->pending_commands |= PC_DLE1; | ||
1315 | atomic_set(&cs->commands_pending, 1); | ||
1316 | break; | ||
1317 | } | ||
1318 | bcs->chstate |= CHS_D_UP; | ||
1319 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); | ||
1320 | cs->ops->init_bchannel(bcs); | ||
1321 | break; | ||
1322 | case ACT_DLE1: | ||
1323 | cs->cur_at_seq = SEQ_NONE; | ||
1324 | bcs = cs->bcs + cs->curchannel; | ||
1325 | |||
1326 | bcs->chstate |= CHS_D_UP; | ||
1327 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); | ||
1328 | cs->ops->init_bchannel(bcs); | ||
1329 | break; | ||
1330 | case ACT_FAKEHUP: | ||
1331 | at_state->int_var[VAR_ZSAU] = ZSAU_NULL; | ||
1332 | /* fall through */ | ||
1333 | case ACT_DISCONNECT: | ||
1334 | cs->cur_at_seq = SEQ_NONE; | ||
1335 | at_state->cid = -1; | ||
1336 | if (bcs && cs->onechannel && cs->dle) { | ||
1337 | /* Check for other open channels not needed: | ||
1338 | * DLE only used for M10x with one B channel. | ||
1339 | */ | ||
1340 | at_state->pending_commands |= PC_DLE0; | ||
1341 | atomic_set(&cs->commands_pending, 1); | ||
1342 | } else { | ||
1343 | disconnect(p_at_state); | ||
1344 | at_state = *p_at_state; | ||
1345 | } | ||
1346 | break; | ||
1347 | case ACT_FAKEDLE0: | ||
1348 | at_state->int_var[VAR_ZDLE] = 0; | ||
1349 | cs->dle = 0; | ||
1350 | /* fall through */ | ||
1351 | case ACT_DLE0: | ||
1352 | cs->cur_at_seq = SEQ_NONE; | ||
1353 | at_state2 = &cs->bcs[cs->curchannel].at_state; | ||
1354 | disconnect(&at_state2); | ||
1355 | break; | ||
1356 | case ACT_ABORTHUP: | ||
1357 | cs->cur_at_seq = SEQ_NONE; | ||
1358 | warn("Could not hang up."); | ||
1359 | at_state->cid = -1; | ||
1360 | if (bcs && cs->onechannel) | ||
1361 | at_state->pending_commands |= PC_DLE0; | ||
1362 | else { | ||
1363 | disconnect(p_at_state); | ||
1364 | at_state = *p_at_state; | ||
1365 | } | ||
1366 | schedule_init(cs, MS_RECOVER); | ||
1367 | break; | ||
1368 | case ACT_FAILDLE0: | ||
1369 | cs->cur_at_seq = SEQ_NONE; | ||
1370 | warn("Could not leave DLE mode."); | ||
1371 | at_state2 = &cs->bcs[cs->curchannel].at_state; | ||
1372 | disconnect(&at_state2); | ||
1373 | schedule_init(cs, MS_RECOVER); | ||
1374 | break; | ||
1375 | case ACT_FAILDLE1: | ||
1376 | cs->cur_at_seq = SEQ_NONE; | ||
1377 | warn("Could not enter DLE mode. Try to hang up."); | ||
1378 | channel = cs->curchannel; | ||
1379 | cs->bcs[channel].at_state.pending_commands |= PC_HUP; | ||
1380 | atomic_set(&cs->commands_pending, 1); | ||
1381 | break; | ||
1382 | |||
1383 | case ACT_CID: /* got cid; start dialing */ | ||
1384 | cs->cur_at_seq = SEQ_NONE; | ||
1385 | channel = cs->curchannel; | ||
1386 | if (ev->parameter > 0 && ev->parameter <= 65535) { | ||
1387 | cs->bcs[channel].at_state.cid = ev->parameter; | ||
1388 | cs->bcs[channel].at_state.pending_commands |= | ||
1389 | PC_DIAL; | ||
1390 | atomic_set(&cs->commands_pending, 1); | ||
1391 | break; | ||
1392 | } | ||
1393 | /* fall through */ | ||
1394 | case ACT_FAILCID: | ||
1395 | cs->cur_at_seq = SEQ_NONE; | ||
1396 | channel = cs->curchannel; | ||
1397 | if (!reinit_and_retry(cs, channel)) { | ||
1398 | warn("Could not get a call id. Dialing not possible"); | ||
1399 | at_state2 = &cs->bcs[channel].at_state; | ||
1400 | disconnect(&at_state2); | ||
1401 | } | ||
1402 | break; | ||
1403 | case ACT_ABORTCID: | ||
1404 | cs->cur_at_seq = SEQ_NONE; | ||
1405 | at_state2 = &cs->bcs[cs->curchannel].at_state; | ||
1406 | disconnect(&at_state2); | ||
1407 | break; | ||
1408 | |||
1409 | case ACT_DIALING: | ||
1410 | case ACT_ACCEPTED: | ||
1411 | cs->cur_at_seq = SEQ_NONE; | ||
1412 | break; | ||
1413 | |||
1414 | case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */ | ||
1415 | disconnect(p_at_state); | ||
1416 | at_state = *p_at_state; | ||
1417 | break; | ||
1418 | |||
1419 | case ACT_ABORTDIAL: /* error/timeout during dial preparation */ | ||
1420 | cs->cur_at_seq = SEQ_NONE; | ||
1421 | at_state->pending_commands |= PC_HUP; | ||
1422 | atomic_set(&cs->commands_pending, 1); | ||
1423 | break; | ||
1424 | |||
1425 | case ACT_REMOTEREJECT: /* DISCONNECT_IND after dialling */ | ||
1426 | case ACT_CONNTIMEOUT: /* timeout waiting for ZSAU=ACTIVE */ | ||
1427 | case ACT_REMOTEHUP: /* DISCONNECT_IND with established connection */ | ||
1428 | at_state->pending_commands |= PC_HUP; | ||
1429 | atomic_set(&cs->commands_pending, 1); | ||
1430 | break; | ||
1431 | case ACT_GETSTRING: /* warning: RING, ZDLE, ... are not handled properly any more */ | ||
1432 | at_state->getstring = 1; | ||
1433 | break; | ||
1434 | case ACT_SETVER: | ||
1435 | if (!ev->ptr) { | ||
1436 | *p_genresp = 1; | ||
1437 | *p_resp_code = RSP_ERROR; | ||
1438 | break; | ||
1439 | } | ||
1440 | s = ev->ptr; | ||
1441 | |||
1442 | if (!strcmp(s, "OK")) { | ||
1443 | *p_genresp = 1; | ||
1444 | *p_resp_code = RSP_ERROR; | ||
1445 | break; | ||
1446 | } | ||
1447 | |||
1448 | for (i = 0; i < 4; ++i) { | ||
1449 | val = simple_strtoul(s, (char **) &e, 10); | ||
1450 | if (val > INT_MAX || e == s) | ||
1451 | break; | ||
1452 | if (i == 3) { | ||
1453 | if (*e) | ||
1454 | break; | ||
1455 | } else if (*e != '.') | ||
1456 | break; | ||
1457 | else | ||
1458 | s = e + 1; | ||
1459 | cs->fwver[i] = val; | ||
1460 | } | ||
1461 | if (i != 4) { | ||
1462 | *p_genresp = 1; | ||
1463 | *p_resp_code = RSP_ERROR; | ||
1464 | break; | ||
1465 | } | ||
1466 | /*at_state->getstring = 1;*/ | ||
1467 | cs->gotfwver = 0; | ||
1468 | break; | ||
1469 | case ACT_GOTVER: | ||
1470 | if (cs->gotfwver == 0) { | ||
1471 | cs->gotfwver = 1; | ||
1472 | dbg(DEBUG_ANY, | ||
1473 | "firmware version %02d.%03d.%02d.%02d", | ||
1474 | cs->fwver[0], cs->fwver[1], | ||
1475 | cs->fwver[2], cs->fwver[3]); | ||
1476 | break; | ||
1477 | } | ||
1478 | /* fall through */ | ||
1479 | case ACT_FAILVER: | ||
1480 | cs->gotfwver = -1; | ||
1481 | err("could not read firmware version."); | ||
1482 | break; | ||
1483 | #ifdef CONFIG_GIGASET_DEBUG | ||
1484 | case ACT_ERROR: | ||
1485 | *p_genresp = 1; | ||
1486 | *p_resp_code = RSP_ERROR; | ||
1487 | break; | ||
1488 | case ACT_TEST: | ||
1489 | { | ||
1490 | static int count = 3; //2; //1; | ||
1491 | *p_genresp = 1; | ||
1492 | *p_resp_code = count ? RSP_ERROR : RSP_OK; | ||
1493 | if (count > 0) | ||
1494 | --count; | ||
1495 | } | ||
1496 | break; | ||
1497 | #endif | ||
1498 | case ACT_DEBUG: | ||
1499 | dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d", | ||
1500 | __func__, ev->type, at_state->ConState); | ||
1501 | break; | ||
1502 | case ACT_WARN: | ||
1503 | warn("%s: resp_code %d in ConState %d!", | ||
1504 | __func__, ev->type, at_state->ConState); | ||
1505 | break; | ||
1506 | case ACT_ZCAU: | ||
1507 | warn("cause code %04x in connection state %d.", | ||
1508 | ev->parameter, at_state->ConState); | ||
1509 | break; | ||
1510 | |||
1511 | /* events from the LL */ | ||
1512 | case ACT_DIAL: | ||
1513 | start_dial(at_state, ev->ptr, ev->parameter); | ||
1514 | break; | ||
1515 | case ACT_ACCEPT: | ||
1516 | start_accept(at_state); | ||
1517 | break; | ||
1518 | case ACT_PROTO_L2: | ||
1519 | dbg(DEBUG_CMD, | ||
1520 | "set protocol to %u", (unsigned) ev->parameter); | ||
1521 | at_state->bcs->proto2 = ev->parameter; | ||
1522 | break; | ||
1523 | case ACT_HUP: | ||
1524 | at_state->pending_commands |= PC_HUP; | ||
1525 | atomic_set(&cs->commands_pending, 1); //FIXME | ||
1526 | dbg(DEBUG_CMD, "Scheduling PC_HUP"); | ||
1527 | break; | ||
1528 | |||
1529 | /* hotplug events */ | ||
1530 | case ACT_STOP: | ||
1531 | do_stop(cs); | ||
1532 | break; | ||
1533 | case ACT_START: | ||
1534 | do_start(cs); | ||
1535 | break; | ||
1536 | |||
1537 | /* events from the interface */ // FIXME without ACT_xxxx? | ||
1538 | case ACT_IF_LOCK: | ||
1539 | cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs); | ||
1540 | cs->waiting = 0; | ||
1541 | wake_up(&cs->waitqueue); | ||
1542 | break; | ||
1543 | case ACT_IF_VER: | ||
1544 | if (ev->parameter != 0) | ||
1545 | cs->cmd_result = -EINVAL; | ||
1546 | else if (cs->gotfwver != 1) { | ||
1547 | cs->cmd_result = -ENOENT; | ||
1548 | } else { | ||
1549 | memcpy(ev->arg, cs->fwver, sizeof cs->fwver); | ||
1550 | cs->cmd_result = 0; | ||
1551 | } | ||
1552 | cs->waiting = 0; | ||
1553 | wake_up(&cs->waitqueue); | ||
1554 | break; | ||
1555 | |||
1556 | /* events from the proc file system */ // FIXME without ACT_xxxx? | ||
1557 | case ACT_PROC_CIDMODE: | ||
1558 | if (ev->parameter != atomic_read(&cs->cidmode)) { | ||
1559 | atomic_set(&cs->cidmode, ev->parameter); | ||
1560 | if (ev->parameter) { | ||
1561 | cs->at_state.pending_commands |= PC_CIDMODE; | ||
1562 | dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | ||
1563 | } else { | ||
1564 | cs->at_state.pending_commands |= PC_UMMODE; | ||
1565 | dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); | ||
1566 | } | ||
1567 | atomic_set(&cs->commands_pending, 1); | ||
1568 | } | ||
1569 | cs->waiting = 0; | ||
1570 | wake_up(&cs->waitqueue); | ||
1571 | break; | ||
1572 | |||
1573 | /* events from the hardware drivers */ | ||
1574 | case ACT_NOTIFY_BC_DOWN: | ||
1575 | bchannel_down(bcs); | ||
1576 | break; | ||
1577 | case ACT_NOTIFY_BC_UP: | ||
1578 | bchannel_up(bcs); | ||
1579 | break; | ||
1580 | case ACT_SHUTDOWN: | ||
1581 | do_shutdown(cs); | ||
1582 | break; | ||
1583 | |||
1584 | |||
1585 | default: | ||
1586 | if (action >= ACT_CMD && action < ACT_CMD + AT_NUM) { | ||
1587 | *pp_command = at_state->bcs->commands[action - ACT_CMD]; | ||
1588 | if (!*pp_command) { | ||
1589 | *p_genresp = 1; | ||
1590 | *p_resp_code = RSP_NULL; | ||
1591 | } | ||
1592 | } else | ||
1593 | err("%s: action==%d!", __func__, action); | ||
1594 | } | ||
1595 | } | ||
1596 | |||
1597 | /* State machine to do the calling and hangup procedure */ | ||
1598 | static void process_event(struct cardstate *cs, struct event_t *ev) | ||
1599 | { | ||
1600 | struct bc_state *bcs; | ||
1601 | char *p_command = NULL; | ||
1602 | struct reply_t *rep; | ||
1603 | int rcode; | ||
1604 | int genresp = 0; | ||
1605 | int resp_code = RSP_ERROR; | ||
1606 | int sendcid; | ||
1607 | struct at_state_t *at_state; | ||
1608 | int index; | ||
1609 | int curact; | ||
1610 | unsigned long flags; | ||
1611 | |||
1612 | IFNULLRET(cs); | ||
1613 | IFNULLRET(ev); | ||
1614 | |||
1615 | if (ev->cid >= 0) { | ||
1616 | at_state = at_state_from_cid(cs, ev->cid); | ||
1617 | if (!at_state) { | ||
1618 | gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID, | ||
1619 | NULL, 0, NULL); | ||
1620 | return; | ||
1621 | } | ||
1622 | } else { | ||
1623 | at_state = ev->at_state; | ||
1624 | if (at_state_invalid(cs, at_state)) { | ||
1625 | dbg(DEBUG_ANY, | ||
1626 | "event for invalid at_state %p", at_state); | ||
1627 | return; | ||
1628 | } | ||
1629 | } | ||
1630 | |||
1631 | dbg(DEBUG_CMD, | ||
1632 | "connection state %d, event %d", at_state->ConState, ev->type); | ||
1633 | |||
1634 | bcs = at_state->bcs; | ||
1635 | sendcid = at_state->cid; | ||
1636 | |||
1637 | /* Setting the pointer to the dial array */ | ||
1638 | rep = at_state->replystruct; | ||
1639 | IFNULLRET(rep); | ||
1640 | |||
1641 | if (ev->type == EV_TIMEOUT) { | ||
1642 | if (ev->parameter != atomic_read(&at_state->timer_index) | ||
1643 | || !at_state->timer_active) { | ||
1644 | ev->type = RSP_NONE; /* old timeout */ | ||
1645 | dbg(DEBUG_ANY, "old timeout"); | ||
1646 | } else if (!at_state->waiting) | ||
1647 | dbg(DEBUG_ANY, "timeout occured"); | ||
1648 | else | ||
1649 | dbg(DEBUG_ANY, "stopped waiting"); | ||
1650 | } | ||
1651 | |||
1652 | /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] or at_state->str_var[STR_XXXX], set it */ | ||
1653 | if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) { | ||
1654 | index = ev->type - RSP_VAR; | ||
1655 | at_state->int_var[index] = ev->parameter; | ||
1656 | } else if (ev->type >= RSP_STR && ev->type < RSP_STR + STR_NUM) { | ||
1657 | index = ev->type - RSP_STR; | ||
1658 | kfree(at_state->str_var[index]); | ||
1659 | at_state->str_var[index] = ev->ptr; | ||
1660 | ev->ptr = NULL; /* prevent process_events() from deallocating ptr */ | ||
1661 | } | ||
1662 | |||
1663 | if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING) | ||
1664 | at_state->getstring = 0; | ||
1665 | |||
1666 | /* Search row in dial array which matches modem response and current constate */ | ||
1667 | for (;; rep++) { | ||
1668 | rcode = rep->resp_code; | ||
1669 | /* dbg (DEBUG_ANY, "rcode %d", rcode); */ | ||
1670 | if (rcode == RSP_LAST) { | ||
1671 | /* found nothing...*/ | ||
1672 | warn("%s: rcode=RSP_LAST: resp_code %d in ConState %d!", | ||
1673 | __func__, ev->type, at_state->ConState); | ||
1674 | return; | ||
1675 | } | ||
1676 | if ((rcode == RSP_ANY || rcode == ev->type) | ||
1677 | && ((int) at_state->ConState >= rep->min_ConState) | ||
1678 | && (rep->max_ConState < 0 | ||
1679 | || (int) at_state->ConState <= rep->max_ConState) | ||
1680 | && (rep->parameter < 0 || rep->parameter == ev->parameter)) | ||
1681 | break; | ||
1682 | } | ||
1683 | |||
1684 | p_command = rep->command; | ||
1685 | |||
1686 | at_state->waiting = 0; | ||
1687 | for (curact = 0; curact < MAXACT; ++curact) { | ||
1688 | /* The row tells us what we should do .. | ||
1689 | */ | ||
1690 | do_action(rep->action[curact], cs, bcs, &at_state, &p_command, &genresp, &resp_code, ev); | ||
1691 | if (!at_state) | ||
1692 | break; /* may be freed after disconnect */ | ||
1693 | } | ||
1694 | |||
1695 | if (at_state) { | ||
1696 | /* Jump to the next con-state regarding the array */ | ||
1697 | if (rep->new_ConState >= 0) | ||
1698 | at_state->ConState = rep->new_ConState; | ||
1699 | |||
1700 | if (genresp) { | ||
1701 | spin_lock_irqsave(&cs->lock, flags); | ||
1702 | at_state->timer_expires = 0; //FIXME | ||
1703 | at_state->timer_active = 0; //FIXME | ||
1704 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1705 | gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL); | ||
1706 | } else { | ||
1707 | /* Send command to modem if not NULL... */ | ||
1708 | if (p_command/*rep->command*/) { | ||
1709 | if (atomic_read(&cs->connected)) | ||
1710 | send_command(cs, p_command, | ||
1711 | sendcid, cs->dle, | ||
1712 | GFP_ATOMIC); | ||
1713 | else | ||
1714 | gigaset_add_event(cs, at_state, | ||
1715 | RSP_NODEV, | ||
1716 | NULL, 0, NULL); | ||
1717 | } | ||
1718 | |||
1719 | spin_lock_irqsave(&cs->lock, flags); | ||
1720 | if (!rep->timeout) { | ||
1721 | at_state->timer_expires = 0; | ||
1722 | at_state->timer_active = 0; | ||
1723 | } else if (rep->timeout > 0) { /* new timeout */ | ||
1724 | at_state->timer_expires = rep->timeout * 10; | ||
1725 | at_state->timer_active = 1; | ||
1726 | new_index(&at_state->timer_index, | ||
1727 | MAX_TIMER_INDEX); | ||
1728 | } | ||
1729 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1730 | } | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | static void schedule_sequence(struct cardstate *cs, | ||
1735 | struct at_state_t *at_state, int sequence) | ||
1736 | { | ||
1737 | cs->cur_at_seq = sequence; | ||
1738 | gigaset_add_event(cs, at_state, RSP_INIT, NULL, sequence, NULL); | ||
1739 | } | ||
1740 | |||
1741 | static void process_command_flags(struct cardstate *cs) | ||
1742 | { | ||
1743 | struct at_state_t *at_state = NULL; | ||
1744 | struct bc_state *bcs; | ||
1745 | int i; | ||
1746 | int sequence; | ||
1747 | |||
1748 | IFNULLRET(cs); | ||
1749 | |||
1750 | atomic_set(&cs->commands_pending, 0); | ||
1751 | |||
1752 | if (cs->cur_at_seq) { | ||
1753 | dbg(DEBUG_CMD, "not searching scheduled commands: busy"); | ||
1754 | return; | ||
1755 | } | ||
1756 | |||
1757 | dbg(DEBUG_CMD, "searching scheduled commands"); | ||
1758 | |||
1759 | sequence = SEQ_NONE; | ||
1760 | |||
1761 | /* clear pending_commands and hangup channels on shutdown */ | ||
1762 | if (cs->at_state.pending_commands & PC_SHUTDOWN) { | ||
1763 | cs->at_state.pending_commands &= ~PC_CIDMODE; | ||
1764 | for (i = 0; i < cs->channels; ++i) { | ||
1765 | bcs = cs->bcs + i; | ||
1766 | at_state = &bcs->at_state; | ||
1767 | at_state->pending_commands &= | ||
1768 | ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); | ||
1769 | if (at_state->cid > 0) | ||
1770 | at_state->pending_commands |= PC_HUP; | ||
1771 | if (at_state->pending_commands & PC_CID) { | ||
1772 | at_state->pending_commands |= PC_NOCID; | ||
1773 | at_state->pending_commands &= ~PC_CID; | ||
1774 | } | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | /* clear pending_commands and hangup channels on reset */ | ||
1779 | if (cs->at_state.pending_commands & PC_INIT) { | ||
1780 | cs->at_state.pending_commands &= ~PC_CIDMODE; | ||
1781 | for (i = 0; i < cs->channels; ++i) { | ||
1782 | bcs = cs->bcs + i; | ||
1783 | at_state = &bcs->at_state; | ||
1784 | at_state->pending_commands &= | ||
1785 | ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); | ||
1786 | if (at_state->cid > 0) | ||
1787 | at_state->pending_commands |= PC_HUP; | ||
1788 | if (atomic_read(&cs->mstate) == MS_RECOVER) { | ||
1789 | if (at_state->pending_commands & PC_CID) { | ||
1790 | at_state->pending_commands |= PC_NOCID; | ||
1791 | at_state->pending_commands &= ~PC_CID; | ||
1792 | } | ||
1793 | } | ||
1794 | } | ||
1795 | } | ||
1796 | |||
1797 | /* only switch back to unimodem mode, if no commands are pending and no channels are up */ | ||
1798 | if (cs->at_state.pending_commands == PC_UMMODE | ||
1799 | && !atomic_read(&cs->cidmode) | ||
1800 | && list_empty(&cs->temp_at_states) | ||
1801 | && atomic_read(&cs->mode) == M_CID) { | ||
1802 | sequence = SEQ_UMMODE; | ||
1803 | at_state = &cs->at_state; | ||
1804 | for (i = 0; i < cs->channels; ++i) { | ||
1805 | bcs = cs->bcs + i; | ||
1806 | if (bcs->at_state.pending_commands || | ||
1807 | bcs->at_state.cid > 0) { | ||
1808 | sequence = SEQ_NONE; | ||
1809 | break; | ||
1810 | } | ||
1811 | } | ||
1812 | } | ||
1813 | cs->at_state.pending_commands &= ~PC_UMMODE; | ||
1814 | if (sequence != SEQ_NONE) { | ||
1815 | schedule_sequence(cs, at_state, sequence); | ||
1816 | return; | ||
1817 | } | ||
1818 | |||
1819 | for (i = 0; i < cs->channels; ++i) { | ||
1820 | bcs = cs->bcs + i; | ||
1821 | if (bcs->at_state.pending_commands & PC_HUP) { | ||
1822 | bcs->at_state.pending_commands &= ~PC_HUP; | ||
1823 | if (bcs->at_state.pending_commands & PC_CID) { | ||
1824 | /* not yet dialing: PC_NOCID is sufficient */ | ||
1825 | bcs->at_state.pending_commands |= PC_NOCID; | ||
1826 | bcs->at_state.pending_commands &= ~PC_CID; | ||
1827 | } else { | ||
1828 | schedule_sequence(cs, &bcs->at_state, SEQ_HUP); | ||
1829 | return; | ||
1830 | } | ||
1831 | } | ||
1832 | if (bcs->at_state.pending_commands & PC_NOCID) { | ||
1833 | bcs->at_state.pending_commands &= ~PC_NOCID; | ||
1834 | cs->curchannel = bcs->channel; | ||
1835 | schedule_sequence(cs, &cs->at_state, SEQ_NOCID); | ||
1836 | return; | ||
1837 | } else if (bcs->at_state.pending_commands & PC_DLE0) { | ||
1838 | bcs->at_state.pending_commands &= ~PC_DLE0; | ||
1839 | cs->curchannel = bcs->channel; | ||
1840 | schedule_sequence(cs, &cs->at_state, SEQ_DLE0); | ||
1841 | return; | ||
1842 | } | ||
1843 | } | ||
1844 | |||
1845 | list_for_each_entry(at_state, &cs->temp_at_states, list) | ||
1846 | if (at_state->pending_commands & PC_HUP) { | ||
1847 | at_state->pending_commands &= ~PC_HUP; | ||
1848 | schedule_sequence(cs, at_state, SEQ_HUP); | ||
1849 | return; | ||
1850 | } | ||
1851 | |||
1852 | if (cs->at_state.pending_commands & PC_INIT) { | ||
1853 | cs->at_state.pending_commands &= ~PC_INIT; | ||
1854 | cs->dle = 0; //FIXME | ||
1855 | cs->inbuf->inputstate = INS_command; | ||
1856 | //FIXME reset card state (or -> LOCK0)? | ||
1857 | schedule_sequence(cs, &cs->at_state, SEQ_INIT); | ||
1858 | return; | ||
1859 | } | ||
1860 | if (cs->at_state.pending_commands & PC_SHUTDOWN) { | ||
1861 | cs->at_state.pending_commands &= ~PC_SHUTDOWN; | ||
1862 | schedule_sequence(cs, &cs->at_state, SEQ_SHUTDOWN); | ||
1863 | return; | ||
1864 | } | ||
1865 | if (cs->at_state.pending_commands & PC_CIDMODE) { | ||
1866 | cs->at_state.pending_commands &= ~PC_CIDMODE; | ||
1867 | if (atomic_read(&cs->mode) == M_UNIMODEM) { | ||
1868 | #if 0 | ||
1869 | cs->retry_count = 2; | ||
1870 | #else | ||
1871 | cs->retry_count = 1; | ||
1872 | #endif | ||
1873 | schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE); | ||
1874 | return; | ||
1875 | } | ||
1876 | } | ||
1877 | |||
1878 | for (i = 0; i < cs->channels; ++i) { | ||
1879 | bcs = cs->bcs + i; | ||
1880 | if (bcs->at_state.pending_commands & PC_DLE1) { | ||
1881 | bcs->at_state.pending_commands &= ~PC_DLE1; | ||
1882 | cs->curchannel = bcs->channel; | ||
1883 | schedule_sequence(cs, &cs->at_state, SEQ_DLE1); | ||
1884 | return; | ||
1885 | } | ||
1886 | if (bcs->at_state.pending_commands & PC_ACCEPT) { | ||
1887 | bcs->at_state.pending_commands &= ~PC_ACCEPT; | ||
1888 | schedule_sequence(cs, &bcs->at_state, SEQ_ACCEPT); | ||
1889 | return; | ||
1890 | } | ||
1891 | if (bcs->at_state.pending_commands & PC_DIAL) { | ||
1892 | bcs->at_state.pending_commands &= ~PC_DIAL; | ||
1893 | schedule_sequence(cs, &bcs->at_state, SEQ_DIAL); | ||
1894 | return; | ||
1895 | } | ||
1896 | if (bcs->at_state.pending_commands & PC_CID) { | ||
1897 | switch (atomic_read(&cs->mode)) { | ||
1898 | case M_UNIMODEM: | ||
1899 | cs->at_state.pending_commands |= PC_CIDMODE; | ||
1900 | dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | ||
1901 | atomic_set(&cs->commands_pending, 1); | ||
1902 | return; | ||
1903 | #ifdef GIG_MAYINITONDIAL | ||
1904 | case M_UNKNOWN: | ||
1905 | schedule_init(cs, MS_INIT); | ||
1906 | return; | ||
1907 | #endif | ||
1908 | } | ||
1909 | bcs->at_state.pending_commands &= ~PC_CID; | ||
1910 | cs->curchannel = bcs->channel; | ||
1911 | #ifdef GIG_RETRYCID | ||
1912 | cs->retry_count = 2; | ||
1913 | #else | ||
1914 | cs->retry_count = 1; | ||
1915 | #endif | ||
1916 | schedule_sequence(cs, &cs->at_state, SEQ_CID); | ||
1917 | return; | ||
1918 | } | ||
1919 | } | ||
1920 | } | ||
1921 | |||
1922 | static void process_events(struct cardstate *cs) | ||
1923 | { | ||
1924 | struct event_t *ev; | ||
1925 | unsigned head, tail; | ||
1926 | int i; | ||
1927 | int check_flags = 0; | ||
1928 | int was_busy; | ||
1929 | |||
1930 | /* no locking needed (only one reader) */ | ||
1931 | head = atomic_read(&cs->ev_head); | ||
1932 | |||
1933 | for (i = 0; i < 2 * MAX_EVENTS; ++i) { | ||
1934 | tail = atomic_read(&cs->ev_tail); | ||
1935 | if (tail == head) { | ||
1936 | if (!check_flags && !atomic_read(&cs->commands_pending)) | ||
1937 | break; | ||
1938 | check_flags = 0; | ||
1939 | process_command_flags(cs); | ||
1940 | tail = atomic_read(&cs->ev_tail); | ||
1941 | if (tail == head) { | ||
1942 | if (!atomic_read(&cs->commands_pending)) | ||
1943 | break; | ||
1944 | continue; | ||
1945 | } | ||
1946 | } | ||
1947 | |||
1948 | ev = cs->events + head; | ||
1949 | was_busy = cs->cur_at_seq != SEQ_NONE; | ||
1950 | process_event(cs, ev); | ||
1951 | kfree(ev->ptr); | ||
1952 | ev->ptr = NULL; | ||
1953 | if (was_busy && cs->cur_at_seq == SEQ_NONE) | ||
1954 | check_flags = 1; | ||
1955 | |||
1956 | head = (head + 1) % MAX_EVENTS; | ||
1957 | atomic_set(&cs->ev_head, head); | ||
1958 | } | ||
1959 | |||
1960 | if (i == 2 * MAX_EVENTS) { | ||
1961 | err("infinite loop in process_events; aborting."); | ||
1962 | } | ||
1963 | } | ||
1964 | |||
1965 | /* tasklet scheduled on any event received from the Gigaset device | ||
1966 | * parameter: | ||
1967 | * data ISDN controller state structure | ||
1968 | */ | ||
1969 | void gigaset_handle_event(unsigned long data) | ||
1970 | { | ||
1971 | struct cardstate *cs = (struct cardstate *) data; | ||
1972 | |||
1973 | IFNULLRET(cs); | ||
1974 | IFNULLRET(cs->inbuf); | ||
1975 | |||
1976 | /* handle incoming data on control/common channel */ | ||
1977 | if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) { | ||
1978 | dbg(DEBUG_INTR, "processing new data"); | ||
1979 | cs->ops->handle_input(cs->inbuf); | ||
1980 | } | ||
1981 | |||
1982 | process_events(cs); | ||
1983 | } | ||
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h new file mode 100644 index 000000000000..729edcdb6dac --- /dev/null +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -0,0 +1,938 @@ | |||
1 | /* Siemens Gigaset 307x driver | ||
2 | * Common header file for all connection variants | ||
3 | * | ||
4 | * Written by Stefan Eilers <Eilers.Stefan@epost.de> | ||
5 | * and Hansjoerg Lipp <hjlipp@web.de> | ||
6 | * | ||
7 | * Version: $Id: gigaset.h,v 1.97.4.26 2006/02/04 18:28:16 hjlipp Exp $ | ||
8 | * =========================================================================== | ||
9 | */ | ||
10 | |||
11 | #ifndef GIGASET_H | ||
12 | #define GIGASET_H | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/compiler.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <asm/atomic.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/isdnif.h> | ||
21 | #include <linux/usb.h> | ||
22 | #include <linux/skbuff.h> | ||
23 | #include <linux/netdevice.h> | ||
24 | #include <linux/ppp_defs.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/tty.h> | ||
28 | #include <linux/tty_driver.h> | ||
29 | #include <linux/list.h> | ||
30 | |||
31 | #define GIG_VERSION {0,5,0,0} | ||
32 | #define GIG_COMPAT {0,4,0,0} | ||
33 | |||
34 | #define MAX_REC_PARAMS 10 /* Max. number of params in response string */ | ||
35 | #define MAX_RESP_SIZE 512 /* Max. size of a response string */ | ||
36 | #define HW_HDR_LEN 2 /* Header size used to store ack info */ | ||
37 | |||
38 | #define MAX_EVENTS 64 /* size of event queue */ | ||
39 | |||
40 | #define RBUFSIZE 8192 | ||
41 | #define SBUFSIZE 4096 /* sk_buff payload size */ | ||
42 | |||
43 | #define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */ | ||
44 | #define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ | ||
45 | |||
46 | /* compile time options */ | ||
47 | #define GIG_MAJOR 0 | ||
48 | |||
49 | #define GIG_MAYINITONDIAL | ||
50 | #define GIG_RETRYCID | ||
51 | #define GIG_X75 | ||
52 | |||
53 | #define MAX_TIMER_INDEX 1000 | ||
54 | #define MAX_SEQ_INDEX 1000 | ||
55 | |||
56 | #define GIG_TICK (HZ / 10) | ||
57 | |||
58 | /* timeout values (unit: 1 sec) */ | ||
59 | #define INIT_TIMEOUT 1 | ||
60 | |||
61 | /* timeout values (unit: 0.1 sec) */ | ||
62 | #define RING_TIMEOUT 3 /* for additional parameters to RING */ | ||
63 | #define BAS_TIMEOUT 20 /* for response to Base USB ops */ | ||
64 | #define ATRDY_TIMEOUT 3 /* for HD_READY_SEND_ATDATA */ | ||
65 | |||
66 | #define BAS_RETRY 3 /* max. retries for base USB ops */ | ||
67 | |||
68 | #define MAXACT 3 | ||
69 | |||
70 | #define IFNULL(a) if (unlikely(!(a))) | ||
71 | #define IFNULLRET(a) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return; } | ||
72 | #define IFNULLRETVAL(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return (b); } | ||
73 | #define IFNULLCONT(a) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); continue; } | ||
74 | #define IFNULLGOTO(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); goto b; } | ||
75 | |||
76 | extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ | ||
77 | |||
78 | /* any combination of these can be given with the 'debug=' parameter to insmod, e.g. | ||
79 | * 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and DEBUG_INTR. */ | ||
80 | enum debuglevel { /* up to 24 bits (atomic_t) */ | ||
81 | DEBUG_REG = 0x0002, /* serial port I/O register operations */ | ||
82 | DEBUG_OPEN = 0x0004, /* open/close serial port */ | ||
83 | DEBUG_INTR = 0x0008, /* interrupt processing */ | ||
84 | DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on interrupt | ||
85 | requests, not available as run-time option */ | ||
86 | DEBUG_CMD = 0x00020, /* sent/received LL commands */ | ||
87 | DEBUG_STREAM = 0x00040, /* application data stream I/O events */ | ||
88 | DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */ | ||
89 | DEBUG_LLDATA = 0x00100, /* sent/received LL data */ | ||
90 | DEBUG_INTR_0 = 0x00200, /* serial port output interrupt processing */ | ||
91 | DEBUG_DRIVER = 0x00400, /* driver structure */ | ||
92 | DEBUG_HDLC = 0x00800, /* M10x HDLC processing */ | ||
93 | DEBUG_WRITE = 0x01000, /* M105 data write */ | ||
94 | DEBUG_TRANSCMD = 0x02000, /*AT-COMMANDS+RESPONSES*/ | ||
95 | DEBUG_MCMD = 0x04000, /*COMMANDS THAT ARE SENT VERY OFTEN*/ | ||
96 | DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data structures */ | ||
97 | DEBUG_LOCK = 0x10000, /* semaphore operations */ | ||
98 | DEBUG_OUTPUT = 0x20000, /* output to device */ | ||
99 | DEBUG_ISO = 0x40000, /* isochronous transfers */ | ||
100 | DEBUG_IF = 0x80000, /* character device operations */ | ||
101 | DEBUG_USBREQ = 0x100000, /* USB communication (except payload data) */ | ||
102 | DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when MS_LOCKED */ | ||
103 | |||
104 | DEBUG_ANY = 0x3fffff, /* print message if any of the others is activated */ | ||
105 | }; | ||
106 | |||
107 | #ifdef CONFIG_GIGASET_DEBUG | ||
108 | #define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) | ||
109 | //#define DEBUG_DEFAULT (DEBUG_LOCK | DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUF_IF | DEBUG_DRIVER | DEBUG_OUTPUT | DEBUG_INTR) | ||
110 | #else | ||
111 | #define DEBUG_DEFAULT 0 | ||
112 | #endif | ||
113 | |||
114 | /* redefine syslog macros to prepend module name instead of entire source path */ | ||
115 | /* The space before the comma in ", ##" is needed by gcc 2.95 */ | ||
116 | #undef info | ||
117 | #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) | ||
118 | |||
119 | #undef notice | ||
120 | #define notice(format, arg...) printk(KERN_NOTICE "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) | ||
121 | |||
122 | #undef warn | ||
123 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) | ||
124 | |||
125 | #undef err | ||
126 | #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) | ||
127 | |||
128 | #undef dbg | ||
129 | #ifdef CONFIG_GIGASET_DEBUG | ||
130 | #define dbg(level, format, arg...) do { if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \ | ||
131 | printk(KERN_DEBUG "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg); } while (0) | ||
132 | #else | ||
133 | #define dbg(level, format, arg...) do {} while (0) | ||
134 | #endif | ||
135 | |||
136 | void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, | ||
137 | size_t len, const unsigned char *buf, int from_user); | ||
138 | |||
139 | /* connection state */ | ||
140 | #define ZSAU_NONE 0 | ||
141 | #define ZSAU_DISCONNECT_IND 4 | ||
142 | #define ZSAU_OUTGOING_CALL_PROCEEDING 1 | ||
143 | #define ZSAU_PROCEEDING 1 | ||
144 | #define ZSAU_CALL_DELIVERED 2 | ||
145 | #define ZSAU_ACTIVE 3 | ||
146 | #define ZSAU_NULL 5 | ||
147 | #define ZSAU_DISCONNECT_REQ 6 | ||
148 | #define ZSAU_UNKNOWN -1 | ||
149 | |||
150 | /* USB control transfer requests */ | ||
151 | #define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) | ||
152 | #define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) | ||
153 | |||
154 | /* int-in-events 3070 */ | ||
155 | #define HD_B1_FLOW_CONTROL 0x80 | ||
156 | #define HD_B2_FLOW_CONTROL 0x81 | ||
157 | #define HD_RECEIVEATDATA_ACK (0x35) // 3070 // att: HD_RECEIVE>>AT<<DATA_ACK | ||
158 | #define HD_READY_SEND_ATDATA (0x36) // 3070 | ||
159 | #define HD_OPEN_ATCHANNEL_ACK (0x37) // 3070 | ||
160 | #define HD_CLOSE_ATCHANNEL_ACK (0x38) // 3070 | ||
161 | #define HD_DEVICE_INIT_OK (0x11) // ISurf USB + 3070 | ||
162 | #define HD_OPEN_B1CHANNEL_ACK (0x51) // ISurf USB + 3070 | ||
163 | #define HD_OPEN_B2CHANNEL_ACK (0x52) // ISurf USB + 3070 | ||
164 | #define HD_CLOSE_B1CHANNEL_ACK (0x53) // ISurf USB + 3070 | ||
165 | #define HD_CLOSE_B2CHANNEL_ACK (0x54) // ISurf USB + 3070 | ||
166 | // Powermangment | ||
167 | #define HD_SUSPEND_END (0x61) // ISurf USB | ||
168 | // Configuration | ||
169 | #define HD_RESET_INTERRUPT_PIPE_ACK (0xFF) // ISurf USB + 3070 | ||
170 | |||
171 | /* control requests 3070 */ | ||
172 | #define HD_OPEN_B1CHANNEL (0x23) // ISurf USB + 3070 | ||
173 | #define HD_CLOSE_B1CHANNEL (0x24) // ISurf USB + 3070 | ||
174 | #define HD_OPEN_B2CHANNEL (0x25) // ISurf USB + 3070 | ||
175 | #define HD_CLOSE_B2CHANNEL (0x26) // ISurf USB + 3070 | ||
176 | #define HD_RESET_INTERRUPT_PIPE (0x27) // ISurf USB + 3070 | ||
177 | #define HD_DEVICE_INIT_ACK (0x34) // ISurf USB + 3070 | ||
178 | #define HD_WRITE_ATMESSAGE (0x12) // 3070 | ||
179 | #define HD_READ_ATMESSAGE (0x13) // 3070 | ||
180 | #define HD_OPEN_ATCHANNEL (0x28) // 3070 | ||
181 | #define HD_CLOSE_ATCHANNEL (0x29) // 3070 | ||
182 | |||
183 | /* USB frames for isochronous transfer */ | ||
184 | #define BAS_FRAMETIME 1 /* number of milliseconds between frames */ | ||
185 | #define BAS_NUMFRAMES 8 /* number of frames per URB */ | ||
186 | #define BAS_MAXFRAME 16 /* allocated bytes per frame */ | ||
187 | #define BAS_NORMFRAME 8 /* send size without flow control */ | ||
188 | #define BAS_HIGHFRAME 10 /* " " with positive flow control */ | ||
189 | #define BAS_LOWFRAME 5 /* " " with negative flow control */ | ||
190 | #define BAS_CORRFRAMES 4 /* flow control multiplicator */ | ||
191 | |||
192 | #define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isochronous input buffer per URB */ | ||
193 | #define BAS_OUTBUFSIZE 4096 /* size of common isochronous output buffer */ | ||
194 | #define BAS_OUTBUFPAD BAS_MAXFRAME /* size of pad area for isochronous output buffer */ | ||
195 | |||
196 | #define BAS_INURBS 3 | ||
197 | #define BAS_OUTURBS 3 | ||
198 | |||
199 | /* variable commands in struct bc_state */ | ||
200 | #define AT_ISO 0 | ||
201 | #define AT_DIAL 1 | ||
202 | #define AT_MSN 2 | ||
203 | #define AT_BC 3 | ||
204 | #define AT_PROTO 4 | ||
205 | #define AT_TYPE 5 | ||
206 | #define AT_HLC 6 | ||
207 | #define AT_NUM 7 | ||
208 | |||
209 | /* variables in struct at_state_t */ | ||
210 | #define VAR_ZSAU 0 | ||
211 | #define VAR_ZDLE 1 | ||
212 | #define VAR_ZVLS 2 | ||
213 | #define VAR_ZCTP 3 | ||
214 | #define VAR_NUM 4 | ||
215 | |||
216 | #define STR_NMBR 0 | ||
217 | #define STR_ZCPN 1 | ||
218 | #define STR_ZCON 2 | ||
219 | #define STR_ZBC 3 | ||
220 | #define STR_ZHLC 4 | ||
221 | #define STR_NUM 5 | ||
222 | |||
223 | #define EV_TIMEOUT -105 | ||
224 | #define EV_IF_VER -106 | ||
225 | #define EV_PROC_CIDMODE -107 | ||
226 | #define EV_SHUTDOWN -108 | ||
227 | #define EV_START -110 | ||
228 | #define EV_STOP -111 | ||
229 | #define EV_IF_LOCK -112 | ||
230 | #define EV_PROTO_L2 -113 | ||
231 | #define EV_ACCEPT -114 | ||
232 | #define EV_DIAL -115 | ||
233 | #define EV_HUP -116 | ||
234 | #define EV_BC_OPEN -117 | ||
235 | #define EV_BC_CLOSED -118 | ||
236 | |||
237 | /* input state */ | ||
238 | #define INS_command 0x0001 | ||
239 | #define INS_DLE_char 0x0002 | ||
240 | #define INS_byte_stuff 0x0004 | ||
241 | #define INS_have_data 0x0008 | ||
242 | #define INS_skip_frame 0x0010 | ||
243 | #define INS_DLE_command 0x0020 | ||
244 | #define INS_flag_hunt 0x0040 | ||
245 | |||
246 | /* channel state */ | ||
247 | #define CHS_D_UP 0x01 | ||
248 | #define CHS_B_UP 0x02 | ||
249 | #define CHS_NOTIFY_LL 0x04 | ||
250 | |||
251 | #define ICALL_REJECT 0 | ||
252 | #define ICALL_ACCEPT 1 | ||
253 | #define ICALL_IGNORE 2 | ||
254 | |||
255 | /* device state */ | ||
256 | #define MS_UNINITIALIZED 0 | ||
257 | #define MS_INIT 1 | ||
258 | #define MS_LOCKED 2 | ||
259 | #define MS_SHUTDOWN 3 | ||
260 | #define MS_RECOVER 4 | ||
261 | #define MS_READY 5 | ||
262 | |||
263 | /* mode */ | ||
264 | #define M_UNKNOWN 0 | ||
265 | #define M_CONFIG 1 | ||
266 | #define M_UNIMODEM 2 | ||
267 | #define M_CID 3 | ||
268 | |||
269 | /* start mode */ | ||
270 | #define SM_LOCKED 0 | ||
271 | #define SM_ISDN 1 /* default */ | ||
272 | |||
273 | struct gigaset_ops; | ||
274 | struct gigaset_driver; | ||
275 | |||
276 | struct usb_cardstate; | ||
277 | struct ser_cardstate; | ||
278 | struct bas_cardstate; | ||
279 | |||
280 | struct bc_state; | ||
281 | struct usb_bc_state; | ||
282 | struct ser_bc_state; | ||
283 | struct bas_bc_state; | ||
284 | |||
285 | struct reply_t { | ||
286 | int resp_code; /* RSP_XXXX */ | ||
287 | int min_ConState; /* <0 => ignore */ | ||
288 | int max_ConState; /* <0 => ignore */ | ||
289 | int parameter; /* e.g. ZSAU_XXXX <0: ignore*/ | ||
290 | int new_ConState; /* <0 => ignore */ | ||
291 | int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/ | ||
292 | int action[MAXACT]; /* ACT_XXXX */ | ||
293 | char *command; /* NULL==none */ | ||
294 | }; | ||
295 | |||
296 | extern struct reply_t gigaset_tab_cid_m10x[]; | ||
297 | extern struct reply_t gigaset_tab_nocid_m10x[]; | ||
298 | |||
299 | struct inbuf_t { | ||
300 | unsigned char *rcvbuf; /* usb-gigaset receive buffer */ | ||
301 | struct bc_state *bcs; | ||
302 | struct cardstate *cs; | ||
303 | int inputstate; | ||
304 | |||
305 | atomic_t head, tail; | ||
306 | unsigned char data[RBUFSIZE]; | ||
307 | }; | ||
308 | |||
309 | /* isochronous write buffer structure | ||
310 | * circular buffer with pad area for extraction of complete USB frames | ||
311 | * - data[read..nextread-1] is valid data already submitted to the USB subsystem | ||
312 | * - data[nextread..write-1] is valid data yet to be sent | ||
313 | * - data[write] is the next byte to write to | ||
314 | * - in byte-oriented L2 procotols, it is completely free | ||
315 | * - in bit-oriented L2 procotols, it may contain a partial byte of valid data | ||
316 | * - data[write+1..read-1] is free | ||
317 | * - wbits is the number of valid data bits in data[write], starting at the LSB | ||
318 | * - writesem is the semaphore for writing to the buffer: | ||
319 | * if writesem <= 0, data[write..read-1] is currently being written to | ||
320 | * - idle contains the byte value to repeat when the end of valid data is | ||
321 | * reached; if nextread==write (buffer contains no data to send), either the | ||
322 | * BAS_OUTBUFPAD bytes immediately before data[write] (if write>=BAS_OUTBUFPAD) | ||
323 | * or those of the pad area (if write<BAS_OUTBUFPAD) are also filled with that | ||
324 | * value | ||
325 | * - optionally, the following statistics on the buffer's usage can be collected: | ||
326 | * maxfill: maximum number of bytes occupied | ||
327 | * idlefills: number of times a frame of idle bytes is prepared | ||
328 | * emptygets: number of times the buffer was empty when a data frame was requested | ||
329 | * backtoback: number of times two data packets were entered into the buffer | ||
330 | * without intervening idle flags | ||
331 | * nakedback: set if no idle flags have been inserted since the last data packet | ||
332 | */ | ||
333 | struct isowbuf_t { | ||
334 | atomic_t read; | ||
335 | atomic_t nextread; | ||
336 | atomic_t write; | ||
337 | atomic_t writesem; | ||
338 | int wbits; | ||
339 | unsigned char data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD]; | ||
340 | unsigned char idle; | ||
341 | }; | ||
342 | |||
343 | /* isochronous write URB context structure | ||
344 | * data to be stored along with the URB and retrieved when it is returned | ||
345 | * as completed by the USB subsystem | ||
346 | * - urb: pointer to the URB itself | ||
347 | * - bcs: pointer to the B Channel control structure | ||
348 | * - limit: end of write buffer area covered by this URB | ||
349 | */ | ||
350 | struct isow_urbctx_t { | ||
351 | struct urb *urb; | ||
352 | struct bc_state *bcs; | ||
353 | int limit; | ||
354 | }; | ||
355 | |||
356 | /* AT state structure | ||
357 | * data associated with the state of an ISDN connection, whether or not | ||
358 | * it is currently assigned a B channel | ||
359 | */ | ||
360 | struct at_state_t { | ||
361 | struct list_head list; | ||
362 | int waiting; | ||
363 | int getstring; | ||
364 | atomic_t timer_index; | ||
365 | unsigned long timer_expires; | ||
366 | int timer_active; | ||
367 | unsigned int ConState; /* State of connection */ | ||
368 | struct reply_t *replystruct; | ||
369 | int cid; | ||
370 | int int_var[VAR_NUM]; /* see VAR_XXXX */ | ||
371 | char *str_var[STR_NUM]; /* see STR_XXXX */ | ||
372 | unsigned pending_commands; /* see PC_XXXX */ | ||
373 | atomic_t seq_index; | ||
374 | |||
375 | struct cardstate *cs; | ||
376 | struct bc_state *bcs; | ||
377 | }; | ||
378 | |||
379 | struct resp_type_t { | ||
380 | unsigned char *response; | ||
381 | int resp_code; /* RSP_XXXX */ | ||
382 | int type; /* RT_XXXX */ | ||
383 | }; | ||
384 | |||
385 | struct prot_skb { | ||
386 | atomic_t empty; | ||
387 | struct semaphore *sem; | ||
388 | struct sk_buff *skb; | ||
389 | }; | ||
390 | |||
391 | struct event_t { | ||
392 | int type; | ||
393 | void *ptr, *arg; | ||
394 | int parameter; | ||
395 | int cid; | ||
396 | struct at_state_t *at_state; | ||
397 | }; | ||
398 | |||
399 | /* This buffer holds all information about the used B-Channel */ | ||
400 | struct bc_state { | ||
401 | struct sk_buff *tx_skb; /* Current transfer buffer to modem */ | ||
402 | struct sk_buff_head squeue; /* B-Channel send Queue */ | ||
403 | |||
404 | /* Variables for debugging .. */ | ||
405 | int corrupted; /* Counter for corrupted packages */ | ||
406 | int trans_down; /* Counter of packages (downstream) */ | ||
407 | int trans_up; /* Counter of packages (upstream) */ | ||
408 | |||
409 | struct at_state_t at_state; | ||
410 | unsigned long rcvbytes; | ||
411 | |||
412 | __u16 fcs; | ||
413 | struct sk_buff *skb; | ||
414 | int inputstate; /* see INS_XXXX */ | ||
415 | |||
416 | int channel; | ||
417 | |||
418 | struct cardstate *cs; | ||
419 | |||
420 | unsigned chstate; /* bitmap (CHS_*) */ | ||
421 | int ignore; | ||
422 | unsigned proto2; /* Layer 2 protocol (ISDN_PROTO_L2_*) */ | ||
423 | char *commands[AT_NUM]; /* see AT_XXXX */ | ||
424 | |||
425 | #ifdef CONFIG_GIGASET_DEBUG | ||
426 | int emptycount; | ||
427 | #endif | ||
428 | int busy; | ||
429 | int use_count; | ||
430 | |||
431 | /* hardware drivers */ | ||
432 | union { | ||
433 | struct ser_bc_state *ser; /* private data of serial hardware driver */ | ||
434 | struct usb_bc_state *usb; /* private data of usb hardware driver */ | ||
435 | struct bas_bc_state *bas; | ||
436 | } hw; | ||
437 | }; | ||
438 | |||
439 | struct cardstate { | ||
440 | struct gigaset_driver *driver; | ||
441 | unsigned minor_index; | ||
442 | |||
443 | const struct gigaset_ops *ops; | ||
444 | |||
445 | /* Stuff to handle communication */ | ||
446 | //wait_queue_head_t initwait; | ||
447 | wait_queue_head_t waitqueue; | ||
448 | int waiting; | ||
449 | atomic_t mode; /* see M_XXXX */ | ||
450 | atomic_t mstate; /* Modem state: see MS_XXXX */ | ||
451 | /* only changed by the event layer */ | ||
452 | int cmd_result; | ||
453 | |||
454 | int channels; | ||
455 | struct bc_state *bcs; /* Array of struct bc_state */ | ||
456 | |||
457 | int onechannel; /* data and commands transmitted in one stream (M10x) */ | ||
458 | |||
459 | spinlock_t lock; | ||
460 | struct at_state_t at_state; /* at_state_t for cid == 0 */ | ||
461 | struct list_head temp_at_states; /* list of temporary "struct at_state_t"s without B channel */ | ||
462 | |||
463 | struct inbuf_t *inbuf; | ||
464 | |||
465 | struct cmdbuf_t *cmdbuf, *lastcmdbuf; | ||
466 | spinlock_t cmdlock; | ||
467 | unsigned curlen, cmdbytes; | ||
468 | |||
469 | unsigned open_count; | ||
470 | struct tty_struct *tty; | ||
471 | struct tasklet_struct if_wake_tasklet; | ||
472 | unsigned control_state; | ||
473 | |||
474 | unsigned fwver[4]; | ||
475 | int gotfwver; | ||
476 | |||
477 | atomic_t running; /* !=0 if events are handled */ | ||
478 | atomic_t connected; /* !=0 if hardware is connected */ | ||
479 | |||
480 | atomic_t cidmode; | ||
481 | |||
482 | int myid; /* id for communication with LL */ | ||
483 | isdn_if iif; | ||
484 | |||
485 | struct reply_t *tabnocid; | ||
486 | struct reply_t *tabcid; | ||
487 | int cs_init; | ||
488 | int ignoreframes; /* frames to ignore after setting up the B channel */ | ||
489 | struct semaphore sem; /* locks this structure: */ | ||
490 | /* connected is not changed, */ | ||
491 | /* hardware_up is not changed, */ | ||
492 | /* MState is not changed to or from MS_LOCKED */ | ||
493 | |||
494 | struct timer_list timer; | ||
495 | int retry_count; | ||
496 | int dle; /* !=0 if modem commands/responses are dle encoded */ | ||
497 | int cur_at_seq; /* sequence of AT commands being processed */ | ||
498 | int curchannel; /* channel, those commands are meant for */ | ||
499 | atomic_t commands_pending; /* flag(s) in xxx.commands_pending have been set */ | ||
500 | struct tasklet_struct event_tasklet; /* tasklet for serializing AT commands. Scheduled | ||
501 | * -> for modem reponses (and incomming data for M10x) | ||
502 | * -> on timeout | ||
503 | * -> after setting bits in xxx.at_state.pending_command | ||
504 | * (e.g. command from LL) */ | ||
505 | struct tasklet_struct write_tasklet; /* tasklet for serial output | ||
506 | * (not used in base driver) */ | ||
507 | |||
508 | /* event queue */ | ||
509 | struct event_t events[MAX_EVENTS]; | ||
510 | atomic_t ev_tail, ev_head; | ||
511 | spinlock_t ev_lock; | ||
512 | |||
513 | /* current modem response */ | ||
514 | unsigned char respdata[MAX_RESP_SIZE]; | ||
515 | unsigned cbytes; | ||
516 | |||
517 | /* hardware drivers */ | ||
518 | union { | ||
519 | struct usb_cardstate *usb; /* private data of USB hardware driver */ | ||
520 | struct ser_cardstate *ser; /* private data of serial hardware driver */ | ||
521 | struct bas_cardstate *bas; /* private data of base hardware driver */ | ||
522 | } hw; | ||
523 | }; | ||
524 | |||
525 | struct gigaset_driver { | ||
526 | struct list_head list; | ||
527 | spinlock_t lock; /* locks minor tables and blocked */ | ||
528 | //struct semaphore sem; /* locks this structure */ | ||
529 | struct tty_driver *tty; | ||
530 | unsigned have_tty; | ||
531 | unsigned minor; | ||
532 | unsigned minors; | ||
533 | struct cardstate *cs; | ||
534 | unsigned *flags; | ||
535 | int blocked; | ||
536 | |||
537 | const struct gigaset_ops *ops; | ||
538 | struct module *owner; | ||
539 | }; | ||
540 | |||
541 | struct cmdbuf_t { | ||
542 | struct cmdbuf_t *next, *prev; | ||
543 | int len, offset; | ||
544 | struct tasklet_struct *wake_tasklet; | ||
545 | unsigned char buf[0]; | ||
546 | }; | ||
547 | |||
548 | struct bas_bc_state { | ||
549 | /* isochronous output state */ | ||
550 | atomic_t running; | ||
551 | atomic_t corrbytes; | ||
552 | spinlock_t isooutlock; | ||
553 | struct isow_urbctx_t isoouturbs[BAS_OUTURBS]; | ||
554 | struct isow_urbctx_t *isooutdone, *isooutfree, *isooutovfl; | ||
555 | struct isowbuf_t *isooutbuf; | ||
556 | unsigned numsub; /* submitted URB counter (for diagnostic messages only) */ | ||
557 | struct tasklet_struct sent_tasklet; | ||
558 | |||
559 | /* isochronous input state */ | ||
560 | spinlock_t isoinlock; | ||
561 | struct urb *isoinurbs[BAS_INURBS]; | ||
562 | unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS]; | ||
563 | struct urb *isoindone; /* completed isoc read URB */ | ||
564 | int loststatus; /* status of dropped URB */ | ||
565 | unsigned isoinlost; /* number of bytes lost */ | ||
566 | /* state of bit unstuffing algorithm (in addition to BC_state.inputstate) */ | ||
567 | unsigned seqlen; /* number of '1' bits not yet unstuffed */ | ||
568 | unsigned inbyte, inbits; /* collected bits for next byte */ | ||
569 | /* statistics */ | ||
570 | unsigned goodbytes; /* bytes correctly received */ | ||
571 | unsigned alignerrs; /* frames with incomplete byte at end */ | ||
572 | unsigned fcserrs; /* FCS errors */ | ||
573 | unsigned frameerrs; /* framing errors */ | ||
574 | unsigned giants; /* long frames */ | ||
575 | unsigned runts; /* short frames */ | ||
576 | unsigned aborts; /* HDLC aborts */ | ||
577 | unsigned shared0s; /* '0' bits shared between flags */ | ||
578 | unsigned stolen0s; /* '0' stuff bits also serving as leading flag bits */ | ||
579 | struct tasklet_struct rcvd_tasklet; | ||
580 | }; | ||
581 | |||
582 | struct gigaset_ops { | ||
583 | /* Called from ev-layer.c/interface.c for sending AT commands to the device */ | ||
584 | int (*write_cmd)(struct cardstate *cs, | ||
585 | const unsigned char *buf, int len, | ||
586 | struct tasklet_struct *wake_tasklet); | ||
587 | |||
588 | /* Called from interface.c for additional device control */ | ||
589 | int (*write_room)(struct cardstate *cs); | ||
590 | int (*chars_in_buffer)(struct cardstate *cs); | ||
591 | int (*brkchars)(struct cardstate *cs, const unsigned char buf[6]); | ||
592 | |||
593 | /* Called from ev-layer.c after setting up connection | ||
594 | * Should call gigaset_bchannel_up(), when finished. */ | ||
595 | int (*init_bchannel)(struct bc_state *bcs); | ||
596 | |||
597 | /* Called from ev-layer.c after hanging up | ||
598 | * Should call gigaset_bchannel_down(), when finished. */ | ||
599 | int (*close_bchannel)(struct bc_state *bcs); | ||
600 | |||
601 | /* Called by gigaset_initcs() for setting up bcs->hw.xxx */ | ||
602 | int (*initbcshw)(struct bc_state *bcs); | ||
603 | |||
604 | /* Called by gigaset_freecs() for freeing bcs->hw.xxx */ | ||
605 | int (*freebcshw)(struct bc_state *bcs); | ||
606 | |||
607 | /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting bcs->hw.xxx */ | ||
608 | void (*reinitbcshw)(struct bc_state *bcs); | ||
609 | |||
610 | /* Called by gigaset_initcs() for setting up cs->hw.xxx */ | ||
611 | int (*initcshw)(struct cardstate *cs); | ||
612 | |||
613 | /* Called by gigaset_freecs() for freeing cs->hw.xxx */ | ||
614 | void (*freecshw)(struct cardstate *cs); | ||
615 | |||
616 | ///* Called by gigaset_stop() for killing URBs, shutting down the device, ... | ||
617 | // hardwareup: ==0: don't try to shut down the device, hardware is really not accessible | ||
618 | // !=0: hardware still up */ | ||
619 | //void (*stophw)(struct cardstate *cs, int hardwareup); | ||
620 | |||
621 | /* Called from common.c/interface.c for additional serial port control */ | ||
622 | int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, unsigned new_state); | ||
623 | int (*baud_rate)(struct cardstate *cs, unsigned cflag); | ||
624 | int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag); | ||
625 | |||
626 | /* Called from i4l.c to put an skb into the send-queue. */ | ||
627 | int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb); | ||
628 | |||
629 | /* Called from ev-layer.c to process a block of data | ||
630 | * received through the common/control channel. */ | ||
631 | void (*handle_input)(struct inbuf_t *inbuf); | ||
632 | |||
633 | }; | ||
634 | |||
635 | /* = Common structures and definitions ======================================= */ | ||
636 | |||
637 | /* Parser states for DLE-Event: | ||
638 | * <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "." | ||
639 | * <DLE_FLAG>: 0x10 | ||
640 | * <EVENT>: ((a-z)* | (A-Z)* | (0-10)*)+ | ||
641 | */ | ||
642 | #define DLE_FLAG 0x10 | ||
643 | |||
644 | /* =========================================================================== | ||
645 | * Functions implemented in asyncdata.c | ||
646 | */ | ||
647 | |||
648 | /* Called from i4l.c to put an skb into the send-queue. | ||
649 | * After sending gigaset_skb_sent() should be called. */ | ||
650 | int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb); | ||
651 | |||
652 | /* Called from ev-layer.c to process a block of data | ||
653 | * received through the common/control channel. */ | ||
654 | void gigaset_m10x_input(struct inbuf_t *inbuf); | ||
655 | |||
656 | /* =========================================================================== | ||
657 | * Functions implemented in isocdata.c | ||
658 | */ | ||
659 | |||
660 | /* Called from i4l.c to put an skb into the send-queue. | ||
661 | * After sending gigaset_skb_sent() should be called. */ | ||
662 | int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb); | ||
663 | |||
664 | /* Called from ev-layer.c to process a block of data | ||
665 | * received through the common/control channel. */ | ||
666 | void gigaset_isoc_input(struct inbuf_t *inbuf); | ||
667 | |||
668 | /* Called from bas-gigaset.c to process a block of data | ||
669 | * received through the isochronous channel */ | ||
670 | void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs); | ||
671 | |||
672 | /* Called from bas-gigaset.c to put a block of data | ||
673 | * into the isochronous output buffer */ | ||
674 | int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len); | ||
675 | |||
676 | /* Called from bas-gigaset.c to initialize the isochronous output buffer */ | ||
677 | void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle); | ||
678 | |||
679 | /* Called from bas-gigaset.c to retrieve a block of bytes for sending */ | ||
680 | int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size); | ||
681 | |||
682 | /* =========================================================================== | ||
683 | * Functions implemented in i4l.c/gigaset.h | ||
684 | */ | ||
685 | |||
686 | /* Called by gigaset_initcs() for setting up with the isdn4linux subsystem */ | ||
687 | int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid); | ||
688 | |||
689 | /* Called from xxx-gigaset.c to indicate completion of sending an skb */ | ||
690 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); | ||
691 | |||
692 | /* Called from common.c/ev-layer.c to indicate events relevant to the LL */ | ||
693 | int gigaset_isdn_icall(struct at_state_t *at_state); | ||
694 | int gigaset_isdn_setup_accept(struct at_state_t *at_state); | ||
695 | int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data); | ||
696 | |||
697 | void gigaset_i4l_cmd(struct cardstate *cs, int cmd); | ||
698 | void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd); | ||
699 | |||
700 | |||
701 | static inline void gigaset_isdn_rcv_err(struct bc_state *bcs) | ||
702 | { | ||
703 | isdn_ctrl response; | ||
704 | |||
705 | /* error -> LL */ | ||
706 | dbg(DEBUG_CMD, "sending L1ERR"); | ||
707 | response.driver = bcs->cs->myid; | ||
708 | response.command = ISDN_STAT_L1ERR; | ||
709 | response.arg = bcs->channel; | ||
710 | response.parm.errcode = ISDN_STAT_L1ERR_RECV; | ||
711 | bcs->cs->iif.statcallb(&response); | ||
712 | } | ||
713 | |||
714 | /* =========================================================================== | ||
715 | * Functions implemented in ev-layer.c | ||
716 | */ | ||
717 | |||
718 | /* tasklet called from common.c to process queued events */ | ||
719 | void gigaset_handle_event(unsigned long data); | ||
720 | |||
721 | /* called from isocdata.c / asyncdata.c | ||
722 | * when a complete modem response line has been received */ | ||
723 | void gigaset_handle_modem_response(struct cardstate *cs); | ||
724 | |||
725 | /* =========================================================================== | ||
726 | * Functions implemented in proc.c | ||
727 | */ | ||
728 | |||
729 | /* initialize sysfs for device */ | ||
730 | void gigaset_init_dev_sysfs(struct usb_interface *interface); | ||
731 | void gigaset_free_dev_sysfs(struct usb_interface *interface); | ||
732 | |||
733 | /* =========================================================================== | ||
734 | * Functions implemented in common.c/gigaset.h | ||
735 | */ | ||
736 | |||
737 | void gigaset_bcs_reinit(struct bc_state *bcs); | ||
738 | void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, | ||
739 | struct cardstate *cs, int cid); | ||
740 | int gigaset_get_channel(struct bc_state *bcs); | ||
741 | void gigaset_free_channel(struct bc_state *bcs); | ||
742 | int gigaset_get_channels(struct cardstate *cs); | ||
743 | void gigaset_free_channels(struct cardstate *cs); | ||
744 | void gigaset_block_channels(struct cardstate *cs); | ||
745 | |||
746 | /* Allocate and initialize driver structure. */ | ||
747 | struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, | ||
748 | const char *procname, | ||
749 | const char *devname, | ||
750 | const char *devfsname, | ||
751 | const struct gigaset_ops *ops, | ||
752 | struct module *owner); | ||
753 | |||
754 | /* Deallocate driver structure. */ | ||
755 | void gigaset_freedriver(struct gigaset_driver *drv); | ||
756 | void gigaset_debugdrivers(void); | ||
757 | struct cardstate *gigaset_get_cs_by_minor(unsigned minor); | ||
758 | struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); | ||
759 | struct cardstate *gigaset_get_cs_by_id(int id); | ||
760 | |||
761 | /* For drivers without fixed assignment device<->cardstate (usb) */ | ||
762 | struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv); | ||
763 | void gigaset_unassign(struct cardstate *cs); | ||
764 | void gigaset_blockdriver(struct gigaset_driver *drv); | ||
765 | |||
766 | /* Allocate and initialize card state. Calls hardware dependent gigaset_init[b]cs(). */ | ||
767 | struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | ||
768 | int onechannel, int ignoreframes, | ||
769 | int cidmode, const char *modulename); | ||
770 | |||
771 | /* Free card state. Calls hardware dependent gigaset_free[b]cs(). */ | ||
772 | void gigaset_freecs(struct cardstate *cs); | ||
773 | |||
774 | /* Tell common.c that hardware and driver are ready. */ | ||
775 | int gigaset_start(struct cardstate *cs); | ||
776 | |||
777 | /* Tell common.c that the device is not present any more. */ | ||
778 | void gigaset_stop(struct cardstate *cs); | ||
779 | |||
780 | /* Tell common.c that the driver is being unloaded. */ | ||
781 | void gigaset_shutdown(struct cardstate *cs); | ||
782 | |||
783 | /* Tell common.c that an skb has been sent. */ | ||
784 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); | ||
785 | |||
786 | /* Append event to the queue. | ||
787 | * Returns NULL on failure or a pointer to the event on success. | ||
788 | * ptr must be kmalloc()ed (and not be freed by the caller). | ||
789 | */ | ||
790 | struct event_t *gigaset_add_event(struct cardstate *cs, | ||
791 | struct at_state_t *at_state, int type, | ||
792 | void *ptr, int parameter, void *arg); | ||
793 | |||
794 | /* Called on CONFIG1 command from frontend. */ | ||
795 | int gigaset_enterconfigmode(struct cardstate *cs); //0: success <0: errorcode | ||
796 | |||
797 | /* cs->lock must not be locked */ | ||
798 | static inline void gigaset_schedule_event(struct cardstate *cs) | ||
799 | { | ||
800 | unsigned long flags; | ||
801 | spin_lock_irqsave(&cs->lock, flags); | ||
802 | if (atomic_read(&cs->running)) | ||
803 | tasklet_schedule(&cs->event_tasklet); | ||
804 | spin_unlock_irqrestore(&cs->lock, flags); | ||
805 | } | ||
806 | |||
807 | /* Tell common.c that B channel has been closed. */ | ||
808 | /* cs->lock must not be locked */ | ||
809 | static inline void gigaset_bchannel_down(struct bc_state *bcs) | ||
810 | { | ||
811 | gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL); | ||
812 | |||
813 | dbg(DEBUG_CMD, "scheduling BC_CLOSED"); | ||
814 | gigaset_schedule_event(bcs->cs); | ||
815 | } | ||
816 | |||
817 | /* Tell common.c that B channel has been opened. */ | ||
818 | /* cs->lock must not be locked */ | ||
819 | static inline void gigaset_bchannel_up(struct bc_state *bcs) | ||
820 | { | ||
821 | gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL); | ||
822 | |||
823 | dbg(DEBUG_CMD, "scheduling BC_OPEN"); | ||
824 | gigaset_schedule_event(bcs->cs); | ||
825 | } | ||
826 | |||
827 | /* handling routines for sk_buff */ | ||
828 | /* ============================= */ | ||
829 | |||
830 | /* private version of __skb_put() | ||
831 | * append 'len' bytes to the content of 'skb', already knowing that the | ||
832 | * existing buffer can accomodate them | ||
833 | * returns a pointer to the location where the new bytes should be copied to | ||
834 | * This function does not take any locks so it must be called with the | ||
835 | * appropriate locks held only. | ||
836 | */ | ||
837 | static inline unsigned char *gigaset_skb_put_quick(struct sk_buff *skb, | ||
838 | unsigned int len) | ||
839 | { | ||
840 | unsigned char *tmp = skb->tail; | ||
841 | /*SKB_LINEAR_ASSERT(skb);*/ /* not needed here */ | ||
842 | skb->tail += len; | ||
843 | skb->len += len; | ||
844 | return tmp; | ||
845 | } | ||
846 | |||
847 | /* pass received skb to LL | ||
848 | * Warning: skb must not be accessed anymore! | ||
849 | */ | ||
850 | static inline void gigaset_rcv_skb(struct sk_buff *skb, | ||
851 | struct cardstate *cs, | ||
852 | struct bc_state *bcs) | ||
853 | { | ||
854 | cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb); | ||
855 | bcs->trans_down++; | ||
856 | } | ||
857 | |||
858 | /* handle reception of corrupted skb | ||
859 | * Warning: skb must not be accessed anymore! | ||
860 | */ | ||
861 | static inline void gigaset_rcv_error(struct sk_buff *procskb, | ||
862 | struct cardstate *cs, | ||
863 | struct bc_state *bcs) | ||
864 | { | ||
865 | if (procskb) | ||
866 | dev_kfree_skb(procskb); | ||
867 | |||
868 | if (bcs->ignore) | ||
869 | --bcs->ignore; | ||
870 | else { | ||
871 | ++bcs->corrupted; | ||
872 | gigaset_isdn_rcv_err(bcs); | ||
873 | } | ||
874 | } | ||
875 | |||
876 | |||
877 | /* bitwise byte inversion table */ | ||
878 | extern __u8 gigaset_invtab[]; /* in common.c */ | ||
879 | |||
880 | |||
881 | /* append received bytes to inbuf */ | ||
882 | static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf, | ||
883 | const unsigned char *src, | ||
884 | unsigned numbytes) | ||
885 | { | ||
886 | unsigned n, head, tail, bytesleft; | ||
887 | |||
888 | dbg(DEBUG_INTR, "received %u bytes", numbytes); | ||
889 | |||
890 | if (!numbytes) | ||
891 | return 0; | ||
892 | |||
893 | bytesleft = numbytes; | ||
894 | tail = atomic_read(&inbuf->tail); | ||
895 | head = atomic_read(&inbuf->head); | ||
896 | dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); | ||
897 | |||
898 | while (bytesleft) { | ||
899 | if (head > tail) | ||
900 | n = head - 1 - tail; | ||
901 | else if (head == 0) | ||
902 | n = (RBUFSIZE-1) - tail; | ||
903 | else | ||
904 | n = RBUFSIZE - tail; | ||
905 | if (!n) { | ||
906 | err("buffer overflow (%u bytes lost)", bytesleft); | ||
907 | break; | ||
908 | } | ||
909 | if (n > bytesleft) | ||
910 | n = bytesleft; | ||
911 | memcpy(inbuf->data + tail, src, n); | ||
912 | bytesleft -= n; | ||
913 | tail = (tail + n) % RBUFSIZE; | ||
914 | src += n; | ||
915 | } | ||
916 | dbg(DEBUG_INTR, "setting tail to %u", tail); | ||
917 | atomic_set(&inbuf->tail, tail); | ||
918 | return numbytes != bytesleft; | ||
919 | } | ||
920 | |||
921 | /* =========================================================================== | ||
922 | * Functions implemented in interface.c | ||
923 | */ | ||
924 | |||
925 | /* initialize interface */ | ||
926 | void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, | ||
927 | const char *devname, const char *devfsname); | ||
928 | /* release interface */ | ||
929 | void gigaset_if_freedriver(struct gigaset_driver *drv); | ||
930 | /* add minor */ | ||
931 | void gigaset_if_init(struct cardstate *cs); | ||
932 | /* remove minor */ | ||
933 | void gigaset_if_free(struct cardstate *cs); | ||
934 | /* device received data */ | ||
935 | void gigaset_if_receive(struct cardstate *cs, | ||
936 | unsigned char *buffer, size_t len); | ||
937 | |||
938 | #endif | ||
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c new file mode 100644 index 000000000000..731a675f21b0 --- /dev/null +++ b/drivers/isdn/gigaset/i4l.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * Stuff used by all variants of the driver | ||
3 | * | ||
4 | * Copyright (c) 2001 by Stefan Eilers (Eilers.Stefan@epost.de), | ||
5 | * Hansjoerg Lipp (hjlipp@web.de), | ||
6 | * Tilman Schmidt (tilman@imap.cc). | ||
7 | * | ||
8 | * ===================================================================== | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of | ||
12 | * the License, or (at your option) any later version. | ||
13 | * ===================================================================== | ||
14 | * ToDo: ... | ||
15 | * ===================================================================== | ||
16 | * Version: $Id: i4l.c,v 1.3.2.9 2006/02/04 18:28:16 hjlipp Exp $ | ||
17 | * ===================================================================== | ||
18 | */ | ||
19 | |||
20 | #include "gigaset.h" | ||
21 | |||
22 | /* == Handling of I4L IO ============================================================================*/ | ||
23 | |||
24 | /* writebuf_from_LL | ||
25 | * called by LL to transmit data on an open channel | ||
26 | * inserts the buffer data into the send queue and starts the transmission | ||
27 | * Note that this operation must not sleep! | ||
28 | * When the buffer is processed completely, gigaset_skb_sent() should be called. | ||
29 | * parameters: | ||
30 | * driverID driver ID as assigned by LL | ||
31 | * channel channel number | ||
32 | * ack if != 0 LL wants to be notified on completion via statcallb(ISDN_STAT_BSENT) | ||
33 | * skb skb containing data to send | ||
34 | * return value: | ||
35 | * number of accepted bytes | ||
36 | * 0 if temporarily unable to accept data (out of buffer space) | ||
37 | * <0 on error (eg. -EINVAL) | ||
38 | */ | ||
39 | static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *skb) | ||
40 | { | ||
41 | struct cardstate *cs; | ||
42 | struct bc_state *bcs; | ||
43 | unsigned len; | ||
44 | unsigned skblen; | ||
45 | |||
46 | if (!(cs = gigaset_get_cs_by_id(driverID))) { | ||
47 | err("%s: invalid driver ID (%d)", __func__, driverID); | ||
48 | return -ENODEV; | ||
49 | } | ||
50 | if (channel < 0 || channel >= cs->channels) { | ||
51 | err("%s: invalid channel ID (%d)", __func__, channel); | ||
52 | return -ENODEV; | ||
53 | } | ||
54 | bcs = &cs->bcs[channel]; | ||
55 | len = skb->len; | ||
56 | |||
57 | dbg(DEBUG_LLDATA, | ||
58 | "Receiving data from LL (id: %d, channel: %d, ack: %d, size: %d)", | ||
59 | driverID, channel, ack, len); | ||
60 | |||
61 | if (!len) { | ||
62 | if (ack) | ||
63 | warn("not ACKing empty packet from LL"); | ||
64 | return 0; | ||
65 | } | ||
66 | if (len > MAX_BUF_SIZE) { | ||
67 | err("%s: packet too large (%d bytes)", __func__, channel); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | if (!atomic_read(&cs->connected)) | ||
72 | return -ENODEV; | ||
73 | |||
74 | skblen = ack ? len : 0; | ||
75 | skb->head[0] = skblen & 0xff; | ||
76 | skb->head[1] = skblen >> 8; | ||
77 | dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", len, skblen, | ||
78 | (unsigned) skb->head[0], (unsigned) skb->head[1]); | ||
79 | |||
80 | /* pass to device-specific module */ | ||
81 | return cs->ops->send_skb(bcs, skb); | ||
82 | } | ||
83 | |||
84 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) | ||
85 | { | ||
86 | unsigned len; | ||
87 | isdn_ctrl response; | ||
88 | |||
89 | ++bcs->trans_up; | ||
90 | |||
91 | if (skb->len) | ||
92 | warn("%s: skb->len==%d", __func__, skb->len); | ||
93 | |||
94 | len = (unsigned char) skb->head[0] | | ||
95 | (unsigned) (unsigned char) skb->head[1] << 8; | ||
96 | if (len) { | ||
97 | dbg(DEBUG_MCMD, | ||
98 | "Acknowledge sending to LL (id: %d, channel: %d size: %u)", | ||
99 | bcs->cs->myid, bcs->channel, len); | ||
100 | |||
101 | response.driver = bcs->cs->myid; | ||
102 | response.command = ISDN_STAT_BSENT; | ||
103 | response.arg = bcs->channel; | ||
104 | response.parm.length = len; | ||
105 | bcs->cs->iif.statcallb(&response); | ||
106 | } | ||
107 | } | ||
108 | EXPORT_SYMBOL_GPL(gigaset_skb_sent); | ||
109 | |||
110 | /* This function will be called by LL to send commands | ||
111 | * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL, | ||
112 | * so don't put too much effort into it. | ||
113 | */ | ||
114 | static int command_from_LL(isdn_ctrl *cntrl) | ||
115 | { | ||
116 | struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver); | ||
117 | //isdn_ctrl response; | ||
118 | //unsigned long flags; | ||
119 | struct bc_state *bcs; | ||
120 | int retval = 0; | ||
121 | struct setup_parm *sp; | ||
122 | |||
123 | //dbg(DEBUG_ANY, "Gigaset_HW: Receiving command"); | ||
124 | gigaset_debugdrivers(); | ||
125 | |||
126 | /* Terminate this call if no device is present. Bt if the command is "ISDN_CMD_LOCK" or | ||
127 | * "ISDN_CMD_UNLOCK" then execute it due to the fact that they are device independent ! | ||
128 | */ | ||
129 | //FIXME "remove test for &connected" | ||
130 | if ((!cs || !atomic_read(&cs->connected))) { | ||
131 | warn("LL tried to access unknown device with nr. %d", | ||
132 | cntrl->driver); | ||
133 | return -ENODEV; | ||
134 | } | ||
135 | |||
136 | switch (cntrl->command) { | ||
137 | case ISDN_CMD_IOCTL: | ||
138 | |||
139 | dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver:%d,arg: %ld)", | ||
140 | cntrl->driver, cntrl->arg); | ||
141 | |||
142 | warn("ISDN_CMD_IOCTL is not supported."); | ||
143 | return -EINVAL; | ||
144 | |||
145 | case ISDN_CMD_DIAL: | ||
146 | dbg(DEBUG_ANY, "ISDN_CMD_DIAL (driver: %d, channel: %ld, " | ||
147 | "phone: %s,ownmsn: %s, si1: %d, si2: %d)", | ||
148 | cntrl->driver, cntrl->arg, | ||
149 | cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn, | ||
150 | cntrl->parm.setup.si1, cntrl->parm.setup.si2); | ||
151 | |||
152 | if (cntrl->arg >= cs->channels) { | ||
153 | err("invalid channel (%d)", (int) cntrl->arg); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | bcs = cs->bcs + cntrl->arg; | ||
158 | |||
159 | if (!gigaset_get_channel(bcs)) { | ||
160 | err("channel not free"); | ||
161 | return -EBUSY; | ||
162 | } | ||
163 | |||
164 | sp = kmalloc(sizeof *sp, GFP_ATOMIC); | ||
165 | if (!sp) { | ||
166 | gigaset_free_channel(bcs); | ||
167 | err("ISDN_CMD_DIAL: out of memory"); | ||
168 | return -ENOMEM; | ||
169 | } | ||
170 | *sp = cntrl->parm.setup; | ||
171 | |||
172 | if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, | ||
173 | atomic_read(&bcs->at_state.seq_index), | ||
174 | NULL)) { | ||
175 | //FIXME what should we do? | ||
176 | kfree(sp); | ||
177 | gigaset_free_channel(bcs); | ||
178 | return -ENOMEM; | ||
179 | } | ||
180 | |||
181 | dbg(DEBUG_CMD, "scheduling DIAL"); | ||
182 | gigaset_schedule_event(cs); | ||
183 | break; | ||
184 | case ISDN_CMD_ACCEPTD: //FIXME | ||
185 | dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD"); | ||
186 | |||
187 | if (cntrl->arg >= cs->channels) { | ||
188 | err("invalid channel (%d)", (int) cntrl->arg); | ||
189 | return -EINVAL; | ||
190 | } | ||
191 | |||
192 | if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state, | ||
193 | EV_ACCEPT, NULL, 0, NULL)) { | ||
194 | //FIXME what should we do? | ||
195 | return -ENOMEM; | ||
196 | } | ||
197 | |||
198 | dbg(DEBUG_CMD, "scheduling ACCEPT"); | ||
199 | gigaset_schedule_event(cs); | ||
200 | |||
201 | break; | ||
202 | case ISDN_CMD_ACCEPTB: | ||
203 | dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB"); | ||
204 | break; | ||
205 | case ISDN_CMD_HANGUP: | ||
206 | dbg(DEBUG_ANY, | ||
207 | "ISDN_CMD_HANGUP (channel: %d)", (int) cntrl->arg); | ||
208 | |||
209 | if (cntrl->arg >= cs->channels) { | ||
210 | err("ISDN_CMD_HANGUP: invalid channel (%u)", | ||
211 | (unsigned) cntrl->arg); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state, | ||
216 | EV_HUP, NULL, 0, NULL)) { | ||
217 | //FIXME what should we do? | ||
218 | return -ENOMEM; | ||
219 | } | ||
220 | |||
221 | dbg(DEBUG_CMD, "scheduling HUP"); | ||
222 | gigaset_schedule_event(cs); | ||
223 | |||
224 | break; | ||
225 | case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME | ||
226 | dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ"); | ||
227 | break; | ||
228 | case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME | ||
229 | dbg(DEBUG_ANY, | ||
230 | "ISDN_CMD_SETEAZ (id:%d, channel: %ld, number: %s)", | ||
231 | cntrl->driver, cntrl->arg, cntrl->parm.num); | ||
232 | break; | ||
233 | case ISDN_CMD_SETL2: /* Set L2 to given protocol */ | ||
234 | dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (Channel: %ld, Proto: %lx)", | ||
235 | cntrl->arg & 0xff, (cntrl->arg >> 8)); | ||
236 | |||
237 | if ((cntrl->arg & 0xff) >= cs->channels) { | ||
238 | err("invalid channel (%u)", | ||
239 | (unsigned) cntrl->arg & 0xff); | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | |||
243 | if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state, | ||
244 | EV_PROTO_L2, NULL, cntrl->arg >> 8, | ||
245 | NULL)) { | ||
246 | //FIXME what should we do? | ||
247 | return -ENOMEM; | ||
248 | } | ||
249 | |||
250 | dbg(DEBUG_CMD, "scheduling PROTO_L2"); | ||
251 | gigaset_schedule_event(cs); | ||
252 | break; | ||
253 | case ISDN_CMD_SETL3: /* Set L3 to given protocol */ | ||
254 | dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (Channel: %ld, Proto: %lx)", | ||
255 | cntrl->arg & 0xff, (cntrl->arg >> 8)); | ||
256 | |||
257 | if ((cntrl->arg & 0xff) >= cs->channels) { | ||
258 | err("invalid channel (%u)", | ||
259 | (unsigned) cntrl->arg & 0xff); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) { | ||
264 | err("invalid protocol %lu", cntrl->arg >> 8); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | |||
268 | break; | ||
269 | case ISDN_CMD_PROCEED: | ||
270 | dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME | ||
271 | break; | ||
272 | case ISDN_CMD_ALERT: | ||
273 | dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME | ||
274 | if (cntrl->arg >= cs->channels) { | ||
275 | err("invalid channel (%d)", (int) cntrl->arg); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | //bcs = cs->bcs + cntrl->arg; | ||
279 | //bcs->proto2 = -1; | ||
280 | // FIXME | ||
281 | break; | ||
282 | case ISDN_CMD_REDIR: | ||
283 | dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME | ||
284 | break; | ||
285 | case ISDN_CMD_PROT_IO: | ||
286 | dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO"); | ||
287 | break; | ||
288 | case ISDN_CMD_FAXCMD: | ||
289 | dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD"); | ||
290 | break; | ||
291 | case ISDN_CMD_GETL2: | ||
292 | dbg(DEBUG_ANY, "ISDN_CMD_GETL2"); | ||
293 | break; | ||
294 | case ISDN_CMD_GETL3: | ||
295 | dbg(DEBUG_ANY, "ISDN_CMD_GETL3"); | ||
296 | break; | ||
297 | case ISDN_CMD_GETEAZ: | ||
298 | dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ"); | ||
299 | break; | ||
300 | case ISDN_CMD_SETSIL: | ||
301 | dbg(DEBUG_ANY, "ISDN_CMD_SETSIL"); | ||
302 | break; | ||
303 | case ISDN_CMD_GETSIL: | ||
304 | dbg(DEBUG_ANY, "ISDN_CMD_GETSIL"); | ||
305 | break; | ||
306 | default: | ||
307 | err("unknown command %d from LL", | ||
308 | cntrl->command); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | return retval; | ||
313 | } | ||
314 | |||
315 | void gigaset_i4l_cmd(struct cardstate *cs, int cmd) | ||
316 | { | ||
317 | isdn_ctrl command; | ||
318 | |||
319 | command.driver = cs->myid; | ||
320 | command.command = cmd; | ||
321 | command.arg = 0; | ||
322 | cs->iif.statcallb(&command); | ||
323 | } | ||
324 | |||
325 | void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd) | ||
326 | { | ||
327 | isdn_ctrl command; | ||
328 | |||
329 | command.driver = bcs->cs->myid; | ||
330 | command.command = cmd; | ||
331 | command.arg = bcs->channel; | ||
332 | bcs->cs->iif.statcallb(&command); | ||
333 | } | ||
334 | |||
335 | int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data) | ||
336 | { | ||
337 | struct bc_state *bcs = at_state->bcs; | ||
338 | unsigned proto; | ||
339 | const char *bc; | ||
340 | size_t length[AT_NUM]; | ||
341 | size_t l; | ||
342 | int i; | ||
343 | struct setup_parm *sp = data; | ||
344 | |||
345 | switch (bcs->proto2) { | ||
346 | case ISDN_PROTO_L2_HDLC: | ||
347 | proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */ | ||
348 | break; | ||
349 | case ISDN_PROTO_L2_TRANS: | ||
350 | proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */ | ||
351 | break; | ||
352 | default: | ||
353 | err("invalid protocol: %u", bcs->proto2); | ||
354 | return -EINVAL; | ||
355 | } | ||
356 | |||
357 | switch (sp->si1) { | ||
358 | case 1: /* audio */ | ||
359 | bc = "9090A3"; /* 3.1 kHz audio, A-law */ | ||
360 | break; | ||
361 | case 7: /* data */ | ||
362 | default: /* hope the app knows what it is doing */ | ||
363 | bc = "8890"; /* unrestricted digital information */ | ||
364 | } | ||
365 | //FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC | ||
366 | |||
367 | length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1; | ||
368 | l = strlen(sp->eazmsn); | ||
369 | length[AT_MSN ] = l ? 6 + l + 1 + 1 : 0; | ||
370 | length[AT_BC ] = 5 + strlen(bc) + 1 + 1; | ||
371 | length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */ | ||
372 | length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */ | ||
373 | length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */ | ||
374 | length[AT_HLC ] = 0; | ||
375 | |||
376 | for (i = 0; i < AT_NUM; ++i) { | ||
377 | kfree(bcs->commands[i]); | ||
378 | bcs->commands[i] = NULL; | ||
379 | if (length[i] && | ||
380 | !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) { | ||
381 | err("out of memory"); | ||
382 | return -ENOMEM; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */ | ||
387 | if (sp->phone[0] == '*' && sp->phone[1] == '*') { | ||
388 | /* internal call: translate ** prefix to CTP value */ | ||
389 | snprintf(bcs->commands[AT_DIAL], length[AT_DIAL], | ||
390 | "D%s\r", sp->phone+2); | ||
391 | strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]); | ||
392 | } else { | ||
393 | snprintf(bcs->commands[AT_DIAL], length[AT_DIAL], | ||
394 | "D%s\r", sp->phone); | ||
395 | strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]); | ||
396 | } | ||
397 | |||
398 | if (bcs->commands[AT_MSN]) | ||
399 | snprintf(bcs->commands[AT_MSN], length[AT_MSN], "^SMSN=%s\r", sp->eazmsn); | ||
400 | snprintf(bcs->commands[AT_BC ], length[AT_BC ], "^SBC=%s\r", bc); | ||
401 | snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto); | ||
402 | snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned)bcs->channel + 1); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | int gigaset_isdn_setup_accept(struct at_state_t *at_state) | ||
408 | { | ||
409 | unsigned proto; | ||
410 | size_t length[AT_NUM]; | ||
411 | int i; | ||
412 | struct bc_state *bcs = at_state->bcs; | ||
413 | |||
414 | switch (bcs->proto2) { | ||
415 | case ISDN_PROTO_L2_HDLC: | ||
416 | proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */ | ||
417 | break; | ||
418 | case ISDN_PROTO_L2_TRANS: | ||
419 | proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */ | ||
420 | break; | ||
421 | default: | ||
422 | err("invalid protocol: %u", bcs->proto2); | ||
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | length[AT_DIAL ] = 0; | ||
427 | length[AT_MSN ] = 0; | ||
428 | length[AT_BC ] = 0; | ||
429 | length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */ | ||
430 | length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */ | ||
431 | length[AT_TYPE ] = 0; | ||
432 | length[AT_HLC ] = 0; | ||
433 | |||
434 | for (i = 0; i < AT_NUM; ++i) { | ||
435 | kfree(bcs->commands[i]); | ||
436 | bcs->commands[i] = NULL; | ||
437 | if (length[i] && | ||
438 | !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) { | ||
439 | err("out of memory"); | ||
440 | return -ENOMEM; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto); | ||
445 | snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned) bcs->channel + 1); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | int gigaset_isdn_icall(struct at_state_t *at_state) | ||
451 | { | ||
452 | struct cardstate *cs = at_state->cs; | ||
453 | struct bc_state *bcs = at_state->bcs; | ||
454 | isdn_ctrl response; | ||
455 | int retval; | ||
456 | |||
457 | /* fill ICALL structure */ | ||
458 | response.parm.setup.si1 = 0; /* default: unknown */ | ||
459 | response.parm.setup.si2 = 0; | ||
460 | response.parm.setup.screen = 0; //FIXME how to set these? | ||
461 | response.parm.setup.plan = 0; | ||
462 | if (!at_state->str_var[STR_ZBC]) { | ||
463 | /* no BC (internal call): assume speech, A-law */ | ||
464 | response.parm.setup.si1 = 1; | ||
465 | } else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) { | ||
466 | /* unrestricted digital information */ | ||
467 | response.parm.setup.si1 = 7; | ||
468 | } else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) { | ||
469 | /* speech, A-law */ | ||
470 | response.parm.setup.si1 = 1; | ||
471 | } else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) { | ||
472 | /* 3,1 kHz audio, A-law */ | ||
473 | response.parm.setup.si1 = 1; | ||
474 | response.parm.setup.si2 = 2; | ||
475 | } else { | ||
476 | warn("RING ignored - unsupported BC %s", | ||
477 | at_state->str_var[STR_ZBC]); | ||
478 | return ICALL_IGNORE; | ||
479 | } | ||
480 | if (at_state->str_var[STR_NMBR]) { | ||
481 | strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR], | ||
482 | sizeof response.parm.setup.phone - 1); | ||
483 | response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0; | ||
484 | } else | ||
485 | response.parm.setup.phone[0] = 0; | ||
486 | if (at_state->str_var[STR_ZCPN]) { | ||
487 | strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN], | ||
488 | sizeof response.parm.setup.eazmsn - 1); | ||
489 | response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0; | ||
490 | } else | ||
491 | response.parm.setup.eazmsn[0] = 0; | ||
492 | |||
493 | if (!bcs) { | ||
494 | notice("no channel for incoming call"); | ||
495 | dbg(DEBUG_CMD, "Sending ICALLW"); | ||
496 | response.command = ISDN_STAT_ICALLW; | ||
497 | response.arg = 0; //FIXME | ||
498 | } else { | ||
499 | dbg(DEBUG_CMD, "Sending ICALL"); | ||
500 | response.command = ISDN_STAT_ICALL; | ||
501 | response.arg = bcs->channel; //FIXME | ||
502 | } | ||
503 | response.driver = cs->myid; | ||
504 | retval = cs->iif.statcallb(&response); | ||
505 | dbg(DEBUG_CMD, "Response: %d", retval); | ||
506 | switch (retval) { | ||
507 | case 0: /* no takers */ | ||
508 | return ICALL_IGNORE; | ||
509 | case 1: /* alerting */ | ||
510 | bcs->chstate |= CHS_NOTIFY_LL; | ||
511 | return ICALL_ACCEPT; | ||
512 | case 2: /* reject */ | ||
513 | return ICALL_REJECT; | ||
514 | case 3: /* incomplete */ | ||
515 | warn("LL requested unsupported feature: Incomplete Number"); | ||
516 | return ICALL_IGNORE; | ||
517 | case 4: /* proceeding */ | ||
518 | /* Gigaset will send ALERTING anyway. | ||
519 | * There doesn't seem to be a way to avoid this. | ||
520 | */ | ||
521 | return ICALL_ACCEPT; | ||
522 | case 5: /* deflect */ | ||
523 | warn("LL requested unsupported feature: Call Deflection"); | ||
524 | return ICALL_IGNORE; | ||
525 | default: | ||
526 | err("LL error %d on ICALL", retval); | ||
527 | return ICALL_IGNORE; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | /* Set Callback function pointer */ | ||
532 | int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) | ||
533 | { | ||
534 | isdn_if *iif = &cs->iif; | ||
535 | |||
536 | dbg(DEBUG_ANY, "Register driver capabilities to LL"); | ||
537 | |||
538 | //iif->id[sizeof(iif->id) - 1]=0; | ||
539 | //strncpy(iif->id, isdnid, sizeof(iif->id) - 1); | ||
540 | if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) | ||
541 | >= sizeof iif->id) | ||
542 | return -ENOMEM; //FIXME EINVAL/...?? | ||
543 | |||
544 | iif->owner = THIS_MODULE; | ||
545 | iif->channels = cs->channels; /* I am supporting just one channel *//* I was supporting...*/ | ||
546 | iif->maxbufsize = MAX_BUF_SIZE; | ||
547 | iif->features = ISDN_FEATURE_L2_TRANS | /* Our device is very advanced, therefore */ | ||
548 | ISDN_FEATURE_L2_HDLC | | ||
549 | #ifdef GIG_X75 | ||
550 | ISDN_FEATURE_L2_X75I | | ||
551 | #endif | ||
552 | ISDN_FEATURE_L3_TRANS | | ||
553 | ISDN_FEATURE_P_EURO; | ||
554 | iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */ | ||
555 | iif->command = command_from_LL; | ||
556 | iif->writebuf_skb = writebuf_from_LL; | ||
557 | iif->writecmd = NULL; /* Don't support isdnctrl */ | ||
558 | iif->readstat = NULL; /* Don't support isdnctrl */ | ||
559 | iif->rcvcallb_skb = NULL; /* Will be set by LL */ | ||
560 | iif->statcallb = NULL; /* Will be set by LL */ | ||
561 | |||
562 | if (!register_isdn(iif)) | ||
563 | return 0; | ||
564 | |||
565 | cs->myid = iif->channels; /* Set my device id */ | ||
566 | return 1; | ||
567 | } | ||
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c new file mode 100644 index 000000000000..3a81d9c65141 --- /dev/null +++ b/drivers/isdn/gigaset/interface.c | |||
@@ -0,0 +1,718 @@ | |||
1 | /* | ||
2 | * interface to user space for the gigaset driver | ||
3 | * | ||
4 | * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de> | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of | ||
10 | * the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * Version: $Id: interface.c,v 1.14.4.15 2006/02/04 18:28:16 hjlipp Exp $ | ||
13 | * ===================================================================== | ||
14 | */ | ||
15 | |||
16 | #include "gigaset.h" | ||
17 | #include <linux/gigaset_dev.h> | ||
18 | #include <linux/tty.h> | ||
19 | #include <linux/tty_flip.h> | ||
20 | |||
21 | /*** our ioctls ***/ | ||
22 | |||
23 | static int if_lock(struct cardstate *cs, int *arg) | ||
24 | { | ||
25 | int cmd = *arg; | ||
26 | |||
27 | dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd); | ||
28 | |||
29 | if (cmd > 1) | ||
30 | return -EINVAL; | ||
31 | |||
32 | if (cmd < 0) { | ||
33 | *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove? | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED | ||
38 | && atomic_read(&cs->connected)) { | ||
39 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); | ||
40 | cs->ops->baud_rate(cs, B115200); | ||
41 | cs->ops->set_line_ctrl(cs, CS8); | ||
42 | cs->control_state = TIOCM_DTR|TIOCM_RTS; | ||
43 | } | ||
44 | |||
45 | cs->waiting = 1; | ||
46 | if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK, | ||
47 | NULL, cmd, NULL)) { | ||
48 | cs->waiting = 0; | ||
49 | return -ENOMEM; | ||
50 | } | ||
51 | |||
52 | dbg(DEBUG_CMD, "scheduling IF_LOCK"); | ||
53 | gigaset_schedule_event(cs); | ||
54 | |||
55 | wait_event(cs->waitqueue, !cs->waiting); | ||
56 | |||
57 | if (cs->cmd_result >= 0) { | ||
58 | *arg = cs->cmd_result; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | return cs->cmd_result; | ||
63 | } | ||
64 | |||
65 | static int if_version(struct cardstate *cs, unsigned arg[4]) | ||
66 | { | ||
67 | static const unsigned version[4] = GIG_VERSION; | ||
68 | static const unsigned compat[4] = GIG_COMPAT; | ||
69 | unsigned cmd = arg[0]; | ||
70 | |||
71 | dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd); | ||
72 | |||
73 | switch (cmd) { | ||
74 | case GIGVER_DRIVER: | ||
75 | memcpy(arg, version, sizeof version); | ||
76 | return 0; | ||
77 | case GIGVER_COMPAT: | ||
78 | memcpy(arg, compat, sizeof compat); | ||
79 | return 0; | ||
80 | case GIGVER_FWBASE: | ||
81 | cs->waiting = 1; | ||
82 | if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER, | ||
83 | NULL, 0, arg)) { | ||
84 | cs->waiting = 0; | ||
85 | return -ENOMEM; | ||
86 | } | ||
87 | |||
88 | dbg(DEBUG_CMD, "scheduling IF_VER"); | ||
89 | gigaset_schedule_event(cs); | ||
90 | |||
91 | wait_event(cs->waitqueue, !cs->waiting); | ||
92 | |||
93 | if (cs->cmd_result >= 0) | ||
94 | return 0; | ||
95 | |||
96 | return cs->cmd_result; | ||
97 | default: | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static int if_config(struct cardstate *cs, int *arg) | ||
103 | { | ||
104 | dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg); | ||
105 | |||
106 | if (*arg != 1) | ||
107 | return -EINVAL; | ||
108 | |||
109 | if (atomic_read(&cs->mstate) != MS_LOCKED) | ||
110 | return -EBUSY; | ||
111 | |||
112 | *arg = 0; | ||
113 | return gigaset_enterconfigmode(cs); | ||
114 | } | ||
115 | |||
116 | /*** the terminal driver ***/ | ||
117 | /* stolen from usbserial and some other tty drivers */ | ||
118 | |||
119 | static int if_open(struct tty_struct *tty, struct file *filp); | ||
120 | static void if_close(struct tty_struct *tty, struct file *filp); | ||
121 | static int if_ioctl(struct tty_struct *tty, struct file *file, | ||
122 | unsigned int cmd, unsigned long arg); | ||
123 | static int if_write_room(struct tty_struct *tty); | ||
124 | static int if_chars_in_buffer(struct tty_struct *tty); | ||
125 | static void if_throttle(struct tty_struct *tty); | ||
126 | static void if_unthrottle(struct tty_struct *tty); | ||
127 | static void if_set_termios(struct tty_struct *tty, struct termios *old); | ||
128 | static int if_tiocmget(struct tty_struct *tty, struct file *file); | ||
129 | static int if_tiocmset(struct tty_struct *tty, struct file *file, | ||
130 | unsigned int set, unsigned int clear); | ||
131 | static int if_write(struct tty_struct *tty, | ||
132 | const unsigned char *buf, int count); | ||
133 | |||
134 | static struct tty_operations if_ops = { | ||
135 | .open = if_open, | ||
136 | .close = if_close, | ||
137 | .ioctl = if_ioctl, | ||
138 | .write = if_write, | ||
139 | .write_room = if_write_room, | ||
140 | .chars_in_buffer = if_chars_in_buffer, | ||
141 | .set_termios = if_set_termios, | ||
142 | .throttle = if_throttle, | ||
143 | .unthrottle = if_unthrottle, | ||
144 | #if 0 | ||
145 | .break_ctl = serial_break, | ||
146 | #endif | ||
147 | .tiocmget = if_tiocmget, | ||
148 | .tiocmset = if_tiocmset, | ||
149 | }; | ||
150 | |||
151 | static int if_open(struct tty_struct *tty, struct file *filp) | ||
152 | { | ||
153 | struct cardstate *cs; | ||
154 | unsigned long flags; | ||
155 | |||
156 | dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, | ||
157 | __FUNCTION__); | ||
158 | |||
159 | tty->driver_data = NULL; | ||
160 | |||
161 | cs = gigaset_get_cs_by_tty(tty); | ||
162 | if (!cs) | ||
163 | return -ENODEV; | ||
164 | |||
165 | if (down_interruptible(&cs->sem)) | ||
166 | return -ERESTARTSYS; // FIXME -EINTR? | ||
167 | tty->driver_data = cs; | ||
168 | |||
169 | ++cs->open_count; | ||
170 | |||
171 | if (cs->open_count == 1) { | ||
172 | spin_lock_irqsave(&cs->lock, flags); | ||
173 | cs->tty = tty; | ||
174 | spin_unlock_irqrestore(&cs->lock, flags); | ||
175 | tty->low_latency = 1; //FIXME test | ||
176 | //FIXME | ||
177 | } | ||
178 | |||
179 | up(&cs->sem); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static void if_close(struct tty_struct *tty, struct file *filp) | ||
184 | { | ||
185 | struct cardstate *cs; | ||
186 | unsigned long flags; | ||
187 | |||
188 | cs = (struct cardstate *) tty->driver_data; | ||
189 | if (!cs) { | ||
190 | err("cs==NULL in %s", __FUNCTION__); | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
195 | |||
196 | down(&cs->sem); | ||
197 | |||
198 | if (!cs->open_count) | ||
199 | warn("%s: device not opened", __FUNCTION__); | ||
200 | else { | ||
201 | if (!--cs->open_count) { | ||
202 | spin_lock_irqsave(&cs->lock, flags); | ||
203 | cs->tty = NULL; | ||
204 | spin_unlock_irqrestore(&cs->lock, flags); | ||
205 | //FIXME | ||
206 | } | ||
207 | } | ||
208 | |||
209 | up(&cs->sem); | ||
210 | } | ||
211 | |||
212 | static int if_ioctl(struct tty_struct *tty, struct file *file, | ||
213 | unsigned int cmd, unsigned long arg) | ||
214 | { | ||
215 | struct cardstate *cs; | ||
216 | int retval = -ENODEV; | ||
217 | int int_arg; | ||
218 | unsigned char buf[6]; | ||
219 | unsigned version[4]; | ||
220 | |||
221 | cs = (struct cardstate *) tty->driver_data; | ||
222 | if (!cs) { | ||
223 | err("cs==NULL in %s", __FUNCTION__); | ||
224 | return -ENODEV; | ||
225 | } | ||
226 | |||
227 | dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __FUNCTION__, cmd); | ||
228 | |||
229 | if (down_interruptible(&cs->sem)) | ||
230 | return -ERESTARTSYS; // FIXME -EINTR? | ||
231 | |||
232 | if (!cs->open_count) | ||
233 | warn("%s: device not opened", __FUNCTION__); | ||
234 | else { | ||
235 | retval = 0; | ||
236 | switch (cmd) { | ||
237 | case GIGASET_REDIR: | ||
238 | retval = get_user(int_arg, (int __user *) arg); | ||
239 | if (retval >= 0) | ||
240 | retval = if_lock(cs, &int_arg); | ||
241 | if (retval >= 0) | ||
242 | retval = put_user(int_arg, (int __user *) arg); | ||
243 | break; | ||
244 | case GIGASET_CONFIG: | ||
245 | retval = get_user(int_arg, (int __user *) arg); | ||
246 | if (retval >= 0) | ||
247 | retval = if_config(cs, &int_arg); | ||
248 | if (retval >= 0) | ||
249 | retval = put_user(int_arg, (int __user *) arg); | ||
250 | break; | ||
251 | case GIGASET_BRKCHARS: | ||
252 | //FIXME test if MS_LOCKED | ||
253 | gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", | ||
254 | 6, (const unsigned char *) arg, 1); | ||
255 | if (!atomic_read(&cs->connected)) { | ||
256 | dbg(DEBUG_ANY, "can't communicate with unplugged device"); | ||
257 | retval = -ENODEV; | ||
258 | break; | ||
259 | } | ||
260 | retval = copy_from_user(&buf, | ||
261 | (const unsigned char __user *) arg, 6) | ||
262 | ? -EFAULT : 0; | ||
263 | if (retval >= 0) | ||
264 | retval = cs->ops->brkchars(cs, buf); | ||
265 | break; | ||
266 | case GIGASET_VERSION: | ||
267 | retval = copy_from_user(version, (unsigned __user *) arg, | ||
268 | sizeof version) ? -EFAULT : 0; | ||
269 | if (retval >= 0) | ||
270 | retval = if_version(cs, version); | ||
271 | if (retval >= 0) | ||
272 | retval = copy_to_user((unsigned __user *) arg, version, | ||
273 | sizeof version) | ||
274 | ? -EFAULT : 0; | ||
275 | break; | ||
276 | default: | ||
277 | dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x", | ||
278 | __FUNCTION__, cmd); | ||
279 | retval = -ENOIOCTLCMD; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | up(&cs->sem); | ||
284 | |||
285 | return retval; | ||
286 | } | ||
287 | |||
288 | static int if_tiocmget(struct tty_struct *tty, struct file *file) | ||
289 | { | ||
290 | struct cardstate *cs; | ||
291 | int retval; | ||
292 | |||
293 | cs = (struct cardstate *) tty->driver_data; | ||
294 | if (!cs) { | ||
295 | err("cs==NULL in %s", __FUNCTION__); | ||
296 | return -ENODEV; | ||
297 | } | ||
298 | |||
299 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
300 | |||
301 | if (down_interruptible(&cs->sem)) | ||
302 | return -ERESTARTSYS; // FIXME -EINTR? | ||
303 | |||
304 | // FIXME read from device? | ||
305 | retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR); | ||
306 | |||
307 | up(&cs->sem); | ||
308 | |||
309 | return retval; | ||
310 | } | ||
311 | |||
312 | static int if_tiocmset(struct tty_struct *tty, struct file *file, | ||
313 | unsigned int set, unsigned int clear) | ||
314 | { | ||
315 | struct cardstate *cs; | ||
316 | int retval; | ||
317 | unsigned mc; | ||
318 | |||
319 | cs = (struct cardstate *) tty->driver_data; | ||
320 | if (!cs) { | ||
321 | err("cs==NULL in %s", __FUNCTION__); | ||
322 | return -ENODEV; | ||
323 | } | ||
324 | |||
325 | dbg(DEBUG_IF, | ||
326 | "%u: %s(0x%x, 0x%x)", cs->minor_index, __FUNCTION__, set, clear); | ||
327 | |||
328 | if (down_interruptible(&cs->sem)) | ||
329 | return -ERESTARTSYS; // FIXME -EINTR? | ||
330 | |||
331 | if (!atomic_read(&cs->connected)) { | ||
332 | dbg(DEBUG_ANY, "can't communicate with unplugged device"); | ||
333 | retval = -ENODEV; | ||
334 | } else { | ||
335 | mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR); | ||
336 | retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc); | ||
337 | cs->control_state = mc; | ||
338 | } | ||
339 | |||
340 | up(&cs->sem); | ||
341 | |||
342 | return retval; | ||
343 | } | ||
344 | |||
345 | static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
346 | { | ||
347 | struct cardstate *cs; | ||
348 | int retval = -ENODEV; | ||
349 | |||
350 | cs = (struct cardstate *) tty->driver_data; | ||
351 | if (!cs) { | ||
352 | err("cs==NULL in %s", __FUNCTION__); | ||
353 | return -ENODEV; | ||
354 | } | ||
355 | |||
356 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
357 | |||
358 | if (down_interruptible(&cs->sem)) | ||
359 | return -ERESTARTSYS; // FIXME -EINTR? | ||
360 | |||
361 | if (!cs->open_count) | ||
362 | warn("%s: device not opened", __FUNCTION__); | ||
363 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { | ||
364 | warn("can't write to unlocked device"); | ||
365 | retval = -EBUSY; | ||
366 | } else if (!atomic_read(&cs->connected)) { | ||
367 | dbg(DEBUG_ANY, "can't write to unplugged device"); | ||
368 | retval = -EBUSY; //FIXME | ||
369 | } else { | ||
370 | retval = cs->ops->write_cmd(cs, buf, count, | ||
371 | &cs->if_wake_tasklet); | ||
372 | } | ||
373 | |||
374 | up(&cs->sem); | ||
375 | |||
376 | return retval; | ||
377 | } | ||
378 | |||
379 | static int if_write_room(struct tty_struct *tty) | ||
380 | { | ||
381 | struct cardstate *cs; | ||
382 | int retval = -ENODEV; | ||
383 | |||
384 | cs = (struct cardstate *) tty->driver_data; | ||
385 | if (!cs) { | ||
386 | err("cs==NULL in %s", __FUNCTION__); | ||
387 | return -ENODEV; | ||
388 | } | ||
389 | |||
390 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
391 | |||
392 | if (down_interruptible(&cs->sem)) | ||
393 | return -ERESTARTSYS; // FIXME -EINTR? | ||
394 | |||
395 | if (!cs->open_count) | ||
396 | warn("%s: device not opened", __FUNCTION__); | ||
397 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { | ||
398 | warn("can't write to unlocked device"); | ||
399 | retval = -EBUSY; //FIXME | ||
400 | } else if (!atomic_read(&cs->connected)) { | ||
401 | dbg(DEBUG_ANY, "can't write to unplugged device"); | ||
402 | retval = -EBUSY; //FIXME | ||
403 | } else | ||
404 | retval = cs->ops->write_room(cs); | ||
405 | |||
406 | up(&cs->sem); | ||
407 | |||
408 | return retval; | ||
409 | } | ||
410 | |||
411 | static int if_chars_in_buffer(struct tty_struct *tty) | ||
412 | { | ||
413 | struct cardstate *cs; | ||
414 | int retval = -ENODEV; | ||
415 | |||
416 | cs = (struct cardstate *) tty->driver_data; | ||
417 | if (!cs) { | ||
418 | err("cs==NULL in %s", __FUNCTION__); | ||
419 | return -ENODEV; | ||
420 | } | ||
421 | |||
422 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
423 | |||
424 | if (down_interruptible(&cs->sem)) | ||
425 | return -ERESTARTSYS; // FIXME -EINTR? | ||
426 | |||
427 | if (!cs->open_count) | ||
428 | warn("%s: device not opened", __FUNCTION__); | ||
429 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { | ||
430 | warn("can't write to unlocked device"); | ||
431 | retval = -EBUSY; | ||
432 | } else if (!atomic_read(&cs->connected)) { | ||
433 | dbg(DEBUG_ANY, "can't write to unplugged device"); | ||
434 | retval = -EBUSY; //FIXME | ||
435 | } else | ||
436 | retval = cs->ops->chars_in_buffer(cs); | ||
437 | |||
438 | up(&cs->sem); | ||
439 | |||
440 | return retval; | ||
441 | } | ||
442 | |||
443 | static void if_throttle(struct tty_struct *tty) | ||
444 | { | ||
445 | struct cardstate *cs; | ||
446 | |||
447 | cs = (struct cardstate *) tty->driver_data; | ||
448 | if (!cs) { | ||
449 | err("cs==NULL in %s", __FUNCTION__); | ||
450 | return; | ||
451 | } | ||
452 | |||
453 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
454 | |||
455 | down(&cs->sem); | ||
456 | |||
457 | if (!cs->open_count) | ||
458 | warn("%s: device not opened", __FUNCTION__); | ||
459 | else { | ||
460 | //FIXME | ||
461 | } | ||
462 | |||
463 | up(&cs->sem); | ||
464 | } | ||
465 | |||
466 | static void if_unthrottle(struct tty_struct *tty) | ||
467 | { | ||
468 | struct cardstate *cs; | ||
469 | |||
470 | cs = (struct cardstate *) tty->driver_data; | ||
471 | if (!cs) { | ||
472 | err("cs==NULL in %s", __FUNCTION__); | ||
473 | return; | ||
474 | } | ||
475 | |||
476 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
477 | |||
478 | down(&cs->sem); | ||
479 | |||
480 | if (!cs->open_count) | ||
481 | warn("%s: device not opened", __FUNCTION__); | ||
482 | else { | ||
483 | //FIXME | ||
484 | } | ||
485 | |||
486 | up(&cs->sem); | ||
487 | } | ||
488 | |||
489 | static void if_set_termios(struct tty_struct *tty, struct termios *old) | ||
490 | { | ||
491 | struct cardstate *cs; | ||
492 | unsigned int iflag; | ||
493 | unsigned int cflag; | ||
494 | unsigned int old_cflag; | ||
495 | unsigned int control_state, new_state; | ||
496 | |||
497 | cs = (struct cardstate *) tty->driver_data; | ||
498 | if (!cs) { | ||
499 | err("cs==NULL in %s", __FUNCTION__); | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); | ||
504 | |||
505 | down(&cs->sem); | ||
506 | |||
507 | if (!cs->open_count) { | ||
508 | warn("%s: device not opened", __FUNCTION__); | ||
509 | goto out; | ||
510 | } | ||
511 | |||
512 | if (!atomic_read(&cs->connected)) { | ||
513 | dbg(DEBUG_ANY, "can't communicate with unplugged device"); | ||
514 | goto out; | ||
515 | } | ||
516 | |||
517 | // stolen from mct_u232.c | ||
518 | iflag = tty->termios->c_iflag; | ||
519 | cflag = tty->termios->c_cflag; | ||
520 | old_cflag = old ? old->c_cflag : cflag; //FIXME? | ||
521 | dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index, | ||
522 | iflag, cflag, old_cflag); | ||
523 | |||
524 | /* get a local copy of the current port settings */ | ||
525 | control_state = cs->control_state; | ||
526 | |||
527 | /* | ||
528 | * Update baud rate. | ||
529 | * Do not attempt to cache old rates and skip settings, | ||
530 | * disconnects screw such tricks up completely. | ||
531 | * Premature optimization is the root of all evil. | ||
532 | */ | ||
533 | |||
534 | /* reassert DTR and (maybe) RTS on transition from B0 */ | ||
535 | if ((old_cflag & CBAUD) == B0) { | ||
536 | new_state = control_state | TIOCM_DTR; | ||
537 | /* don't set RTS if using hardware flow control */ | ||
538 | if (!(old_cflag & CRTSCTS)) | ||
539 | new_state |= TIOCM_RTS; | ||
540 | dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index, | ||
541 | (new_state & TIOCM_RTS) ? " only" : "/RTS"); | ||
542 | cs->ops->set_modem_ctrl(cs, control_state, new_state); | ||
543 | control_state = new_state; | ||
544 | } | ||
545 | |||
546 | cs->ops->baud_rate(cs, cflag & CBAUD); | ||
547 | |||
548 | if ((cflag & CBAUD) == B0) { | ||
549 | /* Drop RTS and DTR */ | ||
550 | dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index); | ||
551 | new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS); | ||
552 | cs->ops->set_modem_ctrl(cs, control_state, new_state); | ||
553 | control_state = new_state; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * Update line control register (LCR) | ||
558 | */ | ||
559 | |||
560 | cs->ops->set_line_ctrl(cs, cflag); | ||
561 | |||
562 | #if 0 | ||
563 | //FIXME this hangs M101 [ts 2005-03-09] | ||
564 | //FIXME do we need this? | ||
565 | /* | ||
566 | * Set flow control: well, I do not really now how to handle DTR/RTS. | ||
567 | * Just do what we have seen with SniffUSB on Win98. | ||
568 | */ | ||
569 | /* Drop DTR/RTS if no flow control otherwise assert */ | ||
570 | dbg(DEBUG_IF, "%u: control_state %x", cs->minor_index, control_state); | ||
571 | new_state = control_state; | ||
572 | if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) | ||
573 | new_state |= TIOCM_DTR | TIOCM_RTS; | ||
574 | else | ||
575 | new_state &= ~(TIOCM_DTR | TIOCM_RTS); | ||
576 | if (new_state != control_state) { | ||
577 | dbg(DEBUG_IF, "%u: new_state %x", cs->minor_index, new_state); | ||
578 | gigaset_set_modem_ctrl(cs, control_state, new_state); // FIXME: mct_u232.c sets the old state here. is this a bug? | ||
579 | control_state = new_state; | ||
580 | } | ||
581 | #endif | ||
582 | |||
583 | /* save off the modified port settings */ | ||
584 | cs->control_state = control_state; | ||
585 | |||
586 | out: | ||
587 | up(&cs->sem); | ||
588 | } | ||
589 | |||
590 | |||
591 | /* wakeup tasklet for the write operation */ | ||
592 | static void if_wake(unsigned long data) | ||
593 | { | ||
594 | struct cardstate *cs = (struct cardstate *) data; | ||
595 | struct tty_struct *tty; | ||
596 | |||
597 | tty = cs->tty; | ||
598 | if (!tty) | ||
599 | return; | ||
600 | |||
601 | if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | ||
602 | tty->ldisc.write_wakeup) { | ||
603 | dbg(DEBUG_IF, "write wakeup call"); | ||
604 | tty->ldisc.write_wakeup(tty); | ||
605 | } | ||
606 | |||
607 | wake_up_interruptible(&tty->write_wait); | ||
608 | } | ||
609 | |||
610 | /*** interface to common ***/ | ||
611 | |||
612 | void gigaset_if_init(struct cardstate *cs) | ||
613 | { | ||
614 | struct gigaset_driver *drv; | ||
615 | |||
616 | drv = cs->driver; | ||
617 | if (!drv->have_tty) | ||
618 | return; | ||
619 | |||
620 | tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); | ||
621 | tty_register_device(drv->tty, cs->minor_index, NULL); | ||
622 | } | ||
623 | |||
624 | void gigaset_if_free(struct cardstate *cs) | ||
625 | { | ||
626 | struct gigaset_driver *drv; | ||
627 | |||
628 | drv = cs->driver; | ||
629 | if (!drv->have_tty) | ||
630 | return; | ||
631 | |||
632 | tasklet_disable(&cs->if_wake_tasklet); | ||
633 | tasklet_kill(&cs->if_wake_tasklet); | ||
634 | tty_unregister_device(drv->tty, cs->minor_index); | ||
635 | } | ||
636 | |||
637 | void gigaset_if_receive(struct cardstate *cs, | ||
638 | unsigned char *buffer, size_t len) | ||
639 | { | ||
640 | unsigned long flags; | ||
641 | struct tty_struct *tty; | ||
642 | |||
643 | spin_lock_irqsave(&cs->lock, flags); | ||
644 | if ((tty = cs->tty) == NULL) | ||
645 | dbg(DEBUG_ANY, "receive on closed device"); | ||
646 | else { | ||
647 | tty_buffer_request_room(tty, len); | ||
648 | tty_insert_flip_string(tty, buffer, len); | ||
649 | tty_flip_buffer_push(tty); | ||
650 | } | ||
651 | spin_unlock_irqrestore(&cs->lock, flags); | ||
652 | } | ||
653 | EXPORT_SYMBOL_GPL(gigaset_if_receive); | ||
654 | |||
655 | /* gigaset_if_initdriver | ||
656 | * Initialize tty interface. | ||
657 | * parameters: | ||
658 | * drv Driver | ||
659 | * procname Name of the driver (e.g. for /proc/tty/drivers) | ||
660 | * devname Name of the device files (prefix without minor number) | ||
661 | * devfsname Devfs name of the device files without %d | ||
662 | */ | ||
663 | void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, | ||
664 | const char *devname, const char *devfsname) | ||
665 | { | ||
666 | unsigned minors = drv->minors; | ||
667 | int ret; | ||
668 | struct tty_driver *tty; | ||
669 | |||
670 | drv->have_tty = 0; | ||
671 | |||
672 | if ((drv->tty = alloc_tty_driver(minors)) == NULL) | ||
673 | goto enomem; | ||
674 | tty = drv->tty; | ||
675 | |||
676 | tty->magic = TTY_DRIVER_MAGIC, | ||
677 | tty->major = GIG_MAJOR, | ||
678 | tty->type = TTY_DRIVER_TYPE_SERIAL, | ||
679 | tty->subtype = SERIAL_TYPE_NORMAL, | ||
680 | tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, | ||
681 | |||
682 | tty->driver_name = procname; | ||
683 | tty->name = devname; | ||
684 | tty->minor_start = drv->minor; | ||
685 | tty->num = drv->minors; | ||
686 | |||
687 | tty->owner = THIS_MODULE; | ||
688 | tty->devfs_name = devfsname; | ||
689 | |||
690 | tty->init_termios = tty_std_termios; //FIXME | ||
691 | tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME | ||
692 | tty_set_operations(tty, &if_ops); | ||
693 | |||
694 | ret = tty_register_driver(tty); | ||
695 | if (ret < 0) { | ||
696 | warn("failed to register tty driver (error %d)", ret); | ||
697 | goto error; | ||
698 | } | ||
699 | dbg(DEBUG_IF, "tty driver initialized"); | ||
700 | drv->have_tty = 1; | ||
701 | return; | ||
702 | |||
703 | enomem: | ||
704 | warn("could not allocate tty structures"); | ||
705 | error: | ||
706 | if (drv->tty) | ||
707 | put_tty_driver(drv->tty); | ||
708 | } | ||
709 | |||
710 | void gigaset_if_freedriver(struct gigaset_driver *drv) | ||
711 | { | ||
712 | if (!drv->have_tty) | ||
713 | return; | ||
714 | |||
715 | drv->have_tty = 0; | ||
716 | tty_unregister_driver(drv->tty); | ||
717 | put_tty_driver(drv->tty); | ||
718 | } | ||
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c new file mode 100644 index 000000000000..5744eb91b315 --- /dev/null +++ b/drivers/isdn/gigaset/isocdata.c | |||
@@ -0,0 +1,1009 @@ | |||
1 | /* | ||
2 | * Common data handling layer for bas_gigaset | ||
3 | * | ||
4 | * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>, | ||
5 | * Hansjoerg Lipp <hjlipp@web.de>. | ||
6 | * | ||
7 | * ===================================================================== | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation; either version 2 of | ||
11 | * the License, or (at your option) any later version. | ||
12 | * ===================================================================== | ||
13 | * ToDo: ... | ||
14 | * ===================================================================== | ||
15 | * Version: $Id: isocdata.c,v 1.2.2.5 2005/11/13 23:05:19 hjlipp Exp $ | ||
16 | * ===================================================================== | ||
17 | */ | ||
18 | |||
19 | #include "gigaset.h" | ||
20 | #include <linux/crc-ccitt.h> | ||
21 | |||
22 | /* access methods for isowbuf_t */ | ||
23 | /* ============================ */ | ||
24 | |||
25 | /* initialize buffer structure | ||
26 | */ | ||
27 | void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle) | ||
28 | { | ||
29 | atomic_set(&iwb->read, 0); | ||
30 | atomic_set(&iwb->nextread, 0); | ||
31 | atomic_set(&iwb->write, 0); | ||
32 | atomic_set(&iwb->writesem, 1); | ||
33 | iwb->wbits = 0; | ||
34 | iwb->idle = idle; | ||
35 | memset(iwb->data + BAS_OUTBUFSIZE, idle, BAS_OUTBUFPAD); | ||
36 | } | ||
37 | |||
38 | /* compute number of bytes which can be appended to buffer | ||
39 | * so that there is still room to append a maximum frame of flags | ||
40 | */ | ||
41 | static inline int isowbuf_freebytes(struct isowbuf_t *iwb) | ||
42 | { | ||
43 | int read, write, freebytes; | ||
44 | |||
45 | read = atomic_read(&iwb->read); | ||
46 | write = atomic_read(&iwb->write); | ||
47 | if ((freebytes = read - write) > 0) { | ||
48 | /* no wraparound: need padding space within regular area */ | ||
49 | return freebytes - BAS_OUTBUFPAD; | ||
50 | } else if (read < BAS_OUTBUFPAD) { | ||
51 | /* wraparound: can use space up to end of regular area */ | ||
52 | return BAS_OUTBUFSIZE - write; | ||
53 | } else { | ||
54 | /* following the wraparound yields more space */ | ||
55 | return freebytes + BAS_OUTBUFSIZE - BAS_OUTBUFPAD; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /* compare two offsets within the buffer | ||
60 | * The buffer is seen as circular, with the read position as start | ||
61 | * returns -1/0/1 if position a </=/> position b without crossing 'read' | ||
62 | */ | ||
63 | static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b) | ||
64 | { | ||
65 | int read; | ||
66 | if (a == b) | ||
67 | return 0; | ||
68 | read = atomic_read(&iwb->read); | ||
69 | if (a < b) { | ||
70 | if (a < read && read <= b) | ||
71 | return +1; | ||
72 | else | ||
73 | return -1; | ||
74 | } else { | ||
75 | if (b < read && read <= a) | ||
76 | return -1; | ||
77 | else | ||
78 | return +1; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | /* start writing | ||
83 | * acquire the write semaphore | ||
84 | * return true if acquired, false if busy | ||
85 | */ | ||
86 | static inline int isowbuf_startwrite(struct isowbuf_t *iwb) | ||
87 | { | ||
88 | if (!atomic_dec_and_test(&iwb->writesem)) { | ||
89 | atomic_inc(&iwb->writesem); | ||
90 | dbg(DEBUG_ISO, | ||
91 | "%s: couldn't acquire iso write semaphore", __func__); | ||
92 | return 0; | ||
93 | } | ||
94 | #ifdef CONFIG_GIGASET_DEBUG | ||
95 | dbg(DEBUG_ISO, | ||
96 | "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", | ||
97 | __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits); | ||
98 | #endif | ||
99 | return 1; | ||
100 | } | ||
101 | |||
102 | /* finish writing | ||
103 | * release the write semaphore and update the maximum buffer fill level | ||
104 | * returns the current write position | ||
105 | */ | ||
106 | static inline int isowbuf_donewrite(struct isowbuf_t *iwb) | ||
107 | { | ||
108 | int write = atomic_read(&iwb->write); | ||
109 | atomic_inc(&iwb->writesem); | ||
110 | return write; | ||
111 | } | ||
112 | |||
113 | /* append bits to buffer without any checks | ||
114 | * - data contains bits to append, starting at LSB | ||
115 | * - nbits is number of bits to append (0..24) | ||
116 | * must be called with the write semaphore held | ||
117 | * If more than nbits bits are set in data, the extraneous bits are set in the | ||
118 | * buffer too, but the write position is only advanced by nbits. | ||
119 | */ | ||
120 | static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits) | ||
121 | { | ||
122 | int write = atomic_read(&iwb->write); | ||
123 | data <<= iwb->wbits; | ||
124 | data |= iwb->data[write]; | ||
125 | nbits += iwb->wbits; | ||
126 | while (nbits >= 8) { | ||
127 | iwb->data[write++] = data & 0xff; | ||
128 | write %= BAS_OUTBUFSIZE; | ||
129 | data >>= 8; | ||
130 | nbits -= 8; | ||
131 | } | ||
132 | iwb->wbits = nbits; | ||
133 | iwb->data[write] = data & 0xff; | ||
134 | atomic_set(&iwb->write, write); | ||
135 | } | ||
136 | |||
137 | /* put final flag on HDLC bitstream | ||
138 | * also sets the idle fill byte to the correspondingly shifted flag pattern | ||
139 | * must be called with the write semaphore held | ||
140 | */ | ||
141 | static inline void isowbuf_putflag(struct isowbuf_t *iwb) | ||
142 | { | ||
143 | int write; | ||
144 | |||
145 | /* add two flags, thus reliably covering one byte */ | ||
146 | isowbuf_putbits(iwb, 0x7e7e, 8); | ||
147 | /* recover the idle flag byte */ | ||
148 | write = atomic_read(&iwb->write); | ||
149 | iwb->idle = iwb->data[write]; | ||
150 | dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle); | ||
151 | /* mask extraneous bits in buffer */ | ||
152 | iwb->data[write] &= (1 << iwb->wbits) - 1; | ||
153 | } | ||
154 | |||
155 | /* retrieve a block of bytes for sending | ||
156 | * The requested number of bytes is provided as a contiguous block. | ||
157 | * If necessary, the frame is filled to the requested number of bytes | ||
158 | * with the idle value. | ||
159 | * returns offset to frame, < 0 on busy or error | ||
160 | */ | ||
161 | int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) | ||
162 | { | ||
163 | int read, write, limit, src, dst; | ||
164 | unsigned char pbyte; | ||
165 | |||
166 | read = atomic_read(&iwb->nextread); | ||
167 | write = atomic_read(&iwb->write); | ||
168 | if (likely(read == write)) { | ||
169 | //dbg(DEBUG_STREAM, "%s: send buffer empty", __func__); | ||
170 | /* return idle frame */ | ||
171 | return read < BAS_OUTBUFPAD ? | ||
172 | BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD; | ||
173 | } | ||
174 | |||
175 | limit = read + size; | ||
176 | dbg(DEBUG_STREAM, | ||
177 | "%s: read=%d write=%d limit=%d", __func__, read, write, limit); | ||
178 | #ifdef CONFIG_GIGASET_DEBUG | ||
179 | if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) { | ||
180 | err("invalid size %d", size); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | src = atomic_read(&iwb->read); | ||
184 | if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD || | ||
185 | (read < src && limit >= src))) { | ||
186 | err("isoc write buffer frame reservation violated"); | ||
187 | return -EFAULT; | ||
188 | } | ||
189 | #endif | ||
190 | |||
191 | if (read < write) { | ||
192 | /* no wraparound in valid data */ | ||
193 | if (limit >= write) { | ||
194 | /* append idle frame */ | ||
195 | if (!isowbuf_startwrite(iwb)) | ||
196 | return -EBUSY; | ||
197 | /* write position could have changed */ | ||
198 | if (limit >= (write = atomic_read(&iwb->write))) { | ||
199 | pbyte = iwb->data[write]; /* save partial byte */ | ||
200 | limit = write + BAS_OUTBUFPAD; | ||
201 | dbg(DEBUG_STREAM, | ||
202 | "%s: filling %d->%d with %02x", | ||
203 | __func__, write, limit, iwb->idle); | ||
204 | if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE) | ||
205 | memset(iwb->data + write, iwb->idle, | ||
206 | BAS_OUTBUFPAD); | ||
207 | else { | ||
208 | /* wraparound, fill entire pad area */ | ||
209 | memset(iwb->data + write, iwb->idle, | ||
210 | BAS_OUTBUFSIZE + BAS_OUTBUFPAD | ||
211 | - write); | ||
212 | limit = 0; | ||
213 | } | ||
214 | dbg(DEBUG_STREAM, "%s: restoring %02x at %d", | ||
215 | __func__, pbyte, limit); | ||
216 | iwb->data[limit] = pbyte; /* restore partial byte */ | ||
217 | atomic_set(&iwb->write, limit); | ||
218 | } | ||
219 | isowbuf_donewrite(iwb); | ||
220 | } | ||
221 | } else { | ||
222 | /* valid data wraparound */ | ||
223 | if (limit >= BAS_OUTBUFSIZE) { | ||
224 | /* copy wrapped part into pad area */ | ||
225 | src = 0; | ||
226 | dst = BAS_OUTBUFSIZE; | ||
227 | while (dst < limit && src < write) | ||
228 | iwb->data[dst++] = iwb->data[src++]; | ||
229 | if (dst <= limit) { | ||
230 | /* fill pad area with idle byte */ | ||
231 | memset(iwb->data + dst, iwb->idle, | ||
232 | BAS_OUTBUFSIZE + BAS_OUTBUFPAD - dst); | ||
233 | } | ||
234 | limit = src; | ||
235 | } | ||
236 | } | ||
237 | atomic_set(&iwb->nextread, limit); | ||
238 | return read; | ||
239 | } | ||
240 | |||
241 | /* dump_bytes | ||
242 | * write hex bytes to syslog for debugging | ||
243 | */ | ||
244 | static inline void dump_bytes(enum debuglevel level, const char *tag, | ||
245 | unsigned char *bytes, int count) | ||
246 | { | ||
247 | #ifdef CONFIG_GIGASET_DEBUG | ||
248 | unsigned char c; | ||
249 | static char dbgline[3 * 32 + 1]; | ||
250 | static const char hexdigit[] = "0123456789abcdef"; | ||
251 | int i = 0; | ||
252 | IFNULLRET(tag); | ||
253 | IFNULLRET(bytes); | ||
254 | while (count-- > 0) { | ||
255 | if (i > sizeof(dbgline) - 4) { | ||
256 | dbgline[i] = '\0'; | ||
257 | dbg(level, "%s:%s", tag, dbgline); | ||
258 | i = 0; | ||
259 | } | ||
260 | c = *bytes++; | ||
261 | dbgline[i] = (i && !(i % 12)) ? '-' : ' '; | ||
262 | i++; | ||
263 | dbgline[i++] = hexdigit[(c >> 4) & 0x0f]; | ||
264 | dbgline[i++] = hexdigit[c & 0x0f]; | ||
265 | } | ||
266 | dbgline[i] = '\0'; | ||
267 | dbg(level, "%s:%s", tag, dbgline); | ||
268 | #endif | ||
269 | } | ||
270 | |||
271 | /*============================================================================*/ | ||
272 | |||
273 | /* bytewise HDLC bitstuffing via table lookup | ||
274 | * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits | ||
275 | * index: 256*(number of preceding '1' bits) + (next byte to stuff) | ||
276 | * value: bit 9.. 0 = result bits | ||
277 | * bit 12..10 = number of trailing '1' bits in result | ||
278 | * bit 14..13 = number of bits added by stuffing | ||
279 | */ | ||
280 | static u16 stufftab[5 * 256] = { | ||
281 | // previous 1s = 0: | ||
282 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, | ||
283 | 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f, | ||
284 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, | ||
285 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f, | ||
286 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, | ||
287 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f, | ||
288 | 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, | ||
289 | 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df, | ||
290 | 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, | ||
291 | 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f, | ||
292 | 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, | ||
293 | 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f, | ||
294 | 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf, | ||
295 | 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f, | ||
296 | 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef, | ||
297 | 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf, | ||
298 | |||
299 | // previous 1s = 1: | ||
300 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f, | ||
301 | 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f, | ||
302 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f, | ||
303 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f, | ||
304 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f, | ||
305 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af, | ||
306 | 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf, | ||
307 | 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef, | ||
308 | 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f, | ||
309 | 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f, | ||
310 | 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f, | ||
311 | 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f, | ||
312 | 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f, | ||
313 | 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af, | ||
314 | 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf, | ||
315 | 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef, | ||
316 | |||
317 | // previous 1s = 2: | ||
318 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017, | ||
319 | 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037, | ||
320 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057, | ||
321 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077, | ||
322 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097, | ||
323 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7, | ||
324 | 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7, | ||
325 | 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7, | ||
326 | 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517, | ||
327 | 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537, | ||
328 | 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557, | ||
329 | 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577, | ||
330 | 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997, | ||
331 | 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7, | ||
332 | 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7, | ||
333 | 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7, | ||
334 | |||
335 | // previous 1s = 3: | ||
336 | 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b, | ||
337 | 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b, | ||
338 | 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b, | ||
339 | 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b, | ||
340 | 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b, | ||
341 | 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb, | ||
342 | 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db, | ||
343 | 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb, | ||
344 | 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b, | ||
345 | 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b, | ||
346 | 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b, | ||
347 | 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b, | ||
348 | 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b, | ||
349 | 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb, | ||
350 | 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb, | ||
351 | 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb, | ||
352 | |||
353 | // previous 1s = 4: | ||
354 | 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d, | ||
355 | 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d, | ||
356 | 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d, | ||
357 | 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d, | ||
358 | 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d, | ||
359 | 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd, | ||
360 | 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd, | ||
361 | 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d, | ||
362 | 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d, | ||
363 | 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d, | ||
364 | 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d, | ||
365 | 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d, | ||
366 | 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d, | ||
367 | 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd, | ||
368 | 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd, | ||
369 | 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d | ||
370 | }; | ||
371 | |||
372 | /* hdlc_bitstuff_byte | ||
373 | * perform HDLC bitstuffing for one input byte (8 bits, LSB first) | ||
374 | * parameters: | ||
375 | * cin input byte | ||
376 | * ones number of trailing '1' bits in result before this step | ||
377 | * iwb pointer to output buffer structure (write semaphore must be held) | ||
378 | * return value: | ||
379 | * number of trailing '1' bits in result after this step | ||
380 | */ | ||
381 | |||
382 | static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin, | ||
383 | int ones) | ||
384 | { | ||
385 | u16 stuff; | ||
386 | int shiftinc, newones; | ||
387 | |||
388 | /* get stuffing information for input byte | ||
389 | * value: bit 9.. 0 = result bits | ||
390 | * bit 12..10 = number of trailing '1' bits in result | ||
391 | * bit 14..13 = number of bits added by stuffing | ||
392 | */ | ||
393 | stuff = stufftab[256 * ones + cin]; | ||
394 | shiftinc = (stuff >> 13) & 3; | ||
395 | newones = (stuff >> 10) & 7; | ||
396 | stuff &= 0x3ff; | ||
397 | |||
398 | /* append stuffed byte to output stream */ | ||
399 | isowbuf_putbits(iwb, stuff, 8 + shiftinc); | ||
400 | return newones; | ||
401 | } | ||
402 | |||
403 | /* hdlc_buildframe | ||
404 | * Perform HDLC framing with bitstuffing on a byte buffer | ||
405 | * The input buffer is regarded as a sequence of bits, starting with the least | ||
406 | * significant bit of the first byte and ending with the most significant bit | ||
407 | * of the last byte. A 16 bit FCS is appended as defined by RFC 1662. | ||
408 | * Whenever five consecutive '1' bits appear in the resulting bit sequence, a | ||
409 | * '0' bit is inserted after them. | ||
410 | * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110') | ||
411 | * are appended to the output buffer starting at the given bit position, which | ||
412 | * is assumed to already contain a leading flag. | ||
413 | * The output buffer must have sufficient length; count + count/5 + 6 bytes | ||
414 | * starting at *out are safe and are verified to be present. | ||
415 | * parameters: | ||
416 | * in input buffer | ||
417 | * count number of bytes in input buffer | ||
418 | * iwb pointer to output buffer structure (write semaphore must be held) | ||
419 | * return value: | ||
420 | * position of end of packet in output buffer on success, | ||
421 | * -EAGAIN if write semaphore busy or buffer full | ||
422 | */ | ||
423 | |||
424 | static inline int hdlc_buildframe(struct isowbuf_t *iwb, | ||
425 | unsigned char *in, int count) | ||
426 | { | ||
427 | int ones; | ||
428 | u16 fcs; | ||
429 | int end; | ||
430 | unsigned char c; | ||
431 | |||
432 | if (isowbuf_freebytes(iwb) < count + count / 5 + 6 || | ||
433 | !isowbuf_startwrite(iwb)) { | ||
434 | dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN", | ||
435 | __func__, isowbuf_freebytes(iwb)); | ||
436 | return -EAGAIN; | ||
437 | } | ||
438 | |||
439 | dump_bytes(DEBUG_STREAM, "snd data", in, count); | ||
440 | |||
441 | /* bitstuff and checksum input data */ | ||
442 | fcs = PPP_INITFCS; | ||
443 | ones = 0; | ||
444 | while (count-- > 0) { | ||
445 | c = *in++; | ||
446 | ones = hdlc_bitstuff_byte(iwb, c, ones); | ||
447 | fcs = crc_ccitt_byte(fcs, c); | ||
448 | } | ||
449 | |||
450 | /* bitstuff and append FCS (complemented, least significant byte first) */ | ||
451 | fcs ^= 0xffff; | ||
452 | ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones); | ||
453 | ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones); | ||
454 | |||
455 | /* put closing flag and repeat byte for flag idle */ | ||
456 | isowbuf_putflag(iwb); | ||
457 | end = isowbuf_donewrite(iwb); | ||
458 | dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1); | ||
459 | return end; | ||
460 | } | ||
461 | |||
462 | /* trans_buildframe | ||
463 | * Append a block of 'transparent' data to the output buffer, | ||
464 | * inverting the bytes. | ||
465 | * The output buffer must have sufficient length; count bytes | ||
466 | * starting at *out are safe and are verified to be present. | ||
467 | * parameters: | ||
468 | * in input buffer | ||
469 | * count number of bytes in input buffer | ||
470 | * iwb pointer to output buffer structure (write semaphore must be held) | ||
471 | * return value: | ||
472 | * position of end of packet in output buffer on success, | ||
473 | * -EAGAIN if write semaphore busy or buffer full | ||
474 | */ | ||
475 | |||
476 | static inline int trans_buildframe(struct isowbuf_t *iwb, | ||
477 | unsigned char *in, int count) | ||
478 | { | ||
479 | int write; | ||
480 | unsigned char c; | ||
481 | |||
482 | if (unlikely(count <= 0)) | ||
483 | return atomic_read(&iwb->write); /* better ideas? */ | ||
484 | |||
485 | if (isowbuf_freebytes(iwb) < count || | ||
486 | !isowbuf_startwrite(iwb)) { | ||
487 | dbg(DEBUG_ISO, "can't put %d bytes", count); | ||
488 | return -EAGAIN; | ||
489 | } | ||
490 | |||
491 | dbg(DEBUG_STREAM, "put %d bytes", count); | ||
492 | write = atomic_read(&iwb->write); | ||
493 | do { | ||
494 | c = gigaset_invtab[*in++]; | ||
495 | iwb->data[write++] = c; | ||
496 | write %= BAS_OUTBUFSIZE; | ||
497 | } while (--count > 0); | ||
498 | atomic_set(&iwb->write, write); | ||
499 | iwb->idle = c; | ||
500 | |||
501 | return isowbuf_donewrite(iwb); | ||
502 | } | ||
503 | |||
504 | int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len) | ||
505 | { | ||
506 | int result; | ||
507 | |||
508 | switch (bcs->proto2) { | ||
509 | case ISDN_PROTO_L2_HDLC: | ||
510 | result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len); | ||
511 | dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", __func__, len, result); | ||
512 | break; | ||
513 | default: /* assume transparent */ | ||
514 | result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len); | ||
515 | dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", __func__, len, result); | ||
516 | } | ||
517 | return result; | ||
518 | } | ||
519 | |||
520 | /* hdlc_putbyte | ||
521 | * append byte c to current skb of B channel structure *bcs, updating fcs | ||
522 | */ | ||
523 | static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) | ||
524 | { | ||
525 | bcs->fcs = crc_ccitt_byte(bcs->fcs, c); | ||
526 | if (unlikely(bcs->skb == NULL)) { | ||
527 | /* skipping */ | ||
528 | return; | ||
529 | } | ||
530 | if (unlikely(bcs->skb->len == SBUFSIZE)) { | ||
531 | warn("received oversized packet discarded"); | ||
532 | bcs->hw.bas->giants++; | ||
533 | dev_kfree_skb_any(bcs->skb); | ||
534 | bcs->skb = NULL; | ||
535 | return; | ||
536 | } | ||
537 | *gigaset_skb_put_quick(bcs->skb, 1) = c; | ||
538 | } | ||
539 | |||
540 | /* hdlc_flush | ||
541 | * drop partial HDLC data packet | ||
542 | */ | ||
543 | static inline void hdlc_flush(struct bc_state *bcs) | ||
544 | { | ||
545 | /* clear skb or allocate new if not skipping */ | ||
546 | if (likely(bcs->skb != NULL)) | ||
547 | skb_trim(bcs->skb, 0); | ||
548 | else if (!bcs->ignore) { | ||
549 | if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) | ||
550 | skb_reserve(bcs->skb, HW_HDR_LEN); | ||
551 | else | ||
552 | err("could not allocate skb"); | ||
553 | } | ||
554 | |||
555 | /* reset packet state */ | ||
556 | bcs->fcs = PPP_INITFCS; | ||
557 | } | ||
558 | |||
559 | /* hdlc_done | ||
560 | * process completed HDLC data packet | ||
561 | */ | ||
562 | static inline void hdlc_done(struct bc_state *bcs) | ||
563 | { | ||
564 | struct sk_buff *procskb; | ||
565 | |||
566 | if (unlikely(bcs->ignore)) { | ||
567 | bcs->ignore--; | ||
568 | hdlc_flush(bcs); | ||
569 | return; | ||
570 | } | ||
571 | |||
572 | if ((procskb = bcs->skb) == NULL) { | ||
573 | /* previous error */ | ||
574 | dbg(DEBUG_ISO, "%s: skb=NULL", __func__); | ||
575 | gigaset_rcv_error(NULL, bcs->cs, bcs); | ||
576 | } else if (procskb->len < 2) { | ||
577 | notice("received short frame (%d octets)", procskb->len); | ||
578 | bcs->hw.bas->runts++; | ||
579 | gigaset_rcv_error(procskb, bcs->cs, bcs); | ||
580 | } else if (bcs->fcs != PPP_GOODFCS) { | ||
581 | notice("frame check error (0x%04x)", bcs->fcs); | ||
582 | bcs->hw.bas->fcserrs++; | ||
583 | gigaset_rcv_error(procskb, bcs->cs, bcs); | ||
584 | } else { | ||
585 | procskb->len -= 2; /* subtract FCS */ | ||
586 | procskb->tail -= 2; | ||
587 | dbg(DEBUG_ISO, | ||
588 | "%s: good frame (%d octets)", __func__, procskb->len); | ||
589 | dump_bytes(DEBUG_STREAM, | ||
590 | "rcv data", procskb->data, procskb->len); | ||
591 | bcs->hw.bas->goodbytes += procskb->len; | ||
592 | gigaset_rcv_skb(procskb, bcs->cs, bcs); | ||
593 | } | ||
594 | |||
595 | if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) | ||
596 | skb_reserve(bcs->skb, HW_HDR_LEN); | ||
597 | else | ||
598 | err("could not allocate skb"); | ||
599 | bcs->fcs = PPP_INITFCS; | ||
600 | } | ||
601 | |||
602 | /* hdlc_frag | ||
603 | * drop HDLC data packet with non-integral last byte | ||
604 | */ | ||
605 | static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits) | ||
606 | { | ||
607 | if (unlikely(bcs->ignore)) { | ||
608 | bcs->ignore--; | ||
609 | hdlc_flush(bcs); | ||
610 | return; | ||
611 | } | ||
612 | |||
613 | notice("received partial byte (%d bits)", inbits); | ||
614 | bcs->hw.bas->alignerrs++; | ||
615 | gigaset_rcv_error(bcs->skb, bcs->cs, bcs); | ||
616 | |||
617 | if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) | ||
618 | skb_reserve(bcs->skb, HW_HDR_LEN); | ||
619 | else | ||
620 | err("could not allocate skb"); | ||
621 | bcs->fcs = PPP_INITFCS; | ||
622 | } | ||
623 | |||
624 | /* bit counts lookup table for HDLC bit unstuffing | ||
625 | * index: input byte | ||
626 | * value: bit 0..3 = number of consecutive '1' bits starting from LSB | ||
627 | * bit 4..6 = number of consecutive '1' bits starting from MSB | ||
628 | * (replacing 8 by 7 to make it fit; the algorithm won't care) | ||
629 | * bit 7 set if there are 5 or more "interior" consecutive '1' bits | ||
630 | */ | ||
631 | static unsigned char bitcounts[256] = { | ||
632 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, | ||
633 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, | ||
634 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, | ||
635 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06, | ||
636 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, | ||
637 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, | ||
638 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, | ||
639 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x80, 0x81, 0x80, 0x07, | ||
640 | 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14, | ||
641 | 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15, | ||
642 | 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14, | ||
643 | 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16, | ||
644 | 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24, | ||
645 | 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25, | ||
646 | 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34, | ||
647 | 0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78 | ||
648 | }; | ||
649 | |||
650 | /* hdlc_unpack | ||
651 | * perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation) | ||
652 | * on a sequence of received data bytes (8 bits each, LSB first) | ||
653 | * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb | ||
654 | * notify of errors via gigaset_rcv_error | ||
655 | * tally frames, errors etc. in BC structure counters | ||
656 | * parameters: | ||
657 | * src received data | ||
658 | * count number of received bytes | ||
659 | * bcs receiving B channel structure | ||
660 | */ | ||
661 | static inline void hdlc_unpack(unsigned char *src, unsigned count, | ||
662 | struct bc_state *bcs) | ||
663 | { | ||
664 | struct bas_bc_state *ubc; | ||
665 | int inputstate; | ||
666 | unsigned seqlen, inbyte, inbits; | ||
667 | |||
668 | IFNULLRET(bcs); | ||
669 | ubc = bcs->hw.bas; | ||
670 | IFNULLRET(ubc); | ||
671 | |||
672 | /* load previous state: | ||
673 | * inputstate = set of flag bits: | ||
674 | * - INS_flag_hunt: no complete opening flag received since connection setup or last abort | ||
675 | * - INS_have_data: at least one complete data byte received since last flag | ||
676 | * seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7) | ||
677 | * inbyte = accumulated partial data byte (if !INS_flag_hunt) | ||
678 | * inbits = number of valid bits in inbyte, starting at LSB (0..6) | ||
679 | */ | ||
680 | inputstate = bcs->inputstate; | ||
681 | seqlen = ubc->seqlen; | ||
682 | inbyte = ubc->inbyte; | ||
683 | inbits = ubc->inbits; | ||
684 | |||
685 | /* bit unstuffing a byte a time | ||
686 | * Take your time to understand this; it's straightforward but tedious. | ||
687 | * The "bitcounts" lookup table is used to speed up the counting of | ||
688 | * leading and trailing '1' bits. | ||
689 | */ | ||
690 | while (count--) { | ||
691 | unsigned char c = *src++; | ||
692 | unsigned char tabentry = bitcounts[c]; | ||
693 | unsigned lead1 = tabentry & 0x0f; | ||
694 | unsigned trail1 = (tabentry >> 4) & 0x0f; | ||
695 | |||
696 | seqlen += lead1; | ||
697 | |||
698 | if (unlikely(inputstate & INS_flag_hunt)) { | ||
699 | if (c == PPP_FLAG) { | ||
700 | /* flag-in-one */ | ||
701 | inputstate &= ~(INS_flag_hunt | INS_have_data); | ||
702 | inbyte = 0; | ||
703 | inbits = 0; | ||
704 | } else if (seqlen == 6 && trail1 != 7) { | ||
705 | /* flag completed & not followed by abort */ | ||
706 | inputstate &= ~(INS_flag_hunt | INS_have_data); | ||
707 | inbyte = c >> (lead1 + 1); | ||
708 | inbits = 7 - lead1; | ||
709 | if (trail1 >= 8) { | ||
710 | /* interior stuffing: omitting the MSB handles most cases */ | ||
711 | inbits--; | ||
712 | /* correct the incorrectly handled cases individually */ | ||
713 | switch (c) { | ||
714 | case 0xbe: | ||
715 | inbyte = 0x3f; | ||
716 | break; | ||
717 | } | ||
718 | } | ||
719 | } | ||
720 | /* else: continue flag-hunting */ | ||
721 | } else if (likely(seqlen < 5 && trail1 < 7)) { | ||
722 | /* streamlined case: 8 data bits, no stuffing */ | ||
723 | inbyte |= c << inbits; | ||
724 | hdlc_putbyte(inbyte & 0xff, bcs); | ||
725 | inputstate |= INS_have_data; | ||
726 | inbyte >>= 8; | ||
727 | /* inbits unchanged */ | ||
728 | } else if (likely(seqlen == 6 && inbits == 7 - lead1 && | ||
729 | trail1 + 1 == inbits && | ||
730 | !(inputstate & INS_have_data))) { | ||
731 | /* streamlined case: flag idle - state unchanged */ | ||
732 | } else if (unlikely(seqlen > 6)) { | ||
733 | /* abort sequence */ | ||
734 | ubc->aborts++; | ||
735 | hdlc_flush(bcs); | ||
736 | inputstate |= INS_flag_hunt; | ||
737 | } else if (seqlen == 6) { | ||
738 | /* closing flag, including (6 - lead1) '1's and one '0' from inbits */ | ||
739 | if (inbits > 7 - lead1) { | ||
740 | hdlc_frag(bcs, inbits + lead1 - 7); | ||
741 | inputstate &= ~INS_have_data; | ||
742 | } else { | ||
743 | if (inbits < 7 - lead1) | ||
744 | ubc->stolen0s ++; | ||
745 | if (inputstate & INS_have_data) { | ||
746 | hdlc_done(bcs); | ||
747 | inputstate &= ~INS_have_data; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | if (c == PPP_FLAG) { | ||
752 | /* complete flag, LSB overlaps preceding flag */ | ||
753 | ubc->shared0s ++; | ||
754 | inbits = 0; | ||
755 | inbyte = 0; | ||
756 | } else if (trail1 != 7) { | ||
757 | /* remaining bits */ | ||
758 | inbyte = c >> (lead1 + 1); | ||
759 | inbits = 7 - lead1; | ||
760 | if (trail1 >= 8) { | ||
761 | /* interior stuffing: omitting the MSB handles most cases */ | ||
762 | inbits--; | ||
763 | /* correct the incorrectly handled cases individually */ | ||
764 | switch (c) { | ||
765 | case 0xbe: | ||
766 | inbyte = 0x3f; | ||
767 | break; | ||
768 | } | ||
769 | } | ||
770 | } else { | ||
771 | /* abort sequence follows, skb already empty anyway */ | ||
772 | ubc->aborts++; | ||
773 | inputstate |= INS_flag_hunt; | ||
774 | } | ||
775 | } else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */ | ||
776 | |||
777 | if (c == PPP_FLAG) { | ||
778 | /* complete flag */ | ||
779 | if (seqlen == 5) | ||
780 | ubc->stolen0s++; | ||
781 | if (inbits) { | ||
782 | hdlc_frag(bcs, inbits); | ||
783 | inbits = 0; | ||
784 | inbyte = 0; | ||
785 | } else if (inputstate & INS_have_data) | ||
786 | hdlc_done(bcs); | ||
787 | inputstate &= ~INS_have_data; | ||
788 | } else if (trail1 == 7) { | ||
789 | /* abort sequence */ | ||
790 | ubc->aborts++; | ||
791 | hdlc_flush(bcs); | ||
792 | inputstate |= INS_flag_hunt; | ||
793 | } else { | ||
794 | /* stuffed data */ | ||
795 | if (trail1 < 7) { /* => seqlen == 5 */ | ||
796 | /* stuff bit at position lead1, no interior stuffing */ | ||
797 | unsigned char mask = (1 << lead1) - 1; | ||
798 | c = (c & mask) | ((c & ~mask) >> 1); | ||
799 | inbyte |= c << inbits; | ||
800 | inbits += 7; | ||
801 | } else if (seqlen < 5) { /* trail1 >= 8 */ | ||
802 | /* interior stuffing: omitting the MSB handles most cases */ | ||
803 | /* correct the incorrectly handled cases individually */ | ||
804 | switch (c) { | ||
805 | case 0xbe: | ||
806 | c = 0x7e; | ||
807 | break; | ||
808 | } | ||
809 | inbyte |= c << inbits; | ||
810 | inbits += 7; | ||
811 | } else { /* seqlen == 5 && trail1 >= 8 */ | ||
812 | |||
813 | /* stuff bit at lead1 *and* interior stuffing */ | ||
814 | switch (c) { /* unstuff individually */ | ||
815 | case 0x7d: | ||
816 | c = 0x3f; | ||
817 | break; | ||
818 | case 0xbe: | ||
819 | c = 0x3f; | ||
820 | break; | ||
821 | case 0x3e: | ||
822 | c = 0x1f; | ||
823 | break; | ||
824 | case 0x7c: | ||
825 | c = 0x3e; | ||
826 | break; | ||
827 | } | ||
828 | inbyte |= c << inbits; | ||
829 | inbits += 6; | ||
830 | } | ||
831 | if (inbits >= 8) { | ||
832 | inbits -= 8; | ||
833 | hdlc_putbyte(inbyte & 0xff, bcs); | ||
834 | inputstate |= INS_have_data; | ||
835 | inbyte >>= 8; | ||
836 | } | ||
837 | } | ||
838 | } | ||
839 | seqlen = trail1 & 7; | ||
840 | } | ||
841 | |||
842 | /* save new state */ | ||
843 | bcs->inputstate = inputstate; | ||
844 | ubc->seqlen = seqlen; | ||
845 | ubc->inbyte = inbyte; | ||
846 | ubc->inbits = inbits; | ||
847 | } | ||
848 | |||
849 | /* trans_receive | ||
850 | * pass on received USB frame transparently as SKB via gigaset_rcv_skb | ||
851 | * invert bytes | ||
852 | * tally frames, errors etc. in BC structure counters | ||
853 | * parameters: | ||
854 | * src received data | ||
855 | * count number of received bytes | ||
856 | * bcs receiving B channel structure | ||
857 | */ | ||
858 | static inline void trans_receive(unsigned char *src, unsigned count, | ||
859 | struct bc_state *bcs) | ||
860 | { | ||
861 | struct sk_buff *skb; | ||
862 | int dobytes; | ||
863 | unsigned char *dst; | ||
864 | |||
865 | if (unlikely(bcs->ignore)) { | ||
866 | bcs->ignore--; | ||
867 | hdlc_flush(bcs); | ||
868 | return; | ||
869 | } | ||
870 | if (unlikely((skb = bcs->skb) == NULL)) { | ||
871 | bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); | ||
872 | if (!skb) { | ||
873 | err("could not allocate skb"); | ||
874 | return; | ||
875 | } | ||
876 | skb_reserve(skb, HW_HDR_LEN); | ||
877 | } | ||
878 | bcs->hw.bas->goodbytes += skb->len; | ||
879 | dobytes = TRANSBUFSIZE - skb->len; | ||
880 | while (count > 0) { | ||
881 | dst = skb_put(skb, count < dobytes ? count : dobytes); | ||
882 | while (count > 0 && dobytes > 0) { | ||
883 | *dst++ = gigaset_invtab[*src++]; | ||
884 | count--; | ||
885 | dobytes--; | ||
886 | } | ||
887 | if (dobytes == 0) { | ||
888 | gigaset_rcv_skb(skb, bcs->cs, bcs); | ||
889 | bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); | ||
890 | if (!skb) { | ||
891 | err("could not allocate skb"); | ||
892 | return; | ||
893 | } | ||
894 | skb_reserve(bcs->skb, HW_HDR_LEN); | ||
895 | dobytes = TRANSBUFSIZE; | ||
896 | } | ||
897 | } | ||
898 | } | ||
899 | |||
900 | void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs) | ||
901 | { | ||
902 | switch (bcs->proto2) { | ||
903 | case ISDN_PROTO_L2_HDLC: | ||
904 | hdlc_unpack(src, count, bcs); | ||
905 | break; | ||
906 | default: /* assume transparent */ | ||
907 | trans_receive(src, count, bcs); | ||
908 | } | ||
909 | } | ||
910 | |||
911 | /* == data input =========================================================== */ | ||
912 | |||
913 | static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) | ||
914 | { | ||
915 | struct cardstate *cs = inbuf->cs; | ||
916 | unsigned cbytes = cs->cbytes; | ||
917 | |||
918 | while (numbytes--) { | ||
919 | /* copy next character, check for end of line */ | ||
920 | switch (cs->respdata[cbytes] = *src++) { | ||
921 | case '\r': | ||
922 | case '\n': | ||
923 | /* end of line */ | ||
924 | dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", | ||
925 | __func__, cbytes); | ||
926 | cs->cbytes = cbytes; | ||
927 | gigaset_handle_modem_response(cs); | ||
928 | cbytes = 0; | ||
929 | break; | ||
930 | default: | ||
931 | /* advance in line buffer, checking for overflow */ | ||
932 | if (cbytes < MAX_RESP_SIZE - 1) | ||
933 | cbytes++; | ||
934 | else | ||
935 | warn("response too large"); | ||
936 | } | ||
937 | } | ||
938 | |||
939 | /* save state */ | ||
940 | cs->cbytes = cbytes; | ||
941 | } | ||
942 | |||
943 | |||
944 | /* process a block of data received through the control channel | ||
945 | */ | ||
946 | void gigaset_isoc_input(struct inbuf_t *inbuf) | ||
947 | { | ||
948 | struct cardstate *cs = inbuf->cs; | ||
949 | unsigned tail, head, numbytes; | ||
950 | unsigned char *src; | ||
951 | |||
952 | head = atomic_read(&inbuf->head); | ||
953 | while (head != (tail = atomic_read(&inbuf->tail))) { | ||
954 | dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); | ||
955 | if (head > tail) | ||
956 | tail = RBUFSIZE; | ||
957 | src = inbuf->data + head; | ||
958 | numbytes = tail - head; | ||
959 | dbg(DEBUG_INTR, "processing %u bytes", numbytes); | ||
960 | |||
961 | if (atomic_read(&cs->mstate) == MS_LOCKED) { | ||
962 | gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", | ||
963 | numbytes, src, 0); | ||
964 | gigaset_if_receive(inbuf->cs, src, numbytes); | ||
965 | } else { | ||
966 | gigaset_dbg_buffer(DEBUG_CMD, "received response", | ||
967 | numbytes, src, 0); | ||
968 | cmd_loop(src, numbytes, inbuf); | ||
969 | } | ||
970 | |||
971 | head += numbytes; | ||
972 | if (head == RBUFSIZE) | ||
973 | head = 0; | ||
974 | dbg(DEBUG_INTR, "setting head to %u", head); | ||
975 | atomic_set(&inbuf->head, head); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | |||
980 | /* == data output ========================================================== */ | ||
981 | |||
982 | /* gigaset_send_skb | ||
983 | * called by common.c to queue an skb for sending | ||
984 | * and start transmission if necessary | ||
985 | * parameters: | ||
986 | * B Channel control structure | ||
987 | * skb | ||
988 | * return value: | ||
989 | * number of bytes accepted for sending | ||
990 | * (skb->len if ok, 0 if out of buffer space) | ||
991 | * or error code (< 0, eg. -EINVAL) | ||
992 | */ | ||
993 | int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) | ||
994 | { | ||
995 | int len; | ||
996 | |||
997 | IFNULLRETVAL(bcs, -EFAULT); | ||
998 | IFNULLRETVAL(skb, -EFAULT); | ||
999 | len = skb->len; | ||
1000 | |||
1001 | skb_queue_tail(&bcs->squeue, skb); | ||
1002 | dbg(DEBUG_ISO, | ||
1003 | "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue)); | ||
1004 | |||
1005 | /* tasklet submits URB if necessary */ | ||
1006 | tasklet_schedule(&bcs->hw.bas->sent_tasklet); | ||
1007 | |||
1008 | return len; /* ok so far */ | ||
1009 | } | ||
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c new file mode 100644 index 000000000000..c6915fa2be6c --- /dev/null +++ b/drivers/isdn/gigaset/proc.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Stuff used by all variants of the driver | ||
3 | * | ||
4 | * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>, | ||
5 | * Hansjoerg Lipp <hjlipp@web.de>, | ||
6 | * Tilman Schmidt <tilman@imap.cc>. | ||
7 | * | ||
8 | * ===================================================================== | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of | ||
12 | * the License, or (at your option) any later version. | ||
13 | * ===================================================================== | ||
14 | * ToDo: ... | ||
15 | * ===================================================================== | ||
16 | * Version: $Id: proc.c,v 1.5.2.13 2006/02/04 18:28:16 hjlipp Exp $ | ||
17 | * ===================================================================== | ||
18 | */ | ||
19 | |||
20 | #include "gigaset.h" | ||
21 | #include <linux/ctype.h> | ||
22 | |||
23 | static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, char *buf) | ||
24 | { | ||
25 | struct usb_interface *intf = to_usb_interface(dev); | ||
26 | struct cardstate *cs = usb_get_intfdata(intf); | ||
27 | return sprintf(buf, "%d\n", atomic_read(&cs->cidmode)); // FIXME use scnprintf for 13607 bit architectures (if PAGE_SIZE==4096) | ||
28 | } | ||
29 | |||
30 | static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
31 | { | ||
32 | struct usb_interface *intf = to_usb_interface(dev); | ||
33 | struct cardstate *cs = usb_get_intfdata(intf); | ||
34 | long int value; | ||
35 | char *end; | ||
36 | |||
37 | value = simple_strtol(buf, &end, 0); | ||
38 | while (*end) | ||
39 | if (!isspace(*end++)) | ||
40 | return -EINVAL; | ||
41 | if (value < 0 || value > 1) | ||
42 | return -EINVAL; | ||
43 | |||
44 | if (down_interruptible(&cs->sem)) | ||
45 | return -ERESTARTSYS; // FIXME -EINTR? | ||
46 | |||
47 | cs->waiting = 1; | ||
48 | if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE, | ||
49 | NULL, value, NULL)) { | ||
50 | cs->waiting = 0; | ||
51 | up(&cs->sem); | ||
52 | return -ENOMEM; | ||
53 | } | ||
54 | |||
55 | dbg(DEBUG_CMD, "scheduling PROC_CIDMODE"); | ||
56 | gigaset_schedule_event(cs); | ||
57 | |||
58 | wait_event(cs->waitqueue, !cs->waiting); | ||
59 | |||
60 | up(&cs->sem); | ||
61 | |||
62 | return count; | ||
63 | } | ||
64 | |||
65 | static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); | ||
66 | |||
67 | /* free sysfs for device */ | ||
68 | void gigaset_free_dev_sysfs(struct usb_interface *interface) | ||
69 | { | ||
70 | dbg(DEBUG_INIT, "removing sysfs entries"); | ||
71 | device_remove_file(&interface->dev, &dev_attr_cidmode); | ||
72 | } | ||
73 | EXPORT_SYMBOL_GPL(gigaset_free_dev_sysfs); | ||
74 | |||
75 | /* initialize sysfs for device */ | ||
76 | void gigaset_init_dev_sysfs(struct usb_interface *interface) | ||
77 | { | ||
78 | dbg(DEBUG_INIT, "setting up sysfs"); | ||
79 | device_create_file(&interface->dev, &dev_attr_cidmode); | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(gigaset_init_dev_sysfs); | ||
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c new file mode 100644 index 000000000000..323fc7349dec --- /dev/null +++ b/drivers/isdn/gigaset/usb-gigaset.c | |||
@@ -0,0 +1,1008 @@ | |||
1 | /* | ||
2 | * USB driver for Gigaset 307x directly or using M105 Data. | ||
3 | * | ||
4 | * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de> | ||
5 | * and Hansjoerg Lipp <hjlipp@web.de>. | ||
6 | * | ||
7 | * This driver was derived from the USB skeleton driver by | ||
8 | * Greg Kroah-Hartman <greg@kroah.com> | ||
9 | * | ||
10 | * ===================================================================== | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; either version 2 of | ||
14 | * the License, or (at your option) any later version. | ||
15 | * ===================================================================== | ||
16 | * ToDo: ... | ||
17 | * ===================================================================== | ||
18 | * Version: $Id: usb-gigaset.c,v 1.85.4.18 2006/02/04 18:28:16 hjlipp Exp $ | ||
19 | * ===================================================================== | ||
20 | */ | ||
21 | |||
22 | #include "gigaset.h" | ||
23 | |||
24 | #include <linux/errno.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/usb.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/moduleparam.h> | ||
30 | |||
31 | /* Version Information */ | ||
32 | #define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>" | ||
33 | #define DRIVER_DESC "USB Driver for Gigaset 307x using M105" | ||
34 | |||
35 | /* Module parameters */ | ||
36 | |||
37 | static int startmode = SM_ISDN; | ||
38 | static int cidmode = 1; | ||
39 | |||
40 | module_param(startmode, int, S_IRUGO); | ||
41 | module_param(cidmode, int, S_IRUGO); | ||
42 | MODULE_PARM_DESC(startmode, "start in isdn4linux mode"); | ||
43 | MODULE_PARM_DESC(cidmode, "Call-ID mode"); | ||
44 | |||
45 | #define GIGASET_MINORS 1 | ||
46 | #define GIGASET_MINOR 8 | ||
47 | #define GIGASET_MODULENAME "usb_gigaset" | ||
48 | #define GIGASET_DEVFSNAME "gig/usb/" | ||
49 | #define GIGASET_DEVNAME "ttyGU" | ||
50 | |||
51 | #define IF_WRITEBUF 2000 //FIXME // WAKEUP_CHARS: 256 | ||
52 | |||
53 | /* Values for the Gigaset M105 Data */ | ||
54 | #define USB_M105_VENDOR_ID 0x0681 | ||
55 | #define USB_M105_PRODUCT_ID 0x0009 | ||
56 | |||
57 | /* table of devices that work with this driver */ | ||
58 | static struct usb_device_id gigaset_table [] = { | ||
59 | { USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) }, | ||
60 | { } /* Terminating entry */ | ||
61 | }; | ||
62 | |||
63 | MODULE_DEVICE_TABLE(usb, gigaset_table); | ||
64 | |||
65 | /* Get a minor range for your devices from the usb maintainer */ | ||
66 | #define USB_SKEL_MINOR_BASE 200 | ||
67 | |||
68 | |||
69 | /* | ||
70 | * Control requests (empty fields: 00) | ||
71 | * | ||
72 | * RT|RQ|VALUE|INDEX|LEN |DATA | ||
73 | * In: | ||
74 | * C1 08 01 | ||
75 | * Get flags (1 byte). Bits: 0=dtr,1=rts,3-7:? | ||
76 | * C1 0F ll ll | ||
77 | * Get device information/status (llll: 0x200 and 0x40 seen). | ||
78 | * Real size: I only saw MIN(llll,0x64). | ||
79 | * Contents: seems to be always the same... | ||
80 | * offset 0x00: Length of this structure (0x64) (len: 1,2,3 bytes) | ||
81 | * offset 0x3c: String (16 bit chars): "MCCI USB Serial V2.0" | ||
82 | * rest: ? | ||
83 | * Out: | ||
84 | * 41 11 | ||
85 | * Initialize/reset device ? | ||
86 | * 41 00 xx 00 | ||
87 | * ? (xx=00 or 01; 01 on start, 00 on close) | ||
88 | * 41 07 vv mm | ||
89 | * Set/clear flags vv=value, mm=mask (see RQ 08) | ||
90 | * 41 12 xx | ||
91 | * Used before the following configuration requests are issued | ||
92 | * (with xx=0x0f). I've seen other values<0xf, though. | ||
93 | * 41 01 xx xx | ||
94 | * Set baud rate. xxxx=ceil(0x384000/rate)=trunc(0x383fff/rate)+1. | ||
95 | * 41 03 ps bb | ||
96 | * Set byte size and parity. p: 0x20=even,0x10=odd,0x00=no parity | ||
97 | * [ 0x30: m, 0x40: s ] | ||
98 | * [s: 0: 1 stop bit; 1: 1.5; 2: 2] | ||
99 | * bb: bits/byte (seen 7 and 8) | ||
100 | * 41 13 -- -- -- -- 10 00 ww 00 00 00 xx 00 00 00 yy 00 00 00 zz 00 00 00 | ||
101 | * ?? | ||
102 | * Initialization: 01, 40, 00, 00 | ||
103 | * Open device: 00 40, 00, 00 | ||
104 | * yy and zz seem to be equal, either 0x00 or 0x0a | ||
105 | * (ww,xx) pairs seen: (00,00), (00,40), (01,40), (09,80), (19,80) | ||
106 | * 41 19 -- -- -- -- 06 00 00 00 00 xx 11 13 | ||
107 | * Used after every "configuration sequence" (RQ 12, RQs 01/03/13). | ||
108 | * xx is usually 0x00 but was 0x7e before starting data transfer | ||
109 | * in unimodem mode. So, this might be an array of characters that need | ||
110 | * special treatment ("commit all bufferd data"?), 11=^Q, 13=^S. | ||
111 | * | ||
112 | * Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two | ||
113 | * flags per packet. | ||
114 | */ | ||
115 | |||
116 | static int gigaset_probe(struct usb_interface *interface, | ||
117 | const struct usb_device_id *id); | ||
118 | static void gigaset_disconnect(struct usb_interface *interface); | ||
119 | |||
120 | static struct gigaset_driver *driver = NULL; | ||
121 | static struct cardstate *cardstate = NULL; | ||
122 | |||
123 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
124 | static struct usb_driver gigaset_usb_driver = { | ||
125 | .name = GIGASET_MODULENAME, | ||
126 | .probe = gigaset_probe, | ||
127 | .disconnect = gigaset_disconnect, | ||
128 | .id_table = gigaset_table, | ||
129 | }; | ||
130 | |||
131 | struct usb_cardstate { | ||
132 | struct usb_device *udev; /* save off the usb device pointer */ | ||
133 | struct usb_interface *interface; /* the interface for this device */ | ||
134 | atomic_t busy; /* bulk output in progress */ | ||
135 | |||
136 | /* Output buffer for commands (M105: and data)*/ | ||
137 | unsigned char *bulk_out_buffer; /* the buffer to send data */ | ||
138 | int bulk_out_size; /* the size of the send buffer */ | ||
139 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ | ||
140 | struct urb *bulk_out_urb; /* the urb used to transmit data */ | ||
141 | |||
142 | /* Input buffer for command responses (M105: and data)*/ | ||
143 | int rcvbuf_size; /* the size of the receive buffer */ | ||
144 | struct urb *read_urb; /* the urb used to receive data */ | ||
145 | __u8 int_in_endpointAddr; /* the address of the bulk in endpoint */ | ||
146 | |||
147 | char bchars[6]; /* req. 0x19 */ | ||
148 | }; | ||
149 | |||
150 | struct usb_bc_state {}; | ||
151 | |||
152 | static inline unsigned tiocm_to_gigaset(unsigned state) | ||
153 | { | ||
154 | return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0); | ||
155 | } | ||
156 | |||
157 | #ifdef CONFIG_GIGASET_UNDOCREQ | ||
158 | /* WARNING: EXPERIMENTAL! */ | ||
159 | static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, | ||
160 | unsigned new_state) | ||
161 | { | ||
162 | unsigned mask, val; | ||
163 | int r; | ||
164 | |||
165 | mask = tiocm_to_gigaset(old_state ^ new_state); | ||
166 | val = tiocm_to_gigaset(new_state); | ||
167 | |||
168 | dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask); | ||
169 | r = usb_control_msg(cs->hw.usb->udev, | ||
170 | usb_sndctrlpipe(cs->hw.usb->udev, 0), 7, 0x41, | ||
171 | (val & 0xff) | ((mask & 0xff) << 8), 0, | ||
172 | NULL, 0, 2000 /*timeout??*/); // don't use this in an interrupt/BH | ||
173 | if (r < 0) | ||
174 | return r; | ||
175 | //.. | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int set_value(struct cardstate *cs, u8 req, u16 val) | ||
180 | { | ||
181 | int r, r2; | ||
182 | |||
183 | dbg(DEBUG_USBREQ, "request %02x (%04x)", (unsigned)req, (unsigned)val); | ||
184 | r = usb_control_msg(cs->hw.usb->udev, | ||
185 | usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x12, 0x41, | ||
186 | 0xf /*?*/, 0, | ||
187 | NULL, 0, 2000 /*?*/); /* no idea, what this does */ | ||
188 | if (r < 0) { | ||
189 | err("error %d on request 0x12", -r); | ||
190 | return r; | ||
191 | } | ||
192 | |||
193 | r = usb_control_msg(cs->hw.usb->udev, | ||
194 | usb_sndctrlpipe(cs->hw.usb->udev, 0), req, 0x41, | ||
195 | val, 0, | ||
196 | NULL, 0, 2000 /*?*/); | ||
197 | if (r < 0) | ||
198 | err("error %d on request 0x%02x", -r, (unsigned)req); | ||
199 | |||
200 | r2 = usb_control_msg(cs->hw.usb->udev, | ||
201 | usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41, | ||
202 | 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/); | ||
203 | if (r2 < 0) | ||
204 | err("error %d on request 0x19", -r2); | ||
205 | |||
206 | return r < 0 ? r : (r2 < 0 ? r2 : 0); | ||
207 | } | ||
208 | |||
209 | /* WARNING: HIGHLY EXPERIMENTAL! */ | ||
210 | // don't use this in an interrupt/BH | ||
211 | static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) | ||
212 | { | ||
213 | u16 val; | ||
214 | u32 rate; | ||
215 | |||
216 | cflag &= CBAUD; | ||
217 | |||
218 | switch (cflag) { | ||
219 | //FIXME more values? | ||
220 | case B300: rate = 300; break; | ||
221 | case B600: rate = 600; break; | ||
222 | case B1200: rate = 1200; break; | ||
223 | case B2400: rate = 2400; break; | ||
224 | case B4800: rate = 4800; break; | ||
225 | case B9600: rate = 9600; break; | ||
226 | case B19200: rate = 19200; break; | ||
227 | case B38400: rate = 38400; break; | ||
228 | case B57600: rate = 57600; break; | ||
229 | case B115200: rate = 115200; break; | ||
230 | default: | ||
231 | rate = 9600; | ||
232 | err("unsupported baudrate request 0x%x," | ||
233 | " using default of B9600", cflag); | ||
234 | } | ||
235 | |||
236 | val = 0x383fff / rate + 1; | ||
237 | |||
238 | return set_value(cs, 1, val); | ||
239 | } | ||
240 | |||
241 | /* WARNING: HIGHLY EXPERIMENTAL! */ | ||
242 | // don't use this in an interrupt/BH | ||
243 | static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) | ||
244 | { | ||
245 | u16 val = 0; | ||
246 | |||
247 | /* set the parity */ | ||
248 | if (cflag & PARENB) | ||
249 | val |= (cflag & PARODD) ? 0x10 : 0x20; | ||
250 | |||
251 | /* set the number of data bits */ | ||
252 | switch (cflag & CSIZE) { | ||
253 | case CS5: | ||
254 | val |= 5 << 8; break; | ||
255 | case CS6: | ||
256 | val |= 6 << 8; break; | ||
257 | case CS7: | ||
258 | val |= 7 << 8; break; | ||
259 | case CS8: | ||
260 | val |= 8 << 8; break; | ||
261 | default: | ||
262 | err("CSIZE was not CS5-CS8, using default of 8"); | ||
263 | val |= 8 << 8; | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | /* set the number of stop bits */ | ||
268 | if (cflag & CSTOPB) { | ||
269 | if ((cflag & CSIZE) == CS5) | ||
270 | val |= 1; /* 1.5 stop bits */ //FIXME is this okay? | ||
271 | else | ||
272 | val |= 2; /* 2 stop bits */ | ||
273 | } | ||
274 | |||
275 | return set_value(cs, 3, val); | ||
276 | } | ||
277 | |||
278 | #else | ||
279 | static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, | ||
280 | unsigned new_state) | ||
281 | { | ||
282 | return -EINVAL; | ||
283 | } | ||
284 | |||
285 | static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) | ||
286 | { | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | |||
290 | static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) | ||
291 | { | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | #endif | ||
295 | |||
296 | |||
297 | /*================================================================================================================*/ | ||
298 | static int gigaset_init_bchannel(struct bc_state *bcs) | ||
299 | { | ||
300 | /* nothing to do for M10x */ | ||
301 | gigaset_bchannel_up(bcs); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int gigaset_close_bchannel(struct bc_state *bcs) | ||
306 | { | ||
307 | /* nothing to do for M10x */ | ||
308 | gigaset_bchannel_down(bcs); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | //void send_ack_to_LL(void *data); | ||
313 | static int write_modem(struct cardstate *cs); | ||
314 | static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb); | ||
315 | |||
316 | |||
317 | /* Handling of send queue. If there is already a skb opened, put data to | ||
318 | * the transfer buffer by calling "write_modem". Otherwise take a new skb out of the queue. | ||
319 | * This function will be called by the ISR via "transmit_chars" (USB: B-Channel Bulk callback handler | ||
320 | * via immediate task queue) or by writebuf_from_LL if the LL wants to transmit data. | ||
321 | */ | ||
322 | static void gigaset_modem_fill(unsigned long data) | ||
323 | { | ||
324 | struct cardstate *cs = (struct cardstate *) data; | ||
325 | struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ | ||
326 | struct cmdbuf_t *cb; | ||
327 | unsigned long flags; | ||
328 | int again; | ||
329 | |||
330 | dbg(DEBUG_OUTPUT, "modem_fill"); | ||
331 | |||
332 | if (atomic_read(&cs->hw.usb->busy)) { | ||
333 | dbg(DEBUG_OUTPUT, "modem_fill: busy"); | ||
334 | return; | ||
335 | } | ||
336 | |||
337 | do { | ||
338 | again = 0; | ||
339 | if (!bcs->tx_skb) { /* no skb is being sent */ | ||
340 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
341 | cb = cs->cmdbuf; | ||
342 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
343 | if (cb) { /* commands to send? */ | ||
344 | dbg(DEBUG_OUTPUT, "modem_fill: cb"); | ||
345 | if (send_cb(cs, cb) < 0) { | ||
346 | dbg(DEBUG_OUTPUT, | ||
347 | "modem_fill: send_cb failed"); | ||
348 | again = 1; /* no callback will be called! */ | ||
349 | } | ||
350 | } else { /* skbs to send? */ | ||
351 | bcs->tx_skb = skb_dequeue(&bcs->squeue); | ||
352 | if (bcs->tx_skb) | ||
353 | dbg(DEBUG_INTR, | ||
354 | "Dequeued skb (Adr: %lx)!", | ||
355 | (unsigned long) bcs->tx_skb); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | if (bcs->tx_skb) { | ||
360 | dbg(DEBUG_OUTPUT, "modem_fill: tx_skb"); | ||
361 | if (write_modem(cs) < 0) { | ||
362 | dbg(DEBUG_OUTPUT, | ||
363 | "modem_fill: write_modem failed"); | ||
364 | // FIXME should we tell the LL? | ||
365 | again = 1; /* no callback will be called! */ | ||
366 | } | ||
367 | } | ||
368 | } while (again); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * gigaset_read_int_callback | ||
373 | * | ||
374 | * It is called if the data was received from the device. This is almost similiar to | ||
375 | * the interrupt service routine in the serial device. | ||
376 | */ | ||
377 | static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) | ||
378 | { | ||
379 | int resubmit = 0; | ||
380 | int r; | ||
381 | struct cardstate *cs; | ||
382 | unsigned numbytes; | ||
383 | unsigned char *src; | ||
384 | //unsigned long flags; | ||
385 | struct inbuf_t *inbuf; | ||
386 | |||
387 | IFNULLRET(urb); | ||
388 | inbuf = (struct inbuf_t *) urb->context; | ||
389 | IFNULLRET(inbuf); | ||
390 | //spin_lock_irqsave(&inbuf->lock, flags); | ||
391 | cs = inbuf->cs; | ||
392 | IFNULLGOTO(cs, exit); | ||
393 | IFNULLGOTO(cardstate, exit); | ||
394 | |||
395 | if (!atomic_read(&cs->connected)) { | ||
396 | err("%s: disconnected", __func__); | ||
397 | goto exit; | ||
398 | } | ||
399 | |||
400 | if (!urb->status) { | ||
401 | numbytes = urb->actual_length; | ||
402 | |||
403 | if (numbytes) { | ||
404 | src = inbuf->rcvbuf; | ||
405 | if (unlikely(*src)) | ||
406 | warn("%s: There was no leading 0, but 0x%02x!", | ||
407 | __func__, (unsigned) *src); | ||
408 | ++src; /* skip leading 0x00 */ | ||
409 | --numbytes; | ||
410 | if (gigaset_fill_inbuf(inbuf, src, numbytes)) { | ||
411 | dbg(DEBUG_INTR, "%s-->BH", __func__); | ||
412 | gigaset_schedule_event(inbuf->cs); | ||
413 | } | ||
414 | } else | ||
415 | dbg(DEBUG_INTR, "Received zero block length"); | ||
416 | resubmit = 1; | ||
417 | } else { | ||
418 | /* The urb might have been killed. */ | ||
419 | dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", | ||
420 | __func__, urb->status); | ||
421 | if (urb->status != -ENOENT) /* not killed */ | ||
422 | resubmit = 1; | ||
423 | } | ||
424 | exit: | ||
425 | //spin_unlock_irqrestore(&inbuf->lock, flags); | ||
426 | if (resubmit) { | ||
427 | r = usb_submit_urb(urb, SLAB_ATOMIC); | ||
428 | if (r) | ||
429 | err("error %d when resubmitting urb.", -r); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | |||
434 | /* This callback routine is called when data was transmitted to a B-Channel. | ||
435 | * Therefore it has to check if there is still data to transmit. This | ||
436 | * happens by calling modem_fill via task queue. | ||
437 | * | ||
438 | */ | ||
439 | static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | ||
440 | { | ||
441 | struct cardstate *cs = (struct cardstate *) urb->context; | ||
442 | |||
443 | IFNULLRET(cs); | ||
444 | #ifdef CONFIG_GIGASET_DEBUG | ||
445 | if (!atomic_read(&cs->connected)) { | ||
446 | err("%s:not connected", __func__); | ||
447 | return; | ||
448 | } | ||
449 | #endif | ||
450 | if (urb->status) | ||
451 | err("bulk transfer failed (status %d)", -urb->status); /* That's all we can do. Communication problems | ||
452 | are handeled by timeouts or network protocols */ | ||
453 | |||
454 | atomic_set(&cs->hw.usb->busy, 0); | ||
455 | tasklet_schedule(&cs->write_tasklet); | ||
456 | } | ||
457 | |||
458 | static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) | ||
459 | { | ||
460 | struct cmdbuf_t *tcb; | ||
461 | unsigned long flags; | ||
462 | int count; | ||
463 | int status = -ENOENT; // FIXME | ||
464 | struct usb_cardstate *ucs = cs->hw.usb; | ||
465 | |||
466 | do { | ||
467 | if (!cb->len) { | ||
468 | tcb = cb; | ||
469 | |||
470 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
471 | cs->cmdbytes -= cs->curlen; | ||
472 | dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left", | ||
473 | cs->curlen, cs->cmdbytes); | ||
474 | cs->cmdbuf = cb = cb->next; | ||
475 | if (cb) { | ||
476 | cb->prev = NULL; | ||
477 | cs->curlen = cb->len; | ||
478 | } else { | ||
479 | cs->lastcmdbuf = NULL; | ||
480 | cs->curlen = 0; | ||
481 | } | ||
482 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
483 | |||
484 | if (tcb->wake_tasklet) | ||
485 | tasklet_schedule(tcb->wake_tasklet); | ||
486 | kfree(tcb); | ||
487 | } | ||
488 | if (cb) { | ||
489 | count = min(cb->len, ucs->bulk_out_size); | ||
490 | usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, | ||
491 | usb_sndbulkpipe(ucs->udev, | ||
492 | ucs->bulk_out_endpointAddr & 0x0f), | ||
493 | cb->buf + cb->offset, count, | ||
494 | gigaset_write_bulk_callback, cs); | ||
495 | |||
496 | cb->offset += count; | ||
497 | cb->len -= count; | ||
498 | atomic_set(&ucs->busy, 1); | ||
499 | dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); | ||
500 | |||
501 | status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); | ||
502 | if (status) { | ||
503 | atomic_set(&ucs->busy, 0); | ||
504 | err("could not submit urb (error %d).", | ||
505 | -status); | ||
506 | cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */ | ||
507 | } | ||
508 | } | ||
509 | } while (cb && status); /* bei Fehler naechster Befehl //FIXME: ist das OK? */ | ||
510 | |||
511 | return status; | ||
512 | } | ||
513 | |||
514 | /* Write string into transbuf and send it to modem. | ||
515 | */ | ||
516 | static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | ||
517 | int len, struct tasklet_struct *wake_tasklet) | ||
518 | { | ||
519 | struct cmdbuf_t *cb; | ||
520 | unsigned long flags; | ||
521 | |||
522 | gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? | ||
523 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | ||
524 | "CMD Transmit", len, buf, 0); | ||
525 | |||
526 | if (!atomic_read(&cs->connected)) { | ||
527 | err("%s: not connected", __func__); | ||
528 | return -ENODEV; | ||
529 | } | ||
530 | |||
531 | if (len <= 0) | ||
532 | return 0; | ||
533 | |||
534 | if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { | ||
535 | err("%s: out of memory", __func__); | ||
536 | return -ENOMEM; | ||
537 | } | ||
538 | |||
539 | memcpy(cb->buf, buf, len); | ||
540 | cb->len = len; | ||
541 | cb->offset = 0; | ||
542 | cb->next = NULL; | ||
543 | cb->wake_tasklet = wake_tasklet; | ||
544 | |||
545 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
546 | cb->prev = cs->lastcmdbuf; | ||
547 | if (cs->lastcmdbuf) | ||
548 | cs->lastcmdbuf->next = cb; | ||
549 | else { | ||
550 | cs->cmdbuf = cb; | ||
551 | cs->curlen = len; | ||
552 | } | ||
553 | cs->cmdbytes += len; | ||
554 | cs->lastcmdbuf = cb; | ||
555 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
556 | |||
557 | tasklet_schedule(&cs->write_tasklet); | ||
558 | return len; | ||
559 | } | ||
560 | |||
561 | static int gigaset_write_room(struct cardstate *cs) | ||
562 | { | ||
563 | unsigned long flags; | ||
564 | unsigned bytes; | ||
565 | |||
566 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
567 | bytes = cs->cmdbytes; | ||
568 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
569 | |||
570 | return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; | ||
571 | } | ||
572 | |||
573 | static int gigaset_chars_in_buffer(struct cardstate *cs) | ||
574 | { | ||
575 | return cs->cmdbytes; | ||
576 | } | ||
577 | |||
578 | static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) | ||
579 | { | ||
580 | #ifdef CONFIG_GIGASET_UNDOCREQ | ||
581 | gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf, 0); | ||
582 | memcpy(cs->hw.usb->bchars, buf, 6); | ||
583 | return usb_control_msg(cs->hw.usb->udev, | ||
584 | usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41, | ||
585 | 0, 0, &buf, 6, 2000); | ||
586 | #else | ||
587 | return -EINVAL; | ||
588 | #endif | ||
589 | } | ||
590 | |||
591 | static int gigaset_freebcshw(struct bc_state *bcs) | ||
592 | { | ||
593 | if (!bcs->hw.usb) | ||
594 | return 0; | ||
595 | //FIXME | ||
596 | kfree(bcs->hw.usb); | ||
597 | return 1; | ||
598 | } | ||
599 | |||
600 | /* Initialize the b-channel structure */ | ||
601 | static int gigaset_initbcshw(struct bc_state *bcs) | ||
602 | { | ||
603 | bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL); | ||
604 | if (!bcs->hw.usb) | ||
605 | return 0; | ||
606 | |||
607 | //bcs->hw.usb->trans_flg = READY_TO_TRNSMIT; /* B-Channel ready to transmit */ | ||
608 | return 1; | ||
609 | } | ||
610 | |||
611 | static void gigaset_reinitbcshw(struct bc_state *bcs) | ||
612 | { | ||
613 | } | ||
614 | |||
615 | static void gigaset_freecshw(struct cardstate *cs) | ||
616 | { | ||
617 | //FIXME | ||
618 | tasklet_kill(&cs->write_tasklet); | ||
619 | kfree(cs->hw.usb); | ||
620 | } | ||
621 | |||
622 | static int gigaset_initcshw(struct cardstate *cs) | ||
623 | { | ||
624 | struct usb_cardstate *ucs; | ||
625 | |||
626 | cs->hw.usb = ucs = | ||
627 | kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); | ||
628 | if (!ucs) | ||
629 | return 0; | ||
630 | |||
631 | ucs->bchars[0] = 0; | ||
632 | ucs->bchars[1] = 0; | ||
633 | ucs->bchars[2] = 0; | ||
634 | ucs->bchars[3] = 0; | ||
635 | ucs->bchars[4] = 0x11; | ||
636 | ucs->bchars[5] = 0x13; | ||
637 | ucs->bulk_out_buffer = NULL; | ||
638 | ucs->bulk_out_urb = NULL; | ||
639 | //ucs->urb_cmd_out = NULL; | ||
640 | ucs->read_urb = NULL; | ||
641 | tasklet_init(&cs->write_tasklet, | ||
642 | &gigaset_modem_fill, (unsigned long) cs); | ||
643 | |||
644 | return 1; | ||
645 | } | ||
646 | |||
647 | /* Writes the data of the current open skb into the modem. | ||
648 | * We have to protect against multiple calls until the | ||
649 | * callback handler () is called , due to the fact that we | ||
650 | * are just allowed to send data once to an endpoint. Therefore | ||
651 | * we using "trans_flg" to synchonize ... | ||
652 | */ | ||
653 | static int write_modem(struct cardstate *cs) | ||
654 | { | ||
655 | int ret; | ||
656 | int count; | ||
657 | struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ | ||
658 | struct usb_cardstate *ucs = cs->hw.usb; | ||
659 | //unsigned long flags; | ||
660 | |||
661 | IFNULLRETVAL(bcs->tx_skb, -EINVAL); | ||
662 | |||
663 | dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); | ||
664 | |||
665 | ret = -ENODEV; | ||
666 | IFNULLGOTO(ucs->bulk_out_buffer, error); | ||
667 | IFNULLGOTO(ucs->bulk_out_urb, error); | ||
668 | ret = 0; | ||
669 | |||
670 | if (!bcs->tx_skb->len) { | ||
671 | dev_kfree_skb_any(bcs->tx_skb); | ||
672 | bcs->tx_skb = NULL; | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | |||
676 | /* Copy data to bulk out buffer and // FIXME copying not necessary | ||
677 | * transmit data | ||
678 | */ | ||
679 | count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); | ||
680 | memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count); | ||
681 | skb_pull(bcs->tx_skb, count); | ||
682 | |||
683 | usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, | ||
684 | usb_sndbulkpipe(ucs->udev, | ||
685 | ucs->bulk_out_endpointAddr & 0x0f), | ||
686 | ucs->bulk_out_buffer, count, | ||
687 | gigaset_write_bulk_callback, cs); | ||
688 | atomic_set(&ucs->busy, 1); | ||
689 | dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); | ||
690 | |||
691 | ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); | ||
692 | if (ret) { | ||
693 | err("could not submit urb (error %d).", -ret); | ||
694 | atomic_set(&ucs->busy, 0); | ||
695 | } | ||
696 | if (!bcs->tx_skb->len) { | ||
697 | /* skb sent completely */ | ||
698 | gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? | ||
699 | |||
700 | dbg(DEBUG_INTR, | ||
701 | "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb); | ||
702 | dev_kfree_skb_any(bcs->tx_skb); | ||
703 | bcs->tx_skb = NULL; | ||
704 | } | ||
705 | |||
706 | return ret; | ||
707 | error: | ||
708 | dev_kfree_skb_any(bcs->tx_skb); | ||
709 | bcs->tx_skb = NULL; | ||
710 | return ret; | ||
711 | |||
712 | } | ||
713 | |||
714 | static int gigaset_probe(struct usb_interface *interface, | ||
715 | const struct usb_device_id *id) | ||
716 | { | ||
717 | int retval; | ||
718 | struct usb_device *udev = interface_to_usbdev(interface); | ||
719 | unsigned int ifnum; | ||
720 | struct usb_host_interface *hostif; | ||
721 | struct cardstate *cs = NULL; | ||
722 | struct usb_cardstate *ucs = NULL; | ||
723 | //struct usb_interface_descriptor *iface_desc; | ||
724 | struct usb_endpoint_descriptor *endpoint; | ||
725 | //isdn_ctrl command; | ||
726 | int buffer_size; | ||
727 | int alt; | ||
728 | //unsigned long flags; | ||
729 | |||
730 | info("%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", | ||
731 | __func__, le16_to_cpu(udev->descriptor.idVendor), | ||
732 | le16_to_cpu(udev->descriptor.idProduct)); | ||
733 | |||
734 | retval = -ENODEV; //FIXME | ||
735 | |||
736 | /* See if the device offered us matches what we can accept */ | ||
737 | if ((le16_to_cpu(udev->descriptor.idVendor != USB_M105_VENDOR_ID)) || | ||
738 | (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID))) | ||
739 | return -ENODEV; | ||
740 | |||
741 | /* this starts to become ascii art... */ | ||
742 | hostif = interface->cur_altsetting; | ||
743 | alt = hostif->desc.bAlternateSetting; | ||
744 | ifnum = hostif->desc.bInterfaceNumber; // FIXME ? | ||
745 | |||
746 | if (alt != 0 || ifnum != 0) { | ||
747 | warn("ifnum %d, alt %d", ifnum, alt); | ||
748 | return -ENODEV; | ||
749 | } | ||
750 | |||
751 | /* Reject application specific intefaces | ||
752 | * | ||
753 | */ | ||
754 | if (hostif->desc.bInterfaceClass != 255) { | ||
755 | info("%s: Device matched, but iface_desc[%d]->bInterfaceClass==%d !", | ||
756 | __func__, ifnum, hostif->desc.bInterfaceClass); | ||
757 | return -ENODEV; | ||
758 | } | ||
759 | |||
760 | info("%s: Device matched ... !", __func__); | ||
761 | |||
762 | cs = gigaset_getunassignedcs(driver); | ||
763 | if (!cs) { | ||
764 | warn("No free cardstate!"); | ||
765 | return -ENODEV; | ||
766 | } | ||
767 | ucs = cs->hw.usb; | ||
768 | |||
769 | #if 0 | ||
770 | if (usb_set_configuration(udev, udev->config[0].desc.bConfigurationValue) < 0) { | ||
771 | warn("set_configuration failed"); | ||
772 | goto error; | ||
773 | } | ||
774 | |||
775 | |||
776 | if (usb_set_interface(udev, ifnum/*==0*/, alt/*==0*/) < 0) { | ||
777 | warn("usb_set_interface failed, device %d interface %d altsetting %d", | ||
778 | udev->devnum, ifnum, alt); | ||
779 | goto error; | ||
780 | } | ||
781 | #endif | ||
782 | |||
783 | /* set up the endpoint information */ | ||
784 | /* check out the endpoints */ | ||
785 | /* We will get 2 endpoints: One for sending commands to the device (bulk out) and one to | ||
786 | * poll messages from the device(int in). | ||
787 | * Therefore we will have an almost similiar situation as with our serial port handler. | ||
788 | * If an connection will be established, we will have to create data in/out pipes | ||
789 | * dynamically... | ||
790 | */ | ||
791 | |||
792 | endpoint = &hostif->endpoint[0].desc; | ||
793 | |||
794 | buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); | ||
795 | ucs->bulk_out_size = buffer_size; | ||
796 | ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress; | ||
797 | ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
798 | if (!ucs->bulk_out_buffer) { | ||
799 | err("Couldn't allocate bulk_out_buffer"); | ||
800 | retval = -ENOMEM; | ||
801 | goto error; | ||
802 | } | ||
803 | |||
804 | ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL); | ||
805 | if (!ucs->bulk_out_urb) { | ||
806 | err("Couldn't allocate bulk_out_buffer"); | ||
807 | retval = -ENOMEM; | ||
808 | goto error; | ||
809 | } | ||
810 | |||
811 | endpoint = &hostif->endpoint[1].desc; | ||
812 | |||
813 | atomic_set(&ucs->busy, 0); | ||
814 | ucs->udev = udev; | ||
815 | ucs->interface = interface; | ||
816 | |||
817 | ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL); | ||
818 | if (!ucs->read_urb) { | ||
819 | err("No free urbs available"); | ||
820 | retval = -ENOMEM; | ||
821 | goto error; | ||
822 | } | ||
823 | buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); | ||
824 | ucs->rcvbuf_size = buffer_size; | ||
825 | ucs->int_in_endpointAddr = endpoint->bEndpointAddress; | ||
826 | cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL); | ||
827 | if (!cs->inbuf[0].rcvbuf) { | ||
828 | err("Couldn't allocate rcvbuf"); | ||
829 | retval = -ENOMEM; | ||
830 | goto error; | ||
831 | } | ||
832 | /* Fill the interrupt urb and send it to the core */ | ||
833 | usb_fill_int_urb(ucs->read_urb, udev, | ||
834 | usb_rcvintpipe(udev, | ||
835 | endpoint->bEndpointAddress & 0x0f), | ||
836 | cs->inbuf[0].rcvbuf, buffer_size, | ||
837 | gigaset_read_int_callback, | ||
838 | cs->inbuf + 0, endpoint->bInterval); | ||
839 | |||
840 | retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL); | ||
841 | if (retval) { | ||
842 | err("Could not submit URB!"); | ||
843 | goto error; | ||
844 | } | ||
845 | |||
846 | /* tell common part that the device is ready */ | ||
847 | if (startmode == SM_LOCKED) | ||
848 | atomic_set(&cs->mstate, MS_LOCKED); | ||
849 | if (!gigaset_start(cs)) { | ||
850 | tasklet_kill(&cs->write_tasklet); | ||
851 | retval = -ENODEV; //FIXME | ||
852 | goto error; | ||
853 | } | ||
854 | |||
855 | /* save address of controller structure */ | ||
856 | usb_set_intfdata(interface, cs); | ||
857 | |||
858 | /* set up device sysfs */ | ||
859 | gigaset_init_dev_sysfs(interface); | ||
860 | return 0; | ||
861 | |||
862 | error: | ||
863 | if (ucs->read_urb) | ||
864 | usb_kill_urb(ucs->read_urb); | ||
865 | kfree(ucs->bulk_out_buffer); | ||
866 | if (ucs->bulk_out_urb != NULL) | ||
867 | usb_free_urb(ucs->bulk_out_urb); | ||
868 | kfree(cs->inbuf[0].rcvbuf); | ||
869 | if (ucs->read_urb != NULL) | ||
870 | usb_free_urb(ucs->read_urb); | ||
871 | ucs->read_urb = ucs->bulk_out_urb = NULL; | ||
872 | cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; | ||
873 | gigaset_unassign(cs); | ||
874 | return retval; | ||
875 | } | ||
876 | |||
877 | /** | ||
878 | * skel_disconnect | ||
879 | */ | ||
880 | static void gigaset_disconnect(struct usb_interface *interface) | ||
881 | { | ||
882 | struct cardstate *cs; | ||
883 | struct usb_cardstate *ucs; | ||
884 | |||
885 | cs = usb_get_intfdata(interface); | ||
886 | |||
887 | /* clear device sysfs */ | ||
888 | gigaset_free_dev_sysfs(interface); | ||
889 | |||
890 | usb_set_intfdata(interface, NULL); | ||
891 | ucs = cs->hw.usb; | ||
892 | usb_kill_urb(ucs->read_urb); | ||
893 | //info("GigaSet USB device #%d will be disconnected", minor); | ||
894 | |||
895 | gigaset_stop(cs); | ||
896 | |||
897 | tasklet_kill(&cs->write_tasklet); | ||
898 | |||
899 | usb_kill_urb(ucs->bulk_out_urb); /* FIXME: nur, wenn noetig */ | ||
900 | //usb_kill_urb(ucs->urb_cmd_out); /* FIXME: nur, wenn noetig */ | ||
901 | |||
902 | kfree(ucs->bulk_out_buffer); | ||
903 | if (ucs->bulk_out_urb != NULL) | ||
904 | usb_free_urb(ucs->bulk_out_urb); | ||
905 | //if(ucs->urb_cmd_out != NULL) | ||
906 | // usb_free_urb(ucs->urb_cmd_out); | ||
907 | kfree(cs->inbuf[0].rcvbuf); | ||
908 | if (ucs->read_urb != NULL) | ||
909 | usb_free_urb(ucs->read_urb); | ||
910 | ucs->read_urb = ucs->bulk_out_urb/*=ucs->urb_cmd_out*/=NULL; | ||
911 | cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; | ||
912 | |||
913 | gigaset_unassign(cs); | ||
914 | } | ||
915 | |||
916 | static struct gigaset_ops ops = { | ||
917 | gigaset_write_cmd, | ||
918 | gigaset_write_room, | ||
919 | gigaset_chars_in_buffer, | ||
920 | gigaset_brkchars, | ||
921 | gigaset_init_bchannel, | ||
922 | gigaset_close_bchannel, | ||
923 | gigaset_initbcshw, | ||
924 | gigaset_freebcshw, | ||
925 | gigaset_reinitbcshw, | ||
926 | gigaset_initcshw, | ||
927 | gigaset_freecshw, | ||
928 | gigaset_set_modem_ctrl, | ||
929 | gigaset_baud_rate, | ||
930 | gigaset_set_line_ctrl, | ||
931 | gigaset_m10x_send_skb, | ||
932 | gigaset_m10x_input, | ||
933 | }; | ||
934 | |||
935 | /** | ||
936 | * usb_gigaset_init | ||
937 | * This function is called while kernel-module is loaded | ||
938 | */ | ||
939 | static int __init usb_gigaset_init(void) | ||
940 | { | ||
941 | int result; | ||
942 | |||
943 | /* allocate memory for our driver state and intialize it */ | ||
944 | if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, | ||
945 | GIGASET_MODULENAME, GIGASET_DEVNAME, | ||
946 | GIGASET_DEVFSNAME, &ops, | ||
947 | THIS_MODULE)) == NULL) | ||
948 | goto error; | ||
949 | |||
950 | /* allocate memory for our device state and intialize it */ | ||
951 | cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); | ||
952 | if (!cardstate) | ||
953 | goto error; | ||
954 | |||
955 | /* register this driver with the USB subsystem */ | ||
956 | result = usb_register(&gigaset_usb_driver); | ||
957 | if (result < 0) { | ||
958 | err("usb_gigaset: usb_register failed (error %d)", | ||
959 | -result); | ||
960 | goto error; | ||
961 | } | ||
962 | |||
963 | info(DRIVER_AUTHOR); | ||
964 | info(DRIVER_DESC); | ||
965 | return 0; | ||
966 | |||
967 | error: if (cardstate) | ||
968 | gigaset_freecs(cardstate); | ||
969 | cardstate = NULL; | ||
970 | if (driver) | ||
971 | gigaset_freedriver(driver); | ||
972 | driver = NULL; | ||
973 | return -1; | ||
974 | } | ||
975 | |||
976 | |||
977 | /** | ||
978 | * usb_gigaset_exit | ||
979 | * This function is called while unloading the kernel-module | ||
980 | */ | ||
981 | static void __exit usb_gigaset_exit(void) | ||
982 | { | ||
983 | gigaset_blockdriver(driver); /* => probe will fail | ||
984 | * => no gigaset_start any more | ||
985 | */ | ||
986 | |||
987 | gigaset_shutdown(cardstate); | ||
988 | /* from now on, no isdn callback should be possible */ | ||
989 | |||
990 | /* deregister this driver with the USB subsystem */ | ||
991 | usb_deregister(&gigaset_usb_driver); | ||
992 | /* this will call the disconnect-callback */ | ||
993 | /* from now on, no disconnect/probe callback should be running */ | ||
994 | |||
995 | gigaset_freecs(cardstate); | ||
996 | cardstate = NULL; | ||
997 | gigaset_freedriver(driver); | ||
998 | driver = NULL; | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | module_init(usb_gigaset_init); | ||
1003 | module_exit(usb_gigaset_exit); | ||
1004 | |||
1005 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1006 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1007 | |||
1008 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h index 296d6a6f749f..3b431723c7cb 100644 --- a/drivers/isdn/hardware/avm/avmcard.h +++ b/drivers/isdn/hardware/avm/avmcard.h | |||
@@ -437,9 +437,7 @@ static inline unsigned int t1_get_slice(unsigned int base, | |||
437 | #endif | 437 | #endif |
438 | dp += i; | 438 | dp += i; |
439 | i = 0; | 439 | i = 0; |
440 | if (i == 0) | 440 | break; |
441 | break; | ||
442 | /* fall through */ | ||
443 | default: | 441 | default: |
444 | *dp++ = b1_get_byte(base); | 442 | *dp++ = b1_get_byte(base); |
445 | i--; | 443 | i--; |
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index 1789b607f090..a4f7288a1fc8 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig | |||
@@ -139,3 +139,4 @@ source "drivers/isdn/hysdn/Kconfig" | |||
139 | 139 | ||
140 | endmenu | 140 | endmenu |
141 | 141 | ||
142 | source "drivers/isdn/gigaset/Kconfig" | ||