]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/pnp/interface.c
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6-omap-h63xx.git] / drivers / pnp / interface.c
1 /*
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@perex.cz>
5  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
6  * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
7  *      Bjorn Helgaas <bjorn.helgaas@hp.com>
8  */
9
10 #include <linux/pnp.h>
11 #include <linux/string.h>
12 #include <linux/errno.h>
13 #include <linux/list.h>
14 #include <linux/types.h>
15 #include <linux/pnp.h>
16 #include <linux/stat.h>
17 #include <linux/ctype.h>
18 #include <linux/slab.h>
19 #include <linux/mutex.h>
20
21 #include <asm/uaccess.h>
22
23 #include "base.h"
24
25 struct pnp_info_buffer {
26         char *buffer;           /* pointer to begin of buffer */
27         char *curr;             /* current position in buffer */
28         unsigned long size;     /* current size */
29         unsigned long len;      /* total length of buffer */
30         int stop;               /* stop flag */
31         int error;              /* error code */
32 };
33
34 typedef struct pnp_info_buffer pnp_info_buffer_t;
35
36 static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
37 {
38         va_list args;
39         int res;
40
41         if (buffer->stop || buffer->error)
42                 return 0;
43         va_start(args, fmt);
44         res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
45         va_end(args);
46         if (buffer->size + res >= buffer->len) {
47                 buffer->stop = 1;
48                 return 0;
49         }
50         buffer->curr += res;
51         buffer->size += res;
52         return res;
53 }
54
55 static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
56                            struct pnp_port *port)
57 {
58         pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "
59                    "%i-bit address decoding\n", space,
60                    (unsigned long long) port->min,
61                    (unsigned long long) port->max,
62                    port->align ? ((unsigned long long) port->align - 1) : 0,
63                    (unsigned long long) port->size,
64                    port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
65 }
66
67 static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
68                           struct pnp_irq *irq)
69 {
70         int first = 1, i;
71
72         pnp_printf(buffer, "%sirq ", space);
73         for (i = 0; i < PNP_IRQ_NR; i++)
74                 if (test_bit(i, irq->map.bits)) {
75                         if (!first) {
76                                 pnp_printf(buffer, ",");
77                         } else {
78                                 first = 0;
79                         }
80                         if (i == 2 || i == 9)
81                                 pnp_printf(buffer, "2/9");
82                         else
83                                 pnp_printf(buffer, "%i", i);
84                 }
85         if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
86                 pnp_printf(buffer, "<none>");
87         if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
88                 pnp_printf(buffer, " High-Edge");
89         if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
90                 pnp_printf(buffer, " Low-Edge");
91         if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
92                 pnp_printf(buffer, " High-Level");
93         if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
94                 pnp_printf(buffer, " Low-Level");
95         if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
96                 pnp_printf(buffer, " (optional)");
97         pnp_printf(buffer, "\n");
98 }
99
100 static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
101                           struct pnp_dma *dma)
102 {
103         int first = 1, i;
104         char *s;
105
106         pnp_printf(buffer, "%sdma ", space);
107         for (i = 0; i < 8; i++)
108                 if (dma->map & (1 << i)) {
109                         if (!first) {
110                                 pnp_printf(buffer, ",");
111                         } else {
112                                 first = 0;
113                         }
114                         pnp_printf(buffer, "%i", i);
115                 }
116         if (!dma->map)
117                 pnp_printf(buffer, "<none>");
118         switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
119         case IORESOURCE_DMA_8BIT:
120                 s = "8-bit";
121                 break;
122         case IORESOURCE_DMA_8AND16BIT:
123                 s = "8-bit&16-bit";
124                 break;
125         default:
126                 s = "16-bit";
127         }
128         pnp_printf(buffer, " %s", s);
129         if (dma->flags & IORESOURCE_DMA_MASTER)
130                 pnp_printf(buffer, " master");
131         if (dma->flags & IORESOURCE_DMA_BYTE)
132                 pnp_printf(buffer, " byte-count");
133         if (dma->flags & IORESOURCE_DMA_WORD)
134                 pnp_printf(buffer, " word-count");
135         switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
136         case IORESOURCE_DMA_TYPEA:
137                 s = "type-A";
138                 break;
139         case IORESOURCE_DMA_TYPEB:
140                 s = "type-B";
141                 break;
142         case IORESOURCE_DMA_TYPEF:
143                 s = "type-F";
144                 break;
145         default:
146                 s = "compatible";
147                 break;
148         }
149         pnp_printf(buffer, " %s\n", s);
150 }
151
152 static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
153                           struct pnp_mem *mem)
154 {
155         char *s;
156
157         pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",
158                    space, (unsigned long long) mem->min,
159                    (unsigned long long) mem->max,
160                    (unsigned long long) mem->align,
161                    (unsigned long long) mem->size);
162         if (mem->flags & IORESOURCE_MEM_WRITEABLE)
163                 pnp_printf(buffer, ", writeable");
164         if (mem->flags & IORESOURCE_MEM_CACHEABLE)
165                 pnp_printf(buffer, ", cacheable");
166         if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
167                 pnp_printf(buffer, ", range-length");
168         if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
169                 pnp_printf(buffer, ", shadowable");
170         if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
171                 pnp_printf(buffer, ", expansion ROM");
172         switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
173         case IORESOURCE_MEM_8BIT:
174                 s = "8-bit";
175                 break;
176         case IORESOURCE_MEM_8AND16BIT:
177                 s = "8-bit&16-bit";
178                 break;
179         case IORESOURCE_MEM_32BIT:
180                 s = "32-bit";
181                 break;
182         default:
183                 s = "16-bit";
184         }
185         pnp_printf(buffer, ", %s\n", s);
186 }
187
188 static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
189                              struct pnp_option *option)
190 {
191         switch (option->type) {
192         case IORESOURCE_IO:
193                 pnp_print_port(buffer, space, &option->u.port);
194                 break;
195         case IORESOURCE_MEM:
196                 pnp_print_mem(buffer, space, &option->u.mem);
197                 break;
198         case IORESOURCE_IRQ:
199                 pnp_print_irq(buffer, space, &option->u.irq);
200                 break;
201         case IORESOURCE_DMA:
202                 pnp_print_dma(buffer, space, &option->u.dma);
203                 break;
204         }
205 }
206
207 static ssize_t pnp_show_options(struct device *dmdev,
208                                 struct device_attribute *attr, char *buf)
209 {
210         struct pnp_dev *dev = to_pnp_dev(dmdev);
211         pnp_info_buffer_t *buffer;
212         struct pnp_option *option;
213         int ret, dep = 0, set = 0;
214         char *indent;
215
216         buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
217         if (!buffer)
218                 return -ENOMEM;
219
220         buffer->len = PAGE_SIZE;
221         buffer->buffer = buf;
222         buffer->curr = buffer->buffer;
223
224         list_for_each_entry(option, &dev->options, list) {
225                 if (pnp_option_is_dependent(option)) {
226                         indent = "  ";
227                         if (!dep || pnp_option_set(option) != set) {
228                                 set = pnp_option_set(option);
229                                 dep = 1;
230                                 pnp_printf(buffer, "Dependent: %02i - "
231                                            "Priority %s\n", set,
232                                            pnp_option_priority_name(option));
233                         }
234                 } else {
235                         dep = 0;
236                         indent = "";
237                 }
238                 pnp_print_option(buffer, indent, option);
239         }
240
241         ret = (buffer->curr - buf);
242         kfree(buffer);
243         return ret;
244 }
245
246 static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL);
247
248 static ssize_t pnp_show_current_resources(struct device *dmdev,
249                                           struct device_attribute *attr,
250                                           char *buf)
251 {
252         struct pnp_dev *dev = to_pnp_dev(dmdev);
253         pnp_info_buffer_t *buffer;
254         struct pnp_resource *pnp_res;
255         struct resource *res;
256         int ret;
257
258         if (!dev)
259                 return -EINVAL;
260
261         buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
262         if (!buffer)
263                 return -ENOMEM;
264
265         buffer->len = PAGE_SIZE;
266         buffer->buffer = buf;
267         buffer->curr = buffer->buffer;
268
269         pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");
270
271         list_for_each_entry(pnp_res, &dev->resources, list) {
272                 res = &pnp_res->res;
273
274                 pnp_printf(buffer, pnp_resource_type_name(res));
275
276                 if (res->flags & IORESOURCE_DISABLED) {
277                         pnp_printf(buffer, " disabled\n");
278                         continue;
279                 }
280
281                 switch (pnp_resource_type(res)) {
282                 case IORESOURCE_IO:
283                 case IORESOURCE_MEM:
284                         pnp_printf(buffer, " %#llx-%#llx\n",
285                                    (unsigned long long) res->start,
286                                    (unsigned long long) res->end);
287                         break;
288                 case IORESOURCE_IRQ:
289                 case IORESOURCE_DMA:
290                         pnp_printf(buffer, " %lld\n",
291                                    (unsigned long long) res->start);
292                         break;
293                 }
294         }
295
296         ret = (buffer->curr - buf);
297         kfree(buffer);
298         return ret;
299 }
300
301 static ssize_t pnp_set_current_resources(struct device *dmdev,
302                                          struct device_attribute *attr,
303                                          const char *ubuf, size_t count)
304 {
305         struct pnp_dev *dev = to_pnp_dev(dmdev);
306         char *buf = (void *)ubuf;
307         int retval = 0;
308         resource_size_t start, end;
309
310         if (dev->status & PNP_ATTACHED) {
311                 retval = -EBUSY;
312                 dev_info(&dev->dev, "in use; can't configure\n");
313                 goto done;
314         }
315
316         while (isspace(*buf))
317                 ++buf;
318         if (!strnicmp(buf, "disable", 7)) {
319                 retval = pnp_disable_dev(dev);
320                 goto done;
321         }
322         if (!strnicmp(buf, "activate", 8)) {
323                 retval = pnp_activate_dev(dev);
324                 goto done;
325         }
326         if (!strnicmp(buf, "fill", 4)) {
327                 if (dev->active)
328                         goto done;
329                 retval = pnp_auto_config_dev(dev);
330                 goto done;
331         }
332         if (!strnicmp(buf, "auto", 4)) {
333                 if (dev->active)
334                         goto done;
335                 pnp_init_resources(dev);
336                 retval = pnp_auto_config_dev(dev);
337                 goto done;
338         }
339         if (!strnicmp(buf, "clear", 5)) {
340                 if (dev->active)
341                         goto done;
342                 pnp_init_resources(dev);
343                 goto done;
344         }
345         if (!strnicmp(buf, "get", 3)) {
346                 mutex_lock(&pnp_res_mutex);
347                 if (pnp_can_read(dev))
348                         dev->protocol->get(dev);
349                 mutex_unlock(&pnp_res_mutex);
350                 goto done;
351         }
352         if (!strnicmp(buf, "set", 3)) {
353                 if (dev->active)
354                         goto done;
355                 buf += 3;
356                 pnp_init_resources(dev);
357                 mutex_lock(&pnp_res_mutex);
358                 while (1) {
359                         while (isspace(*buf))
360                                 ++buf;
361                         if (!strnicmp(buf, "io", 2)) {
362                                 buf += 2;
363                                 while (isspace(*buf))
364                                         ++buf;
365                                 start = simple_strtoul(buf, &buf, 0);
366                                 while (isspace(*buf))
367                                         ++buf;
368                                 if (*buf == '-') {
369                                         buf += 1;
370                                         while (isspace(*buf))
371                                                 ++buf;
372                                         end = simple_strtoul(buf, &buf, 0);
373                                 } else
374                                         end = start;
375                                 pnp_add_io_resource(dev, start, end, 0);
376                                 continue;
377                         }
378                         if (!strnicmp(buf, "mem", 3)) {
379                                 buf += 3;
380                                 while (isspace(*buf))
381                                         ++buf;
382                                 start = simple_strtoul(buf, &buf, 0);
383                                 while (isspace(*buf))
384                                         ++buf;
385                                 if (*buf == '-') {
386                                         buf += 1;
387                                         while (isspace(*buf))
388                                                 ++buf;
389                                         end = simple_strtoul(buf, &buf, 0);
390                                 } else
391                                         end = start;
392                                 pnp_add_mem_resource(dev, start, end, 0);
393                                 continue;
394                         }
395                         if (!strnicmp(buf, "irq", 3)) {
396                                 buf += 3;
397                                 while (isspace(*buf))
398                                         ++buf;
399                                 start = simple_strtoul(buf, &buf, 0);
400                                 pnp_add_irq_resource(dev, start, 0);
401                                 continue;
402                         }
403                         if (!strnicmp(buf, "dma", 3)) {
404                                 buf += 3;
405                                 while (isspace(*buf))
406                                         ++buf;
407                                 start = simple_strtoul(buf, &buf, 0);
408                                 pnp_add_dma_resource(dev, start, 0);
409                                 continue;
410                         }
411                         break;
412                 }
413                 mutex_unlock(&pnp_res_mutex);
414                 goto done;
415         }
416
417 done:
418         if (retval < 0)
419                 return retval;
420         return count;
421 }
422
423 static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR,
424                    pnp_show_current_resources, pnp_set_current_resources);
425
426 static ssize_t pnp_show_current_ids(struct device *dmdev,
427                                     struct device_attribute *attr, char *buf)
428 {
429         char *str = buf;
430         struct pnp_dev *dev = to_pnp_dev(dmdev);
431         struct pnp_id *pos = dev->id;
432
433         while (pos) {
434                 str += sprintf(str, "%s\n", pos->id);
435                 pos = pos->next;
436         }
437         return (str - buf);
438 }
439
440 static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL);
441
442 int pnp_interface_attach_device(struct pnp_dev *dev)
443 {
444         int rc = device_create_file(&dev->dev, &dev_attr_options);
445
446         if (rc)
447                 goto err;
448         rc = device_create_file(&dev->dev, &dev_attr_resources);
449         if (rc)
450                 goto err_opt;
451         rc = device_create_file(&dev->dev, &dev_attr_id);
452         if (rc)
453                 goto err_res;
454
455         return 0;
456
457 err_res:
458         device_remove_file(&dev->dev, &dev_attr_resources);
459 err_opt:
460         device_remove_file(&dev->dev, &dev_attr_options);
461 err:
462         return rc;
463 }