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