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 struct class_device_attribute *pccard_socket_attributes[] = { 191 &class_device_attr_card_type, 192 &class_device_attr_card_voltage, 193 &class_device_attr_card_vpp, 194 &class_device_attr_card_vcc, 195 &class_device_attr_card_insert, 196 &class_device_attr_card_eject, 197 &class_device_attr_card_irq_mask, 198 &class_device_attr_available_resources_setup_done, 199 NULL, 200 }; 201 202 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) 203 { 204 struct class_device_attribute **attr; 205 int ret = 0; 206 207 for (attr = pccard_socket_attributes; *attr; attr++) { 208 ret = class_device_create_file(class_dev, *attr); 209 if (ret) 210 break; 211 } 212 213 return ret; 214 } 215 216 static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) 217 { 218 struct class_device_attribute **attr; 219 220 for (attr = pccard_socket_attributes; *attr; attr++) 221 class_device_remove_file(class_dev, *attr); 222 } 223 224 struct class_interface pccard_sysfs_interface = { 225 .class = &pcmcia_socket_class, 226 .add = &pccard_sysfs_add_socket, 227 .remove = __devexit_p(&pccard_sysfs_remove_socket), 228 }; 229