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