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
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
16 If you say N, all options in this submenu will be skipped and disabled.
18 if ATM_DRIVERS && NETDEVICES && ATM
21 + tristate "ATM loopback"
22 + depends on INET && ATM
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.
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
35 +#######################################################################
38 +# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
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.
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.
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,
54 +#######################################################################
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.
61 +#######################################################################
64 +/*############ Includes ###############################################*/
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 */
76 +/*############ Defines ################################################*/
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
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 */
88 +# define DEBUG(format,args...) printk(format,##args)
90 +# define DEBUG(format,args...)
92 +/*############ Types ##################################################*/
94 +/* status flags shared between s/w and emulated h/w */
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;
101 +/* status flags shared between s/w and emulated h/w */
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;
109 + struct sk_buff **start;
110 + struct sk_buff **end;
111 + struct sk_buff **head;
112 + struct sk_buff **tail;
114 + /* everything below this line emulates h/w */
115 + myatmdd_rxstatus_e *status;
116 + struct sk_buff **hw_ptr;
122 + struct sk_buff **start;
123 + struct sk_buff **end;
124 + struct sk_buff **head;
125 + struct sk_buff **tail;
127 + /* everything below this line emulates h/w */
128 + myatmdd_txstatus_e *status;
129 + struct sk_buff **hw_ptr;
135 +} myatmdd_devdata_t;
138 + myatmdd_rxq_t rxqueue;
139 + myatmdd_txq_t txqueue;
140 +} myatmdd_vccdata_t;
142 +/*############ Module paramters #######################################*/
144 +MODULE_AUTHOR("Alex Zeffertt, ajz@cambridgebroadband.com");
145 +MODULE_DESCRIPTION("Example ATM device driver (loopback)");
146 +#ifdef MODULE_LICENSE
147 +MODULE_LICENSE("GPL");
149 +/*#################### Forward declarations ###########################*/
151 +static void myatmdd_emulate_loopback_hardware(struct atm_vcc *vcc);
153 +static void myatmdd_free_tx_skb(struct sk_buff *skb);
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);
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);
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);
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);
184 +/*#################### Global scope variables #########################*/
186 +/* operations registered by the atm device */
187 +static const struct atmdev_ops myatmdd_ops =
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,
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,
207 +struct atm_dev *myatmdd_dev;
209 +/*#################### Function definitions ###########################*/
213 +#########################################################
215 +# Function : myatmdd_rx_interrupt, and myatmdd_tx_interrupt
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.
222 +# Args : pointer to private data of the VCC concerned
228 +##########################################################
231 +# AJZ 10Apr03 Created
232 +##########################################################
235 +static void myatmdd_rx_interrupt(struct atm_vcc *vcc)
237 + struct sk_buff *skb;
238 + myatmdd_vccdata_t *priv = vcc->dev_data;
241 + DEBUG("%s\n", __FUNCTION__);
243 + while ((skb = myatmdd_rxq_dequeue(&priv->rxqueue, &pkt_len)))
245 + struct sk_buff *newskb;
246 + struct timeval stamp;
248 + /* Get a new skb to replace the one just consumed */
249 + if (!(newskb = dev_alloc_skb(AAL5_BUFLEN)))
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);
257 + myatmdd_rxq_enqueue(&priv->rxqueue, newskb);
259 + if (!atm_charge (vcc, skb->truesize))
261 + /* Exceeded memory quota for this vcc
262 + * NOTE: if atm_charge succeeds you must then push or accounting will screw up
264 + dev_kfree_skb(skb);
265 + /* &vcc->stats->drop stats incremented in atm_charge */
269 + /* sk_buff passed all sanity checks! */
271 + /* Add received length to socket buffer */
272 + skb_put(skb, pkt_len);
274 + /* update device stats */
275 + atomic_inc(&vcc->stats->rx);
277 + /* add timestamp for upper layers to use */
278 + do_gettimeofday(&stamp);
279 + skb->tstamp = timeval_to_ktime(stamp);
281 + /* Point socket buffer at the right VCC before giving to socket layer */
282 + ATM_SKB(skb)->vcc = vcc;
284 + /* push socket buffer up to ATM layer */
285 + vcc->push(vcc, skb);
290 +static void myatmdd_tx_interrupt(struct atm_vcc *vcc)
292 + struct sk_buff *skb;
293 + myatmdd_vccdata_t *priv = vcc->dev_data;
295 + DEBUG("%s\n", __FUNCTION__);
297 + while ((skb = myatmdd_txq_dequeue(&priv->txqueue)))
299 + // Update channel stats and free the memory
300 + atomic_inc(&vcc->stats->tx);
301 + myatmdd_free_tx_skb(skb);
306 +#########################################################
308 +# Function : myatmdd_emulate_loopback_hardware
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.
315 +# Args : priv = data private to VCC
321 +##########################################################
324 +# AJZ 10Apr03 Created
325 +##########################################################
327 +static void myatmdd_emulate_loopback_hardware(struct atm_vcc *vcc)
329 + myatmdd_vccdata_t *priv = vcc->dev_data;
330 + struct sk_buff **ptxskb;
331 + struct sk_buff **prxskb;
333 + DEBUG("%s\n", __FUNCTION__);
335 + ptxskb = priv->txqueue.hw_ptr;
336 + prxskb = priv->rxqueue.hw_ptr;
338 + /* Send each tx buff waiting to go */
339 + while (priv->txqueue.status[ptxskb - priv->txqueue.start] == TX_FULL)
341 + struct sk_buff *txskb = *ptxskb;
342 + struct sk_buff *rxskb = *prxskb;
343 + int pkt_len = priv->txqueue.pkt_len[ptxskb - priv->txqueue.start];
345 + /* Is there an rx buffer? */
346 + if (priv->rxqueue.status[prxskb - priv->rxqueue.start] == RX_FULL)
348 + /* Yes - Is the length in range? */
349 + if (pkt_len <= AAL5_BUFLEN)
351 + /* Yes - do the copy */
352 + memcpy(rxskb->data, txskb->data,pkt_len);
353 + priv->rxqueue.pkt_len[prxskb - priv->rxqueue.start] = pkt_len;
355 + /* Indicate rx buffer recvd */
356 + priv->rxqueue.status[prxskb - priv->rxqueue.start] = RX_RECVD;
358 + /* increment and maybe wrap rx pointer */
359 + if (++prxskb == priv->rxqueue.end)
360 + prxskb = priv->rxqueue.start;
361 + priv->rxqueue.hw_ptr = prxskb;
365 + /* No - then h/w cannot do a recv */
366 + printk(KERN_ERR KLOG_PREAMBLE "recvd frame too long - discarded\n");
371 + /* No - then h/w cannot do a recv */
372 + printk(KERN_ERR KLOG_PREAMBLE "no rx buffers available\n");
375 + /* Indicate tx buffer sent */
376 + priv->txqueue.status[ptxskb - priv->txqueue.start] = TX_SENT;
378 + /* increment and maybe wrap tx pointer */
379 + if (++ptxskb == priv->txqueue.end)
380 + ptxskb = priv->txqueue.start;
381 + priv->txqueue.hw_ptr = ptxskb;
383 + /* Call tx ring interrupt handler */
384 + myatmdd_tx_interrupt(vcc);
386 + /* Call tx ring interrupt handler */
387 + myatmdd_rx_interrupt(vcc);
392 +#########################################################
394 +# Function : functions for manipulating circular buffs
404 +##########################################################
407 +# AJZ 10Apr03 Created
408 +##########################################################
411 +static int myatmdd_init_rxq(myatmdd_rxq_t *queue, int size)
413 + /* TODO - cope with kmalloc failure */
414 + struct sk_buff **pskb;
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++)
424 + queue->status = kmalloc(size * sizeof(myatmdd_rxstatus_e),GFP_KERNEL);
425 + for (i = 0; i < size; i++)
426 + queue->status[i] = RX_EMPTY;
428 + queue->pkt_len = kmalloc(size * sizeof(int),GFP_KERNEL);
429 + for (i = 0; i < size; i++)
430 + queue->pkt_len[i] = 0;
435 +static int myatmdd_init_txq(myatmdd_txq_t *queue, int size)
437 + /* TODO - cope with kmalloc failure */
438 + struct sk_buff **pskb;
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++)
448 + queue->status = kmalloc(size * sizeof(myatmdd_rxstatus_e),GFP_KERNEL);
449 + for (i = 0; i < size; i++)
450 + queue->status[i] = TX_EMPTY;
452 + queue->pkt_len = kmalloc(size * sizeof(int),GFP_KERNEL);
453 + for (i = 0; i < size; i++)
454 + queue->pkt_len[i] = 0;
459 +static int myatmdd_release_rxq(myatmdd_rxq_t *queue)
461 + struct sk_buff **pskb;
463 + DEBUG("%s\n", __FUNCTION__);
464 + for (pskb = queue->start; pskb < queue->end; pskb++)
466 + /* Is there an skb here */
468 + continue; /* No, so skip this entry in ring */
470 + /* Yes - free it */
471 + dev_kfree_skb(*pskb);
473 + kfree(queue->start);
474 + kfree(queue->status);
475 + kfree(queue->pkt_len);
480 +static int myatmdd_release_txq(myatmdd_txq_t *queue)
482 + struct sk_buff **pskb;
484 + DEBUG("%s\n", __FUNCTION__);
485 + /* Scan through all TX bd's and cleanup */
486 + for (pskb = queue->start; pskb < queue->end; pskb++)
488 + /* Is this buffer currently unused - i.e. no skb */
490 + continue; /* Yes, so ignore it */
492 + /* If we reach here, we have found a socket buffer that
493 + * exists in the TX ring and is waiting to be released.
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);
499 + kfree(queue->start);
500 + kfree(queue->status);
501 + kfree(queue->pkt_len);
506 +/* returns non-zero for "out of space" */
507 +static int myatmdd_txq_enqueue(myatmdd_txq_t *queue, struct sk_buff *skb)
509 + /* increment head and wrap */
510 + struct sk_buff **newhead = queue->head + 1;
511 + if (newhead == queue->end)
512 + newhead = queue->start;
514 + DEBUG("%s\n", __FUNCTION__);
516 + /* abort if tx ring full */
517 + if (newhead == queue->tail)
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;
529 +/* returns non-zero for "out of space" */
530 +static int myatmdd_rxq_enqueue(myatmdd_rxq_t *queue, struct sk_buff *skb /* empty buffer */)
532 + /* increment head and wrap */
533 + struct sk_buff **newhead = queue->head + 1;
534 + if (newhead == queue->end)
535 + newhead = queue->start;
537 + DEBUG("%s\n", __FUNCTION__);
539 + /* abort if rx ring full */
540 + if (newhead == queue->tail)
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;
551 +static struct sk_buff *myatmdd_txq_dequeue(myatmdd_txq_t *queue)
553 + DEBUG("%s\n", __FUNCTION__);
554 + if (queue->tail != queue->head && queue->status[queue->tail - queue->start] == TX_SENT)
556 + struct sk_buff *skb = *queue->tail;
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;
570 +/* returns NULL for "no new recvd frames" */
571 +static struct sk_buff *myatmdd_rxq_dequeue(myatmdd_rxq_t *queue, int *pkt_len)
573 + DEBUG("%s\n", __FUNCTION__);
574 + if (queue->tail != queue->head && queue->status[queue->tail - queue->start] == RX_RECVD)
576 + struct sk_buff *skb = *queue->tail;
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;
592 +#########################################################
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,
600 +# Purpose : See ATM device driver interface v0.1
602 +# Notes : Conforming to Linux ATM device driver i/f
603 +# interface. Draft version 0.1
605 +# Designed to work with multiple devices
606 +##########################################################
609 +# AJZ 10Apr03 Created
610 +##########################################################
612 +static int myatmdd_phy_start(struct atm_dev *dev)
614 + /* Provide ATM driver with a pointer via which it
615 + * may invoke PHY driver's IOCTL or interrupt
618 + dev->phy = &myatmdd_phy_ops;
620 + /* If required allocate phy private data and save
621 + * pointer in dev->phy_data;
624 + /* TODO Initialise PHY hardware... */
629 +/* Should be called by SAR driver when it needs to handle an interrupt
630 + * triggered by PHY.
632 +static void myatmdd_phy_int(struct atm_dev *dev)
634 + /* Handle interrupt triggered by PHY */
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)
642 +// case SONET_GETSTATZ:
649 +#########################################################
651 +# Function : myatmdd_free_tx_skb
653 +# Purpose : frees an sk_buff.
655 +# Args : skb=pointer to socket buffer
657 +# Notes : Tries to use the upper layer pop() function
658 +# but uses dev_kfree_skb() if this doesn't exist
659 +##########################################################
662 +# AJZ 10Apr03 Created
663 +##########################################################
665 +static void myatmdd_free_tx_skb(struct sk_buff *skb)
667 + struct atm_vcc *vcc;
669 + DEBUG("%s\n", __FUNCTION__);
671 + /* See if we can use the VCC pop function */
672 + if (((vcc = ATM_SKB(skb)->vcc) != NULL) && (vcc->pop != NULL))
674 + /* Yes, so use ATM socket layer pop function */
675 + vcc->pop(vcc, skb);
679 + printk(KERN_WARNING KLOG_PREAMBLE "unable to call skb free function\n");
680 + /* No, so free socket buffer */
681 + dev_kfree_skb(skb);
686 +#########################################################
688 +# Functions : Implementations of function ptrs in
693 +# myatmdd_getsockopt(),
694 +# myatmdd_setsockopt(),
696 +# myatmdd_sg_send(),
697 +# myatmdd_change_qos(),
698 +# myatmdd_proc_read()
701 +# Purpose : See ATM device driver interface v0.1
703 +# Notes : Conforming to Linux ATM device driver i/f
704 +# interface. Draft version 0.1
706 +# Designed to work with multiple devices
707 +##########################################################
710 +# AJZ 10Apr03 Created
711 +##########################################################
713 +static int myatmdd_open(struct atm_vcc *vcc)
715 + myatmdd_vccdata_t *priv;
718 + DEBUG("%s\n", __FUNCTION__);
720 + /* Make sure we are opening a AAL0 or AAL5 connection */
721 + if ((vcc->qos.aal != ATM_AAL5) && (vcc->qos.aal != ATM_AAL0))
723 + printk(KERN_WARNING KLOG_PREAMBLE "invalid AAL\n");
727 + /* Address is in use */
728 + set_bit(ATM_VF_ADDR, &vcc->flags);
730 + /* Allocate some vcc-private memory */
731 + vcc->dev_data = kmalloc(sizeof(myatmdd_vccdata_t), GFP_KERNEL);
732 + if (vcc->dev_data == NULL)
734 + priv = vcc->dev_data;
736 + /* Setup the hardware for new VC... */
738 + /* Do not allow half open VCs - otherwise the example driver will not be able
739 + * to loop back frames sent !
741 + if (vcc->qos.rxtp.traffic_class == ATM_NONE || vcc->qos.txtp.traffic_class == ATM_NONE)
743 + kfree(vcc->dev_data);
747 + /* Create rx/tx queues for this VC */
748 + myatmdd_init_txq(&priv->txqueue, TXQ_SZ);
749 + myatmdd_init_rxq(&priv->rxqueue, RXQ_SZ);
751 + /* Fill rx queue with empty skbuffs */
752 + for (i = 0 ; i < RXQ_SZ - 1; i++)
754 + struct sk_buff *skb = dev_alloc_skb(AAL5_BUFLEN);
755 + myatmdd_rxq_enqueue(&priv->rxqueue,skb);
758 + /* Connection is now ready to receive data */
759 + set_bit(ATM_VF_READY, &vcc->flags);
764 +static void myatmdd_close(struct atm_vcc *vcc)
766 + myatmdd_vccdata_t *priv = vcc->dev_data;
768 + DEBUG("%s\n", __FUNCTION__);
770 + /* Indicate channel closed */
771 + clear_bit(ATM_VF_READY, &vcc->flags);
773 + /* TODO Uninitialise the hardware for this VC... */
775 + /* empty the rx and tx queues */
776 + myatmdd_release_txq(&priv->txqueue);
777 + myatmdd_release_rxq(&priv->rxqueue);
779 + /* Free the vcc-private memory */
780 + kfree(vcc->dev_data);
783 +static int myatmdd_ioctl(struct atm_dev *dev, unsigned int cmd,void *arg)
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);
792 +static int myatmdd_getsockopt(struct atm_vcc *vcc,int level,int optname, void __user *optval,int optlen)
797 +static int myatmdd_setsockopt(struct atm_vcc *vcc,int level,int optname, void __user *optval,unsigned int optlen)
802 +/* Note may be called in either process or interrupt context! */
803 +static int myatmdd_send(struct atm_vcc *vcc,struct sk_buff *skb)
805 + myatmdd_vccdata_t *priv = vcc->dev_data;
807 + DEBUG("%s\n", __FUNCTION__);
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()
813 + ATM_SKB(skb)->vcc = vcc;
815 + /* Setup hardware to send and arrange callback of myatmdd_send_complete... */
817 + /* In this example ATM device driver all VCs are looped back.
818 + * So copy to the rxq and emulate an rx interrupt
821 + /* Can we accept another skb to send ? */
822 + if (myatmdd_txq_enqueue(&priv->txqueue, skb))
824 + /* No - free socket buffer */
825 + myatmdd_free_tx_skb(skb);
827 + /* Update tx channel stats */
828 + atomic_inc(&vcc->stats->tx_err);
830 + /* Tell protocol layer to back off */
834 + /* This is the bit which copies the tx ring to the rx ring,
835 + * and triggers emulated rx and tx interrupts
837 + myatmdd_emulate_loopback_hardware(vcc);
842 +static int myatmdd_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs)
847 +static int myatmdd_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
849 + int left = (int) *pos;
852 + return sprintf(page, "1st line of stats\n");
854 + return sprintf(page, "2nd line of stats\n");
856 + return sprintf(page, "3rd line of stats\n");
862 +#########################################################
864 +# Function : myatmdd_init
866 +# Purpose : init the module, init and register the ATM device
870 +# Returns : return code
874 +##########################################################
877 +# AJZ 10Apr03 Created
878 +##########################################################
880 +int __init myatmdd_init(void)
882 + myatmdd_devdata_t *priv = kmalloc(sizeof(myatmdd_devdata_t),GFP_KERNEL);
887 + /* Register the new device */
888 + myatmdd_dev = atm_dev_register(MYATMDD,NULL,&myatmdd_ops,-1,NULL);
890 + /* Were we able to register this device? */
891 + if (myatmdd_dev == NULL)
893 + printk(KERN_ERR KLOG_PREAMBLE "failed to register CPM ATM device\n");
897 + /* Save pointer to device private data */
898 + myatmdd_dev->dev_data = priv;
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;
905 + /* Set up phy device */
906 + myatmdd_phy_start(myatmdd_dev);
908 + /* TODO Initialise SAR hardware... */
910 + /* Console output */
911 + printk(KERN_INFO KLOG_PREAMBLE "Initialised\n");
917 + * module_init() is called by insmod, if built as module,
918 + * or by do_initcalls(), if built as a resident driver.
920 +module_init(myatmdd_init);
923 +#########################################################
925 +# Function : myatmdd_exit
927 +# Purpose : delete module, uninit and dereg ATM device
935 +##########################################################
938 +# AJZ 10Apr03 Created
939 +##########################################################
943 +static void __exit myatmdd_exit(void)
945 + /* Disable SAR hardware... */
947 + /* Console output */
948 + printk(KERN_ERR KLOG_PREAMBLE "Uninitialised\n");
949 + kfree(myatmdd_dev->dev_data);
950 + atm_dev_deregister(myatmdd_dev);
952 +module_exit(myatmdd_exit);