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