1 /* 2 * socket_sysfs.c -- most of socket-related sysfs output 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * (C) 2003 - 2004 Dominik Brodowski 9 */ 10 11 #include <linux/module.h> 12 #include <linux/moduleparam.h> 13 #include <linux/init.h> 14 #include <linux/kernel.h> 15 #include <linux/config.h> 16 #include <linux/string.h> 17 #include <linux/major.h> 18 #include <linux/errno.h> 19 #include <linux/slab.h> 20 #include <linux/mm.h> 21 #include <linux/interrupt.h> 22 #include <linux/timer.h> 23 #include <linux/ioport.h> 24 #include <linux/delay.h> 25 #include <linux/pm.h> 26 #include <linux/pci.h> 27 #include <linux/device.h> 28 #include <asm/system.h> 29 #include <asm/irq.h> 30 31 #define IN_CARD_SERVICES 32 #include <pcmcia/version.h> 33 #include <pcmcia/cs_types.h> 34 #include <pcmcia/ss.h> 35 #include <pcmcia/cs.h> 36 #include <pcmcia/bulkmem.h> 37 #include <pcmcia/cistpl.h> 38 #include <pcmcia/cisreg.h> 39 #include <pcmcia/ds.h> 40 #include "cs_internal.h" 41 42 #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) 43 44 static ssize_t pccard_show_type(struct class_device *dev, char *buf) 45 { 46 int val; 47 struct pcmcia_socket *s = to_socket(dev); 48 49 if (!(s->state & SOCKET_PRESENT)) 50 return -ENODEV; 51 s->ops->get_status(s, &val); 52 if (val & SS_CARDBUS) 53 return sprintf(buf, "32-bit\n"); 54 if (val & SS_DETECT) 55 return sprintf(buf, "16-bit\n"); 56 return sprintf(buf, "invalid\n"); 57 } 58 static CLASS_DEVICE_ATTR(card_type, 0400, pccard_show_type, NULL); 59 60 static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) 61 { 62 int val; 63 struct pcmcia_socket *s = to_socket(dev); 64 65 if (!(s->state & SOCKET_PRESENT)) 66 return -ENODEV; 67 s->ops->get_status(s, &val); 68 if (val & SS_3VCARD) 69 return sprintf(buf, "3.3V\n"); 70 if (val & SS_XVCARD) 71 return sprintf(buf, "X.XV\n"); 72 return sprintf(buf, "5.0V\n"); 73 } 74 static CLASS_DEVICE_ATTR(card_voltage, 0400, pccard_show_voltage, NULL); 75 76 static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) 77 { 78 struct pcmcia_socket *s = to_socket(dev); 79 if (!(s->state & SOCKET_PRESENT)) 80 return -ENODEV; 81 return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); 82 } 83 static CLASS_DEVICE_ATTR(card_vpp, 0400, pccard_show_vpp, NULL); 84 85 static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) 86 { 87 struct pcmcia_socket *s = to_socket(dev); 88 if (!(s->state & SOCKET_PRESENT)) 89 return -ENODEV; 90 return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); 91 } 92 static CLASS_DEVICE_ATTR(card_vcc, 0400, pccard_show_vcc, NULL); 93 94 95 static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) 96 { 97 ssize_t ret; 98 struct pcmcia_socket *s = to_socket(dev); 99 100 if (!count) 101 return -EINVAL; 102 103 ret = pcmcia_insert_card(s); 104 105 return ret ? ret : count; 106 } 107 static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); 108 109 static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count) 110 { 111 ssize_t ret; 112 struct pcmcia_socket *s = to_socket(dev); 113 114 if (!count) 115 return -EINVAL; 116 117 ret = pcmcia_eject_card(s); 118 119 return ret ? ret : count; 120 } 121 static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); 122 123 124 static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf) 125 { 126 struct pcmcia_socket *s = to_socket(dev); 127 return sprintf(buf, "0x%04x\n", s->irq_mask); 128 } 129 130 static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count) 131 { 132 ssize_t ret; 133 struct pcmcia_socket *s = to_socket(dev); 134 u32 mask; 135 136 if (!count) 137 return -EINVAL; 138 139 ret = sscanf (buf, "0x%x\n", &mask); 140 141 if (ret == 1) { 142 s->irq_mask &= mask; 143 ret = 0; 144 } 145 146 return ret ? ret : count; 147 } 148 static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); 149 150 151 static ssize_t pccard_show_resource(struct class_device *dev, char *buf) 152 { 153 struct pcmcia_socket *s = to_socket(dev); 154 return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); 155 } 156 157 static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count) 158 { 159 unsigned long flags; 160 struct pcmcia_socket *s = to_socket(dev); 161 162 if (!count) 163 return -EINVAL; 164 165 spin_lock_irqsave(&s->lock, flags); 166 if (!s->resource_setup_done) { 167 s->resource_setup_done = 1; 168 spin_unlock_irqrestore(&s->lock, flags); 169 170 down(&s->skt_sem); 171 if ((s->callback) && 172 (s->state & SOCKET_PRESENT) && 173 !(s->state & SOCKET_CARDBUS)) { 174 if (try_module_get(s->callback->owner)) { 175 s->callback->resources_done(s); 176 module_put(s->callback->owner); 177 } 178 } 179 up(&s->skt_sem); 180 181 return count; 182 } 183 spin_unlock_irqrestore(&s->lock, flags); 184 185 return count; 186 } 187 static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); 188 189 190 static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) 191 { 192 tuple_t tuple; 193 int status, i; 194 loff_t pointer = 0; 195 ssize_t ret = 0; 196 u_char *tuplebuffer; 197 u_char *tempbuffer; 198 199 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); 200 if (!tuplebuffer) 201 return -ENOMEM; 202 203 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); 204 if (!tempbuffer) { 205 ret = -ENOMEM; 206 goto free_tuple; 207 } 208 209 memset(&tuple, 0, sizeof(tuple_t)); 210 211 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; 212 tuple.DesiredTuple = RETURN_FIRST_TUPLE; 213 tuple.TupleOffset = 0; 214 215 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); 216 while (!status) { 217 tuple.TupleData = tuplebuffer; 218 tuple.TupleDataMax = 255; 219 memset(tuplebuffer, 0, sizeof(u_char) * 255); 220 221 status = pccard_get_tuple_data(s, &tuple); 222 if (status) 223 break; 224 225 if (off < (pointer + 2 + tuple.TupleDataLen)) { 226 tempbuffer[0] = tuple.TupleCode & 0xff; 227 tempbuffer[1] = tuple.TupleLink & 0xff; 228 for (i = 0; i < tuple.TupleDataLen; i++) 229 tempbuffer[i + 2] = tuplebuffer[i] & 0xff; 230 231 for (i = 0; i < (2 + tuple.TupleDataLen); i++) { 232 if (((i + pointer) >= off) && 233 (i + pointer) < (off + count)) { 234 buf[ret] = tempbuffer[i]; 235 ret++; 236 } 237 } 238 } 239 240 pointer += 2 + tuple.TupleDataLen; 241 242 if (pointer >= (off + count)) 243 break; 244 245 if (tuple.TupleCode == CISTPL_END) 246 break; 247 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); 248 } 249 250 kfree(tempbuffer); 251 free_tuple: 252 kfree(tuplebuffer); 253 254 return (ret); 255 } 256 257 static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) 258 { 259 unsigned int size = 0x200; 260 261 if (off >= size) 262 count = 0; 263 else { 264 struct pcmcia_socket *s; 265 cisinfo_t cisinfo; 266 267 if (off + count > size) 268 count = size - off; 269 270 s = to_socket(container_of(kobj, struct class_device, kobj)); 271 272 if (!(s->state & SOCKET_PRESENT)) 273 return -ENODEV; 274 if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) 275 return -EIO; 276 if (!cisinfo.Chains) 277 return -ENODATA; 278 279 count = pccard_extract_cis(s, buf, off, count); 280 } 281 282 return (count); 283 } 284 285 286 static struct class_device_attribute *pccard_socket_attributes[] = { 287 &class_device_attr_card_type, 288 &class_device_attr_card_voltage, 289 &class_device_attr_card_vpp, 290 &class_device_attr_card_vcc, 291 &class_device_attr_card_insert, 292 &class_device_attr_card_eject, 293 &class_device_attr_card_irq_mask, 294 &class_device_attr_available_resources_setup_done, 295 NULL, 296 }; 297 298 static struct bin_attribute pccard_cis_attr = { 299 .attr = { .name = "cis", .mode = S_IRUGO, .owner = THIS_MODULE}, 300 .size = 0x200, 301 .read = pccard_show_cis, 302 }; 303 304 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) 305 { 306 struct class_device_attribute **attr; 307 int ret = 0; 308 309 for (attr = pccard_socket_attributes; *attr; attr++) { 310 ret = class_device_create_file(class_dev, *attr); 311 if (ret) 312 break; 313 } 314 if (!ret) 315 ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); 316 317 return ret; 318 } 319 320 static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) 321 { 322 struct class_device_attribute **attr; 323 324 sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); 325 for (attr = pccard_socket_attributes; *attr; attr++) 326 class_device_remove_file(class_dev, *attr); 327 } 328 329 struct class_interface pccard_sysfs_interface = { 330 .class = &pcmcia_socket_class, 331 .add = &pccard_sysfs_add_socket, 332 .remove = __devexit_p(&pccard_sysfs_remove_socket), 333 }; 334