root/drivers/pnp/interface.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pnp_printf
  2. pnp_print_port
  3. pnp_print_irq
  4. pnp_print_dma
  5. pnp_print_mem
  6. pnp_print_option
  7. options_show
  8. resources_show
  9. pnp_get_resource_value
  10. resources_store
  11. id_show

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

/* [<][>][^][v][top][bottom][index][help] */