1 /* ATM driver model support. */ 2 3 #include <linux/kernel.h> 4 #include <linux/slab.h> 5 #include <linux/init.h> 6 #include <linux/kobject.h> 7 #include <linux/atmdev.h> 8 #include "common.h" 9 #include "resources.h" 10 11 #define to_atm_dev(cldev) container_of(cldev, struct atm_dev, class_dev) 12 13 static ssize_t show_type(struct device *cdev, 14 struct device_attribute *attr, char *buf) 15 { 16 struct atm_dev *adev = to_atm_dev(cdev); 17 return sprintf(buf, "%s\n", adev->type); 18 } 19 20 static ssize_t show_address(struct device *cdev, 21 struct device_attribute *attr, char *buf) 22 { 23 char *pos = buf; 24 struct atm_dev *adev = to_atm_dev(cdev); 25 int i; 26 27 for (i = 0; i < (ESI_LEN - 1); i++) 28 pos += sprintf(pos, "%02x:", adev->esi[i]); 29 pos += sprintf(pos, "%02x\n", adev->esi[i]); 30 31 return pos - buf; 32 } 33 34 static ssize_t show_atmaddress(struct device *cdev, 35 struct device_attribute *attr, char *buf) 36 { 37 unsigned long flags; 38 char *pos = buf; 39 struct atm_dev *adev = to_atm_dev(cdev); 40 struct atm_dev_addr *aaddr; 41 int bin[] = { 1, 2, 10, 6, 1 }, *fmt = bin; 42 int i, j; 43 44 spin_lock_irqsave(&adev->lock, flags); 45 list_for_each_entry(aaddr, &adev->local, entry) { 46 for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) { 47 if (j == *fmt) { 48 pos += sprintf(pos, "."); 49 ++fmt; 50 j = 0; 51 } 52 pos += sprintf(pos, "%02x", 53 aaddr->addr.sas_addr.prv[i]); 54 } 55 pos += sprintf(pos, "\n"); 56 } 57 spin_unlock_irqrestore(&adev->lock, flags); 58 59 return pos - buf; 60 } 61 62 static ssize_t show_atmindex(struct device *cdev, 63 struct device_attribute *attr, char *buf) 64 { 65 struct atm_dev *adev = to_atm_dev(cdev); 66 67 return sprintf(buf, "%d\n", adev->number); 68 } 69 70 static ssize_t show_carrier(struct device *cdev, 71 struct device_attribute *attr, char *buf) 72 { 73 char *pos = buf; 74 struct atm_dev *adev = to_atm_dev(cdev); 75 76 pos += sprintf(pos, "%d\n", 77 adev->signal == ATM_PHY_SIG_LOST ? 0 : 1); 78 79 return pos - buf; 80 } 81 82 static ssize_t show_link_rate(struct device *cdev, 83 struct device_attribute *attr, char *buf) 84 { 85 char *pos = buf; 86 struct atm_dev *adev = to_atm_dev(cdev); 87 int link_rate; 88 89 /* show the link rate, not the data rate */ 90 switch (adev->link_rate) { 91 case ATM_OC3_PCR: 92 link_rate = 155520000; 93 break; 94 case ATM_OC12_PCR: 95 link_rate = 622080000; 96 break; 97 case ATM_25_PCR: 98 link_rate = 25600000; 99 break; 100 default: 101 link_rate = adev->link_rate * 8 * 53; 102 } 103 pos += sprintf(pos, "%d\n", link_rate); 104 105 return pos - buf; 106 } 107 108 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); 109 static DEVICE_ATTR(atmaddress, S_IRUGO, show_atmaddress, NULL); 110 static DEVICE_ATTR(atmindex, S_IRUGO, show_atmindex, NULL); 111 static DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL); 112 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); 113 static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL); 114 115 static struct device_attribute *atm_attrs[] = { 116 &dev_attr_atmaddress, 117 &dev_attr_address, 118 &dev_attr_atmindex, 119 &dev_attr_carrier, 120 &dev_attr_type, 121 &dev_attr_link_rate, 122 NULL 123 }; 124 125 126 static int atm_uevent(struct device *cdev, struct kobj_uevent_env *env) 127 { 128 struct atm_dev *adev; 129 130 if (!cdev) 131 return -ENODEV; 132 133 adev = to_atm_dev(cdev); 134 if (!adev) 135 return -ENODEV; 136 137 if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number)) 138 return -ENOMEM; 139 140 return 0; 141 } 142 143 static void atm_release(struct device *cdev) 144 { 145 struct atm_dev *adev = to_atm_dev(cdev); 146 147 kfree(adev); 148 } 149 150 static struct class atm_class = { 151 .name = "atm", 152 .dev_release = atm_release, 153 .dev_uevent = atm_uevent, 154 }; 155 156 int atm_register_sysfs(struct atm_dev *adev, struct device *parent) 157 { 158 struct device *cdev = &adev->class_dev; 159 int i, j, err; 160 161 cdev->class = &atm_class; 162 cdev->parent = parent; 163 dev_set_drvdata(cdev, adev); 164 165 dev_set_name(cdev, "%s%d", adev->type, adev->number); 166 err = device_register(cdev); 167 if (err < 0) 168 return err; 169 170 for (i = 0; atm_attrs[i]; i++) { 171 err = device_create_file(cdev, atm_attrs[i]); 172 if (err) 173 goto err_out; 174 } 175 176 return 0; 177 178 err_out: 179 for (j = 0; j < i; j++) 180 device_remove_file(cdev, atm_attrs[j]); 181 device_del(cdev); 182 return err; 183 } 184 185 void atm_unregister_sysfs(struct atm_dev *adev) 186 { 187 struct device *cdev = &adev->class_dev; 188 189 device_del(cdev); 190 } 191 192 int __init atm_sysfs_init(void) 193 { 194 return class_register(&atm_class); 195 } 196 197 void __exit atm_sysfs_exit(void) 198 { 199 class_unregister(&atm_class); 200 } 201