1 /* 2 * adummy.c: a dummy ATM driver 3 */ 4 5 #include <linux/module.h> 6 #include <linux/version.h> 7 #include <linux/kernel.h> 8 #include <linux/skbuff.h> 9 #include <linux/pci.h> 10 #include <linux/errno.h> 11 #include <linux/types.h> 12 #include <linux/string.h> 13 #include <linux/delay.h> 14 #include <linux/init.h> 15 #include <linux/mm.h> 16 #include <linux/sched.h> 17 #include <linux/timer.h> 18 #include <linux/interrupt.h> 19 #include <asm/io.h> 20 #include <asm/byteorder.h> 21 #include <asm/uaccess.h> 22 23 #include <linux/atmdev.h> 24 #include <linux/atm.h> 25 #include <linux/sonet.h> 26 27 /* version definition */ 28 29 #define DRV_VERSION "1.0" 30 31 #define DEV_LABEL "adummy" 32 33 #define ADUMMY_DEV(dev) ((struct adummy_dev *) (dev)->dev_data) 34 35 struct adummy_dev { 36 struct atm_dev *atm_dev; 37 38 struct list_head entry; 39 }; 40 41 /* globals */ 42 43 static LIST_HEAD(adummy_devs); 44 45 static int __init 46 adummy_start(struct atm_dev *dev) 47 { 48 dev->ci_range.vpi_bits = 4; 49 dev->ci_range.vci_bits = 12; 50 51 return 0; 52 } 53 54 static int 55 adummy_open(struct atm_vcc *vcc) 56 { 57 short vpi = vcc->vpi; 58 int vci = vcc->vci; 59 60 if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) 61 return 0; 62 63 set_bit(ATM_VF_ADDR, &vcc->flags); 64 set_bit(ATM_VF_READY, &vcc->flags); 65 66 return 0; 67 } 68 69 static void 70 adummy_close(struct atm_vcc *vcc) 71 { 72 clear_bit(ATM_VF_READY, &vcc->flags); 73 clear_bit(ATM_VF_ADDR, &vcc->flags); 74 } 75 76 static int 77 adummy_send(struct atm_vcc *vcc, struct sk_buff *skb) 78 { 79 if (vcc->pop) 80 vcc->pop(vcc, skb); 81 else 82 dev_kfree_skb_any(skb); 83 atomic_inc(&vcc->stats->tx); 84 85 return 0; 86 } 87 88 static int 89 adummy_proc_read(struct atm_dev *dev, loff_t *pos, char *page) 90 { 91 int left = *pos; 92 93 if (!left--) 94 return sprintf(page, "version %s\n", DRV_VERSION); 95 96 return 0; 97 } 98 99 static struct atmdev_ops adummy_ops = 100 { 101 .open = adummy_open, 102 .close = adummy_close, 103 .send = adummy_send, 104 .proc_read = adummy_proc_read, 105 .owner = THIS_MODULE 106 }; 107 108 static int __init adummy_init(void) 109 { 110 struct atm_dev *atm_dev; 111 struct adummy_dev *adummy_dev; 112 int err = 0; 113 114 printk(KERN_ERR "adummy: version %s\n", DRV_VERSION); 115 116 adummy_dev = (struct adummy_dev *) kmalloc(sizeof(struct adummy_dev), 117 GFP_KERNEL); 118 if (!adummy_dev) { 119 printk(KERN_ERR DEV_LABEL ": kmalloc() failed\n"); 120 err = -ENOMEM; 121 goto out; 122 } 123 memset(adummy_dev, 0, sizeof(struct adummy_dev)); 124 125 atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL); 126 if (!atm_dev) { 127 printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n"); 128 err = -ENODEV; 129 goto out_kfree; 130 } 131 132 adummy_dev->atm_dev = atm_dev; 133 atm_dev->dev_data = adummy_dev; 134 135 if (adummy_start(atm_dev)) { 136 printk(KERN_ERR DEV_LABEL ": adummy_start() failed\n"); 137 err = -ENODEV; 138 goto out_unregister; 139 } 140 141 list_add(&adummy_dev->entry, &adummy_devs); 142 out: 143 return err; 144 145 out_unregister: 146 atm_dev_deregister(atm_dev); 147 out_kfree: 148 kfree(adummy_dev); 149 goto out; 150 } 151 152 static void __exit adummy_cleanup(void) 153 { 154 struct adummy_dev *adummy_dev, *next; 155 156 list_for_each_entry_safe(adummy_dev, next, &adummy_devs, entry) { 157 atm_dev_deregister(adummy_dev->atm_dev); 158 kfree(adummy_dev); 159 } 160 } 161 162 module_init(adummy_init); 163 module_exit(adummy_cleanup); 164 165 MODULE_AUTHOR("chas williams <chas@cmf.nrl.navy.mil>"); 166 MODULE_DESCRIPTION("dummy ATM driver"); 167 MODULE_LICENSE("GPL"); 168