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