at v2.6.12 228 lines 5.8 kB view raw
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 44static 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} 58static CLASS_DEVICE_ATTR(card_type, 0400, pccard_show_type, NULL); 59 60static 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} 74static CLASS_DEVICE_ATTR(card_voltage, 0400, pccard_show_voltage, NULL); 75 76static 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} 83static CLASS_DEVICE_ATTR(card_vpp, 0400, pccard_show_vpp, NULL); 84 85static 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} 92static CLASS_DEVICE_ATTR(card_vcc, 0400, pccard_show_vcc, NULL); 93 94 95static 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} 107static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); 108 109static 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} 121static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); 122 123 124static 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 130static 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} 148static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); 149 150 151static 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 157static 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} 187static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); 188 189 190static 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 202static 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 216static 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 224struct 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};