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