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