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