Blame view

drivers/pcmcia/socket_sysfs.c 9.25 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * socket_sysfs.c -- most of socket-related sysfs output
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * (C) 2003 - 2004		Dominik Brodowski
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
24
  #include <linux/string.h>
  #include <linux/major.h>
  #include <linux/errno.h>
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/interrupt.h>
  #include <linux/timer.h>
  #include <linux/ioport.h>
  #include <linux/delay.h>
  #include <linux/pm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/device.h>
7fe908dd1   Dominik Brodowski   [PATCH] pcmcia: u...
26
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  #include <asm/system.h>
  #include <asm/irq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
  #include <pcmcia/cs_types.h>
  #include <pcmcia/ss.h>
  #include <pcmcia/cs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
  #include <pcmcia/cistpl.h>
  #include <pcmcia/cisreg.h>
  #include <pcmcia/ds.h>
  #include "cs_internal.h"
  
  #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
873733188   Greg Kroah-Hartman   Driver core: conv...
38
39
  static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
  				char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
  	struct pcmcia_socket *s = to_socket(dev);
  
  	if (!(s->state & SOCKET_PRESENT))
  		return -ENODEV;
002dbb2d0   Dominik Brodowski   [PATCH] pcmcia: e...
45
  	if (s->state & SOCKET_CARDBUS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  		return sprintf(buf, "32-bit
  ");
002dbb2d0   Dominik Brodowski   [PATCH] pcmcia: e...
48
49
  	return sprintf(buf, "16-bit
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
51
  static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

873733188   Greg Kroah-Hartman   Driver core: conv...
53
54
  static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
  				   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
  	struct pcmcia_socket *s = to_socket(dev);
  
  	if (!(s->state & SOCKET_PRESENT))
  		return -ENODEV;
002dbb2d0   Dominik Brodowski   [PATCH] pcmcia: e...
60
61
62
63
64
65
  	if (s->socket.Vcc)
  		return sprintf(buf, "%d.%dV
  ", s->socket.Vcc / 10,
  			       s->socket.Vcc % 10);
  	return sprintf(buf, "X.XV
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
67
  static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

873733188   Greg Kroah-Hartman   Driver core: conv...
69
70
  static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
  			       char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
  {
  	struct pcmcia_socket *s = to_socket(dev);
  	if (!(s->state & SOCKET_PRESENT))
  		return -ENODEV;
  	return sprintf(buf, "%d.%dV
  ", s->socket.Vpp / 10, s->socket.Vpp % 10);
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
78
  static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

873733188   Greg Kroah-Hartman   Driver core: conv...
80
81
  static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
  			       char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
87
88
  {
  	struct pcmcia_socket *s = to_socket(dev);
  	if (!(s->state & SOCKET_PRESENT))
  		return -ENODEV;
  	return sprintf(buf, "%d.%dV
  ", s->socket.Vcc / 10, s->socket.Vcc % 10);
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
89
  static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90

873733188   Greg Kroah-Hartman   Driver core: conv...
91
92
  static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
  				   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
99
100
101
102
103
  {
  	ssize_t ret;
  	struct pcmcia_socket *s = to_socket(dev);
  
  	if (!count)
  		return -EINVAL;
  
  	ret = pcmcia_insert_card(s);
  
  	return ret ? ret : count;
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
104
  static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

db1019ca0   Dominik Brodowski   [PATCH] pcmcia: r...
106

873733188   Greg Kroah-Hartman   Driver core: conv...
107
108
109
  static ssize_t pccard_show_card_pm_state(struct device *dev,
  					 struct device_attribute *attr,
  					 char *buf)
db1019ca0   Dominik Brodowski   [PATCH] pcmcia: r...
110
111
112
113
114
  {
  	struct pcmcia_socket *s = to_socket(dev);
  	return sprintf(buf, "%s
  ", s->state & SOCKET_SUSPEND ? "off" : "on");
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
115
116
117
  static ssize_t pccard_store_card_pm_state(struct device *dev,
  					  struct device_attribute *attr,
  					  const char *buf, size_t count)
db1019ca0   Dominik Brodowski   [PATCH] pcmcia: r...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  {
  	ssize_t ret = -EINVAL;
  	struct pcmcia_socket *s = to_socket(dev);
  
  	if (!count)
  		return -EINVAL;
  
  	if (!(s->state & SOCKET_SUSPEND) && !strncmp(buf, "off", 3))
  		ret = pcmcia_suspend_card(s);
  	else if ((s->state & SOCKET_SUSPEND) && !strncmp(buf, "on", 2))
  		ret = pcmcia_resume_card(s);
  
  	return ret ? -ENODEV : count;
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
132
  static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
db1019ca0   Dominik Brodowski   [PATCH] pcmcia: r...
133

873733188   Greg Kroah-Hartman   Driver core: conv...
134
135
136
  static ssize_t pccard_store_eject(struct device *dev,
  				  struct device_attribute *attr,
  				  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
142
143
144
145
146
147
  {
  	ssize_t ret;
  	struct pcmcia_socket *s = to_socket(dev);
  
  	if (!count)
  		return -EINVAL;
  
  	ret = pcmcia_eject_card(s);
  
  	return ret ? ret : count;
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
148
  static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

873733188   Greg Kroah-Hartman   Driver core: conv...
150
151
152
  static ssize_t pccard_show_irq_mask(struct device *dev,
  				    struct device_attribute *attr,
  				    char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
  {
  	struct pcmcia_socket *s = to_socket(dev);
  	return sprintf(buf, "0x%04x
  ", s->irq_mask);
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
158
159
160
  static ssize_t pccard_store_irq_mask(struct device *dev,
  				     struct device_attribute *attr,
  				     const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  {
  	ssize_t ret;
  	struct pcmcia_socket *s = to_socket(dev);
  	u32 mask;
  
  	if (!count)
  		return -EINVAL;
  
  	ret = sscanf (buf, "0x%x
  ", &mask);
  
  	if (ret == 1) {
  		s->irq_mask &= mask;
  		ret = 0;
  	}
  
  	return ret ? ret : count;
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
179
  static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180

873733188   Greg Kroah-Hartman   Driver core: conv...
181
182
  static ssize_t pccard_show_resource(struct device *dev,
  				    struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
  {
  	struct pcmcia_socket *s = to_socket(dev);
  	return sprintf(buf, "%s
  ", s->resource_setup_done ? "yes" : "no");
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
188
189
190
  static ssize_t pccard_store_resource(struct device *dev,
  				     struct device_attribute *attr,
  				     const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
  {
  	unsigned long flags;
  	struct pcmcia_socket *s = to_socket(dev);
  
  	if (!count)
  		return -EINVAL;
  
  	spin_lock_irqsave(&s->lock, flags);
e2f0b5344   Dominik Brodowski   [PATCH] pcmcia: r...
199
  	if (!s->resource_setup_done)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  		s->resource_setup_done = 1;
e2f0b5344   Dominik Brodowski   [PATCH] pcmcia: r...
201
  	spin_unlock_irqrestore(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

7fe908dd1   Dominik Brodowski   [PATCH] pcmcia: u...
203
  	mutex_lock(&s->skt_mutex);
e2f0b5344   Dominik Brodowski   [PATCH] pcmcia: r...
204
205
206
207
  	if ((s->callback) &&
  	    (s->state & SOCKET_PRESENT) &&
  	    !(s->state & SOCKET_CARDBUS)) {
  		if (try_module_get(s->callback->owner)) {
4ae1cbf17   Dominik Brodowski   [PATCH] pcmcia: s...
208
  			s->callback->requery(s, 0);
e2f0b5344   Dominik Brodowski   [PATCH] pcmcia: r...
209
  			module_put(s->callback->owner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  	}
7fe908dd1   Dominik Brodowski   [PATCH] pcmcia: u...
212
  	mutex_unlock(&s->skt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
  
  	return count;
  }
873733188   Greg Kroah-Hartman   Driver core: conv...
216
  static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217

7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
  {
  	tuple_t tuple;
  	int status, i;
  	loff_t pointer = 0;
  	ssize_t ret = 0;
  	u_char *tuplebuffer;
  	u_char *tempbuffer;
  
  	tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
  	if (!tuplebuffer)
  		return -ENOMEM;
  
  	tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
  	if (!tempbuffer) {
  		ret = -ENOMEM;
  		goto free_tuple;
  	}
  
  	memset(&tuple, 0, sizeof(tuple_t));
  
  	tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
  	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
  	tuple.TupleOffset = 0;
  
  	status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
  	while (!status) {
  		tuple.TupleData = tuplebuffer;
  		tuple.TupleDataMax = 255;
  		memset(tuplebuffer, 0, sizeof(u_char) * 255);
  
  		status = pccard_get_tuple_data(s, &tuple);
  		if (status)
  			break;
  
  		if (off < (pointer + 2 + tuple.TupleDataLen)) {
  			tempbuffer[0] = tuple.TupleCode & 0xff;
  			tempbuffer[1] = tuple.TupleLink & 0xff;
  			for (i = 0; i < tuple.TupleDataLen; i++)
  				tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
  
  			for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
  				if (((i + pointer) >= off) &&
  				    (i + pointer) < (off + count)) {
  					buf[ret] = tempbuffer[i];
  					ret++;
  				}
  			}
  		}
  
  		pointer += 2 + tuple.TupleDataLen;
  
  		if (pointer >= (off + count))
  			break;
  
  		if (tuple.TupleCode == CISTPL_END)
  			break;
  		status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
  	}
  
  	kfree(tempbuffer);
   free_tuple:
  	kfree(tuplebuffer);
  
  	return (ret);
  }
91a690295   Zhang Rui   sysfs: add parame...
284
285
286
  static ssize_t pccard_show_cis(struct kobject *kobj,
  			       struct bin_attribute *bin_attr,
  			       char *buf, loff_t off, size_t count)
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
287
288
289
290
291
292
293
  {
  	unsigned int size = 0x200;
  
  	if (off >= size)
  		count = 0;
  	else {
  		struct pcmcia_socket *s;
c5081d5f4   Dominik Brodowski   pcmcia: simplify ...
294
  		unsigned int chains;
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
295
296
297
  
  		if (off + count > size)
  			count = size - off;
873733188   Greg Kroah-Hartman   Driver core: conv...
298
  		s = to_socket(container_of(kobj, struct device, kobj));
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
299
300
301
  
  		if (!(s->state & SOCKET_PRESENT))
  			return -ENODEV;
c5081d5f4   Dominik Brodowski   pcmcia: simplify ...
302
  		if (pccard_validate_cis(s, BIND_FN_ALL, &chains))
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
303
  			return -EIO;
c5081d5f4   Dominik Brodowski   pcmcia: simplify ...
304
  		if (!chains)
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
305
306
307
308
309
310
311
  			return -ENODATA;
  
  		count = pccard_extract_cis(s, buf, off, count);
  	}
  
  	return (count);
  }
91a690295   Zhang Rui   sysfs: add parame...
312
313
314
  static ssize_t pccard_store_cis(struct kobject *kobj,
  				struct bin_attribute *bin_attr,
  				char *buf, loff_t off, size_t count)
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
315
  {
873733188   Greg Kroah-Hartman   Driver core: conv...
316
  	struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
d834c1651   Linus Torvalds   pccard_store_cis:...
317
  	int error;
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
318
319
320
  
  	if (off)
  		return -EINVAL;
53efec951   Dominik Brodowski   pcmcia: only copy...
321
  	if (count >= CISTPL_MAX_CIS_SIZE)
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
322
323
324
325
  		return -EINVAL;
  
  	if (!(s->state & SOCKET_PRESENT))
  		return -ENODEV;
53efec951   Dominik Brodowski   pcmcia: only copy...
326
  	error = pcmcia_replace_cis(s, buf, count);
d834c1651   Linus Torvalds   pccard_store_cis:...
327
328
  	if (error)
  		return -EIO;
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
329

d834c1651   Linus Torvalds   pccard_store_cis:...
330
331
332
333
  	mutex_lock(&s->skt_mutex);
  	if ((s->callback) && (s->state & SOCKET_PRESENT) &&
  	    !(s->state & SOCKET_CARDBUS)) {
  		if (try_module_get(s->callback->owner)) {
4ae1cbf17   Dominik Brodowski   [PATCH] pcmcia: s...
334
  			s->callback->requery(s, 1);
d834c1651   Linus Torvalds   pccard_store_cis:...
335
  			module_put(s->callback->owner);
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
336
  		}
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
337
  	}
d834c1651   Linus Torvalds   pccard_store_cis:...
338
  	mutex_unlock(&s->skt_mutex);
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
339

d834c1651   Linus Torvalds   pccard_store_cis:...
340
  	return count;
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
341
  }
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
342

4356d73d0   David Brownell   pcmcia: remove pc...
343
344
345
346
347
348
349
350
351
352
  static struct attribute *pccard_socket_attributes[] = {
  	&dev_attr_card_type.attr,
  	&dev_attr_card_voltage.attr,
  	&dev_attr_card_vpp.attr,
  	&dev_attr_card_vcc.attr,
  	&dev_attr_card_insert.attr,
  	&dev_attr_card_pm_state.attr,
  	&dev_attr_card_eject.attr,
  	&dev_attr_card_irq_mask.attr,
  	&dev_attr_available_resources_setup_done.attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  	NULL,
  };
4356d73d0   David Brownell   pcmcia: remove pc...
355
356
357
  static const struct attribute_group socket_attrs = {
  	.attrs = pccard_socket_attributes,
  };
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
358
  static struct bin_attribute pccard_cis_attr = {
7b595756e   Tejun Heo   sysfs: kill unnec...
359
  	.attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
360
361
  	.size = 0x200,
  	.read = pccard_show_cis,
ff1fa9ef3   Dominik Brodowski   [PATCH] pcmcia: C...
362
  	.write = pccard_store_cis,
7f299bccb   Dominik Brodowski   [PATCH] pcmcia: e...
363
  };
4356d73d0   David Brownell   pcmcia: remove pc...
364
  int pccard_sysfs_add_socket(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	int ret = 0;
4356d73d0   David Brownell   pcmcia: remove pc...
367
368
369
  	ret = sysfs_create_group(&dev->kobj, &socket_attrs);
  	if (!ret) {
  		ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  		if (ret)
4356d73d0   David Brownell   pcmcia: remove pc...
371
  			sysfs_remove_group(&dev->kobj, &socket_attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
  	return ret;
  }
4356d73d0   David Brownell   pcmcia: remove pc...
375
  void pccard_sysfs_remove_socket(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  {
873733188   Greg Kroah-Hartman   Driver core: conv...
377
  	sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
4356d73d0   David Brownell   pcmcia: remove pc...
378
  	sysfs_remove_group(&dev->kobj, &socket_attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  }