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