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