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 23 struct 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 32 typedef struct pnp_info_buffer pnp_info_buffer_t; 33 34 static 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 53 static 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 63 static 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 94 static 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 146 static 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 179 static 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 215 static 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 244 static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL); 245 246 static 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 int i, ret; 252 pnp_info_buffer_t *buffer; 253 254 if (!dev) 255 return -EINVAL; 256 257 buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); 258 if (!buffer) 259 return -ENOMEM; 260 buffer->len = PAGE_SIZE; 261 buffer->buffer = buf; 262 buffer->curr = buffer->buffer; 263 264 pnp_printf(buffer, "state = "); 265 if (dev->active) 266 pnp_printf(buffer, "active\n"); 267 else 268 pnp_printf(buffer, "disabled\n"); 269 270 for (i = 0; i < PNP_MAX_PORT; i++) { 271 if (pnp_port_valid(dev, i)) { 272 pnp_printf(buffer, "io"); 273 if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED) 274 pnp_printf(buffer, " disabled\n"); 275 else 276 pnp_printf(buffer, " 0x%llx-0x%llx\n", 277 (unsigned long long) 278 pnp_port_start(dev, i), 279 (unsigned long long)pnp_port_end(dev, 280 i)); 281 } 282 } 283 for (i = 0; i < PNP_MAX_MEM; i++) { 284 if (pnp_mem_valid(dev, i)) { 285 pnp_printf(buffer, "mem"); 286 if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED) 287 pnp_printf(buffer, " disabled\n"); 288 else 289 pnp_printf(buffer, " 0x%llx-0x%llx\n", 290 (unsigned long long) 291 pnp_mem_start(dev, i), 292 (unsigned long long)pnp_mem_end(dev, 293 i)); 294 } 295 } 296 for (i = 0; i < PNP_MAX_IRQ; i++) { 297 if (pnp_irq_valid(dev, i)) { 298 pnp_printf(buffer, "irq"); 299 if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED) 300 pnp_printf(buffer, " disabled\n"); 301 else 302 pnp_printf(buffer, " %lld\n", 303 (unsigned long long)pnp_irq(dev, i)); 304 } 305 } 306 for (i = 0; i < PNP_MAX_DMA; i++) { 307 if (pnp_dma_valid(dev, i)) { 308 pnp_printf(buffer, "dma"); 309 if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED) 310 pnp_printf(buffer, " disabled\n"); 311 else 312 pnp_printf(buffer, " %lld\n", 313 (unsigned long long)pnp_dma(dev, i)); 314 } 315 } 316 ret = (buffer->curr - buf); 317 kfree(buffer); 318 return ret; 319 } 320 321 static ssize_t 322 pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, 323 const char *ubuf, size_t count) 324 { 325 struct pnp_dev *dev = to_pnp_dev(dmdev); 326 char *buf = (void *)ubuf; 327 int retval = 0; 328 329 if (dev->status & PNP_ATTACHED) { 330 retval = -EBUSY; 331 dev_info(&dev->dev, "in use; can't configure\n"); 332 goto done; 333 } 334 335 while (isspace(*buf)) 336 ++buf; 337 if (!strnicmp(buf, "disable", 7)) { 338 retval = pnp_disable_dev(dev); 339 goto done; 340 } 341 if (!strnicmp(buf, "activate", 8)) { 342 retval = pnp_activate_dev(dev); 343 goto done; 344 } 345 if (!strnicmp(buf, "fill", 4)) { 346 if (dev->active) 347 goto done; 348 retval = pnp_auto_config_dev(dev); 349 goto done; 350 } 351 if (!strnicmp(buf, "auto", 4)) { 352 if (dev->active) 353 goto done; 354 pnp_init_resource_table(&dev->res); 355 retval = pnp_auto_config_dev(dev); 356 goto done; 357 } 358 if (!strnicmp(buf, "clear", 5)) { 359 if (dev->active) 360 goto done; 361 pnp_init_resource_table(&dev->res); 362 goto done; 363 } 364 if (!strnicmp(buf, "get", 3)) { 365 mutex_lock(&pnp_res_mutex); 366 if (pnp_can_read(dev)) 367 dev->protocol->get(dev, &dev->res); 368 mutex_unlock(&pnp_res_mutex); 369 goto done; 370 } 371 if (!strnicmp(buf, "set", 3)) { 372 int nport = 0, nmem = 0, nirq = 0, ndma = 0; 373 if (dev->active) 374 goto done; 375 buf += 3; 376 pnp_init_resource_table(&dev->res); 377 mutex_lock(&pnp_res_mutex); 378 while (1) { 379 while (isspace(*buf)) 380 ++buf; 381 if (!strnicmp(buf, "io", 2)) { 382 buf += 2; 383 while (isspace(*buf)) 384 ++buf; 385 dev->res.port_resource[nport].start = 386 simple_strtoul(buf, &buf, 0); 387 while (isspace(*buf)) 388 ++buf; 389 if (*buf == '-') { 390 buf += 1; 391 while (isspace(*buf)) 392 ++buf; 393 dev->res.port_resource[nport].end = 394 simple_strtoul(buf, &buf, 0); 395 } else 396 dev->res.port_resource[nport].end = 397 dev->res.port_resource[nport].start; 398 dev->res.port_resource[nport].flags = 399 IORESOURCE_IO; 400 nport++; 401 if (nport >= PNP_MAX_PORT) 402 break; 403 continue; 404 } 405 if (!strnicmp(buf, "mem", 3)) { 406 buf += 3; 407 while (isspace(*buf)) 408 ++buf; 409 dev->res.mem_resource[nmem].start = 410 simple_strtoul(buf, &buf, 0); 411 while (isspace(*buf)) 412 ++buf; 413 if (*buf == '-') { 414 buf += 1; 415 while (isspace(*buf)) 416 ++buf; 417 dev->res.mem_resource[nmem].end = 418 simple_strtoul(buf, &buf, 0); 419 } else 420 dev->res.mem_resource[nmem].end = 421 dev->res.mem_resource[nmem].start; 422 dev->res.mem_resource[nmem].flags = 423 IORESOURCE_MEM; 424 nmem++; 425 if (nmem >= PNP_MAX_MEM) 426 break; 427 continue; 428 } 429 if (!strnicmp(buf, "irq", 3)) { 430 buf += 3; 431 while (isspace(*buf)) 432 ++buf; 433 dev->res.irq_resource[nirq].start = 434 dev->res.irq_resource[nirq].end = 435 simple_strtoul(buf, &buf, 0); 436 dev->res.irq_resource[nirq].flags = 437 IORESOURCE_IRQ; 438 nirq++; 439 if (nirq >= PNP_MAX_IRQ) 440 break; 441 continue; 442 } 443 if (!strnicmp(buf, "dma", 3)) { 444 buf += 3; 445 while (isspace(*buf)) 446 ++buf; 447 dev->res.dma_resource[ndma].start = 448 dev->res.dma_resource[ndma].end = 449 simple_strtoul(buf, &buf, 0); 450 dev->res.dma_resource[ndma].flags = 451 IORESOURCE_DMA; 452 ndma++; 453 if (ndma >= PNP_MAX_DMA) 454 break; 455 continue; 456 } 457 break; 458 } 459 mutex_unlock(&pnp_res_mutex); 460 goto done; 461 } 462 463 done: 464 if (retval < 0) 465 return retval; 466 return count; 467 } 468 469 static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR, 470 pnp_show_current_resources, pnp_set_current_resources); 471 472 static ssize_t pnp_show_current_ids(struct device *dmdev, 473 struct device_attribute *attr, char *buf) 474 { 475 char *str = buf; 476 struct pnp_dev *dev = to_pnp_dev(dmdev); 477 struct pnp_id *pos = dev->id; 478 479 while (pos) { 480 str += sprintf(str, "%s\n", pos->id); 481 pos = pos->next; 482 } 483 return (str - buf); 484 } 485 486 static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL); 487 488 int pnp_interface_attach_device(struct pnp_dev *dev) 489 { 490 int rc = device_create_file(&dev->dev, &dev_attr_options); 491 492 if (rc) 493 goto err; 494 rc = device_create_file(&dev->dev, &dev_attr_resources); 495 if (rc) 496 goto err_opt; 497 rc = device_create_file(&dev->dev, &dev_attr_id); 498 if (rc) 499 goto err_res; 500 501 return 0; 502 503 err_res: 504 device_remove_file(&dev->dev, &dev_attr_resources); 505 err_opt: 506 device_remove_file(&dev->dev, &dev_attr_options); 507 err: 508 return rc; 509 } 510