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