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