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