blob: b6beb8a36da70ffeba4288db5b9b8dcb6efb38bc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * interface.c - contains everything related to the user interface
3 *
4 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
5 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
6 *
7 */
8
9#include <linux/pnp.h>
10#include <linux/string.h>
11#include <linux/errno.h>
12#include <linux/list.h>
13#include <linux/types.h>
14#include <linux/stat.h>
15#include <linux/ctype.h>
16#include <linux/slab.h>
17#include <asm/uaccess.h>
18
19#include "base.h"
20
21struct pnp_info_buffer {
22 char *buffer; /* pointer to begin of buffer */
23 char *curr; /* current position in buffer */
24 unsigned long size; /* current size */
25 unsigned long len; /* total length of buffer */
26 int stop; /* stop flag */
27 int error; /* error code */
28};
29
30typedef struct pnp_info_buffer pnp_info_buffer_t;
31
Bjorn Helgaas9dd78462007-07-26 10:41:20 -070032static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033{
34 va_list args;
35 int res;
36
37 if (buffer->stop || buffer->error)
38 return 0;
39 va_start(args, fmt);
40 res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
41 va_end(args);
42 if (buffer->size + res >= buffer->len) {
43 buffer->stop = 1;
44 return 0;
45 }
46 buffer->curr += res;
47 buffer->size += res;
48 return res;
49}
50
Bjorn Helgaas9dd78462007-07-26 10:41:20 -070051static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
52 struct pnp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053{
Bjorn Helgaas9dd78462007-07-26 10:41:20 -070054 pnp_printf(buffer,
55 "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
56 space, port->min, port->max,
57 port->align ? (port->align - 1) : 0, port->size,
58 port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059}
60
Bjorn Helgaas9dd78462007-07-26 10:41:20 -070061static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
62 struct pnp_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
64 int first = 1, i;
65
66 pnp_printf(buffer, "%sirq ", space);
67 for (i = 0; i < PNP_IRQ_NR; i++)
68 if (test_bit(i, irq->map)) {
69 if (!first) {
70 pnp_printf(buffer, ",");
71 } else {
72 first = 0;
73 }
74 if (i == 2 || i == 9)
75 pnp_printf(buffer, "2/9");
76 else
77 pnp_printf(buffer, "%i", i);
78 }
79 if (bitmap_empty(irq->map, PNP_IRQ_NR))
80 pnp_printf(buffer, "<none>");
81 if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
82 pnp_printf(buffer, " High-Edge");
83 if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
84 pnp_printf(buffer, " Low-Edge");
85 if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
86 pnp_printf(buffer, " High-Level");
87 if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
88 pnp_printf(buffer, " Low-Level");
89 pnp_printf(buffer, "\n");
90}
91
Bjorn Helgaas9dd78462007-07-26 10:41:20 -070092static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
93 struct pnp_dma *dma)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 int first = 1, i;
96 char *s;
97
98 pnp_printf(buffer, "%sdma ", space);
99 for (i = 0; i < 8; i++)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700100 if (dma->map & (1 << i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (!first) {
102 pnp_printf(buffer, ",");
103 } else {
104 first = 0;
105 }
106 pnp_printf(buffer, "%i", i);
107 }
108 if (!dma->map)
109 pnp_printf(buffer, "<none>");
110 switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
111 case IORESOURCE_DMA_8BIT:
112 s = "8-bit";
113 break;
114 case IORESOURCE_DMA_8AND16BIT:
115 s = "8-bit&16-bit";
116 break;
117 default:
118 s = "16-bit";
119 }
120 pnp_printf(buffer, " %s", s);
121 if (dma->flags & IORESOURCE_DMA_MASTER)
122 pnp_printf(buffer, " master");
123 if (dma->flags & IORESOURCE_DMA_BYTE)
124 pnp_printf(buffer, " byte-count");
125 if (dma->flags & IORESOURCE_DMA_WORD)
126 pnp_printf(buffer, " word-count");
127 switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
128 case IORESOURCE_DMA_TYPEA:
129 s = "type-A";
130 break;
131 case IORESOURCE_DMA_TYPEB:
132 s = "type-B";
133 break;
134 case IORESOURCE_DMA_TYPEF:
135 s = "type-F";
136 break;
137 default:
138 s = "compatible";
139 break;
140 }
141 pnp_printf(buffer, " %s\n", s);
142}
143
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700144static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
145 struct pnp_mem *mem)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 char *s;
148
149 pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700150 space, mem->min, mem->max, mem->align, mem->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 if (mem->flags & IORESOURCE_MEM_WRITEABLE)
152 pnp_printf(buffer, ", writeable");
153 if (mem->flags & IORESOURCE_MEM_CACHEABLE)
154 pnp_printf(buffer, ", cacheable");
155 if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
156 pnp_printf(buffer, ", range-length");
157 if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
158 pnp_printf(buffer, ", shadowable");
159 if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
160 pnp_printf(buffer, ", expansion ROM");
161 switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
162 case IORESOURCE_MEM_8BIT:
163 s = "8-bit";
164 break;
165 case IORESOURCE_MEM_8AND16BIT:
166 s = "8-bit&16-bit";
167 break;
168 case IORESOURCE_MEM_32BIT:
169 s = "32-bit";
170 break;
171 default:
172 s = "16-bit";
173 }
174 pnp_printf(buffer, ", %s\n", s);
175}
176
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700177static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 struct pnp_option *option, int dep)
179{
180 char *s;
181 struct pnp_port *port;
182 struct pnp_irq *irq;
183 struct pnp_dma *dma;
184 struct pnp_mem *mem;
185
186 if (dep) {
187 switch (option->priority) {
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700188 case PNP_RES_PRIORITY_PREFERRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 s = "preferred";
190 break;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700191 case PNP_RES_PRIORITY_ACCEPTABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 s = "acceptable";
193 break;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700194 case PNP_RES_PRIORITY_FUNCTIONAL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 s = "functional";
196 break;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700197 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 s = "invalid";
199 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700200 pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 }
202
203 for (port = option->port; port; port = port->next)
204 pnp_print_port(buffer, space, port);
205 for (irq = option->irq; irq; irq = irq->next)
206 pnp_print_irq(buffer, space, irq);
207 for (dma = option->dma; dma; dma = dma->next)
208 pnp_print_dma(buffer, space, dma);
209 for (mem = option->mem; mem; mem = mem->next)
210 pnp_print_mem(buffer, space, mem);
211}
212
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700213static ssize_t pnp_show_options(struct device *dmdev,
214 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 struct pnp_dev *dev = to_pnp_dev(dmdev);
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700217 struct pnp_option *independent = dev->independent;
218 struct pnp_option *dependent = dev->dependent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 int ret, dep = 1;
220
221 pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700222 pnp_alloc(sizeof(pnp_info_buffer_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 if (!buffer)
224 return -ENOMEM;
225
226 buffer->len = PAGE_SIZE;
227 buffer->buffer = buf;
228 buffer->curr = buffer->buffer;
229 if (independent)
230 pnp_print_option(buffer, "", independent, 0);
231
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700232 while (dependent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 pnp_print_option(buffer, " ", dependent, dep);
234 dependent = dependent->next;
235 dep++;
236 }
237 ret = (buffer->curr - buf);
238 kfree(buffer);
239 return ret;
240}
241
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700242static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700244static ssize_t pnp_show_current_resources(struct device *dmdev,
245 struct device_attribute *attr,
246 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{
248 struct pnp_dev *dev = to_pnp_dev(dmdev);
249 int i, ret;
250 pnp_info_buffer_t *buffer;
251
252 if (!dev)
253 return -EINVAL;
254
255 buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t));
256 if (!buffer)
257 return -ENOMEM;
258 buffer->len = PAGE_SIZE;
259 buffer->buffer = buf;
260 buffer->curr = buffer->buffer;
261
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700262 pnp_printf(buffer, "state = ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 if (dev->active)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700264 pnp_printf(buffer, "active\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700266 pnp_printf(buffer, "disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 for (i = 0; i < PNP_MAX_PORT; i++) {
269 if (pnp_port_valid(dev, i)) {
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700270 pnp_printf(buffer, "io");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700272 pnp_printf(buffer, " disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700274 pnp_printf(buffer, " 0x%llx-0x%llx\n",
275 (unsigned long long)
276 pnp_port_start(dev, i),
277 (unsigned long long)pnp_port_end(dev,
278 i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 }
280 }
281 for (i = 0; i < PNP_MAX_MEM; i++) {
282 if (pnp_mem_valid(dev, i)) {
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700283 pnp_printf(buffer, "mem");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700285 pnp_printf(buffer, " disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700287 pnp_printf(buffer, " 0x%llx-0x%llx\n",
288 (unsigned long long)
289 pnp_mem_start(dev, i),
290 (unsigned long long)pnp_mem_end(dev,
291 i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
293 }
294 for (i = 0; i < PNP_MAX_IRQ; i++) {
295 if (pnp_irq_valid(dev, i)) {
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700296 pnp_printf(buffer, "irq");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700298 pnp_printf(buffer, " disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700300 pnp_printf(buffer, " %lld\n",
301 (unsigned long long)pnp_irq(dev, i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
303 }
304 for (i = 0; i < PNP_MAX_DMA; i++) {
305 if (pnp_dma_valid(dev, i)) {
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700306 pnp_printf(buffer, "dma");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700308 pnp_printf(buffer, " disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700310 pnp_printf(buffer, " %lld\n",
311 (unsigned long long)pnp_dma(dev, i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
313 }
314 ret = (buffer->curr - buf);
315 kfree(buffer);
316 return ret;
317}
318
319extern struct semaphore pnp_res_mutex;
320
321static ssize_t
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700322pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
323 const char *ubuf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 struct pnp_dev *dev = to_pnp_dev(dmdev);
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700326 char *buf = (void *)ubuf;
327 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 if (dev->status & PNP_ATTACHED) {
330 retval = -EBUSY;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700331 pnp_info("Device %s cannot be configured because it is in use.",
332 dev->dev.bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 goto done;
334 }
335
336 while (isspace(*buf))
337 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700338 if (!strnicmp(buf, "disable", 7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 retval = pnp_disable_dev(dev);
340 goto done;
341 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700342 if (!strnicmp(buf, "activate", 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 retval = pnp_activate_dev(dev);
344 goto done;
345 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700346 if (!strnicmp(buf, "fill", 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 if (dev->active)
348 goto done;
349 retval = pnp_auto_config_dev(dev);
350 goto done;
351 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700352 if (!strnicmp(buf, "auto", 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (dev->active)
354 goto done;
355 pnp_init_resource_table(&dev->res);
356 retval = pnp_auto_config_dev(dev);
357 goto done;
358 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700359 if (!strnicmp(buf, "clear", 5)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if (dev->active)
361 goto done;
362 pnp_init_resource_table(&dev->res);
363 goto done;
364 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700365 if (!strnicmp(buf, "get", 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 down(&pnp_res_mutex);
367 if (pnp_can_read(dev))
368 dev->protocol->get(dev, &dev->res);
369 up(&pnp_res_mutex);
370 goto done;
371 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700372 if (!strnicmp(buf, "set", 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 int nport = 0, nmem = 0, nirq = 0, ndma = 0;
374 if (dev->active)
375 goto done;
376 buf += 3;
377 pnp_init_resource_table(&dev->res);
378 down(&pnp_res_mutex);
379 while (1) {
380 while (isspace(*buf))
381 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700382 if (!strnicmp(buf, "io", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 buf += 2;
384 while (isspace(*buf))
385 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700386 dev->res.port_resource[nport].start =
387 simple_strtoul(buf, &buf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 while (isspace(*buf))
389 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700390 if (*buf == '-') {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 buf += 1;
392 while (isspace(*buf))
393 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700394 dev->res.port_resource[nport].end =
395 simple_strtoul(buf, &buf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 } else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700397 dev->res.port_resource[nport].end =
398 dev->res.port_resource[nport].start;
399 dev->res.port_resource[nport].flags =
400 IORESOURCE_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 nport++;
402 if (nport >= PNP_MAX_PORT)
403 break;
404 continue;
405 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700406 if (!strnicmp(buf, "mem", 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 buf += 3;
408 while (isspace(*buf))
409 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700410 dev->res.mem_resource[nmem].start =
411 simple_strtoul(buf, &buf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 while (isspace(*buf))
413 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700414 if (*buf == '-') {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 buf += 1;
416 while (isspace(*buf))
417 ++buf;
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700418 dev->res.mem_resource[nmem].end =
419 simple_strtoul(buf, &buf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 } else
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700421 dev->res.mem_resource[nmem].end =
422 dev->res.mem_resource[nmem].start;
423 dev->res.mem_resource[nmem].flags =
424 IORESOURCE_MEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 nmem++;
426 if (nmem >= PNP_MAX_MEM)
427 break;
428 continue;
429 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700430 if (!strnicmp(buf, "irq", 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 buf += 3;
432 while (isspace(*buf))
433 ++buf;
434 dev->res.irq_resource[nirq].start =
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700435 dev->res.irq_resource[nirq].end =
436 simple_strtoul(buf, &buf, 0);
437 dev->res.irq_resource[nirq].flags =
438 IORESOURCE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 nirq++;
440 if (nirq >= PNP_MAX_IRQ)
441 break;
442 continue;
443 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700444 if (!strnicmp(buf, "dma", 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 buf += 3;
446 while (isspace(*buf))
447 ++buf;
448 dev->res.dma_resource[ndma].start =
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700449 dev->res.dma_resource[ndma].end =
450 simple_strtoul(buf, &buf, 0);
451 dev->res.dma_resource[ndma].flags =
452 IORESOURCE_DMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 ndma++;
454 if (ndma >= PNP_MAX_DMA)
455 break;
456 continue;
457 }
458 break;
459 }
460 up(&pnp_res_mutex);
461 goto done;
462 }
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700463 done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if (retval < 0)
465 return retval;
466 return count;
467}
468
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700469static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR,
470 pnp_show_current_resources, pnp_set_current_resources);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700472static ssize_t pnp_show_current_ids(struct device *dmdev,
473 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
475 char *str = buf;
476 struct pnp_dev *dev = to_pnp_dev(dmdev);
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700477 struct pnp_id *pos = dev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 while (pos) {
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700480 str += sprintf(str, "%s\n", pos->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 pos = pos->next;
482 }
483 return (str - buf);
484}
485
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700486static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488int pnp_interface_attach_device(struct pnp_dev *dev)
489{
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700490 int rc = device_create_file(&dev->dev, &dev_attr_options);
491 if (rc)
492 goto err;
493 rc = device_create_file(&dev->dev, &dev_attr_resources);
494 if (rc)
495 goto err_opt;
496 rc = device_create_file(&dev->dev, &dev_attr_id);
497 if (rc)
498 goto err_res;
Jeff Garzikbfc7ee22006-12-06 20:35:33 -0800499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return 0;
Jeff Garzikbfc7ee22006-12-06 20:35:33 -0800501
Bjorn Helgaas9dd78462007-07-26 10:41:20 -0700502 err_res:
503 device_remove_file(&dev->dev, &dev_attr_resources);
504 err_opt:
505 device_remove_file(&dev->dev, &dev_attr_options);
506 err:
Jeff Garzikbfc7ee22006-12-06 20:35:33 -0800507 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}