Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
interface.c
Go to the documentation of this file.
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 <[email protected]>
5  * Copyright 2002 Adam Belay <[email protected]>
6  * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
7  * Bjorn Helgaas <[email protected]>
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/stat.h>
16 #include <linux/ctype.h>
17 #include <linux/slab.h>
18 #include <linux/mutex.h>
19 
20 #include <asm/uaccess.h>
21 
22 #include "base.h"
23 
25  char *buffer; /* pointer to begin of buffer */
26  char *curr; /* current position in buffer */
27  unsigned long size; /* current size */
28  unsigned long len; /* total length of buffer */
29  int stop; /* stop flag */
30  int error; /* error code */
31 };
32 
34 
35 static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
36 {
37  va_list args;
38  int res;
39 
40  if (buffer->stop || buffer->error)
41  return 0;
42  va_start(args, fmt);
43  res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
44  va_end(args);
45  if (buffer->size + res >= buffer->len) {
46  buffer->stop = 1;
47  return 0;
48  }
49  buffer->curr += res;
50  buffer->size += res;
51  return res;
52 }
53 
54 static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
55  struct pnp_port *port)
56 {
57  pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "
58  "%i-bit address decoding\n", space,
59  (unsigned long long) port->min,
60  (unsigned long long) port->max,
61  port->align ? ((unsigned long long) port->align - 1) : 0,
62  (unsigned long long) port->size,
63  port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
64 }
65 
66 static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
67  struct pnp_irq *irq)
68 {
69  int first = 1, i;
70 
71  pnp_printf(buffer, "%sirq ", space);
72  for (i = 0; i < PNP_IRQ_NR; i++)
73  if (test_bit(i, irq->map.bits)) {
74  if (!first) {
75  pnp_printf(buffer, ",");
76  } else {
77  first = 0;
78  }
79  if (i == 2 || i == 9)
80  pnp_printf(buffer, "2/9");
81  else
82  pnp_printf(buffer, "%i", i);
83  }
84  if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
85  pnp_printf(buffer, "<none>");
86  if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
87  pnp_printf(buffer, " High-Edge");
88  if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
89  pnp_printf(buffer, " Low-Edge");
91  pnp_printf(buffer, " High-Level");
92  if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
93  pnp_printf(buffer, " Low-Level");
94  if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
95  pnp_printf(buffer, " (optional)");
96  pnp_printf(buffer, "\n");
97 }
98 
99 static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
100  struct pnp_dma *dma)
101 {
102  int first = 1, i;
103  char *s;
104 
105  pnp_printf(buffer, "%sdma ", space);
106  for (i = 0; i < 8; i++)
107  if (dma->map & (1 << i)) {
108  if (!first) {
109  pnp_printf(buffer, ",");
110  } else {
111  first = 0;
112  }
113  pnp_printf(buffer, "%i", i);
114  }
115  if (!dma->map)
116  pnp_printf(buffer, "<none>");
117  switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
118  case IORESOURCE_DMA_8BIT:
119  s = "8-bit";
120  break;
122  s = "8-bit&16-bit";
123  break;
124  default:
125  s = "16-bit";
126  }
127  pnp_printf(buffer, " %s", s);
128  if (dma->flags & IORESOURCE_DMA_MASTER)
129  pnp_printf(buffer, " master");
130  if (dma->flags & IORESOURCE_DMA_BYTE)
131  pnp_printf(buffer, " byte-count");
132  if (dma->flags & IORESOURCE_DMA_WORD)
133  pnp_printf(buffer, " word-count");
134  switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
136  s = "type-A";
137  break;
139  s = "type-B";
140  break;
142  s = "type-F";
143  break;
144  default:
145  s = "compatible";
146  break;
147  }
148  pnp_printf(buffer, " %s\n", s);
149 }
150 
151 static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
152  struct pnp_mem *mem)
153 {
154  char *s;
155 
156  pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",
157  space, (unsigned long long) mem->min,
158  (unsigned long long) mem->max,
159  (unsigned long long) mem->align,
160  (unsigned long long) mem->size);
161  if (mem->flags & IORESOURCE_MEM_WRITEABLE)
162  pnp_printf(buffer, ", writeable");
163  if (mem->flags & IORESOURCE_MEM_CACHEABLE)
164  pnp_printf(buffer, ", cacheable");
166  pnp_printf(buffer, ", range-length");
167  if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
168  pnp_printf(buffer, ", shadowable");
170  pnp_printf(buffer, ", expansion ROM");
171  switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
172  case IORESOURCE_MEM_8BIT:
173  s = "8-bit";
174  break;
176  s = "8-bit&16-bit";
177  break;
179  s = "32-bit";
180  break;
181  default:
182  s = "16-bit";
183  }
184  pnp_printf(buffer, ", %s\n", s);
185 }
186 
187 static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
188  struct pnp_option *option)
189 {
190  switch (option->type) {
191  case IORESOURCE_IO:
192  pnp_print_port(buffer, space, &option->u.port);
193  break;
194  case IORESOURCE_MEM:
195  pnp_print_mem(buffer, space, &option->u.mem);
196  break;
197  case IORESOURCE_IRQ:
198  pnp_print_irq(buffer, space, &option->u.irq);
199  break;
200  case IORESOURCE_DMA:
201  pnp_print_dma(buffer, space, &option->u.dma);
202  break;
203  }
204 }
205 
206 static ssize_t pnp_show_options(struct device *dmdev,
207  struct device_attribute *attr, char *buf)
208 {
209  struct pnp_dev *dev = to_pnp_dev(dmdev);
211  struct pnp_option *option;
212  int ret, dep = 0, set = 0;
213  char *indent;
214 
215  buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
216  if (!buffer)
217  return -ENOMEM;
218 
219  buffer->len = PAGE_SIZE;
220  buffer->buffer = buf;
221  buffer->curr = buffer->buffer;
222 
223  list_for_each_entry(option, &dev->options, list) {
224  if (pnp_option_is_dependent(option)) {
225  indent = " ";
226  if (!dep || pnp_option_set(option) != set) {
227  set = pnp_option_set(option);
228  dep = 1;
229  pnp_printf(buffer, "Dependent: %02i - "
230  "Priority %s\n", set,
231  pnp_option_priority_name(option));
232  }
233  } else {
234  dep = 0;
235  indent = "";
236  }
237  pnp_print_option(buffer, indent, option);
238  }
239 
240  ret = (buffer->curr - buf);
241  kfree(buffer);
242  return ret;
243 }
244 
245 static ssize_t pnp_show_current_resources(struct device *dmdev,
246  struct device_attribute *attr,
247  char *buf)
248 {
249  struct pnp_dev *dev = to_pnp_dev(dmdev);
251  struct pnp_resource *pnp_res;
252  struct resource *res;
253  int ret;
254 
255  if (!dev)
256  return -EINVAL;
257 
258  buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
259  if (!buffer)
260  return -ENOMEM;
261 
262  buffer->len = PAGE_SIZE;
263  buffer->buffer = buf;
264  buffer->curr = buffer->buffer;
265 
266  pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");
267 
268  list_for_each_entry(pnp_res, &dev->resources, list) {
269  res = &pnp_res->res;
270 
271  pnp_printf(buffer, pnp_resource_type_name(res));
272 
273  if (res->flags & IORESOURCE_DISABLED) {
274  pnp_printf(buffer, " disabled\n");
275  continue;
276  }
277 
278  switch (pnp_resource_type(res)) {
279  case IORESOURCE_IO:
280  case IORESOURCE_MEM:
281  case IORESOURCE_BUS:
282  pnp_printf(buffer, " %#llx-%#llx%s\n",
283  (unsigned long long) res->start,
284  (unsigned long long) res->end,
285  res->flags & IORESOURCE_WINDOW ?
286  " window" : "");
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;
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  buf = skip_spaces(buf);
317  if (!strnicmp(buf, "disable", 7)) {
318  retval = pnp_disable_dev(dev);
319  goto done;
320  }
321  if (!strnicmp(buf, "activate", 8)) {
322  retval = pnp_activate_dev(dev);
323  goto done;
324  }
325  if (!strnicmp(buf, "fill", 4)) {
326  if (dev->active)
327  goto done;
328  retval = pnp_auto_config_dev(dev);
329  goto done;
330  }
331  if (!strnicmp(buf, "auto", 4)) {
332  if (dev->active)
333  goto done;
334  pnp_init_resources(dev);
335  retval = pnp_auto_config_dev(dev);
336  goto done;
337  }
338  if (!strnicmp(buf, "clear", 5)) {
339  if (dev->active)
340  goto done;
341  pnp_init_resources(dev);
342  goto done;
343  }
344  if (!strnicmp(buf, "get", 3)) {
345  mutex_lock(&pnp_res_mutex);
346  if (pnp_can_read(dev))
347  dev->protocol->get(dev);
348  mutex_unlock(&pnp_res_mutex);
349  goto done;
350  }
351  if (!strnicmp(buf, "set", 3)) {
352  if (dev->active)
353  goto done;
354  buf += 3;
355  pnp_init_resources(dev);
356  mutex_lock(&pnp_res_mutex);
357  while (1) {
358  buf = skip_spaces(buf);
359  if (!strnicmp(buf, "io", 2)) {
360  buf = skip_spaces(buf + 2);
361  start = simple_strtoul(buf, &buf, 0);
362  buf = skip_spaces(buf);
363  if (*buf == '-') {
364  buf = skip_spaces(buf + 1);
365  end = simple_strtoul(buf, &buf, 0);
366  } else
367  end = start;
368  pnp_add_io_resource(dev, start, end, 0);
369  continue;
370  }
371  if (!strnicmp(buf, "mem", 3)) {
372  buf = skip_spaces(buf + 3);
373  start = simple_strtoul(buf, &buf, 0);
374  buf = skip_spaces(buf);
375  if (*buf == '-') {
376  buf = skip_spaces(buf + 1);
377  end = simple_strtoul(buf, &buf, 0);
378  } else
379  end = start;
380  pnp_add_mem_resource(dev, start, end, 0);
381  continue;
382  }
383  if (!strnicmp(buf, "irq", 3)) {
384  buf = skip_spaces(buf + 3);
385  start = simple_strtoul(buf, &buf, 0);
386  pnp_add_irq_resource(dev, start, 0);
387  continue;
388  }
389  if (!strnicmp(buf, "dma", 3)) {
390  buf = skip_spaces(buf + 3);
391  start = simple_strtoul(buf, &buf, 0);
392  pnp_add_dma_resource(dev, start, 0);
393  continue;
394  }
395  break;
396  }
397  mutex_unlock(&pnp_res_mutex);
398  goto done;
399  }
400 
401 done:
402  if (retval < 0)
403  return retval;
404  return count;
405 }
406 
407 static ssize_t pnp_show_current_ids(struct device *dmdev,
408  struct device_attribute *attr, char *buf)
409 {
410  char *str = buf;
411  struct pnp_dev *dev = to_pnp_dev(dmdev);
412  struct pnp_id *pos = dev->id;
413 
414  while (pos) {
415  str += sprintf(str, "%s\n", pos->id);
416  pos = pos->next;
417  }
418  return (str - buf);
419 }
420 
423  pnp_show_current_resources,
424  pnp_set_current_resources),
425  __ATTR(options, S_IRUGO, pnp_show_options, NULL),
426  __ATTR(id, S_IRUGO, pnp_show_current_ids, NULL),
427  __ATTR_NULL,
428 };