]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-atmdd.patch
- up to 4.9.217
[packages/kernel.git] / kernel-atmdd.patch
1 diff -urN linux-2.4.25/drivers/atm/Makefile linux-2.4.25-atmdd/drivers/atm/Makefile
2 --- linux-2.4.25/drivers/atm/Makefile   2004-02-23 15:18:29.000000000 +0100
3 +++ linux-2.4.25-atmdd/drivers/atm/Makefile     2004-02-29 22:51:26.000000000 +0100
4 @@ -31,6 +31,7 @@
5  endif
6  
7  obj-$(CONFIG_ATM_DUMMY)                += adummy.o
8 +obj-$(CONFIG_ATM_DD)           += atmdd.o
9  obj-$(CONFIG_ATM_TCP)          += atmtcp.o
10  obj-$(CONFIG_ATM_FIRESTREAM)   += firestream.o
11  obj-$(CONFIG_ATM_LANAI)                += lanai.o
12 diff -urN linux-2.4.25/drivers/atm/Kconfig linux-2.4.25-atmdd/drivers/atm/Kconfig
13 --- linux-2.4.25/drivers/atm/Kcnfig     2003-08-25 13:44:41.000000000 +0200
14 +++ linux-2.4.25-atmdd/drivers/atm/Kconfig      2004-02-29 22:52:59.000000000 +0100
15 @@ -4,6 +4,14 @@
16         default y
17  
18  if ATM_DRIVERS && NETDEVICES && ATM
19 +
20 +config ATM_DD
21 +       tristate "ATM loopback"
22 +       depends on INET && ATM
23 +       help
24 +         This is an example atm driver.  It does not require any actual ATM
25 +         hardware.  It supports AAL5 and AAL0.  Frames are merely looped back
26 +         to the sender on the same VC they were sent.
27  
28  config ATM_DUMMY
29         tristate "Dummy ATM driver"
30 diff -urN linux-2.4.25/drivers/atm/atmdd.c linux-2.4.25-atmdd/drivers/atm/atmdd.c
31 --- linux-2.4.25/drivers/atm/atmdd.c    1970-01-01 01:00:00.000000000 +0100
32 +++ linux-2.4.25-atmdd/drivers/atm/atmdd.c      2004-02-29 22:58:11.000000000 +0100
33 @@ -0,0 +1,921 @@
34 +/*
35 +#######################################################################
36 +#
37 +# (C) Copyright 2001
38 +# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
39 +#
40 +# This program is free software; you can redistribute it and/or
41 +# modify it under the terms of the GNU General Public License as
42 +# published by the Free Software Foundation; either version 2 of
43 +# the License, or (at your option) any later version.
44 +#
45 +# This program is distributed in the hope that it will be useful,
46 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
47 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
48 +# GNU General Public License for more details.
49 +#
50 +# You should have received a copy of the GNU General Public License
51 +# along with this program; if not, write to the Free Software
52 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
53 +# MA 02111-1307 USA
54 +#######################################################################
55 +# Notes:
56 +# 
57 +# This is an example atm driver.  It does not require any actual ATM
58 +# hardware.  It supports AAL5 and AAL0.  frames are merely looped back
59 +# to the sender on the same VC they were sent.
60 +# 
61 +#######################################################################
62 +*/
63 +
64 +/*############ Includes ###############################################*/
65 +
66 +#include <linux/module.h>
67 +#include <linux/kernel.h>
68 +#include <linux/errno.h>
69 +#include <linux/atm.h>
70 +#include <linux/atmdev.h>
71 +#include <linux/skbuff.h>
72 +#include <linux/init.h>
73 +#include <linux/netdevice.h>
74 +#include <linux/sched.h> /* for xtime */
75 +
76 +/*############ Defines ################################################*/
77 +
78 +#define MYATMDD "atmdd"
79 +#define KLOG_PREAMBLE MYATMDD ": "
80 +#define MYATMDD_VPI_BITS 1     /* Allow ?.1.? but not ?.2.? */
81 +#define MYATMDD_VCI_BITS 11    /* Allow ?.?.2047 but not ?.?.2048 */
82 +#define MYATMDD_PCR 100000
83 +#define RXQ_SZ 16
84 +#define TXQ_SZ 16
85 +#define AAL5_MTU (1510+8) /* Default AAL5 Maximum Transmission Unit (and length of AAL5 buffers) */
86 +#define AAL5_BUFLEN (((AAL5_MTU + 47)/48)*48) /* Round up to n*48 bytes */
87 +#if 0
88 +# define DEBUG(format,args...) printk(format,##args)
89 +#else
90 +# define DEBUG(format,args...)
91 +#endif
92 +/*############ Types ##################################################*/
93 +
94 +/* status flags shared between s/w and emulated h/w */
95 +typedef enum {
96 +    RX_EMPTY, /* No sk_buff present */
97 +    RX_FULL,  /* sk_buff present and awaiting data */
98 +    RX_RECVD, /* sk_buff present and contains valid data */
99 +} myatmdd_rxstatus_e;
100 +
101 +/* status flags shared between s/w and emulated h/w */
102 +typedef enum {
103 +    TX_EMPTY, /* No sk_buff present */
104 +    TX_FULL,  /* sk_buff present and awaiting transmission */
105 +    TX_SENT,  /* sk_buff present and has been sent */
106 +} myatmdd_txstatus_e;
107 +
108 +typedef struct {
109 +    struct sk_buff **start;
110 +    struct sk_buff **end;
111 +    struct sk_buff **head;
112 +    struct sk_buff **tail;
113 +
114 +    /* everything below this line emulates h/w */
115 +    myatmdd_rxstatus_e *status;
116 +    struct sk_buff **hw_ptr;
117 +    int *pkt_len;
118 +
119 +} myatmdd_rxq_t;
120 +
121 +typedef struct {
122 +    struct sk_buff **start;
123 +    struct sk_buff **end;
124 +    struct sk_buff **head;
125 +    struct sk_buff **tail;
126 +
127 +    /* everything below this line emulates h/w */
128 +    myatmdd_txstatus_e *status;
129 +    struct sk_buff **hw_ptr;
130 +    int *pkt_len;
131 +
132 +} myatmdd_txq_t;
133 +
134 +typedef struct {
135 +} myatmdd_devdata_t;
136 +
137 +typedef struct {
138 +    myatmdd_rxq_t rxqueue;
139 +    myatmdd_txq_t txqueue;
140 +} myatmdd_vccdata_t;
141 +
142 +/*############ Module paramters #######################################*/
143 +
144 +MODULE_AUTHOR("Alex Zeffertt, ajz@cambridgebroadband.com");
145 +MODULE_DESCRIPTION("Example ATM device driver (loopback)");
146 +#ifdef MODULE_LICENSE
147 +MODULE_LICENSE("GPL");
148 +#endif
149 +/*#################### Forward declarations ###########################*/
150 +
151 +static void myatmdd_emulate_loopback_hardware(struct atm_vcc *vcc);
152 +
153 +static void myatmdd_free_tx_skb(struct sk_buff *skb);
154 +
155 +/* these functions will need modifying in a real ATM driver */
156 +static void myatmdd_rx_interrupt(struct atm_vcc *vcc);
157 +static void myatmdd_tx_interrupt(struct atm_vcc *vcc);
158 +
159 +/* functions for manipulating circular bufs */
160 +static int myatmdd_init_rxq(myatmdd_rxq_t *queue, int size);
161 +static int myatmdd_init_txq(myatmdd_txq_t *queue, int size);
162 +static int myatmdd_release_rxq(myatmdd_rxq_t *queue);
163 +static int myatmdd_release_txq(myatmdd_txq_t *queue);
164 +static int myatmdd_txq_enqueue(myatmdd_txq_t *queue, struct sk_buff *skb);
165 +static int myatmdd_rxq_enqueue(myatmdd_rxq_t *queue, struct sk_buff *skb /* empty buffer */);
166 +static struct sk_buff *myatmdd_txq_dequeue(myatmdd_txq_t *queue);
167 +static struct sk_buff *myatmdd_rxq_dequeue(myatmdd_rxq_t *queue, int *pkt_len);
168 +
169 +/* myatmdd_ops registered by ATM device */
170 +static int myatmdd_open(struct atm_vcc *vcc);
171 +static void myatmdd_close(struct atm_vcc *vcc);
172 +static int myatmdd_ioctl(struct atm_dev *dev, unsigned int cmd,void *arg);
173 +static int myatmdd_setsockopt(struct atm_vcc *vcc,int level,int optname, void __user *optval,unsigned int optlen);
174 +static int myatmdd_getsockopt(struct atm_vcc *vcc,int level,int optname, void __user *optval,int optlen);
175 +static int myatmdd_send(struct atm_vcc *vcc,struct sk_buff *skb);
176 +static int myatmdd_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs);
177 +static int myatmdd_proc_read(struct atm_dev *dev,loff_t *pos,char *page);
178 +
179 +/* myatmdd_phy_ops registered by phy driver */
180 +static void myatmdd_phy_int(struct atm_dev *dev);
181 +static int myatmdd_phy_start(struct atm_dev *dev); /* <-- This is the only thing exported by PHY driver */
182 +static int myatmdd_phy_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg);
183 +
184 +/*#################### Global scope variables #########################*/
185 +
186 +/* operations registered by the atm device */
187 +static const struct atmdev_ops myatmdd_ops =
188 +{
189 +       open:        myatmdd_open,
190 +       close:       myatmdd_close,
191 +       ioctl:       myatmdd_ioctl,
192 +       getsockopt:  myatmdd_getsockopt,
193 +       setsockopt:  myatmdd_setsockopt,
194 +       send:        myatmdd_send,
195 +       change_qos:  myatmdd_change_qos,
196 +       proc_read:   myatmdd_proc_read,
197 +    owner:       THIS_MODULE,
198 +};
199 +
200 +/* operations registered by the phy driver */
201 +static const struct atmphy_ops myatmdd_phy_ops = {
202 +       start:      myatmdd_phy_start,
203 +       ioctl:      myatmdd_phy_ioctl,
204 +       interrupt:  myatmdd_phy_int,
205 +};
206 +
207 +struct atm_dev *myatmdd_dev;
208 +
209 +/*#################### Function definitions ###########################*/
210 +
211 +
212 +/*
213 +#########################################################
214 +#
215 +#  Function : myatmdd_rx_interrupt, and myatmdd_tx_interrupt
216 +#             
217 +#  Purpose  : handle interrupt from hardware.  In first 
218 +#             case this means extract recvd buffers and pass
219 +#             it up protocol stack.  In 2nd case this means
220 +#             free the sent buffers.
221 +#             
222 +#  Args     : pointer to private data of the VCC concerned
223 +#             
224 +#  Returns  : nowt
225 +#             
226 +#  Notes    : 
227 +#             
228 +##########################################################
229 +#  Edit history:
230 +#  Who     When    What
231 +#  AJZ     10Apr03 Created
232 +##########################################################
233 +*/
234 +
235 +static void myatmdd_rx_interrupt(struct atm_vcc *vcc)
236 +{
237 +    struct sk_buff *skb;
238 +    myatmdd_vccdata_t *priv = vcc->dev_data;
239 +    int pkt_len;
240 +
241 +    DEBUG("%s\n", __FUNCTION__);
242 +
243 +    while ((skb = myatmdd_rxq_dequeue(&priv->rxqueue, &pkt_len)))
244 +    {
245 +        struct sk_buff *newskb;
246 +        struct timeval stamp;
247 +
248 +        /* Get a new skb to replace the one just consumed */
249 +        if (!(newskb = dev_alloc_skb(AAL5_BUFLEN)))
250 +        {
251 +            atomic_inc(&vcc->stats->rx_err);
252 +            printk(KERN_ERR KLOG_PREAMBLE "cannot receive packet - out of memory\n");
253 +            /* put skb back in rx queue) */
254 +            myatmdd_rxq_enqueue(&priv->rxqueue, skb);
255 +            return;
256 +        }
257 +        myatmdd_rxq_enqueue(&priv->rxqueue, newskb);
258 +
259 +        if (!atm_charge (vcc, skb->truesize))
260 +        {
261 +            /* Exceeded memory quota for this vcc
262 +             * NOTE: if atm_charge succeeds you must then push or accounting will screw up
263 +             */
264 +            dev_kfree_skb(skb);
265 +            /* &vcc->stats->drop stats incremented in atm_charge */
266 +        }
267 +        else
268 +        {
269 +            /* sk_buff passed all sanity checks! */
270 +            
271 +            /* Add received length to socket buffer */
272 +            skb_put(skb, pkt_len);
273 +        
274 +            /* update device stats */
275 +            atomic_inc(&vcc->stats->rx);
276 +
277 +            /* add timestamp for upper layers to use */
278 +           do_gettimeofday(&stamp);
279 +           skb->tstamp = timeval_to_ktime(stamp);
280 +        
281 +            /* Point socket buffer at the right VCC before giving to socket layer */
282 +            ATM_SKB(skb)->vcc = vcc;
283 +        
284 +            /* push socket buffer up to ATM layer */
285 +            vcc->push(vcc, skb);
286 +        }
287 +    }
288 +}
289 +
290 +static void myatmdd_tx_interrupt(struct atm_vcc *vcc)
291 +{
292 +    struct sk_buff *skb;
293 +    myatmdd_vccdata_t *priv = vcc->dev_data;
294 +
295 +    DEBUG("%s\n", __FUNCTION__);
296 +
297 +    while ((skb = myatmdd_txq_dequeue(&priv->txqueue)))
298 +    {
299 +        // Update channel stats and free the memory
300 +        atomic_inc(&vcc->stats->tx);
301 +        myatmdd_free_tx_skb(skb);
302 +    }
303 +}
304 +
305 +/*
306 +#########################################################
307 +#
308 +#  Function : myatmdd_emulate_loopback_hardware
309 +#             
310 +#  Purpose  : emulate things normally done by hardware
311 +#             i.e. copying tx bufs to rx bufs (we're modelling
312 +#             a loopback system here), calling the tx done
313 +#             interrupt, and calling the rx done interrupt.
314 +#
315 +#  Args     : priv = data private to VCC
316 +#             
317 +#  Returns  : nowt
318 +#             
319 +#  Notes    : 
320 +#             
321 +##########################################################
322 +#  Edit history:
323 +#  Who     When    What
324 +#  AJZ     10Apr03 Created
325 +##########################################################
326 +*/
327 +static void myatmdd_emulate_loopback_hardware(struct atm_vcc *vcc)
328 +{
329 +    myatmdd_vccdata_t *priv = vcc->dev_data;
330 +    struct sk_buff **ptxskb;
331 +    struct sk_buff **prxskb;
332 +
333 +    DEBUG("%s\n", __FUNCTION__);
334 +
335 +    ptxskb = priv->txqueue.hw_ptr;
336 +    prxskb = priv->rxqueue.hw_ptr;
337 +
338 +    /* Send each tx buff waiting to go */
339 +    while (priv->txqueue.status[ptxskb - priv->txqueue.start] == TX_FULL)
340 +    {
341 +        struct sk_buff *txskb = *ptxskb;
342 +        struct sk_buff *rxskb = *prxskb;
343 +        int pkt_len = priv->txqueue.pkt_len[ptxskb - priv->txqueue.start];
344 +        
345 +        /* Is there an rx buffer? */
346 +        if (priv->rxqueue.status[prxskb - priv->rxqueue.start] == RX_FULL)
347 +        {
348 +            /* Yes - Is the length in range? */
349 +            if (pkt_len <= AAL5_BUFLEN)
350 +            {
351 +                /* Yes - do the copy */
352 +                memcpy(rxskb->data, txskb->data,pkt_len);
353 +                priv->rxqueue.pkt_len[prxskb - priv->rxqueue.start] = pkt_len;
354 +                
355 +                /* Indicate rx buffer recvd */
356 +                priv->rxqueue.status[prxskb - priv->rxqueue.start] = RX_RECVD;
357 +                
358 +                /* increment and maybe wrap rx pointer */
359 +                if (++prxskb == priv->rxqueue.end)
360 +                    prxskb = priv->rxqueue.start;
361 +                priv->rxqueue.hw_ptr = prxskb;
362 +            }
363 +            else
364 +            {
365 +                /* No - then h/w cannot do a recv */
366 +                printk(KERN_ERR KLOG_PREAMBLE "recvd frame too long - discarded\n");
367 +            }
368 +        }
369 +        else
370 +        {
371 +            /* No - then h/w cannot do a recv */
372 +            printk(KERN_ERR KLOG_PREAMBLE "no rx buffers available\n");
373 +        }
374 +        
375 +        /* Indicate tx buffer sent */
376 +        priv->txqueue.status[ptxskb - priv->txqueue.start] = TX_SENT;
377 +
378 +        /* increment and maybe wrap tx pointer */
379 +        if (++ptxskb == priv->txqueue.end)
380 +            ptxskb = priv->txqueue.start;
381 +        priv->txqueue.hw_ptr = ptxskb;
382 +        
383 +        /* Call tx ring interrupt handler */
384 +        myatmdd_tx_interrupt(vcc);
385 +           
386 +        /* Call tx ring interrupt handler */
387 +        myatmdd_rx_interrupt(vcc);
388 +    }
389 +}
390 +
391 +/*
392 +#########################################################
393 +#
394 +#  Function : functions for manipulating circular buffs
395 +#             
396 +#  Purpose  : 
397 +#             
398 +#  Args     : 
399 +#             
400 +#  Returns  : 
401 +#             
402 +#  Notes    : 
403 +#             
404 +##########################################################
405 +#  Edit history:
406 +#  Who     When    What
407 +#  AJZ     10Apr03 Created
408 +##########################################################
409 +*/
410 +
411 +static int myatmdd_init_rxq(myatmdd_rxq_t *queue, int size)
412 +{
413 +    /* TODO - cope with kmalloc failure */
414 +    struct sk_buff **pskb;
415 +    int i;
416 +
417 +    DEBUG("%s\n", __FUNCTION__);
418 +    queue->hw_ptr = queue->head = queue->tail = 
419 +        queue->start = kmalloc(size * sizeof(struct sk_buff *), GFP_KERNEL);
420 +    queue->end = &queue->start[size];
421 +    for (pskb = queue->start; pskb < queue->end; pskb++)
422 +        *pskb = NULL;
423 +
424 +    queue->status = kmalloc(size * sizeof(myatmdd_rxstatus_e),GFP_KERNEL);
425 +    for (i = 0; i < size; i++)
426 +        queue->status[i] = RX_EMPTY;
427 +
428 +    queue->pkt_len = kmalloc(size * sizeof(int),GFP_KERNEL);
429 +    for (i = 0; i < size; i++)
430 +        queue->pkt_len[i] = 0;
431 +
432 +    return 0;
433 +}
434 +
435 +static int myatmdd_init_txq(myatmdd_txq_t *queue, int size)
436 +{
437 +    /* TODO - cope with kmalloc failure */
438 +    struct sk_buff **pskb;
439 +    int i;
440 +
441 +    DEBUG("%s\n", __FUNCTION__);
442 +    queue->hw_ptr = queue->head = queue->tail = 
443 +        queue->start = kmalloc(size * sizeof(struct sk_buff *), GFP_KERNEL);
444 +    queue->end = &queue->start[size];
445 +    for (pskb = queue->start; pskb < queue->end; pskb++)
446 +        *pskb = NULL;
447 +
448 +    queue->status = kmalloc(size * sizeof(myatmdd_rxstatus_e),GFP_KERNEL);
449 +    for (i = 0; i < size; i++)
450 +        queue->status[i] = TX_EMPTY;
451 +
452 +    queue->pkt_len = kmalloc(size * sizeof(int),GFP_KERNEL);
453 +    for (i = 0; i < size; i++)
454 +        queue->pkt_len[i] = 0;
455 +
456 +    return 0;
457 +}
458 +
459 +static int myatmdd_release_rxq(myatmdd_rxq_t *queue)
460 +{
461 +    struct sk_buff **pskb;
462 +
463 +    DEBUG("%s\n", __FUNCTION__);
464 +    for (pskb = queue->start; pskb < queue->end; pskb++)
465 +    {
466 +        /* Is there an skb here */
467 +        if (*pskb == NULL)
468 +            continue;   /* No, so skip this entry in ring */
469 +
470 +        /* Yes - free it */
471 +        dev_kfree_skb(*pskb);
472 +    }
473 +    kfree(queue->start);
474 +    kfree(queue->status);
475 +    kfree(queue->pkt_len);
476 +
477 +    return 0;
478 +}
479 +
480 +static int myatmdd_release_txq(myatmdd_txq_t *queue)
481 +{
482 +    struct sk_buff **pskb;
483 +
484 +    DEBUG("%s\n", __FUNCTION__);
485 +    /* Scan through all TX bd's and cleanup */
486 +    for (pskb = queue->start; pskb < queue->end; pskb++)
487 +    {  
488 +        /* Is this buffer currently unused - i.e. no skb */
489 +        if (*pskb == NULL)
490 +            continue;             /* Yes, so ignore it */
491 +
492 +        /* If we reach here, we have found a socket buffer that
493 +         * exists in the TX ring and is waiting to be released.
494 +         */
495 +        printk(KERN_WARNING KLOG_PREAMBLE "discarding unsent tx sk_buff\n");
496 +        atomic_inc(&ATM_SKB(*pskb)->vcc->stats->tx_err);
497 +        myatmdd_free_tx_skb(*pskb);
498 +    }
499 +    kfree(queue->start);
500 +    kfree(queue->status);
501 +    kfree(queue->pkt_len);
502 +
503 +    return 0;
504 +}
505 +
506 +/* returns non-zero for "out of space" */
507 +static int myatmdd_txq_enqueue(myatmdd_txq_t *queue, struct sk_buff *skb)
508 +{
509 +    /* increment head and wrap */
510 +    struct sk_buff **newhead = queue->head + 1;
511 +    if (newhead == queue->end)
512 +        newhead = queue->start;
513 +
514 +    DEBUG("%s\n", __FUNCTION__);
515 +
516 +    /* abort if tx ring full */
517 +    if (newhead == queue->tail)
518 +        return -1;
519 +    
520 +    /* all is okay if we're here */
521 +    *queue->head = skb;
522 +    /* Tell hardware there's a buffer to send */
523 +    queue->status[queue->head - queue->start] = TX_FULL;
524 +    queue->pkt_len[queue->head - queue->start] = skb->len;
525 +    queue->head = newhead;
526 +    return 0;
527 +}
528 +
529 +/* returns non-zero for "out of space" */
530 +static int myatmdd_rxq_enqueue(myatmdd_rxq_t *queue, struct sk_buff *skb /* empty buffer */)
531 +{
532 +    /* increment head and wrap */
533 +    struct sk_buff **newhead = queue->head + 1;
534 +    if (newhead == queue->end)
535 +        newhead = queue->start;
536 +
537 +    DEBUG("%s\n", __FUNCTION__);
538 +
539 +    /* abort if rx ring full */
540 +    if (newhead == queue->tail)
541 +        return -1;
542 +    
543 +    /* all is okay if we're here */
544 +    *queue->head = skb;
545 +    /* Tell hardware there's a buffer to send */
546 +    queue->status[queue->head - queue->start] = RX_FULL;
547 +    queue->head = newhead;
548 +    return 0;
549 +}
550 +
551 +static struct sk_buff *myatmdd_txq_dequeue(myatmdd_txq_t *queue)
552 +{
553 +    DEBUG("%s\n", __FUNCTION__);
554 +    if (queue->tail != queue->head && queue->status[queue->tail - queue->start] == TX_SENT)
555 +    {
556 +        struct sk_buff *skb = *queue->tail;
557 +
558 +        /* increment tail and wrap */
559 +        struct sk_buff **newtail = queue->tail + 1;
560 +        if (newtail == queue->end)
561 +            newtail = queue->start;
562 +        *queue->tail = NULL;
563 +        queue->status[queue->tail - queue->start] = TX_EMPTY;
564 +        queue->tail = newtail;
565 +        return skb;
566 +    }
567 +    return NULL;
568 +}
569 +
570 +/* returns NULL for "no new recvd frames" */
571 +static struct sk_buff *myatmdd_rxq_dequeue(myatmdd_rxq_t *queue, int *pkt_len)
572 +{
573 +    DEBUG("%s\n", __FUNCTION__);
574 +    if (queue->tail != queue->head && queue->status[queue->tail - queue->start] == RX_RECVD)
575 +    {
576 +        struct sk_buff *skb = *queue->tail;
577 +
578 +        /* increment tail and wrap */
579 +        struct sk_buff **newtail = queue->tail + 1;
580 +        if (newtail == queue->end)
581 +            newtail = queue->start;
582 +        *queue->tail = NULL;
583 +        queue->status[queue->tail - queue->start] = RX_EMPTY;
584 +        *pkt_len = queue->pkt_len[queue->tail - queue->start];
585 +        queue->tail = newtail;
586 +        return skb;
587 +    }
588 +    return NULL;
589 +}
590 +
591 +/*
592 +#########################################################
593 +#
594 +#  Functions :         Implementations of function ptrs in
595 +#               myatmdd_phy_ops.  This is the phy driver
596 +#      start:      myatmdd_phy_start,
597 +#      ioctl:      myatmdd_phy_ioctl,
598 +#      interrupt:  myatmdd_phy_int,
599 +#             
600 +#  Purpose  : See ATM device driver interface v0.1
601 +#             
602 +#  Notes    : Conforming to Linux ATM device driver i/f
603 +#             interface.  Draft version 0.1
604 +#             
605 +#             Designed to work with multiple devices
606 +##########################################################
607 +#  Edit history:
608 +#  Who     When    What
609 +#  AJZ     10Apr03 Created
610 +##########################################################
611 +*/
612 +static int myatmdd_phy_start(struct atm_dev *dev)
613 +{
614 +    /* Provide ATM driver with a pointer via which it
615 +     * may invoke PHY driver's IOCTL or interrupt 
616 +     * handlers.
617 +     */
618 +    dev->phy = &myatmdd_phy_ops;
619 +
620 +    /* If required allocate phy private data and save
621 +     * pointer in dev->phy_data;
622 +     */
623 +    
624 +    /* TODO Initialise PHY hardware... */
625 +
626 +    return 0;
627 +}
628 +
629 +/* Should be called by SAR driver when it needs to handle an interrupt
630 + * triggered by PHY.
631 + */
632 +static void myatmdd_phy_int(struct atm_dev *dev)
633 +{
634 +    /* Handle interrupt triggered by PHY */
635 +}
636 +
637 +/* Gets called by SAR driver IOCTL handler for IOCTLS it doesn't recognise */
638 +static int myatmdd_phy_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
639 +{
640 +       switch (cmd)
641 +    {
642 +//             case SONET_GETSTATZ:
643 +        default:
644 +            return -EINVAL;
645 +    }
646 +}
647 +
648 +/*
649 +#########################################################
650 +#
651 +#  Function : myatmdd_free_tx_skb
652 +#             
653 +#  Purpose  : frees an sk_buff.
654 +#             
655 +#  Args     : skb=pointer to socket buffer
656 +#             
657 +#  Notes    : Tries to use the upper layer pop() function
658 +#             but uses dev_kfree_skb() if this doesn't exist
659 +##########################################################
660 +#  Edit history:
661 +#  Who     When    What
662 +#  AJZ     10Apr03 Created
663 +##########################################################
664 +*/
665 +static void myatmdd_free_tx_skb(struct sk_buff *skb)
666 +{  
667 +    struct atm_vcc *vcc;
668 +
669 +    DEBUG("%s\n", __FUNCTION__);
670 +
671 +    /* See if we can use the VCC pop function */
672 +    if (((vcc = ATM_SKB(skb)->vcc) != NULL) && (vcc->pop != NULL))
673 +    {
674 +        /* Yes, so use ATM socket layer pop function */
675 +        vcc->pop(vcc, skb);
676 +    }
677 +    else
678 +    {  
679 +        printk(KERN_WARNING KLOG_PREAMBLE "unable to call skb free function\n");
680 +        /* No, so free socket buffer */
681 +        dev_kfree_skb(skb);
682 +    }
683 +}
684 +
685 +/*
686 +#########################################################
687 +#
688 +#  Functions :         Implementations of function ptrs in
689 +#               myatmdd_ops.
690 +#   myatmdd_open(),
691 +#      myatmdd_close(),
692 +#      myatmdd_ioctl(),
693 +#      myatmdd_getsockopt(),
694 +#      myatmdd_setsockopt(),
695 +#      myatmdd_send(),
696 +#      myatmdd_sg_send(),
697 +#      myatmdd_change_qos(),
698 +#      myatmdd_proc_read()
699 +# 
700 +#             
701 +#  Purpose  : See ATM device driver interface v0.1
702 +#             
703 +#  Notes    : Conforming to Linux ATM device driver i/f
704 +#             interface.  Draft version 0.1
705 +#             
706 +#             Designed to work with multiple devices
707 +##########################################################
708 +#  Edit history:
709 +#  Who     When    What
710 +#  AJZ     10Apr03 Created
711 +##########################################################
712 +*/
713 +static int myatmdd_open(struct atm_vcc *vcc)
714 +{
715 +    myatmdd_vccdata_t *priv;
716 +    int i;
717 +
718 +    DEBUG("%s\n", __FUNCTION__);
719 +
720 +    /* Make sure we are opening a AAL0 or AAL5 connection */
721 +    if ((vcc->qos.aal != ATM_AAL5) && (vcc->qos.aal != ATM_AAL0))
722 +    {
723 +        printk(KERN_WARNING KLOG_PREAMBLE "invalid AAL\n");
724 +        return -EINVAL;
725 +    }
726 +
727 +    /* Address is in use */
728 +    set_bit(ATM_VF_ADDR, &vcc->flags);
729 +
730 +    /* Allocate some vcc-private memory */
731 +    vcc->dev_data = kmalloc(sizeof(myatmdd_vccdata_t), GFP_KERNEL);
732 +    if (vcc->dev_data == NULL)
733 +        return -ENOMEM;
734 +    priv = vcc->dev_data;
735 +
736 +    /* Setup the hardware for new VC... */
737 +
738 +    /* Do not allow half open VCs - otherwise the example driver will not be able
739 +     * to loop back frames sent !
740 +     */
741 +    if (vcc->qos.rxtp.traffic_class == ATM_NONE || vcc->qos.txtp.traffic_class == ATM_NONE)
742 +    {
743 +        kfree(vcc->dev_data);
744 +        return -EPERM;
745 +    }
746 +
747 +    /* Create rx/tx queues for this VC */
748 +    myatmdd_init_txq(&priv->txqueue, TXQ_SZ);
749 +    myatmdd_init_rxq(&priv->rxqueue, RXQ_SZ);
750 +    
751 +    /* Fill rx queue with empty skbuffs */
752 +    for (i = 0 ; i < RXQ_SZ - 1; i++)
753 +    {
754 +        struct sk_buff *skb = dev_alloc_skb(AAL5_BUFLEN);
755 +        myatmdd_rxq_enqueue(&priv->rxqueue,skb);
756 +    }
757 +   
758 +    /* Connection is now ready to receive data */
759 +    set_bit(ATM_VF_READY, &vcc->flags);
760 +
761 +    return 0;
762 +}
763 +
764 +static void myatmdd_close(struct atm_vcc *vcc)
765 +{
766 +    myatmdd_vccdata_t *priv = vcc->dev_data;
767 +
768 +    DEBUG("%s\n", __FUNCTION__);
769 +
770 +    /* Indicate channel closed */
771 +    clear_bit(ATM_VF_READY, &vcc->flags);
772 +
773 +    /* TODO Uninitialise the hardware for this VC... */
774 +    
775 +    /* empty the rx and tx queues */
776 +    myatmdd_release_txq(&priv->txqueue);
777 +    myatmdd_release_rxq(&priv->rxqueue);
778 +
779 +    /* Free the vcc-private memory */
780 +    kfree(vcc->dev_data);
781 +}
782 +  
783 +static int myatmdd_ioctl(struct atm_dev *dev, unsigned int cmd,void *arg)
784 +{
785 +    /* myatmdd does not currently have an ioctl interface so pass ioctl onto PHY */
786 +    if (dev->phy && dev->phy->ioctl) {
787 +        return dev->phy->ioctl(dev, cmd, arg);
788 +    }
789 +    return -EINVAL;
790 +}
791 +
792 +static int myatmdd_getsockopt(struct atm_vcc *vcc,int level,int optname, void __user *optval,int optlen)
793 +{
794 +    return -EINVAL;
795 +}
796 +
797 +static int myatmdd_setsockopt(struct atm_vcc *vcc,int level,int optname, void __user *optval,unsigned int optlen)
798 +{
799 +    return -EINVAL;
800 +}
801 +
802 +/* Note may be called in either process or interrupt context! */
803 +static int myatmdd_send(struct atm_vcc *vcc,struct sk_buff *skb)
804 +{
805 +    myatmdd_vccdata_t *priv = vcc->dev_data;
806 +
807 +    DEBUG("%s\n", __FUNCTION__);
808 +
809 +    /* Assign VCC to socket buffer
810 +     * Note: this must be done before attempting to call
811 +     * myatmdd_free_tx_skb() as this may use ATM_SKB(skb)->vcc->pop()
812 +     */
813 +    ATM_SKB(skb)->vcc = vcc;
814 +
815 +    /* Setup hardware to send and arrange callback of myatmdd_send_complete... */
816 +
817 +    /* In this example ATM device driver all VCs are looped back.
818 +     * So copy to the rxq and emulate an rx interrupt
819 +     */
820 +
821 +    /* Can we accept another skb to send ? */
822 +    if (myatmdd_txq_enqueue(&priv->txqueue, skb))
823 +    {
824 +        /* No - free socket buffer */
825 +        myatmdd_free_tx_skb(skb);
826 +        
827 +        /* Update tx channel stats */
828 +        atomic_inc(&vcc->stats->tx_err);
829 +        
830 +        /* Tell protocol layer to back off */
831 +        return(-EBUSY);
832 +    }
833 +
834 +    /* This is the bit which copies the tx ring to the rx ring,
835 +     * and triggers emulated rx and tx interrupts
836 +     */
837 +    myatmdd_emulate_loopback_hardware(vcc);
838 +    
839 +    return 0;
840 +}
841 +
842 +static int myatmdd_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs)
843 +{
844 +    return 0;
845 +}
846 +
847 +static int myatmdd_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
848 +{
849 +    int left = (int) *pos;
850 +    
851 +    if (!left--)
852 +        return sprintf(page, "1st line of stats\n");
853 +    if (!left--)
854 +        return sprintf(page, "2nd line of stats\n");
855 +    if (!left--)
856 +        return sprintf(page, "3rd line of stats\n");
857 +
858 +    return 0;
859 +}
860 +
861 +/*
862 +#########################################################
863 +#
864 +#  Function : myatmdd_init
865 +#             
866 +#  Purpose  : init the module, init and register the ATM device
867 +#             
868 +#  Args     : none
869 +#             
870 +#  Returns  : return code
871 +#             
872 +#  Notes    : 
873 +#             
874 +##########################################################
875 +#  Edit history:
876 +#  Who     When    What
877 +#  AJZ     10Apr03 Created
878 +##########################################################
879 +*/
880 +int __init myatmdd_init(void)
881 +{
882 +    myatmdd_devdata_t *priv = kmalloc(sizeof(myatmdd_devdata_t),GFP_KERNEL);
883 +
884 +    if (priv == NULL)
885 +        return -ENOMEM;
886 +
887 +    /* Register the new device */
888 +    myatmdd_dev = atm_dev_register(MYATMDD,NULL,&myatmdd_ops,-1,NULL);
889 +    
890 +    /* Were we able to register this device? */
891 +    if (myatmdd_dev == NULL)
892 +    {
893 +        printk(KERN_ERR KLOG_PREAMBLE "failed to register CPM ATM device\n");
894 +        return -EPERM;
895 +    }
896 +
897 +    /* Save pointer to device private data */
898 +    myatmdd_dev->dev_data = priv;
899 +
900 +    /* Initialise device parameters */
901 +    myatmdd_dev->ci_range.vpi_bits = MYATMDD_VPI_BITS;
902 +    myatmdd_dev->ci_range.vci_bits = MYATMDD_VCI_BITS;
903 +    myatmdd_dev->link_rate = MYATMDD_PCR;
904 +    
905 +    /* Set up phy device */
906 +    myatmdd_phy_start(myatmdd_dev);
907 +    
908 +    /* TODO Initialise SAR hardware... */
909 +
910 +    /* Console output */
911 +    printk(KERN_INFO KLOG_PREAMBLE "Initialised\n");
912 +
913 +    return 0;
914 +}
915 +
916 +/* NOTE:
917 + * module_init() is called by insmod, if built as module, 
918 + * or by do_initcalls(), if built as a resident driver.
919 + */
920 +module_init(myatmdd_init);
921 +
922 +/*
923 +#########################################################
924 +#
925 +#  Function : myatmdd_exit
926 +#             
927 +#  Purpose  : delete module, uninit and dereg ATM device
928 +#             
929 +#  Args     : none
930 +#             
931 +#  Returns  : none
932 +#             
933 +#  Notes    : 
934 +#             
935 +##########################################################
936 +#  Edit history:
937 +#  Who     When    What
938 +#  AJZ     10Apr03 Created
939 +##########################################################
940 +*/
941 +
942 +#ifdef MODULE
943 +static void __exit myatmdd_exit(void)
944 +{
945 +    /* Disable SAR hardware... */
946 +
947 +    /* Console output */
948 +    printk(KERN_ERR KLOG_PREAMBLE "Uninitialised\n");
949 +    kfree(myatmdd_dev->dev_data);
950 +    atm_dev_deregister(myatmdd_dev);
951 +}
952 +module_exit(myatmdd_exit);
953 +
954 +#endif /* MODULE */
This page took 0.153685 seconds and 3 git commands to generate.