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/string.h> 16 #include <linux/major.h> 17 #include <linux/errno.h> 18 #include <linux/slab.h> 19 #include <linux/mm.h> 20 #include <linux/interrupt.h> 21 #include <linux/timer.h> 22 #include <linux/ioport.h> 23 #include <linux/delay.h> 24 #include <linux/pm.h> 25 #include <linux/device.h> 26 #include <linux/mutex.h> 27 #include <asm/system.h> 28 #include <asm/irq.h> 29 30 #include <pcmcia/cs_types.h> 31 #include <pcmcia/ss.h> 32 #include <pcmcia/cs.h> 33 #include <pcmcia/cistpl.h> 34 #include <pcmcia/cisreg.h> 35 #include <pcmcia/ds.h> 36 #include "cs_internal.h" 37 38 #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) 39 40 static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr, 41 char *buf) 42 { 43 struct pcmcia_socket *s = to_socket(dev); 44 45 if (!(s->state & SOCKET_PRESENT)) 46 return -ENODEV; 47 if (s->state & SOCKET_CARDBUS) 48 return sprintf(buf, "32-bit\n"); 49 return sprintf(buf, "16-bit\n"); 50 } 51 static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); 52 53 static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr, 54 char *buf) 55 { 56 struct pcmcia_socket *s = to_socket(dev); 57 58 if (!(s->state & SOCKET_PRESENT)) 59 return -ENODEV; 60 if (s->socket.Vcc) 61 return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, 62 s->socket.Vcc % 10); 63 return sprintf(buf, "X.XV\n"); 64 } 65 static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); 66 67 static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr, 68 char *buf) 69 { 70 struct pcmcia_socket *s = to_socket(dev); 71 if (!(s->state & SOCKET_PRESENT)) 72 return -ENODEV; 73 return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); 74 } 75 static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); 76 77 static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr, 78 char *buf) 79 { 80 struct pcmcia_socket *s = to_socket(dev); 81 if (!(s->state & SOCKET_PRESENT)) 82 return -ENODEV; 83 return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); 84 } 85 static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); 86 87 88 static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, 89 const char *buf, size_t count) 90 { 91 struct pcmcia_socket *s = to_socket(dev); 92 93 if (!count) 94 return -EINVAL; 95 96 pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT); 97 98 return count; 99 } 100 static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); 101 102 103 static ssize_t pccard_show_card_pm_state(struct device *dev, 104 struct device_attribute *attr, 105 char *buf) 106 { 107 struct pcmcia_socket *s = to_socket(dev); 108 return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on"); 109 } 110 111 static ssize_t pccard_store_card_pm_state(struct device *dev, 112 struct device_attribute *attr, 113 const char *buf, size_t count) 114 { 115 struct pcmcia_socket *s = to_socket(dev); 116 ssize_t ret = count; 117 118 if (!count) 119 return -EINVAL; 120 121 if (!strncmp(buf, "off", 3)) 122 pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND); 123 else { 124 if (!strncmp(buf, "on", 2)) 125 pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME); 126 else 127 ret = -EINVAL; 128 } 129 130 return ret; 131 } 132 static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); 133 134 static ssize_t pccard_store_eject(struct device *dev, 135 struct device_attribute *attr, 136 const char *buf, size_t count) 137 { 138 struct pcmcia_socket *s = to_socket(dev); 139 140 if (!count) 141 return -EINVAL; 142 143 pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT); 144 145 return count; 146 } 147 static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); 148 149 150 static ssize_t pccard_show_irq_mask(struct device *dev, 151 struct device_attribute *attr, 152 char *buf) 153 { 154 struct pcmcia_socket *s = to_socket(dev); 155 return sprintf(buf, "0x%04x\n", s->irq_mask); 156 } 157 158 static ssize_t pccard_store_irq_mask(struct device *dev, 159 struct device_attribute *attr, 160 const char *buf, size_t count) 161 { 162 ssize_t ret; 163 struct pcmcia_socket *s = to_socket(dev); 164 u32 mask; 165 166 if (!count) 167 return -EINVAL; 168 169 ret = sscanf(buf, "0x%x\n", &mask); 170 171 if (ret == 1) { 172 mutex_lock(&s->ops_mutex); 173 s->irq_mask &= mask; 174 mutex_unlock(&s->ops_mutex); 175 ret = 0; 176 } 177 178 return ret ? ret : count; 179 } 180 static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); 181 182 183 static ssize_t pccard_show_resource(struct device *dev, 184 struct device_attribute *attr, char *buf) 185 { 186 struct pcmcia_socket *s = to_socket(dev); 187 return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); 188 } 189 190 static ssize_t pccard_store_resource(struct device *dev, 191 struct device_attribute *attr, 192 const char *buf, size_t count) 193 { 194 struct pcmcia_socket *s = to_socket(dev); 195 196 if (!count) 197 return -EINVAL; 198 199 mutex_lock(&s->ops_mutex); 200 if (!s->resource_setup_done) 201 s->resource_setup_done = 1; 202 mutex_unlock(&s->ops_mutex); 203 204 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY); 205 206 return count; 207 } 208 static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); 209 210 static struct attribute *pccard_socket_attributes[] = { 211 &dev_attr_card_type.attr, 212 &dev_attr_card_voltage.attr, 213 &dev_attr_card_vpp.attr, 214 &dev_attr_card_vcc.attr, 215 &dev_attr_card_insert.attr, 216 &dev_attr_card_pm_state.attr, 217 &dev_attr_card_eject.attr, 218 &dev_attr_card_irq_mask.attr, 219 &dev_attr_available_resources_setup_done.attr, 220 NULL, 221 }; 222 223 static const struct attribute_group socket_attrs = { 224 .attrs = pccard_socket_attributes, 225 }; 226 227 int pccard_sysfs_add_socket(struct device *dev) 228 { 229 return sysfs_create_group(&dev->kobj, &socket_attrs); 230 } 231 232 void pccard_sysfs_remove_socket(struct device *dev) 233 { 234 sysfs_remove_group(&dev->kobj, &socket_attrs); 235 } 236