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->requery(s); 176 module_put(s->callback->owner); 177 } 178 } 179 up(&s->skt_sem); 180 181 return count; 182 } 183 static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); 184 185 186 static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) 187 { 188 tuple_t tuple; 189 int status, i; 190 loff_t pointer = 0; 191 ssize_t ret = 0; 192 u_char *tuplebuffer; 193 u_char *tempbuffer; 194 195 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); 196 if (!tuplebuffer) 197 return -ENOMEM; 198 199 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); 200 if (!tempbuffer) { 201 ret = -ENOMEM; 202 goto free_tuple; 203 } 204 205 memset(&tuple, 0, sizeof(tuple_t)); 206 207 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; 208 tuple.DesiredTuple = RETURN_FIRST_TUPLE; 209 tuple.TupleOffset = 0; 210 211 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); 212 while (!status) { 213 tuple.TupleData = tuplebuffer; 214 tuple.TupleDataMax = 255; 215 memset(tuplebuffer, 0, sizeof(u_char) * 255); 216 217 status = pccard_get_tuple_data(s, &tuple); 218 if (status) 219 break; 220 221 if (off < (pointer + 2 + tuple.TupleDataLen)) { 222 tempbuffer[0] = tuple.TupleCode & 0xff; 223 tempbuffer[1] = tuple.TupleLink & 0xff; 224 for (i = 0; i < tuple.TupleDataLen; i++) 225 tempbuffer[i + 2] = tuplebuffer[i] & 0xff; 226 227 for (i = 0; i < (2 + tuple.TupleDataLen); i++) { 228 if (((i + pointer) >= off) && 229 (i + pointer) < (off + count)) { 230 buf[ret] = tempbuffer[i]; 231 ret++; 232 } 233 } 234 } 235 236 pointer += 2 + tuple.TupleDataLen; 237 238 if (pointer >= (off + count)) 239 break; 240 241 if (tuple.TupleCode == CISTPL_END) 242 break; 243 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); 244 } 245 246 kfree(tempbuffer); 247 free_tuple: 248 kfree(tuplebuffer); 249 250 return (ret); 251 } 252 253 static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) 254 { 255 unsigned int size = 0x200; 256 257 if (off >= size) 258 count = 0; 259 else { 260 struct pcmcia_socket *s; 261 cisinfo_t cisinfo; 262 263 if (off + count > size) 264 count = size - off; 265 266 s = to_socket(container_of(kobj, struct class_device, kobj)); 267 268 if (!(s->state & SOCKET_PRESENT)) 269 return -ENODEV; 270 if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) 271 return -EIO; 272 if (!cisinfo.Chains) 273 return -ENODATA; 274 275 count = pccard_extract_cis(s, buf, off, count); 276 } 277 278 return (count); 279 } 280 281 static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) 282 { 283 struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); 284 cisdump_t *cis; 285 ssize_t ret = count; 286 287 if (off) 288 return -EINVAL; 289 290 if (count >= 0x200) 291 return -EINVAL; 292 293 if (!(s->state & SOCKET_PRESENT)) 294 return -ENODEV; 295 296 cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); 297 if (!cis) 298 return -ENOMEM; 299 memset(cis, 0, sizeof(cisdump_t)); 300 301 cis->Length = count + 1; 302 memcpy(cis->Data, buf, count); 303 304 if (pcmcia_replace_cis(s, cis)) 305 ret = -EIO; 306 307 kfree(cis); 308 309 if (!ret) { 310 down(&s->skt_sem); 311 if ((s->callback) && (s->state & SOCKET_PRESENT) && 312 !(s->state & SOCKET_CARDBUS)) { 313 if (try_module_get(s->callback->owner)) { 314 s->callback->requery(s); 315 module_put(s->callback->owner); 316 } 317 } 318 up(&s->skt_sem); 319 } 320 321 322 return (ret); 323 } 324 325 326 static struct class_device_attribute *pccard_socket_attributes[] = { 327 &class_device_attr_card_type, 328 &class_device_attr_card_voltage, 329 &class_device_attr_card_vpp, 330 &class_device_attr_card_vcc, 331 &class_device_attr_card_insert, 332 &class_device_attr_card_eject, 333 &class_device_attr_card_irq_mask, 334 &class_device_attr_available_resources_setup_done, 335 NULL, 336 }; 337 338 static struct bin_attribute pccard_cis_attr = { 339 .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE}, 340 .size = 0x200, 341 .read = pccard_show_cis, 342 .write = pccard_store_cis, 343 }; 344 345 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) 346 { 347 struct class_device_attribute **attr; 348 int ret = 0; 349 350 for (attr = pccard_socket_attributes; *attr; attr++) { 351 ret = class_device_create_file(class_dev, *attr); 352 if (ret) 353 break; 354 } 355 if (!ret) 356 ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); 357 358 return ret; 359 } 360 361 static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) 362 { 363 struct class_device_attribute **attr; 364 365 sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); 366 for (attr = pccard_socket_attributes; *attr; attr++) 367 class_device_remove_file(class_dev, *attr); 368 } 369 370 struct class_interface pccard_sysfs_interface = { 371 .class = &pcmcia_socket_class, 372 .add = &pccard_sysfs_add_socket, 373 .remove = __devexit_p(&pccard_sysfs_remove_socket), 374 }; 375