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