root/drivers/ssb/sprom.c

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

DEFINITIONS

This source file includes following definitions.
  1. sprom2hex
  2. hex2sprom
  3. ssb_attr_sprom_show
  4. ssb_attr_sprom_store
  5. ssb_arch_register_fallback_sprom
  6. ssb_fill_sprom_with_fallback
  7. ssb_is_sprom_available

   1 /*
   2  * Sonics Silicon Backplane
   3  * Common SPROM support routines
   4  *
   5  * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
   6  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
   7  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
   8  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
   9  * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
  10  *
  11  * Licensed under the GNU/GPL. See COPYING for details.
  12  */
  13 
  14 #include "ssb_private.h"
  15 
  16 #include <linux/ctype.h>
  17 #include <linux/slab.h>
  18 
  19 
  20 static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out);
  21 
  22 
  23 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
  24                      size_t sprom_size_words)
  25 {
  26         int i, pos = 0;
  27 
  28         for (i = 0; i < sprom_size_words; i++)
  29                 pos += snprintf(buf + pos, buf_len - pos - 1,
  30                                 "%04X", swab16(sprom[i]) & 0xFFFF);
  31         pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
  32 
  33         return pos + 1;
  34 }
  35 
  36 static int hex2sprom(u16 *sprom, const char *dump, size_t len,
  37                      size_t sprom_size_words)
  38 {
  39         char c, tmp[5] = { 0 };
  40         int err, cnt = 0;
  41         unsigned long parsed;
  42 
  43         /* Strip whitespace at the end. */
  44         while (len) {
  45                 c = dump[len - 1];
  46                 if (!isspace(c) && c != '\0')
  47                         break;
  48                 len--;
  49         }
  50         /* Length must match exactly. */
  51         if (len != sprom_size_words * 4)
  52                 return -EINVAL;
  53 
  54         while (cnt < sprom_size_words) {
  55                 memcpy(tmp, dump, 4);
  56                 dump += 4;
  57                 err = kstrtoul(tmp, 16, &parsed);
  58                 if (err)
  59                         return err;
  60                 sprom[cnt++] = swab16((u16)parsed);
  61         }
  62 
  63         return 0;
  64 }
  65 
  66 /* Common sprom device-attribute show-handler */
  67 ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
  68                             int (*sprom_read)(struct ssb_bus *bus, u16 *sprom))
  69 {
  70         u16 *sprom;
  71         int err = -ENOMEM;
  72         ssize_t count = 0;
  73         size_t sprom_size_words = bus->sprom_size;
  74 
  75         sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
  76         if (!sprom)
  77                 goto out;
  78 
  79         /* Use interruptible locking, as the SPROM write might
  80          * be holding the lock for several seconds. So allow userspace
  81          * to cancel operation. */
  82         err = -ERESTARTSYS;
  83         if (mutex_lock_interruptible(&bus->sprom_mutex))
  84                 goto out_kfree;
  85         err = sprom_read(bus, sprom);
  86         mutex_unlock(&bus->sprom_mutex);
  87 
  88         if (!err)
  89                 count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words);
  90 
  91 out_kfree:
  92         kfree(sprom);
  93 out:
  94         return err ? err : count;
  95 }
  96 
  97 /* Common sprom device-attribute store-handler */
  98 ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
  99                              const char *buf, size_t count,
 100                              int (*sprom_check_crc)(const u16 *sprom, size_t size),
 101                              int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom))
 102 {
 103         u16 *sprom;
 104         int res = 0, err = -ENOMEM;
 105         size_t sprom_size_words = bus->sprom_size;
 106         struct ssb_freeze_context freeze;
 107 
 108         sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
 109         if (!sprom)
 110                 goto out;
 111         err = hex2sprom(sprom, buf, count, sprom_size_words);
 112         if (err) {
 113                 err = -EINVAL;
 114                 goto out_kfree;
 115         }
 116         err = sprom_check_crc(sprom, sprom_size_words);
 117         if (err) {
 118                 err = -EINVAL;
 119                 goto out_kfree;
 120         }
 121 
 122         /* Use interruptible locking, as the SPROM write might
 123          * be holding the lock for several seconds. So allow userspace
 124          * to cancel operation. */
 125         err = -ERESTARTSYS;
 126         if (mutex_lock_interruptible(&bus->sprom_mutex))
 127                 goto out_kfree;
 128         err = ssb_devices_freeze(bus, &freeze);
 129         if (err) {
 130                 pr_err("SPROM write: Could not freeze all devices\n");
 131                 goto out_unlock;
 132         }
 133         res = sprom_write(bus, sprom);
 134         err = ssb_devices_thaw(&freeze);
 135         if (err)
 136                 pr_err("SPROM write: Could not thaw all devices\n");
 137 out_unlock:
 138         mutex_unlock(&bus->sprom_mutex);
 139 out_kfree:
 140         kfree(sprom);
 141 out:
 142         if (res)
 143                 return res;
 144         return err ? err : count;
 145 }
 146 
 147 /**
 148  * ssb_arch_register_fallback_sprom - Registers a method providing a
 149  * fallback SPROM if no SPROM is found.
 150  *
 151  * @sprom_callback: The callback function.
 152  *
 153  * With this function the architecture implementation may register a
 154  * callback handler which fills the SPROM data structure. The fallback is
 155  * only used for PCI based SSB devices, where no valid SPROM can be found
 156  * in the shadow registers.
 157  *
 158  * This function is useful for weird architectures that have a half-assed
 159  * SSB device hardwired to their PCI bus.
 160  *
 161  * Note that it does only work with PCI attached SSB devices. PCMCIA
 162  * devices currently don't use this fallback.
 163  * Architectures must provide the SPROM for native SSB devices anyway, so
 164  * the fallback also isn't used for native devices.
 165  *
 166  * This function is available for architecture code, only. So it is not
 167  * exported.
 168  */
 169 int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus,
 170                                      struct ssb_sprom *out))
 171 {
 172         if (get_fallback_sprom)
 173                 return -EEXIST;
 174         get_fallback_sprom = sprom_callback;
 175 
 176         return 0;
 177 }
 178 
 179 int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out)
 180 {
 181         if (!get_fallback_sprom)
 182                 return -ENOENT;
 183 
 184         return get_fallback_sprom(bus, out);
 185 }
 186 
 187 /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
 188 bool ssb_is_sprom_available(struct ssb_bus *bus)
 189 {
 190         /* status register only exists on chipcomon rev >= 11 and we need check
 191            for >= 31 only */
 192         /* this routine differs from specs as we do not access SPROM directly
 193            on PCMCIA */
 194         if (bus->bustype == SSB_BUSTYPE_PCI &&
 195             bus->chipco.dev &&  /* can be unavailable! */
 196             bus->chipco.dev->id.revision >= 31)
 197                 return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
 198 
 199         return true;
 200 }

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