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/cs_types.h> 33 #include <pcmcia/ss.h> 34 #include <pcmcia/cs.h> 35 #include <pcmcia/bulkmem.h> 36 #include <pcmcia/cistpl.h> 37 #include <pcmcia/cisreg.h> 38 #include <pcmcia/ds.h> 39 #include "cs_internal.h" 40 41 #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) 42 43 static ssize_t pccard_show_type(struct class_device *dev, char *buf) 44 { 45 int val; 46 struct pcmcia_socket *s = to_socket(dev); 47 48 if (!(s->state & SOCKET_PRESENT)) 49 return -ENODEV; 50 s->ops->get_status(s, &val); 51 if (val & SS_CARDBUS) 52 return sprintf(buf, "32-bit\n"); 53 if (val & SS_DETECT) 54 return sprintf(buf, "16-bit\n"); 55 return sprintf(buf, "invalid\n"); 56 } 57 static CLASS_DEVICE_ATTR(card_type, 0400, pccard_show_type, NULL); 58 59 static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) 60 { 61 int val; 62 struct pcmcia_socket *s = to_socket(dev); 63 64 if (!(s->state & SOCKET_PRESENT)) 65 return -ENODEV; 66 s->ops->get_status(s, &val); 67 if (val & SS_3VCARD) 68 return sprintf(buf, "3.3V\n"); 69 if (val & SS_XVCARD) 70 return sprintf(buf, "X.XV\n"); 71 return sprintf(buf, "5.0V\n"); 72 } 73 static CLASS_DEVICE_ATTR(card_voltage, 0400, pccard_show_voltage, NULL); 74 75 static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) 76 { 77 struct pcmcia_socket *s = to_socket(dev); 78 if (!(s->state & SOCKET_PRESENT)) 79 return -ENODEV; 80 return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); 81 } 82 static CLASS_DEVICE_ATTR(card_vpp, 0400, pccard_show_vpp, NULL); 83 84 static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) 85 { 86 struct pcmcia_socket *s = to_socket(dev); 87 if (!(s->state & SOCKET_PRESENT)) 88 return -ENODEV; 89 return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); 90 } 91 static CLASS_DEVICE_ATTR(card_vcc, 0400, pccard_show_vcc, NULL); 92 93 94 static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) 95 { 96 ssize_t ret; 97 struct pcmcia_socket *s = to_socket(dev); 98 99 if (!count) 100 return -EINVAL; 101 102 ret = pcmcia_insert_card(s); 103 104 return ret ? ret : count; 105 } 106 static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); 107 108 static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count) 109 { 110 ssize_t ret; 111 struct pcmcia_socket *s = to_socket(dev); 112 113 if (!count) 114 return -EINVAL; 115 116 ret = pcmcia_eject_card(s); 117 118 return ret ? ret : count; 119 } 120 static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); 121 122 123 static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf) 124 { 125 struct pcmcia_socket *s = to_socket(dev); 126 return sprintf(buf, "0x%04x\n", s->irq_mask); 127 } 128 129 static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count) 130 { 131 ssize_t ret; 132 struct pcmcia_socket *s = to_socket(dev); 133 u32 mask; 134 135 if (!count) 136 return -EINVAL; 137 138 ret = sscanf (buf, "0x%x\n", &mask); 139 140 if (ret == 1) { 141 s->irq_mask &= mask; 142 ret = 0; 143 } 144 145 return ret ? ret : count; 146 } 147 static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); 148 149 150 static ssize_t pccard_show_resource(struct class_device *dev, char *buf) 151 { 152 struct pcmcia_socket *s = to_socket(dev); 153 return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); 154 } 155 156 static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count) 157 { 158 unsigned long flags; 159 struct pcmcia_socket *s = to_socket(dev); 160 161 if (!count) 162 return -EINVAL; 163 164 spin_lock_irqsave(&s->lock, flags); 165 if (!s->resource_setup_done) 166 s->resource_setup_done = 1; 167 spin_unlock_irqrestore(&s->lock, flags); 168 169 down(&s->skt_sem); 170 if ((s->callback) && 171 (s->state & SOCKET_PRESENT) && 172 !(s->state & SOCKET_CARDBUS)) { 173 if (try_module_get(s->callback->owner)) { 174 s->callback->requery(s); 175 module_put(s->callback->owner); 176 } 177 } 178 up(&s->skt_sem); 179 180 return count; 181 } 182 static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); 183 184 185 static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) 186 { 187 tuple_t tuple; 188 int status, i; 189 loff_t pointer = 0; 190 ssize_t ret = 0; 191 u_char *tuplebuffer; 192 u_char *tempbuffer; 193 194 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); 195 if (!tuplebuffer) 196 return -ENOMEM; 197 198 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); 199 if (!tempbuffer) { 200 ret = -ENOMEM; 201 goto free_tuple; 202 } 203 204 memset(&tuple, 0, sizeof(tuple_t)); 205 206 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; 207 tuple.DesiredTuple = RETURN_FIRST_TUPLE; 208 tuple.TupleOffset = 0; 209 210 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); 211 while (!status) { 212 tuple.TupleData = tuplebuffer; 213 tuple.TupleDataMax = 255; 214 memset(tuplebuffer, 0, sizeof(u_char) * 255); 215 216 status = pccard_get_tuple_data(s, &tuple); 217 if (status) 218 break; 219 220 if (off < (pointer + 2 + tuple.TupleDataLen)) { 221 tempbuffer[0] = tuple.TupleCode & 0xff; 222 tempbuffer[1] = tuple.TupleLink & 0xff; 223 for (i = 0; i < tuple.TupleDataLen; i++) 224 tempbuffer[i + 2] = tuplebuffer[i] & 0xff; 225 226 for (i = 0; i < (2 + tuple.TupleDataLen); i++) { 227 if (((i + pointer) >= off) && 228 (i + pointer) < (off + count)) { 229 buf[ret] = tempbuffer[i]; 230 ret++; 231 } 232 } 233 } 234 235 pointer += 2 + tuple.TupleDataLen; 236 237 if (pointer >= (off + count)) 238 break; 239 240 if (tuple.TupleCode == CISTPL_END) 241 break; 242 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); 243 } 244 245 kfree(tempbuffer); 246 free_tuple: 247 kfree(tuplebuffer); 248 249 return (ret); 250 } 251 252 static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) 253 { 254 unsigned int size = 0x200; 255 256 if (off >= size) 257 count = 0; 258 else { 259 struct pcmcia_socket *s; 260 cisinfo_t cisinfo; 261 262 if (off + count > size) 263 count = size - off; 264 265 s = to_socket(container_of(kobj, struct class_device, kobj)); 266 267 if (!(s->state & SOCKET_PRESENT)) 268 return -ENODEV; 269 if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) 270 return -EIO; 271 if (!cisinfo.Chains) 272 return -ENODATA; 273 274 count = pccard_extract_cis(s, buf, off, count); 275 } 276 277 return (count); 278 } 279 280 static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) 281 { 282 struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); 283 cisdump_t *cis; 284 ssize_t ret = count; 285 286 if (off) 287 return -EINVAL; 288 289 if (count >= 0x200) 290 return -EINVAL; 291 292 if (!(s->state & SOCKET_PRESENT)) 293 return -ENODEV; 294 295 cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); 296 if (!cis) 297 return -ENOMEM; 298 memset(cis, 0, sizeof(cisdump_t)); 299 300 cis->Length = count + 1; 301 memcpy(cis->Data, buf, count); 302 303 if (pcmcia_replace_cis(s, cis)) 304 ret = -EIO; 305 306 kfree(cis); 307 308 if (!ret) { 309 down(&s->skt_sem); 310 if ((s->callback) && (s->state & SOCKET_PRESENT) && 311 !(s->state & SOCKET_CARDBUS)) { 312 if (try_module_get(s->callback->owner)) { 313 s->callback->requery(s); 314 module_put(s->callback->owner); 315 } 316 } 317 up(&s->skt_sem); 318 } 319 320 321 return (ret); 322 } 323 324 325 static struct class_device_attribute *pccard_socket_attributes[] = { 326 &class_device_attr_card_type, 327 &class_device_attr_card_voltage, 328 &class_device_attr_card_vpp, 329 &class_device_attr_card_vcc, 330 &class_device_attr_card_insert, 331 &class_device_attr_card_eject, 332 &class_device_attr_card_irq_mask, 333 &class_device_attr_available_resources_setup_done, 334 NULL, 335 }; 336 337 static struct bin_attribute pccard_cis_attr = { 338 .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE}, 339 .size = 0x200, 340 .read = pccard_show_cis, 341 .write = pccard_store_cis, 342 }; 343 344 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) 345 { 346 struct class_device_attribute **attr; 347 int ret = 0; 348 349 for (attr = pccard_socket_attributes; *attr; attr++) { 350 ret = class_device_create_file(class_dev, *attr); 351 if (ret) 352 break; 353 } 354 if (!ret) 355 ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); 356 357 return ret; 358 } 359 360 static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) 361 { 362 struct class_device_attribute **attr; 363 364 sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); 365 for (attr = pccard_socket_attributes; *attr; attr++) 366 class_device_remove_file(class_dev, *attr); 367 } 368 369 struct class_interface pccard_sysfs_interface = { 370 .class = &pcmcia_socket_class, 371 .add = &pccard_sysfs_add_socket, 372 .remove = __devexit_p(&pccard_sysfs_remove_socket), 373 }; 374