linux-old/lib/firmware_class.c
<<
>>
Prefs
   1/*
   2 * firmware_class.c - Multi purpose firmware loading support
   3 *
   4 * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
   5 *
   6 * Please see Documentation/firmware_class/ for more information.
   7 *
   8 */
   9/*
  10 * Based on kernel/kmod.c and drivers/usb/usb.c
  11 */
  12/*
  13        kernel/kmod.c
  14        Kirk Petersen
  15
  16        Reorganized not to be a daemon by Adam Richter, with guidance
  17        from Greg Zornetzer.
  18
  19        Modified to avoid chroot and file sharing problems.
  20        Mikael Pettersson
  21
  22        Limit the concurrent number of kmod modprobes to catch loops from
  23        "modprobe needs a service that is in a module".
  24        Keith Owens <kaos@ocs.com.au> December 1999
  25
  26        Unblock all signals when we exec a usermode process.
  27        Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
  28*/
  29/*
  30 * drivers/usb/usb.c
  31 *
  32 * (C) Copyright Linus Torvalds 1999
  33 * (C) Copyright Johannes Erdfelt 1999-2001
  34 * (C) Copyright Andreas Gal 1999
  35 * (C) Copyright Gregory P. Smith 1999
  36 * (C) Copyright Deti Fliegl 1999 (new USB architecture)
  37 * (C) Copyright Randy Dunlap 2000
  38 * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
  39 * (C) Copyright Yggdrasil Computing, Inc. 2000
  40 *     (usb_device_id matching changes by Adam J. Richter)
  41 */
  42
  43#include <linux/config.h>
  44#include <linux/module.h>
  45#include <linux/string.h>
  46#include <linux/types.h>
  47#include <linux/init.h>
  48#include <linux/slab.h>
  49#include <linux/kmod.h>
  50#include <linux/proc_fs.h>
  51#include <linux/vmalloc.h>
  52#include <asm/hardirq.h>
  53
  54#include "linux/firmware.h"
  55
  56MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
  57MODULE_DESCRIPTION("Multi purpose firmware loading support");
  58MODULE_LICENSE("GPL");
  59
  60#define err(format, arg...) \
  61     printk(KERN_ERR  "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
  62#define warn(format, arg...) \
  63     printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
  64#define dbg(format, arg...) \
  65     printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
  66
  67static int loading_timeout = 10;        /* In seconds */
  68static struct proc_dir_entry *proc_dir_timeout;
  69static struct proc_dir_entry *proc_dir;
  70
  71#ifdef CONFIG_HOTPLUG
  72
  73static int
  74call_helper(char *verb, const char *name, const char *device)
  75{
  76        char *argv[3], **envp, *buf, *scratch;
  77        int i = 0;
  78
  79        int retval = 0;
  80
  81        if (!hotplug_path[0])
  82                return -ENOENT;
  83        if (in_interrupt()) {
  84                err("in_interrupt");
  85                return -EFAULT;
  86        }
  87        if (!current->fs->root) {
  88                warn("call_policy %s -- no FS yet", verb);
  89                return -EPERM;
  90        }
  91
  92        if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
  93                err("unable to allocate envp");
  94                return -ENOMEM;
  95        }
  96        if (!(buf = kmalloc(256, GFP_KERNEL))) {
  97                kfree(envp);
  98                err("unable to allocate buf");
  99                return -ENOMEM;
 100        }
 101
 102        /* only one standardized param to hotplug command: type */
 103        argv[0] = hotplug_path;
 104        argv[1] = "firmware";
 105        argv[2] = 0;
 106
 107        /* minimal command environment */
 108        envp[i++] = "HOME=/";
 109        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
 110
 111#ifdef  DEBUG
 112        /* hint that policy agent should enter no-stdout debug mode */
 113        envp[i++] = "DEBUG=kernel";
 114#endif
 115        scratch = buf;
 116
 117        if (device) {
 118                envp[i++] = scratch;
 119                scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
 120                                    "DEVPATH=/driver/firmware/%s", device) + 1;
 121        }
 122
 123        envp[i++] = scratch;
 124        scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
 125
 126        envp[i++] = scratch;
 127        scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
 128                            "FIRMWARE=%s", name) + 1;
 129
 130        envp[i++] = 0;
 131
 132#ifdef  DEBUG
 133        dbg("firmware: %s %s %s", argv[0], argv[1], verb);
 134#endif
 135
 136        retval = call_usermodehelper(argv[0], argv, envp);
 137        if (retval) {
 138                printk("call_usermodehelper return %d\n", retval);
 139        }
 140
 141        kfree(buf);
 142        kfree(envp);
 143        return retval;
 144}
 145#else
 146
 147static inline int
 148call_helper(char *verb, const char *name, const char *device)
 149{
 150        return -ENOENT;
 151}
 152
 153#endif /* CONFIG_HOTPLUG */
 154
 155struct firmware_priv {
 156        struct completion completion;
 157        struct proc_dir_entry *proc_dir;
 158        struct proc_dir_entry *attr_data;
 159        struct proc_dir_entry *attr_loading;
 160        struct firmware *fw;
 161        int loading;
 162        int abort;
 163        int alloc_size;
 164        struct timer_list timeout;
 165};
 166
 167static int
 168firmware_timeout_show(char *buf, char **start, off_t off,
 169                      int count, int *eof, void *data)
 170{
 171        return sprintf(buf, "%d\n", loading_timeout);
 172}
 173
 174/**
 175 * firmware_timeout_store:
 176 * Description:
 177 *      Sets the number of seconds to wait for the firmware.  Once
 178 *      this expires an error will be return to the driver and no
 179 *      firmware will be provided.
 180 *
 181 *      Note: zero means 'wait for ever'
 182 *  
 183 **/
 184static int
 185firmware_timeout_store(struct file *file, const char *buf,
 186                       unsigned long count, void *data)
 187{
 188        loading_timeout = simple_strtol(buf, NULL, 10);
 189        return count;
 190}
 191
 192static int
 193firmware_loading_show(char *buf, char **start, off_t off,
 194                      int count, int *eof, void *data)
 195{
 196        struct firmware_priv *fw_priv = data;
 197        return sprintf(buf, "%d\n", fw_priv->loading);
 198}
 199
 200/**
 201 * firmware_loading_store: - loading control file
 202 * Description:
 203 *      The relevant values are: 
 204 *
 205 *       1: Start a load, discarding any previous partial load.
 206 *       0: Conclude the load and handle the data to the driver code.
 207 *      -1: Conclude the load with an error and discard any written data.
 208 **/
 209static int
 210firmware_loading_store(struct file *file, const char *buf,
 211                       unsigned long count, void *data)
 212{
 213        struct firmware_priv *fw_priv = data;
 214        int prev_loading = fw_priv->loading;
 215
 216        fw_priv->loading = simple_strtol(buf, NULL, 10);
 217
 218        switch (fw_priv->loading) {
 219        case -1:
 220                fw_priv->abort = 1;
 221                wmb();
 222                complete(&fw_priv->completion);
 223                break;
 224        case 1:
 225                kfree(fw_priv->fw->data);
 226                fw_priv->fw->data = NULL;
 227                fw_priv->fw->size = 0;
 228                fw_priv->alloc_size = 0;
 229                break;
 230        case 0:
 231                if (prev_loading == 1)
 232                        complete(&fw_priv->completion);
 233                break;
 234        }
 235
 236        return count;
 237}
 238
 239static int
 240firmware_data_read(char *buffer, char **start, off_t offset,
 241                   int count, int *eof, void *data)
 242{
 243        struct firmware_priv *fw_priv = data;
 244        struct firmware *fw = fw_priv->fw;
 245
 246        if (offset > fw->size)
 247                return 0;
 248        if (offset + count > fw->size)
 249                count = fw->size - offset;
 250
 251        memcpy(buffer, fw->data + offset, count);
 252        *start = (void *) ((long) count);
 253        return count;
 254}
 255static int
 256fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 257{
 258        u8 *new_data;
 259        int new_size;
 260
 261        if (min_size <= fw_priv->alloc_size)
 262                return 0;
 263        if((min_size % PAGE_SIZE) == 0)
 264                new_size = min_size;
 265        else
 266                new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
 267        new_data = vmalloc(new_size);
 268        if (!new_data) {
 269                printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
 270                /* Make sure that we don't keep incomplete data */
 271                fw_priv->abort = 1;
 272                return -ENOMEM;
 273        }
 274        fw_priv->alloc_size = new_size;
 275        if (fw_priv->fw->data) {
 276                memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
 277                vfree(fw_priv->fw->data);
 278        }
 279        fw_priv->fw->data = new_data;
 280        BUG_ON(min_size > fw_priv->alloc_size);
 281        return 0;
 282}
 283
 284/**
 285 * firmware_data_write:
 286 *
 287 * Description:
 288 *
 289 *      Data written to the 'data' attribute will be later handled to
 290 *      the driver as a firmware image.
 291 **/
 292static int
 293firmware_data_write(struct file *file, const char *buffer,
 294                    unsigned long count, void *data)
 295{
 296        struct firmware_priv *fw_priv = data;
 297        struct firmware *fw = fw_priv->fw;
 298        int offset = file->f_pos;
 299        int retval;
 300
 301        retval = fw_realloc_buffer(fw_priv, offset + count);
 302        if (retval) {
 303                printk("%s: retval:%d\n", __FUNCTION__, retval);
 304                return retval;
 305        }
 306
 307        memcpy(fw->data + offset, buffer, count);
 308
 309        fw->size = max_t(size_t, offset + count, fw->size);
 310        file->f_pos += count;
 311        return count;
 312}
 313
 314static void
 315firmware_class_timeout(u_long data)
 316{
 317        struct firmware_priv *fw_priv = (struct firmware_priv *) data;
 318        fw_priv->abort = 1;
 319        wmb();
 320        complete(&fw_priv->completion);
 321}
 322static int
 323fw_setup_class_device(struct firmware_priv **fw_priv_p,
 324                      const char *fw_name, const char *device)
 325{
 326        int retval;
 327        struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
 328                                                GFP_KERNEL);
 329        *fw_priv_p = fw_priv;
 330        if (!fw_priv) {
 331                retval = -ENOMEM;
 332                goto out;
 333        }
 334        memset(fw_priv, 0, sizeof (*fw_priv));
 335
 336        init_completion(&fw_priv->completion);
 337
 338        fw_priv->timeout.function = firmware_class_timeout;
 339        fw_priv->timeout.data = (u_long) fw_priv;
 340        init_timer(&fw_priv->timeout);
 341
 342        retval = -EAGAIN;
 343        fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
 344        if (!fw_priv->proc_dir)
 345                goto err_free_fw_priv;
 346
 347        fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
 348                                               fw_priv->proc_dir);
 349        if (!fw_priv->attr_data)
 350                goto err_remove_dir;
 351
 352        fw_priv->attr_data->read_proc = firmware_data_read;
 353        fw_priv->attr_data->write_proc = firmware_data_write;
 354        fw_priv->attr_data->data = fw_priv;
 355
 356        fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
 357                                                  fw_priv->proc_dir);
 358        if (!fw_priv->attr_loading)
 359                goto err_remove_data;
 360
 361        fw_priv->attr_loading->read_proc = firmware_loading_show;
 362        fw_priv->attr_loading->write_proc = firmware_loading_store;
 363        fw_priv->attr_loading->data = fw_priv;
 364
 365        retval = 0;
 366        fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
 367        if (!fw_priv->fw) {
 368                printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
 369                       __FUNCTION__);
 370                retval = -ENOMEM;
 371                goto err_remove_loading;
 372        }
 373        memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
 374
 375        goto out;
 376
 377err_remove_loading:
 378        remove_proc_entry("loading", fw_priv->proc_dir);
 379err_remove_data:
 380        remove_proc_entry("data", fw_priv->proc_dir);
 381err_remove_dir:
 382        remove_proc_entry(device, proc_dir);
 383err_free_fw_priv:
 384        kfree(fw_priv);
 385out:
 386        return retval;
 387}
 388static void
 389fw_remove_class_device(struct firmware_priv *fw_priv)
 390{
 391        remove_proc_entry("loading", fw_priv->proc_dir);
 392        remove_proc_entry("data", fw_priv->proc_dir);
 393        remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
 394}
 395
 396/** 
 397 * request_firmware: - request firmware to hotplug and wait for it
 398 * Description:
 399 *      @firmware will be used to return a firmware image by the name
 400 *      of @name for device @device.
 401 *
 402 *      Should be called from user context where sleeping is allowed.
 403 *
 404 *      @name will be use as $FIRMWARE in the hotplug environment and
 405 *      should be distinctive enough not to be confused with any other
 406 *      firmware image for this or any other device.
 407 **/
 408int
 409request_firmware(const struct firmware **firmware, const char *name,
 410                 const char *device)
 411{
 412        struct firmware_priv *fw_priv;
 413        int retval;
 414
 415        if (!firmware) {
 416                retval = -EINVAL;
 417                goto out;
 418        }
 419        *firmware = NULL;
 420
 421        retval = fw_setup_class_device(&fw_priv, name, device);
 422        if (retval)
 423                goto out;
 424
 425        retval = call_helper("add", name, device);
 426        if (retval)
 427                goto out;
 428        if (loading_timeout) {
 429                fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
 430                add_timer(&fw_priv->timeout);
 431        }
 432
 433        wait_for_completion(&fw_priv->completion);
 434
 435        del_timer(&fw_priv->timeout);
 436        fw_remove_class_device(fw_priv);
 437
 438        if (fw_priv->fw->size && !fw_priv->abort) {
 439                *firmware = fw_priv->fw;
 440        } else {
 441                retval = -ENOENT;
 442                vfree(fw_priv->fw->data);
 443                kfree(fw_priv->fw);
 444        }
 445out:
 446        kfree(fw_priv);
 447        return retval;
 448}
 449
 450void
 451release_firmware(const struct firmware *fw)
 452{
 453        if (fw) {
 454                vfree(fw->data);
 455                kfree(fw);
 456        }
 457}
 458
 459/**
 460 * register_firmware: - provide a firmware image for later usage
 461 * 
 462 * Description:
 463 *      Make sure that @data will be available by requesting firmware @name.
 464 *
 465 *      Note: This will not be possible until some kind of persistence
 466 *      is available.
 467 **/
 468void
 469register_firmware(const char *name, const u8 *data, size_t size)
 470{
 471        /* This is meaningless without firmware caching, so until we
 472         * decide if firmware caching is reasonable just leave it as a
 473         * noop */
 474}
 475
 476/* Async support */
 477struct firmware_work {
 478        struct tq_struct work;
 479        struct module *module;
 480        const char *name;
 481        const char *device;
 482        void *context;
 483        void (*cont)(const struct firmware *fw, void *context);
 484};
 485
 486static void
 487request_firmware_work_func(void *arg)
 488{
 489        struct firmware_work *fw_work = arg;
 490        const struct firmware *fw;
 491        if (!arg)
 492                return;
 493        request_firmware(&fw, fw_work->name, fw_work->device);
 494        fw_work->cont(fw, fw_work->context);
 495        release_firmware(fw);
 496        __MOD_DEC_USE_COUNT(fw_work->module);
 497        kfree(fw_work);
 498}
 499
 500/**
 501 * request_firmware_nowait:
 502 *
 503 * Description:
 504 *      Asynchronous variant of request_firmware() for contexts where
 505 *      it is not possible to sleep.
 506 *
 507 *      @cont will be called asynchronously when the firmware request is over.
 508 *
 509 *      @context will be passed over to @cont.
 510 *
 511 *      @fw may be %NULL if firmware request fails.
 512 *
 513 **/
 514int
 515request_firmware_nowait(
 516        struct module *module,
 517        const char *name, const char *device, void *context,
 518        void (*cont)(const struct firmware *fw, void *context))
 519{
 520        struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
 521                                                GFP_ATOMIC);
 522        if (!fw_work)
 523                return -ENOMEM;
 524        if (!try_inc_mod_count(module)) {
 525                kfree(fw_work);
 526                return -EFAULT;
 527        }
 528
 529        *fw_work = (struct firmware_work) {
 530                .module = module,
 531                .name = name,
 532                .device = device,
 533                .context = context,
 534                .cont = cont,
 535        };
 536        INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
 537
 538        schedule_task(&fw_work->work);
 539        return 0;
 540}
 541
 542static int __init
 543firmware_class_init(void)
 544{
 545        proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
 546        if (!proc_dir)
 547                return -EAGAIN;
 548        proc_dir_timeout = create_proc_entry("timeout",
 549                                             0644 | S_IFREG, proc_dir);
 550        if (!proc_dir_timeout) {
 551                remove_proc_entry("driver/firmware", NULL);
 552                return -EAGAIN;
 553        }
 554        proc_dir_timeout->read_proc = firmware_timeout_show;
 555        proc_dir_timeout->write_proc = firmware_timeout_store;
 556        return 0;
 557}
 558static void __exit
 559firmware_class_exit(void)
 560{
 561        remove_proc_entry("timeout", proc_dir);
 562        remove_proc_entry("driver/firmware", NULL);
 563}
 564
 565module_init(firmware_class_init);
 566module_exit(firmware_class_exit);
 567
 568#ifndef CONFIG_FW_LOADER
 569EXPORT_SYMBOL(release_firmware);
 570EXPORT_SYMBOL(request_firmware);
 571EXPORT_SYMBOL(request_firmware_nowait);
 572EXPORT_SYMBOL(register_firmware);
 573#endif
 574
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.