aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHansjoerg Lipp <hjlipp@web.de>2006-03-26 04:38:31 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-26 11:57:05 -0500
commit3c66a22545dd88356bbf4efa45a7b178df8154e9 (patch)
tree96d6115cddf69655d6b4b7b3866fdad8e2cef0a8
parent14fa73a75df6a0ffe866f750e8dcd218d0171f51 (diff)
[PATCH] isdn4linux: Siemens Gigaset drivers - isdn4linux interface
And: Tilman Schmidt <tilman@imap.cc> This patch adds the isdn4linux subsystem interface to the gigaset module. The isdn4linux subsystem interface handles requests from and notifications to the isdn4linux subsystem. Signed-off-by: Hansjoerg Lipp <hjlipp@web.de> Signed-off-by: Tilman Schmidt <tilman@imap.cc> Cc: Karsten Keil <kkeil@suse.de> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/isdn/gigaset/i4l.c567
1 files changed, 567 insertions, 0 deletions
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 */
39static 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
84void 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}
108EXPORT_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 */
114static 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?