blob: edbcaa3887f13c526849cbacdbe6f528956e7d14 [file] [log] [blame]
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001/*
2 * Stuff used by all variants of the driver
3 *
Tilman Schmidt70440cf2006-04-10 22:55:14 -07004 * Copyright (c) 2001 by Stefan Eilers,
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08005 * 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 * =====================================================================
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080014 */
15
16#include "gigaset.h"
17#include <linux/ctype.h>
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20
21/* Version Information */
Tilman Schmidt70440cf2006-04-10 22:55:14 -070022#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080023#define DRIVER_DESC "Driver for Gigaset 307x"
24
Tilman Schmidt20387242009-10-06 12:18:41 +000025#ifdef CONFIG_GIGASET_DEBUG
26#define DRIVER_DESC_DEBUG " (debug build)"
27#else
28#define DRIVER_DESC_DEBUG ""
29#endif
30
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080031/* Module parameters */
32int gigaset_debuglevel = DEBUG_DEFAULT;
33EXPORT_SYMBOL_GPL(gigaset_debuglevel);
34module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR);
35MODULE_PARM_DESC(debug, "debug level");
36
Tilman Schmidt70440cf2006-04-10 22:55:14 -070037/* driver state flags */
Tilman Schmidt784d5852006-04-10 22:55:04 -070038#define VALID_MINOR 0x01
39#define VALID_ID 0x02
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080040
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080041void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
Tilman Schmidt01371502006-04-10 22:55:11 -070042 size_t len, const unsigned char *buf)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080043{
44 unsigned char outbuf[80];
Tilman Schmidt784d5852006-04-10 22:55:04 -070045 unsigned char c;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080046 size_t space = sizeof outbuf - 1;
47 unsigned char *out = outbuf;
Tilman Schmidt01371502006-04-10 22:55:11 -070048 size_t numin = len;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080049
Tilman Schmidt01371502006-04-10 22:55:11 -070050 while (numin--) {
Tilman Schmidt784d5852006-04-10 22:55:04 -070051 c = *buf++;
52 if (c == '~' || c == '^' || c == '\\') {
Tilman Schmidt01371502006-04-10 22:55:11 -070053 if (!space--)
Tilman Schmidt784d5852006-04-10 22:55:04 -070054 break;
55 *out++ = '\\';
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080056 }
Tilman Schmidt784d5852006-04-10 22:55:04 -070057 if (c & 0x80) {
Tilman Schmidt01371502006-04-10 22:55:11 -070058 if (!space--)
Tilman Schmidt784d5852006-04-10 22:55:04 -070059 break;
60 *out++ = '~';
61 c ^= 0x80;
62 }
63 if (c < 0x20 || c == 0x7f) {
Tilman Schmidt01371502006-04-10 22:55:11 -070064 if (!space--)
Tilman Schmidt784d5852006-04-10 22:55:04 -070065 break;
66 *out++ = '^';
67 c ^= 0x40;
68 }
Tilman Schmidt01371502006-04-10 22:55:11 -070069 if (!space--)
Tilman Schmidt784d5852006-04-10 22:55:04 -070070 break;
71 *out++ = c;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080072 }
73 *out = 0;
74
Tilman Schmidt784d5852006-04-10 22:55:04 -070075 gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -080076}
77EXPORT_SYMBOL_GPL(gigaset_dbg_buffer);
78
79static int setflags(struct cardstate *cs, unsigned flags, unsigned delay)
80{
81 int r;
82
83 r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags);
84 cs->control_state = flags;
85 if (r < 0)
86 return r;
87
88 if (delay) {
89 set_current_state(TASK_INTERRUPTIBLE);
90 schedule_timeout(delay * HZ / 1000);
91 }
92
93 return 0;
94}
95
96int gigaset_enterconfigmode(struct cardstate *cs)
97{
98 int i, r;
99
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800100 cs->control_state = TIOCM_RTS; //FIXME
101
102 r = setflags(cs, TIOCM_DTR, 200);
103 if (r < 0)
104 goto error;
105 r = setflags(cs, 0, 200);
106 if (r < 0)
107 goto error;
108 for (i = 0; i < 5; ++i) {
109 r = setflags(cs, TIOCM_RTS, 100);
110 if (r < 0)
111 goto error;
112 r = setflags(cs, 0, 100);
113 if (r < 0)
114 goto error;
115 }
116 r = setflags(cs, TIOCM_RTS|TIOCM_DTR, 800);
117 if (r < 0)
118 goto error;
119
120 return 0;
121
122error:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700123 dev_err(cs->dev, "error %d on setuartbits\n", -r);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800124 cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value?
125 cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR);
126
127 return -1; //r
128}
129
130static int test_timeout(struct at_state_t *at_state)
131{
132 if (!at_state->timer_expires)
133 return 0;
134
135 if (--at_state->timer_expires) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700136 gig_dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
137 at_state, at_state->timer_expires);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800138 return 0;
139 }
140
141 if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700142 at_state->timer_index, NULL)) {
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800143 //FIXME what should we do?
144 }
145
146 return 1;
147}
148
149static void timer_tick(unsigned long data)
150{
151 struct cardstate *cs = (struct cardstate *) data;
152 unsigned long flags;
153 unsigned channel;
154 struct at_state_t *at_state;
155 int timeout = 0;
156
157 spin_lock_irqsave(&cs->lock, flags);
158
159 for (channel = 0; channel < cs->channels; ++channel)
160 if (test_timeout(&cs->bcs[channel].at_state))
161 timeout = 1;
162
163 if (test_timeout(&cs->at_state))
164 timeout = 1;
165
166 list_for_each_entry(at_state, &cs->temp_at_states, list)
167 if (test_timeout(at_state))
168 timeout = 1;
169
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700170 if (cs->running) {
Tilman Schmidtec81b5e62006-04-10 22:55:03 -0700171 mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800172 if (timeout) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700173 gig_dbg(DEBUG_CMD, "scheduling timeout");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800174 tasklet_schedule(&cs->event_tasklet);
175 }
176 }
177
178 spin_unlock_irqrestore(&cs->lock, flags);
179}
180
181int gigaset_get_channel(struct bc_state *bcs)
182{
183 unsigned long flags;
184
185 spin_lock_irqsave(&bcs->cs->lock, flags);
Tilman Schmidte468c042008-02-06 01:38:29 -0800186 if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700187 gig_dbg(DEBUG_ANY, "could not allocate channel %d",
188 bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800189 spin_unlock_irqrestore(&bcs->cs->lock, flags);
190 return 0;
191 }
192 ++bcs->use_count;
193 bcs->busy = 1;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700194 gig_dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800195 spin_unlock_irqrestore(&bcs->cs->lock, flags);
196 return 1;
197}
198
199void gigaset_free_channel(struct bc_state *bcs)
200{
201 unsigned long flags;
202
203 spin_lock_irqsave(&bcs->cs->lock, flags);
204 if (!bcs->busy) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700205 gig_dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800206 spin_unlock_irqrestore(&bcs->cs->lock, flags);
207 return;
208 }
209 --bcs->use_count;
210 bcs->busy = 0;
Tilman Schmidte468c042008-02-06 01:38:29 -0800211 module_put(bcs->cs->driver->owner);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700212 gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800213 spin_unlock_irqrestore(&bcs->cs->lock, flags);
214}
215
216int gigaset_get_channels(struct cardstate *cs)
217{
218 unsigned long flags;
219 int i;
220
221 spin_lock_irqsave(&cs->lock, flags);
222 for (i = 0; i < cs->channels; ++i)
223 if (cs->bcs[i].use_count) {
224 spin_unlock_irqrestore(&cs->lock, flags);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700225 gig_dbg(DEBUG_ANY, "could not allocate all channels");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800226 return 0;
227 }
228 for (i = 0; i < cs->channels; ++i)
229 ++cs->bcs[i].use_count;
230 spin_unlock_irqrestore(&cs->lock, flags);
231
Tilman Schmidt784d5852006-04-10 22:55:04 -0700232 gig_dbg(DEBUG_ANY, "allocated all channels");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800233
234 return 1;
235}
236
237void gigaset_free_channels(struct cardstate *cs)
238{
239 unsigned long flags;
240 int i;
241
Tilman Schmidt784d5852006-04-10 22:55:04 -0700242 gig_dbg(DEBUG_ANY, "unblocking all channels");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800243 spin_lock_irqsave(&cs->lock, flags);
244 for (i = 0; i < cs->channels; ++i)
245 --cs->bcs[i].use_count;
246 spin_unlock_irqrestore(&cs->lock, flags);
247}
248
249void gigaset_block_channels(struct cardstate *cs)
250{
251 unsigned long flags;
252 int i;
253
Tilman Schmidt784d5852006-04-10 22:55:04 -0700254 gig_dbg(DEBUG_ANY, "blocking all channels");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800255 spin_lock_irqsave(&cs->lock, flags);
256 for (i = 0; i < cs->channels; ++i)
257 ++cs->bcs[i].use_count;
258 spin_unlock_irqrestore(&cs->lock, flags);
259}
260
261static void clear_events(struct cardstate *cs)
262{
263 struct event_t *ev;
264 unsigned head, tail;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700265 unsigned long flags;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800266
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700267 spin_lock_irqsave(&cs->ev_lock, flags);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800268
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700269 head = cs->ev_head;
270 tail = cs->ev_tail;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800271
272 while (tail != head) {
273 ev = cs->events + head;
274 kfree(ev->ptr);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800275 head = (head + 1) % MAX_EVENTS;
276 }
277
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700278 cs->ev_head = tail;
279
280 spin_unlock_irqrestore(&cs->ev_lock, flags);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800281}
282
283struct event_t *gigaset_add_event(struct cardstate *cs,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700284 struct at_state_t *at_state, int type,
285 void *ptr, int parameter, void *arg)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800286{
287 unsigned long flags;
288 unsigned next, tail;
289 struct event_t *event = NULL;
290
291 spin_lock_irqsave(&cs->ev_lock, flags);
292
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700293 tail = cs->ev_tail;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800294 next = (tail + 1) % MAX_EVENTS;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700295 if (unlikely(next == cs->ev_head))
Tilman Schmidt50027792008-07-23 21:28:27 -0700296 dev_err(cs->dev, "event queue full\n");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800297 else {
298 event = cs->events + tail;
299 event->type = type;
300 event->at_state = at_state;
301 event->cid = -1;
302 event->ptr = ptr;
303 event->arg = arg;
304 event->parameter = parameter;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700305 cs->ev_tail = next;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800306 }
307
308 spin_unlock_irqrestore(&cs->ev_lock, flags);
309
310 return event;
311}
312EXPORT_SYMBOL_GPL(gigaset_add_event);
313
314static void free_strings(struct at_state_t *at_state)
315{
316 int i;
317
318 for (i = 0; i < STR_NUM; ++i) {
319 kfree(at_state->str_var[i]);
320 at_state->str_var[i] = NULL;
321 }
322}
323
324static void clear_at_state(struct at_state_t *at_state)
325{
326 free_strings(at_state);
327}
328
329static void dealloc_at_states(struct cardstate *cs)
330{
331 struct at_state_t *cur, *next;
332
333 list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) {
334 list_del(&cur->list);
335 free_strings(cur);
336 kfree(cur);
337 }
338}
339
340static void gigaset_freebcs(struct bc_state *bcs)
341{
342 int i;
343
Tilman Schmidt784d5852006-04-10 22:55:04 -0700344 gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800345 if (!bcs->cs->ops->freebcshw(bcs)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700346 gig_dbg(DEBUG_INIT, "failed");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800347 }
348
Tilman Schmidt784d5852006-04-10 22:55:04 -0700349 gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800350 clear_at_state(&bcs->at_state);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700351 gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800352
353 if (bcs->skb)
354 dev_kfree_skb(bcs->skb);
355 for (i = 0; i < AT_NUM; ++i) {
356 kfree(bcs->commands[i]);
357 bcs->commands[i] = NULL;
358 }
359}
360
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700361static struct cardstate *alloc_cs(struct gigaset_driver *drv)
362{
363 unsigned long flags;
364 unsigned i;
Tilman Schmidte468c042008-02-06 01:38:29 -0800365 struct cardstate *cs;
Tilman Schmidte702ff02007-01-26 00:56:56 -0800366 struct cardstate *ret = NULL;
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700367
368 spin_lock_irqsave(&drv->lock, flags);
Tilman Schmidte468c042008-02-06 01:38:29 -0800369 if (drv->blocked)
370 goto exit;
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700371 for (i = 0; i < drv->minors; ++i) {
Tilman Schmidte468c042008-02-06 01:38:29 -0800372 cs = drv->cs + i;
373 if (!(cs->flags & VALID_MINOR)) {
374 cs->flags = VALID_MINOR;
375 ret = cs;
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700376 break;
Tilman Schmidte702ff02007-01-26 00:56:56 -0800377 }
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700378 }
Tilman Schmidte468c042008-02-06 01:38:29 -0800379exit:
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700380 spin_unlock_irqrestore(&drv->lock, flags);
381 return ret;
382}
383
384static void free_cs(struct cardstate *cs)
385{
Tilman Schmidte468c042008-02-06 01:38:29 -0800386 cs->flags = 0;
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700387}
388
389static void make_valid(struct cardstate *cs, unsigned mask)
390{
391 unsigned long flags;
392 struct gigaset_driver *drv = cs->driver;
393 spin_lock_irqsave(&drv->lock, flags);
Tilman Schmidte468c042008-02-06 01:38:29 -0800394 cs->flags |= mask;
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700395 spin_unlock_irqrestore(&drv->lock, flags);
396}
397
398static void make_invalid(struct cardstate *cs, unsigned mask)
399{
400 unsigned long flags;
401 struct gigaset_driver *drv = cs->driver;
402 spin_lock_irqsave(&drv->lock, flags);
Tilman Schmidte468c042008-02-06 01:38:29 -0800403 cs->flags &= ~mask;
Tilman Schmidt70440cf2006-04-10 22:55:14 -0700404 spin_unlock_irqrestore(&drv->lock, flags);
405}
406
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800407void gigaset_freecs(struct cardstate *cs)
408{
409 int i;
410 unsigned long flags;
411
412 if (!cs)
413 return;
414
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700415 mutex_lock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800416
417 if (!cs->bcs)
418 goto f_cs;
419 if (!cs->inbuf)
420 goto f_bcs;
421
422 spin_lock_irqsave(&cs->lock, flags);
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700423 cs->running = 0;
Tilman Schmidt917f5082006-04-10 22:55:00 -0700424 spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
425 not rescheduled below */
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800426
427 tasklet_kill(&cs->event_tasklet);
428 del_timer_sync(&cs->timer);
429
430 switch (cs->cs_init) {
431 default:
Hansjoerg Lipp3dda4e32006-04-22 18:43:00 +0200432 /* clear device sysfs */
433 gigaset_free_dev_sysfs(cs);
434
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800435 gigaset_if_free(cs);
436
Tilman Schmidt784d5852006-04-10 22:55:04 -0700437 gig_dbg(DEBUG_INIT, "clearing hw");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800438 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);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700446 gig_dbg(DEBUG_INIT, "clearing iif");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800447 gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
448
449 /* fall through */
450 case 1: /* error when regestering to LL */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700451 gig_dbg(DEBUG_INIT, "clearing at_state");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800452 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) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700458 gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800459 gigaset_freebcs(cs->bcs + i);
460 }
461
462 clear_events(cs);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700463 gig_dbg(DEBUG_INIT, "freeing inbuf");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800464 kfree(cs->inbuf);
465 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700466f_bcs: gig_dbg(DEBUG_INIT, "freeing bcs[]");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800467 kfree(cs->bcs);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700468f_cs: gig_dbg(DEBUG_INIT, "freeing cs");
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700469 mutex_unlock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800470 free_cs(cs);
471}
472EXPORT_SYMBOL_GPL(gigaset_freecs);
473
474void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700475 struct cardstate *cs, int cid)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800476{
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;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700485 at_state->timer_index = 0;
486 at_state->seq_index = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800487 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
503static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700504 struct cardstate *cs, int inputstate)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800505/* inbuf->read must be allocated before! */
506{
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800507 inbuf->head = 0;
508 inbuf->tail = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800509 inbuf->cs = cs;
510 inbuf->bcs = bcs; /*base driver: NULL*/
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800511 inbuf->rcvbuf = NULL;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800512 inbuf->inputstate = inputstate;
513}
514
Tilman Schmidt714e8232006-04-10 22:55:09 -0700515/* append received bytes to inbuf */
516int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
517 unsigned numbytes)
518{
519 unsigned n, head, tail, bytesleft;
520
521 gig_dbg(DEBUG_INTR, "received %u bytes", numbytes);
522
523 if (!numbytes)
524 return 0;
525
526 bytesleft = numbytes;
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800527 tail = inbuf->tail;
528 head = inbuf->head;
Tilman Schmidt714e8232006-04-10 22:55:09 -0700529 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
530
531 while (bytesleft) {
532 if (head > tail)
533 n = head - 1 - tail;
534 else if (head == 0)
535 n = (RBUFSIZE-1) - tail;
536 else
537 n = RBUFSIZE - tail;
538 if (!n) {
539 dev_err(inbuf->cs->dev,
Joe Perches898eb712007-10-18 03:06:30 -0700540 "buffer overflow (%u bytes lost)\n",
541 bytesleft);
Tilman Schmidt714e8232006-04-10 22:55:09 -0700542 break;
543 }
544 if (n > bytesleft)
545 n = bytesleft;
546 memcpy(inbuf->data + tail, src, n);
547 bytesleft -= n;
548 tail = (tail + n) % RBUFSIZE;
549 src += n;
550 }
551 gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800552 inbuf->tail = tail;
Tilman Schmidt714e8232006-04-10 22:55:09 -0700553 return numbytes != bytesleft;
554}
555EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
556
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800557/* Initialize the b-channel structure */
558static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700559 struct cardstate *cs, int channel)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800560{
561 int i;
562
563 bcs->tx_skb = NULL; //FIXME -> hw part
564
565 skb_queue_head_init(&bcs->squeue);
566
567 bcs->corrupted = 0;
568 bcs->trans_down = 0;
569 bcs->trans_up = 0;
570
Tilman Schmidt784d5852006-04-10 22:55:04 -0700571 gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800572 gigaset_at_init(&bcs->at_state, bcs, cs, -1);
573
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800574#ifdef CONFIG_GIGASET_DEBUG
575 bcs->emptycount = 0;
576#endif
577
Tilman Schmidt784d5852006-04-10 22:55:04 -0700578 gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800579 bcs->fcs = PPP_INITFCS;
580 bcs->inputstate = 0;
581 if (cs->ignoreframes) {
582 bcs->inputstate |= INS_skip_frame;
583 bcs->skb = NULL;
584 } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
585 skb_reserve(bcs->skb, HW_HDR_LEN);
586 else {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800587 pr_err("out of memory\n");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800588 bcs->inputstate |= INS_skip_frame;
589 }
590
591 bcs->channel = channel;
592 bcs->cs = cs;
593
594 bcs->chstate = 0;
595 bcs->use_count = 1;
596 bcs->busy = 0;
597 bcs->ignore = cs->ignoreframes;
598
599 for (i = 0; i < AT_NUM; ++i)
600 bcs->commands[i] = NULL;
601
Tilman Schmidt784d5852006-04-10 22:55:04 -0700602 gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800603 if (cs->ops->initbcshw(bcs))
604 return bcs;
605
Tilman Schmidt784d5852006-04-10 22:55:04 -0700606 gig_dbg(DEBUG_INIT, " failed");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800607
Tilman Schmidt784d5852006-04-10 22:55:04 -0700608 gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800609 if (bcs->skb)
610 dev_kfree_skb(bcs->skb);
611
612 return NULL;
613}
614
615/* gigaset_initcs
616 * Allocate and initialize cardstate structure for Gigaset driver
617 * Calls hardware dependent gigaset_initcshw() function
618 * Calls B channel initialization function gigaset_initbcs() for each B channel
619 * parameters:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700620 * drv hardware driver the device belongs to
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800621 * channels number of B channels supported by device
Tilman Schmidt917f5082006-04-10 22:55:00 -0700622 * onechannel !=0: B channel data and AT commands share one
623 * communication channel
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800624 * ==0: B channels have separate communication channels
625 * ignoreframes number of frames to ignore after setting up B channel
626 * cidmode !=0: start in CallID mode
627 * modulename name of driver module (used for I4L registration)
628 * return value:
629 * pointer to cardstate structure
630 */
631struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
632 int onechannel, int ignoreframes,
633 int cidmode, const char *modulename)
634{
635 struct cardstate *cs = NULL;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700636 unsigned long flags;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800637 int i;
638
Tilman Schmidt784d5852006-04-10 22:55:04 -0700639 gig_dbg(DEBUG_INIT, "allocating cs");
Tilman Schmidte702ff02007-01-26 00:56:56 -0800640 if (!(cs = alloc_cs(drv))) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800641 pr_err("maximum number of devices exceeded\n");
Tilman Schmidte702ff02007-01-26 00:56:56 -0800642 return NULL;
643 }
Tilman Schmidte702ff02007-01-26 00:56:56 -0800644
Tilman Schmidt784d5852006-04-10 22:55:04 -0700645 gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800646 cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
Tilman Schmidte702ff02007-01-26 00:56:56 -0800647 if (!cs->bcs) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800648 pr_err("out of memory\n");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800649 goto error;
Tilman Schmidte702ff02007-01-26 00:56:56 -0800650 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700651 gig_dbg(DEBUG_INIT, "allocating inbuf");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800652 cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
Tilman Schmidte702ff02007-01-26 00:56:56 -0800653 if (!cs->inbuf) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800654 pr_err("out of memory\n");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800655 goto error;
Tilman Schmidte702ff02007-01-26 00:56:56 -0800656 }
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800657
658 cs->cs_init = 0;
659 cs->channels = channels;
660 cs->onechannel = onechannel;
661 cs->ignoreframes = ignoreframes;
662 INIT_LIST_HEAD(&cs->temp_at_states);
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700663 cs->running = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800664 init_timer(&cs->timer); /* clear next & prev */
665 spin_lock_init(&cs->ev_lock);
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700666 cs->ev_tail = 0;
667 cs->ev_head = 0;
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700668
Tilman Schmidt917f5082006-04-10 22:55:00 -0700669 tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
670 (unsigned long) cs);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800671 cs->commands_pending = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800672 cs->cur_at_seq = 0;
673 cs->gotfwver = -1;
674 cs->open_count = 0;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700675 cs->dev = NULL;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800676 cs->tty = NULL;
Greg Kroah-Hartman01107d32006-08-07 22:19:37 -0700677 cs->tty_dev = NULL;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700678 cs->cidmode = cidmode != 0;
Tilman Schmidt528efc62009-05-13 12:44:17 +0000679 cs->tabnocid = gigaset_tab_nocid;
680 cs->tabcid = gigaset_tab_cid;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800681
682 init_waitqueue_head(&cs->waitqueue);
683 cs->waiting = 0;
684
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800685 cs->mode = M_UNKNOWN;
686 cs->mstate = MS_UNINITIALIZED;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800687
688 for (i = 0; i < channels; ++i) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700689 gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
Tilman Schmidte702ff02007-01-26 00:56:56 -0800690 if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800691 pr_err("could not allocate channel %d data\n", i);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800692 goto error;
Tilman Schmidte702ff02007-01-26 00:56:56 -0800693 }
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800694 }
695
696 ++cs->cs_init;
697
Tilman Schmidt784d5852006-04-10 22:55:04 -0700698 gig_dbg(DEBUG_INIT, "setting up at_state");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800699 spin_lock_init(&cs->lock);
700 gigaset_at_init(&cs->at_state, NULL, cs, 0);
701 cs->dle = 0;
702 cs->cbytes = 0;
703
Tilman Schmidt784d5852006-04-10 22:55:04 -0700704 gig_dbg(DEBUG_INIT, "setting up inbuf");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800705 if (onechannel) { //FIXME distinction necessary?
706 gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command);
707 } else
708 gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command);
709
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700710 cs->connected = 0;
711 cs->isdn_up = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800712
Tilman Schmidt784d5852006-04-10 22:55:04 -0700713 gig_dbg(DEBUG_INIT, "setting up cmdbuf");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800714 cs->cmdbuf = cs->lastcmdbuf = NULL;
715 spin_lock_init(&cs->cmdlock);
716 cs->curlen = 0;
717 cs->cmdbytes = 0;
718
Tilman Schmidt784d5852006-04-10 22:55:04 -0700719 gig_dbg(DEBUG_INIT, "setting up iif");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800720 if (!gigaset_register_to_LL(cs, modulename)) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800721 pr_err("error registering ISDN device\n");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800722 goto error;
723 }
724
725 make_valid(cs, VALID_ID);
726 ++cs->cs_init;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700727 gig_dbg(DEBUG_INIT, "setting up hw");
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800728 if (!cs->ops->initcshw(cs))
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800729 goto error;
730
731 ++cs->cs_init;
732
Tilman Schmidt7435f502007-02-12 00:52:24 -0800733 /* set up character device */
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800734 gigaset_if_init(cs);
735
Hansjoerg Lipp3dda4e32006-04-22 18:43:00 +0200736 /* set up device sysfs */
737 gigaset_init_dev_sysfs(cs);
738
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700739 spin_lock_irqsave(&cs->lock, flags);
740 cs->running = 1;
741 spin_unlock_irqrestore(&cs->lock, flags);
Tilman Schmidtec81b5e62006-04-10 22:55:03 -0700742 setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
743 cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800744 /* FIXME: can jiffies increase too much until the timer is added?
745 * Same problem(?) with mod_timer() in timer_tick(). */
746 add_timer(&cs->timer);
747
Tilman Schmidt784d5852006-04-10 22:55:04 -0700748 gig_dbg(DEBUG_INIT, "cs initialized");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800749 return cs;
750
Tilman Schmidte702ff02007-01-26 00:56:56 -0800751error:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700752 gig_dbg(DEBUG_INIT, "failed");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800753 gigaset_freecs(cs);
754 return NULL;
755}
756EXPORT_SYMBOL_GPL(gigaset_initcs);
757
Tilman Schmidt73a88812006-04-22 02:35:30 -0700758/* ReInitialize the b-channel structure on hangup */
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800759void gigaset_bcs_reinit(struct bc_state *bcs)
760{
761 struct sk_buff *skb;
762 struct cardstate *cs = bcs->cs;
763 unsigned long flags;
764
765 while ((skb = skb_dequeue(&bcs->squeue)) != NULL)
766 dev_kfree_skb(skb);
767
Tilman Schmidt917f5082006-04-10 22:55:00 -0700768 spin_lock_irqsave(&cs->lock, flags);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800769 clear_at_state(&bcs->at_state);
770 bcs->at_state.ConState = 0;
771 bcs->at_state.timer_active = 0;
772 bcs->at_state.timer_expires = 0;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700773 bcs->at_state.cid = -1; /* No CID defined */
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800774 spin_unlock_irqrestore(&cs->lock, flags);
775
776 bcs->inputstate = 0;
777
778#ifdef CONFIG_GIGASET_DEBUG
779 bcs->emptycount = 0;
780#endif
781
782 bcs->fcs = PPP_INITFCS;
783 bcs->chstate = 0;
784
785 bcs->ignore = cs->ignoreframes;
786 if (bcs->ignore)
787 bcs->inputstate |= INS_skip_frame;
788
789
790 cs->ops->reinitbcshw(bcs);
791}
792
793static void cleanup_cs(struct cardstate *cs)
794{
795 struct cmdbuf_t *cb, *tcb;
796 int i;
797 unsigned long flags;
798
799 spin_lock_irqsave(&cs->lock, flags);
800
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800801 cs->mode = M_UNKNOWN;
802 cs->mstate = MS_UNINITIALIZED;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800803
804 clear_at_state(&cs->at_state);
805 dealloc_at_states(cs);
806 free_strings(&cs->at_state);
807 gigaset_at_init(&cs->at_state, NULL, cs, 0);
808
809 kfree(cs->inbuf->rcvbuf);
810 cs->inbuf->rcvbuf = NULL;
811 cs->inbuf->inputstate = INS_command;
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800812 cs->inbuf->head = 0;
813 cs->inbuf->tail = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800814
815 cb = cs->cmdbuf;
816 while (cb) {
817 tcb = cb;
818 cb = cb->next;
819 kfree(tcb);
820 }
821 cs->cmdbuf = cs->lastcmdbuf = NULL;
822 cs->curlen = 0;
823 cs->cmdbytes = 0;
824 cs->gotfwver = -1;
825 cs->dle = 0;
826 cs->cur_at_seq = 0;
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800827 cs->commands_pending = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800828 cs->cbytes = 0;
829
830 spin_unlock_irqrestore(&cs->lock, flags);
831
832 for (i = 0; i < cs->channels; ++i) {
833 gigaset_freebcs(cs->bcs + i);
834 if (!gigaset_initbcs(cs->bcs + i, cs, i))
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800835 pr_err("could not allocate channel %d data\n", i);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800836 }
837
838 if (cs->waiting) {
839 cs->cmd_result = -ENODEV;
840 cs->waiting = 0;
841 wake_up_interruptible(&cs->waitqueue);
842 }
843}
844
845
846int gigaset_start(struct cardstate *cs)
847{
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700848 unsigned long flags;
849
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700850 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800851 return 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800852
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700853 spin_lock_irqsave(&cs->lock, flags);
854 cs->connected = 1;
855 spin_unlock_irqrestore(&cs->lock, flags);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800856
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800857 if (cs->mstate != MS_LOCKED) {
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800858 cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
859 cs->ops->baud_rate(cs, B115200);
860 cs->ops->set_line_ctrl(cs, CS8);
861 cs->control_state = TIOCM_DTR|TIOCM_RTS;
862 } else {
863 //FIXME use some saved values?
864 }
865
866 cs->waiting = 1;
867
868 if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
869 cs->waiting = 0;
870 //FIXME what should we do?
871 goto error;
872 }
873
Tilman Schmidt784d5852006-04-10 22:55:04 -0700874 gig_dbg(DEBUG_CMD, "scheduling START");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800875 gigaset_schedule_event(cs);
876
877 wait_event(cs->waitqueue, !cs->waiting);
878
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700879 mutex_unlock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800880 return 1;
881
882error:
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700883 mutex_unlock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800884 return 0;
885}
886EXPORT_SYMBOL_GPL(gigaset_start);
887
Tilman Schmidte468c042008-02-06 01:38:29 -0800888/* gigaset_shutdown
889 * check if a device is associated to the cardstate structure and stop it
890 * return value: 0 if ok, -1 if no device was associated
891 */
892int gigaset_shutdown(struct cardstate *cs)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800893{
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700894 mutex_lock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800895
Tilman Schmidt5d49c1012008-03-07 19:47:08 +0100896 if (!(cs->flags & VALID_MINOR)) {
897 mutex_unlock(&cs->mutex);
Tilman Schmidte468c042008-02-06 01:38:29 -0800898 return -1;
Tilman Schmidt5d49c1012008-03-07 19:47:08 +0100899 }
Tilman Schmidte468c042008-02-06 01:38:29 -0800900
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800901 cs->waiting = 1;
902
903 if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
904 //FIXME what should we do?
905 goto exit;
906 }
907
Tilman Schmidt784d5852006-04-10 22:55:04 -0700908 gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800909 gigaset_schedule_event(cs);
910
Tilman Schmidt2869b232007-02-12 00:52:34 -0800911 wait_event(cs->waitqueue, !cs->waiting);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800912
913 cleanup_cs(cs);
914
915exit:
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700916 mutex_unlock(&cs->mutex);
Tilman Schmidte468c042008-02-06 01:38:29 -0800917 return 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800918}
919EXPORT_SYMBOL_GPL(gigaset_shutdown);
920
921void gigaset_stop(struct cardstate *cs)
922{
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700923 mutex_lock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800924
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800925 cs->waiting = 1;
926
927 if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
928 //FIXME what should we do?
929 goto exit;
930 }
931
Tilman Schmidt784d5852006-04-10 22:55:04 -0700932 gig_dbg(DEBUG_CMD, "scheduling STOP");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800933 gigaset_schedule_event(cs);
934
Tilman Schmidt2869b232007-02-12 00:52:34 -0800935 wait_event(cs->waitqueue, !cs->waiting);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800936
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800937 cleanup_cs(cs);
938
939exit:
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700940 mutex_unlock(&cs->mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800941}
942EXPORT_SYMBOL_GPL(gigaset_stop);
943
944static LIST_HEAD(drivers);
Ingo Molnar34af9462006-06-27 02:53:55 -0700945static DEFINE_SPINLOCK(driver_lock);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800946
947struct cardstate *gigaset_get_cs_by_id(int id)
948{
949 unsigned long flags;
Tilman Schmidt35dc8452007-03-29 01:20:34 -0700950 struct cardstate *ret = NULL;
951 struct cardstate *cs;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800952 struct gigaset_driver *drv;
953 unsigned i;
954
955 spin_lock_irqsave(&driver_lock, flags);
956 list_for_each_entry(drv, &drivers, list) {
957 spin_lock(&drv->lock);
958 for (i = 0; i < drv->minors; ++i) {
Tilman Schmidte468c042008-02-06 01:38:29 -0800959 cs = drv->cs + i;
960 if ((cs->flags & VALID_ID) && cs->myid == id) {
961 ret = cs;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800962 break;
Tilman Schmidte468c042008-02-06 01:38:29 -0800963 }
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800964 }
965 spin_unlock(&drv->lock);
966 if (ret)
967 break;
968 }
969 spin_unlock_irqrestore(&driver_lock, flags);
970 return ret;
971}
972
973void gigaset_debugdrivers(void)
974{
975 unsigned long flags;
976 static struct cardstate *cs;
977 struct gigaset_driver *drv;
978 unsigned i;
979
980 spin_lock_irqsave(&driver_lock, flags);
981 list_for_each_entry(drv, &drivers, list) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700982 gig_dbg(DEBUG_DRIVER, "driver %p", drv);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800983 spin_lock(&drv->lock);
984 for (i = 0; i < drv->minors; ++i) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700985 gig_dbg(DEBUG_DRIVER, " index %u", i);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800986 cs = drv->cs + i;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700987 gig_dbg(DEBUG_DRIVER, " cardstate %p", cs);
Tilman Schmidte468c042008-02-06 01:38:29 -0800988 gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700989 gig_dbg(DEBUG_DRIVER, " minor_index %u",
990 cs->minor_index);
991 gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver);
992 gig_dbg(DEBUG_DRIVER, " i4l id %d", cs->myid);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800993 }
994 spin_unlock(&drv->lock);
995 }
996 spin_unlock_irqrestore(&driver_lock, flags);
997}
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -0800998
Adrian Bunk8ca445d2006-04-10 22:55:18 -0700999static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001000{
1001 unsigned long flags;
Tilman Schmidt35dc8452007-03-29 01:20:34 -07001002 struct cardstate *ret = NULL;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001003 struct gigaset_driver *drv;
1004 unsigned index;
1005
1006 spin_lock_irqsave(&driver_lock, flags);
1007 list_for_each_entry(drv, &drivers, list) {
1008 if (minor < drv->minor || minor >= drv->minor + drv->minors)
1009 continue;
1010 index = minor - drv->minor;
1011 spin_lock(&drv->lock);
Tilman Schmidte468c042008-02-06 01:38:29 -08001012 if (drv->cs[index].flags & VALID_MINOR)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001013 ret = drv->cs + index;
1014 spin_unlock(&drv->lock);
1015 if (ret)
1016 break;
1017 }
1018 spin_unlock_irqrestore(&driver_lock, flags);
1019 return ret;
1020}
1021
Adrian Bunk8ca445d2006-04-10 22:55:18 -07001022struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
1023{
1024 if (tty->index < 0 || tty->index >= tty->driver->num)
1025 return NULL;
1026 return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
1027}
1028
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001029void gigaset_freedriver(struct gigaset_driver *drv)
1030{
1031 unsigned long flags;
1032
1033 spin_lock_irqsave(&driver_lock, flags);
1034 list_del(&drv->list);
1035 spin_unlock_irqrestore(&driver_lock, flags);
1036
1037 gigaset_if_freedriver(drv);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001038
1039 kfree(drv->cs);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001040 kfree(drv);
1041}
1042EXPORT_SYMBOL_GPL(gigaset_freedriver);
1043
1044/* gigaset_initdriver
1045 * Allocate and initialize gigaset_driver structure. Initialize interface.
1046 * parameters:
Tilman Schmidt784d5852006-04-10 22:55:04 -07001047 * minor First minor number
1048 * minors Number of minors this driver can handle
1049 * procname Name of the driver
1050 * devname Name of the device files (prefix without minor number)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001051 * return value:
Tilman Schmidt784d5852006-04-10 22:55:04 -07001052 * Pointer to the gigaset_driver structure on success, NULL on failure.
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001053 */
1054struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
Tilman Schmidt784d5852006-04-10 22:55:04 -07001055 const char *procname,
1056 const char *devname,
Tilman Schmidt784d5852006-04-10 22:55:04 -07001057 const struct gigaset_ops *ops,
1058 struct module *owner)
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001059{
1060 struct gigaset_driver *drv;
1061 unsigned long flags;
1062 unsigned i;
1063
1064 drv = kmalloc(sizeof *drv, GFP_KERNEL);
1065 if (!drv)
1066 return NULL;
Adrian Bunkf4675c72006-04-10 22:55:19 -07001067
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001068 drv->have_tty = 0;
1069 drv->minor = minor;
1070 drv->minors = minors;
1071 spin_lock_init(&drv->lock);
1072 drv->blocked = 0;
1073 drv->ops = ops;
1074 drv->owner = owner;
1075 INIT_LIST_HEAD(&drv->list);
1076
1077 drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL);
1078 if (!drv->cs)
Tilman Schmidte702ff02007-01-26 00:56:56 -08001079 goto error;
Adrian Bunkf4675c72006-04-10 22:55:19 -07001080
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001081 for (i = 0; i < minors; ++i) {
Tilman Schmidte468c042008-02-06 01:38:29 -08001082 drv->cs[i].flags = 0;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001083 drv->cs[i].driver = drv;
1084 drv->cs[i].ops = drv->ops;
1085 drv->cs[i].minor_index = i;
Tilman Schmidt5d49c1012008-03-07 19:47:08 +01001086 mutex_init(&drv->cs[i].mutex);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001087 }
1088
Greg Kroah-Hartmanf4eaa372005-06-20 21:15:16 -07001089 gigaset_if_initdriver(drv, procname, devname);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001090
1091 spin_lock_irqsave(&driver_lock, flags);
1092 list_add(&drv->list, &drivers);
1093 spin_unlock_irqrestore(&driver_lock, flags);
1094
1095 return drv;
1096
Tilman Schmidte702ff02007-01-26 00:56:56 -08001097error:
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001098 kfree(drv->cs);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001099 kfree(drv);
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001100 return NULL;
1101}
1102EXPORT_SYMBOL_GPL(gigaset_initdriver);
1103
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001104void gigaset_blockdriver(struct gigaset_driver *drv)
1105{
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001106 drv->blocked = 1;
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001107}
1108EXPORT_SYMBOL_GPL(gigaset_blockdriver);
1109
1110static int __init gigaset_init_module(void)
1111{
1112 /* in accordance with the principle of least astonishment,
1113 * setting the 'debug' parameter to 1 activates a sensible
1114 * set of default debug levels
1115 */
1116 if (gigaset_debuglevel == 1)
1117 gigaset_debuglevel = DEBUG_DEFAULT;
1118
Tilman Schmidt20387242009-10-06 12:18:41 +00001119 pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n");
Hansjoerg Lipp6fd5ea62006-03-26 01:38:29 -08001120 return 0;
1121}
1122
1123static void __exit gigaset_exit_module(void)
1124{
1125}
1126
1127module_init(gigaset_init_module);
1128module_exit(gigaset_exit_module);
1129
1130MODULE_AUTHOR(DRIVER_AUTHOR);
1131MODULE_DESCRIPTION(DRIVER_DESC);
1132
1133MODULE_LICENSE("GPL");