1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * adummy.c: a dummy ATM driver
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/module.h>
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/skbuff.h>
9*4882a593Smuzhiyun #include <linux/errno.h>
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <linux/string.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/mm.h>
15*4882a593Smuzhiyun #include <linux/timer.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <asm/io.h>
19*4882a593Smuzhiyun #include <asm/byteorder.h>
20*4882a593Smuzhiyun #include <linux/uaccess.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/atmdev.h>
23*4882a593Smuzhiyun #include <linux/atm.h>
24*4882a593Smuzhiyun #include <linux/sonet.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* version definition */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define DRV_VERSION "1.0"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define DEV_LABEL "adummy"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define ADUMMY_DEV(dev) ((struct adummy_dev *) (dev)->dev_data)
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun struct adummy_dev {
35*4882a593Smuzhiyun struct atm_dev *atm_dev;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun struct list_head entry;
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* globals */
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static LIST_HEAD(adummy_devs);
43*4882a593Smuzhiyun
__set_signal(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)44*4882a593Smuzhiyun static ssize_t __set_signal(struct device *dev,
45*4882a593Smuzhiyun struct device_attribute *attr,
46*4882a593Smuzhiyun const char *buf, size_t len)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev);
49*4882a593Smuzhiyun int signal;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (sscanf(buf, "%d", &signal) == 1) {
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND)
54*4882a593Smuzhiyun signal = ATM_PHY_SIG_UNKNOWN;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun atm_dev_signal_change(atm_dev, signal);
57*4882a593Smuzhiyun return 1;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun return -EINVAL;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
__show_signal(struct device * dev,struct device_attribute * attr,char * buf)62*4882a593Smuzhiyun static ssize_t __show_signal(struct device *dev,
63*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev);
66*4882a593Smuzhiyun return sprintf(buf, "%d\n", atm_dev->signal);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun static DEVICE_ATTR(signal, 0644, __show_signal, __set_signal);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun static struct attribute *adummy_attrs[] = {
71*4882a593Smuzhiyun &dev_attr_signal.attr,
72*4882a593Smuzhiyun NULL
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static const struct attribute_group adummy_group_attrs = {
76*4882a593Smuzhiyun .name = NULL, /* We want them in dev's root folder */
77*4882a593Smuzhiyun .attrs = adummy_attrs
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun static int __init
adummy_start(struct atm_dev * dev)81*4882a593Smuzhiyun adummy_start(struct atm_dev *dev)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun dev->ci_range.vpi_bits = 4;
84*4882a593Smuzhiyun dev->ci_range.vci_bits = 12;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun return 0;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun static int
adummy_open(struct atm_vcc * vcc)90*4882a593Smuzhiyun adummy_open(struct atm_vcc *vcc)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun short vpi = vcc->vpi;
93*4882a593Smuzhiyun int vci = vcc->vci;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
96*4882a593Smuzhiyun return 0;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun set_bit(ATM_VF_ADDR, &vcc->flags);
99*4882a593Smuzhiyun set_bit(ATM_VF_READY, &vcc->flags);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun static void
adummy_close(struct atm_vcc * vcc)105*4882a593Smuzhiyun adummy_close(struct atm_vcc *vcc)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun clear_bit(ATM_VF_READY, &vcc->flags);
108*4882a593Smuzhiyun clear_bit(ATM_VF_ADDR, &vcc->flags);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun static int
adummy_send(struct atm_vcc * vcc,struct sk_buff * skb)112*4882a593Smuzhiyun adummy_send(struct atm_vcc *vcc, struct sk_buff *skb)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun if (vcc->pop)
115*4882a593Smuzhiyun vcc->pop(vcc, skb);
116*4882a593Smuzhiyun else
117*4882a593Smuzhiyun dev_kfree_skb_any(skb);
118*4882a593Smuzhiyun atomic_inc(&vcc->stats->tx);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return 0;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun static int
adummy_proc_read(struct atm_dev * dev,loff_t * pos,char * page)124*4882a593Smuzhiyun adummy_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun int left = *pos;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (!left--)
129*4882a593Smuzhiyun return sprintf(page, "version %s\n", DRV_VERSION);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun static const struct atmdev_ops adummy_ops =
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun .open = adummy_open,
137*4882a593Smuzhiyun .close = adummy_close,
138*4882a593Smuzhiyun .send = adummy_send,
139*4882a593Smuzhiyun .proc_read = adummy_proc_read,
140*4882a593Smuzhiyun .owner = THIS_MODULE
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
adummy_init(void)143*4882a593Smuzhiyun static int __init adummy_init(void)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun struct atm_dev *atm_dev;
146*4882a593Smuzhiyun struct adummy_dev *adummy_dev;
147*4882a593Smuzhiyun int err = 0;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun printk(KERN_ERR "adummy: version %s\n", DRV_VERSION);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun adummy_dev = kzalloc(sizeof(struct adummy_dev),
152*4882a593Smuzhiyun GFP_KERNEL);
153*4882a593Smuzhiyun if (!adummy_dev) {
154*4882a593Smuzhiyun printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n");
155*4882a593Smuzhiyun err = -ENOMEM;
156*4882a593Smuzhiyun goto out;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun atm_dev = atm_dev_register(DEV_LABEL, NULL, &adummy_ops, -1, NULL);
159*4882a593Smuzhiyun if (!atm_dev) {
160*4882a593Smuzhiyun printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
161*4882a593Smuzhiyun err = -ENODEV;
162*4882a593Smuzhiyun goto out_kfree;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun adummy_dev->atm_dev = atm_dev;
166*4882a593Smuzhiyun atm_dev->dev_data = adummy_dev;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (sysfs_create_group(&atm_dev->class_dev.kobj, &adummy_group_attrs))
169*4882a593Smuzhiyun dev_err(&atm_dev->class_dev, "Could not register attrs for adummy\n");
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (adummy_start(atm_dev)) {
172*4882a593Smuzhiyun printk(KERN_ERR DEV_LABEL ": adummy_start() failed\n");
173*4882a593Smuzhiyun err = -ENODEV;
174*4882a593Smuzhiyun goto out_unregister;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun list_add(&adummy_dev->entry, &adummy_devs);
178*4882a593Smuzhiyun out:
179*4882a593Smuzhiyun return err;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun out_unregister:
182*4882a593Smuzhiyun atm_dev_deregister(atm_dev);
183*4882a593Smuzhiyun out_kfree:
184*4882a593Smuzhiyun kfree(adummy_dev);
185*4882a593Smuzhiyun goto out;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
adummy_cleanup(void)188*4882a593Smuzhiyun static void __exit adummy_cleanup(void)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun struct adummy_dev *adummy_dev, *next;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun list_for_each_entry_safe(adummy_dev, next, &adummy_devs, entry) {
193*4882a593Smuzhiyun atm_dev_deregister(adummy_dev->atm_dev);
194*4882a593Smuzhiyun kfree(adummy_dev);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun module_init(adummy_init);
199*4882a593Smuzhiyun module_exit(adummy_cleanup);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun MODULE_AUTHOR("chas williams <chas@cmf.nrl.navy.mil>");
202*4882a593Smuzhiyun MODULE_DESCRIPTION("dummy ATM driver");
203*4882a593Smuzhiyun MODULE_LICENSE("GPL");
204