]> err.no Git - linux-2.6/blob - drivers/char/pcmcia/ipwireless/network.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6] / drivers / char / pcmcia / ipwireless / network.c
1 /*
2  * IPWireless 3G PCMCIA Network Driver
3  *
4  * Original code
5  *   by Stephen Blackheath <stephen@blacksapphire.com>,
6  *      Ben Martel <benm@symmetric.co.nz>
7  *
8  * Copyrighted as follows:
9  *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
10  *
11  * Various driver changes and rewrites, port to new kernels
12  *   Copyright (C) 2006-2007 Jiri Kosina
13  *
14  * Misc code cleanups and updates
15  *   Copyright (C) 2007 David Sterba
16  */
17
18 #include <linux/interrupt.h>
19 #include <linux/kernel.h>
20 #include <linux/mutex.h>
21 #include <linux/netdevice.h>
22 #include <linux/ppp_channel.h>
23 #include <linux/ppp_defs.h>
24 #include <linux/if_ppp.h>
25 #include <linux/skbuff.h>
26
27 #include "network.h"
28 #include "hardware.h"
29 #include "main.h"
30 #include "tty.h"
31
32 #define MAX_OUTGOING_PACKETS_QUEUED   ipwireless_out_queue
33 #define MAX_ASSOCIATED_TTYS 2
34
35 #define SC_RCV_BITS     (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
36
37 struct ipw_network {
38         /* Hardware context, used for calls to hardware layer. */
39         struct ipw_hardware *hardware;
40         /* Context for kernel 'generic_ppp' functionality */
41         struct ppp_channel *ppp_channel;
42         /* tty context connected with IPW console */
43         struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS];
44         /* True if ppp needs waking up once we're ready to xmit */
45         int ppp_blocked;
46         /* Number of packets queued up in hardware module. */
47         int outgoing_packets_queued;
48         /* Spinlock to avoid interrupts during shutdown */
49         spinlock_t spinlock;
50         struct mutex close_lock;
51
52         /* PPP ioctl data, not actually used anywere */
53         unsigned int flags;
54         unsigned int rbits;
55         u32 xaccm[8];
56         u32 raccm;
57         int mru;
58
59         int shutting_down;
60         unsigned int ras_control_lines;
61
62         struct work_struct work_go_online;
63         struct work_struct work_go_offline;
64 };
65
66 static void notify_packet_sent(void *callback_data, unsigned int packet_length)
67 {
68         struct ipw_network *network = callback_data;
69         unsigned long flags;
70
71         spin_lock_irqsave(&network->spinlock, flags);
72         network->outgoing_packets_queued--;
73         if (network->ppp_channel != NULL) {
74                 if (network->ppp_blocked) {
75                         network->ppp_blocked = 0;
76                         spin_unlock_irqrestore(&network->spinlock, flags);
77                         ppp_output_wakeup(network->ppp_channel);
78                         if (ipwireless_debug)
79                                 printk(KERN_INFO IPWIRELESS_PCCARD_NAME
80                                        ": ppp unblocked\n");
81                 } else
82                         spin_unlock_irqrestore(&network->spinlock, flags);
83         } else
84                 spin_unlock_irqrestore(&network->spinlock, flags);
85 }
86
87 /*
88  * Called by the ppp system when it has a packet to send to the hardware.
89  */
90 static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
91                                      struct sk_buff *skb)
92 {
93         struct ipw_network *network = ppp_channel->private;
94         unsigned long flags;
95
96         spin_lock_irqsave(&network->spinlock, flags);
97         if (network->outgoing_packets_queued < MAX_OUTGOING_PACKETS_QUEUED) {
98                 unsigned char *buf;
99                 static unsigned char header[] = {
100                         PPP_ALLSTATIONS, /* 0xff */
101                         PPP_UI,          /* 0x03 */
102                 };
103                 int ret;
104
105                 network->outgoing_packets_queued++;
106                 spin_unlock_irqrestore(&network->spinlock, flags);
107
108                 /*
109                  * If we have the requested amount of headroom in the skb we
110                  * were handed, then we can add the header efficiently.
111                  */
112                 if (skb_headroom(skb) >= 2) {
113                         memcpy(skb_push(skb, 2), header, 2);
114                         ret = ipwireless_send_packet(network->hardware,
115                                                IPW_CHANNEL_RAS, skb->data,
116                                                skb->len,
117                                                notify_packet_sent,
118                                                network);
119                         if (ret == -1) {
120                                 skb_pull(skb, 2);
121                                 return 0;
122                         }
123                 } else {
124                         /* Otherwise (rarely) we do it inefficiently. */
125                         buf = kmalloc(skb->len + 2, GFP_ATOMIC);
126                         if (!buf)
127                                 return 0;
128                         memcpy(buf + 2, skb->data, skb->len);
129                         memcpy(buf, header, 2);
130                         ret = ipwireless_send_packet(network->hardware,
131                                                IPW_CHANNEL_RAS, buf,
132                                                skb->len + 2,
133                                                notify_packet_sent,
134                                                network);
135                         kfree(buf);
136                         if (ret == -1)
137                                 return 0;
138                 }
139                 kfree_skb(skb);
140                 return 1;
141         } else {
142                 /*
143                  * Otherwise reject the packet, and flag that the ppp system
144                  * needs to be unblocked once we are ready to send.
145                  */
146                 network->ppp_blocked = 1;
147                 spin_unlock_irqrestore(&network->spinlock, flags);
148                 return 0;
149         }
150 }
151
152 /* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */
153 static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel,
154                                 unsigned int cmd, unsigned long arg)
155 {
156         struct ipw_network *network = ppp_channel->private;
157         int err, val;
158         u32 accm[8];
159         int __user *user_arg = (int __user *) arg;
160
161         err = -EFAULT;
162         switch (cmd) {
163         case PPPIOCGFLAGS:
164                 val = network->flags | network->rbits;
165                 if (put_user(val, user_arg))
166                         break;
167                 err = 0;
168                 break;
169
170         case PPPIOCSFLAGS:
171                 if (get_user(val, user_arg))
172                         break;
173                 network->flags = val & ~SC_RCV_BITS;
174                 network->rbits = val & SC_RCV_BITS;
175                 err = 0;
176                 break;
177
178         case PPPIOCGASYNCMAP:
179                 if (put_user(network->xaccm[0], user_arg))
180                         break;
181                 err = 0;
182                 break;
183
184         case PPPIOCSASYNCMAP:
185                 if (get_user(network->xaccm[0], user_arg))
186                         break;
187                 err = 0;
188                 break;
189
190         case PPPIOCGRASYNCMAP:
191                 if (put_user(network->raccm, user_arg))
192                         break;
193                 err = 0;
194                 break;
195
196         case PPPIOCSRASYNCMAP:
197                 if (get_user(network->raccm, user_arg))
198                         break;
199                 err = 0;
200                 break;
201
202         case PPPIOCGXASYNCMAP:
203                 if (copy_to_user((void __user *) arg, network->xaccm,
204                                         sizeof(network->xaccm)))
205                         break;
206                 err = 0;
207                 break;
208
209         case PPPIOCSXASYNCMAP:
210                 if (copy_from_user(accm, (void __user *) arg, sizeof(accm)))
211                         break;
212                 accm[2] &= ~0x40000000U;        /* can't escape 0x5e */
213                 accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
214                 memcpy(network->xaccm, accm, sizeof(network->xaccm));
215                 err = 0;
216                 break;
217
218         case PPPIOCGMRU:
219                 if (put_user(network->mru, user_arg))
220                         break;
221                 err = 0;
222                 break;
223
224         case PPPIOCSMRU:
225                 if (get_user(val, user_arg))
226                         break;
227                 if (val < PPP_MRU)
228                         val = PPP_MRU;
229                 network->mru = val;
230                 err = 0;
231                 break;
232
233         default:
234                 err = -ENOTTY;
235         }
236
237         return err;
238 }
239
240 static struct ppp_channel_ops ipwireless_ppp_channel_ops = {
241         .start_xmit = ipwireless_ppp_start_xmit,
242         .ioctl      = ipwireless_ppp_ioctl
243 };
244
245 static void do_go_online(struct work_struct *work_go_online)
246 {
247         struct ipw_network *network =
248                 container_of(work_go_online, struct ipw_network,
249                                 work_go_online);
250         unsigned long flags;
251
252         spin_lock_irqsave(&network->spinlock, flags);
253         if (!network->ppp_channel) {
254                 struct ppp_channel *channel;
255
256                 spin_unlock_irqrestore(&network->spinlock, flags);
257                 channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL);
258                 if (!channel) {
259                         printk(KERN_ERR IPWIRELESS_PCCARD_NAME
260                                         ": unable to allocate PPP channel\n");
261                         return;
262                 }
263                 channel->private = network;
264                 channel->mtu = 16384;   /* Wild guess */
265                 channel->hdrlen = 2;
266                 channel->ops = &ipwireless_ppp_channel_ops;
267
268                 network->flags = 0;
269                 network->rbits = 0;
270                 network->mru = PPP_MRU;
271                 memset(network->xaccm, 0, sizeof(network->xaccm));
272                 network->xaccm[0] = ~0U;
273                 network->xaccm[3] = 0x60000000U;
274                 network->raccm = ~0U;
275                 ppp_register_channel(channel);
276                 spin_lock_irqsave(&network->spinlock, flags);
277                 network->ppp_channel = channel;
278         }
279         spin_unlock_irqrestore(&network->spinlock, flags);
280 }
281
282 static void do_go_offline(struct work_struct *work_go_offline)
283 {
284         struct ipw_network *network =
285                 container_of(work_go_offline, struct ipw_network,
286                                 work_go_offline);
287         unsigned long flags;
288
289         mutex_lock(&network->close_lock);
290         spin_lock_irqsave(&network->spinlock, flags);
291         if (network->ppp_channel != NULL) {
292                 struct ppp_channel *channel = network->ppp_channel;
293
294                 network->ppp_channel = NULL;
295                 spin_unlock_irqrestore(&network->spinlock, flags);
296                 mutex_unlock(&network->close_lock);
297                 ppp_unregister_channel(channel);
298         } else {
299                 spin_unlock_irqrestore(&network->spinlock, flags);
300                 mutex_unlock(&network->close_lock);
301         }
302 }
303
304 void ipwireless_network_notify_control_line_change(struct ipw_network *network,
305                                                    unsigned int channel_idx,
306                                                    unsigned int control_lines,
307                                                    unsigned int changed_mask)
308 {
309         int i;
310
311         if (channel_idx == IPW_CHANNEL_RAS)
312                 network->ras_control_lines = control_lines;
313
314         for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
315                 struct ipw_tty *tty =
316                         network->associated_ttys[channel_idx][i];
317
318                 /*
319                  * If it's associated with a tty (other than the RAS channel
320                  * when we're online), then send the data to that tty.  The RAS
321                  * channel's data is handled above - it always goes through
322                  * ppp_generic.
323                  */
324                 if (tty)
325                         ipwireless_tty_notify_control_line_change(tty,
326                                                                   channel_idx,
327                                                                   control_lines,
328                                                                   changed_mask);
329         }
330 }
331
332 /*
333  * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI)
334  * bytes, which are required on sent packet, but not always present on received
335  * packets
336  */
337 static struct sk_buff *ipw_packet_received_skb(unsigned char *data,
338                                                unsigned int length)
339 {
340         struct sk_buff *skb;
341
342         if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) {
343                 length -= 2;
344                 data += 2;
345         }
346
347         skb = dev_alloc_skb(length + 4);
348         skb_reserve(skb, 2);
349         memcpy(skb_put(skb, length), data, length);
350
351         return skb;
352 }
353
354 void ipwireless_network_packet_received(struct ipw_network *network,
355                                         unsigned int channel_idx,
356                                         unsigned char *data,
357                                         unsigned int length)
358 {
359         int i;
360         unsigned long flags;
361
362         for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
363                 struct ipw_tty *tty = network->associated_ttys[channel_idx][i];
364
365                 if (!tty)
366                         continue;
367
368                 /*
369                  * If it's associated with a tty (other than the RAS channel
370                  * when we're online), then send the data to that tty.  The RAS
371                  * channel's data is handled above - it always goes through
372                  * ppp_generic.
373                  */
374                 if (channel_idx == IPW_CHANNEL_RAS
375                                 && (network->ras_control_lines &
376                                         IPW_CONTROL_LINE_DCD) != 0
377                                 && ipwireless_tty_is_modem(tty)) {
378                         /*
379                          * If data came in on the RAS channel and this tty is
380                          * the modem tty, and we are online, then we send it to
381                          * the PPP layer.
382                          */
383                         mutex_lock(&network->close_lock);
384                         spin_lock_irqsave(&network->spinlock, flags);
385                         if (network->ppp_channel != NULL) {
386                                 struct sk_buff *skb;
387
388                                 spin_unlock_irqrestore(&network->spinlock,
389                                                 flags);
390
391                                 /* Send the data to the ppp_generic module. */
392                                 skb = ipw_packet_received_skb(data, length);
393                                 ppp_input(network->ppp_channel, skb);
394                         } else
395                                 spin_unlock_irqrestore(&network->spinlock,
396                                                 flags);
397                         mutex_unlock(&network->close_lock);
398                 }
399                 /* Otherwise we send it out the tty. */
400                 else
401                         ipwireless_tty_received(tty, data, length);
402         }
403 }
404
405 struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw)
406 {
407         struct ipw_network *network =
408                 kzalloc(sizeof(struct ipw_network), GFP_ATOMIC);
409
410         if (!network)
411                 return NULL;
412
413         spin_lock_init(&network->spinlock);
414         mutex_init(&network->close_lock);
415
416         network->hardware = hw;
417
418         INIT_WORK(&network->work_go_online, do_go_online);
419         INIT_WORK(&network->work_go_offline, do_go_offline);
420
421         ipwireless_associate_network(hw, network);
422
423         return network;
424 }
425
426 void ipwireless_network_free(struct ipw_network *network)
427 {
428         network->shutting_down = 1;
429
430         ipwireless_ppp_close(network);
431         flush_scheduled_work();
432
433         ipwireless_stop_interrupts(network->hardware);
434         ipwireless_associate_network(network->hardware, NULL);
435
436         kfree(network);
437 }
438
439 void ipwireless_associate_network_tty(struct ipw_network *network,
440                                       unsigned int channel_idx,
441                                       struct ipw_tty *tty)
442 {
443         int i;
444
445         for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
446                 if (network->associated_ttys[channel_idx][i] == NULL) {
447                         network->associated_ttys[channel_idx][i] = tty;
448                         break;
449                 }
450 }
451
452 void ipwireless_disassociate_network_ttys(struct ipw_network *network,
453                                           unsigned int channel_idx)
454 {
455         int i;
456
457         for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
458                 network->associated_ttys[channel_idx][i] = NULL;
459 }
460
461 void ipwireless_ppp_open(struct ipw_network *network)
462 {
463         if (ipwireless_debug)
464                 printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n");
465         schedule_work(&network->work_go_online);
466 }
467
468 void ipwireless_ppp_close(struct ipw_network *network)
469 {
470         /* Disconnect from the wireless network. */
471         if (ipwireless_debug)
472                 printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n");
473         schedule_work(&network->work_go_offline);
474 }
475
476 int ipwireless_ppp_channel_index(struct ipw_network *network)
477 {
478         int ret = -1;
479         unsigned long flags;
480
481         spin_lock_irqsave(&network->spinlock, flags);
482         if (network->ppp_channel != NULL)
483                 ret = ppp_channel_index(network->ppp_channel);
484         spin_unlock_irqrestore(&network->spinlock, flags);
485
486         return ret;
487 }
488
489 int ipwireless_ppp_unit_number(struct ipw_network *network)
490 {
491         int ret = -1;
492         unsigned long flags;
493
494         spin_lock_irqsave(&network->spinlock, flags);
495         if (network->ppp_channel != NULL)
496                 ret = ppp_unit_number(network->ppp_channel);
497         spin_unlock_irqrestore(&network->spinlock, flags);
498
499         return ret;
500 }