2 * Sonics Silicon Backplane
3 * Common SPROM support routines
5 * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
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>
11 * Licensed under the GNU/GPL. See COPYING for details.
14 #include "ssb_private.h"
16 #include <linux/ctype.h>
19 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
20 size_t sprom_size_words)
24 for (i = 0; i < sprom_size_words; i++)
25 pos += snprintf(buf + pos, buf_len - pos - 1,
26 "%04X", swab16(sprom[i]) & 0xFFFF);
27 pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
32 static int hex2sprom(u16 *sprom, const char *dump, size_t len,
33 size_t sprom_size_words)
35 char c, tmp[5] = { 0 };
39 /* Strip whitespace at the end. */
42 if (!isspace(c) && c != '\0')
46 /* Length must match exactly. */
47 if (len != sprom_size_words * 4)
50 while (cnt < sprom_size_words) {
53 err = strict_strtoul(tmp, 16, &parsed);
56 sprom[cnt++] = swab16((u16)parsed);
62 /* Common sprom device-attribute show-handler */
63 ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
64 int (*sprom_read)(struct ssb_bus *bus, u16 *sprom))
69 size_t sprom_size_words = bus->sprom_size;
71 sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
75 /* Use interruptible locking, as the SPROM write might
76 * be holding the lock for several seconds. So allow userspace
77 * to cancel operation. */
79 if (mutex_lock_interruptible(&bus->sprom_mutex))
81 err = sprom_read(bus, sprom);
82 mutex_unlock(&bus->sprom_mutex);
85 count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words);
90 return err ? err : count;
93 /* Common sprom device-attribute store-handler */
94 ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
95 const char *buf, size_t count,
96 int (*sprom_check_crc)(const u16 *sprom, size_t size),
97 int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom))
100 int res = 0, err = -ENOMEM;
101 size_t sprom_size_words = bus->sprom_size;
103 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
106 err = hex2sprom(sprom, buf, count, sprom_size_words);
111 err = sprom_check_crc(sprom, sprom_size_words);
117 /* Use interruptible locking, as the SPROM write might
118 * be holding the lock for several seconds. So allow userspace
119 * to cancel operation. */
121 if (mutex_lock_interruptible(&bus->sprom_mutex))
123 err = ssb_devices_freeze(bus);
124 if (err == -EOPNOTSUPP) {
125 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
126 "No suspend support. Is CONFIG_PM enabled?\n");
130 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
133 res = sprom_write(bus, sprom);
134 err = ssb_devices_thaw(bus);
136 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
138 mutex_unlock(&bus->sprom_mutex);
144 return err ? err : count;