Skip to content

Commit 1f8fef7

Browse files
cladischStefan Richter
authored andcommitted
firewire: add fw_csr_string() helper function
The core (sysfs attributes), the firedtv driver, and possible future drivers all read strings from some configuration ROM directory. Factor out the generic code from show_text_leaf() into a new helper function, modified slightly to handle arbitrary buffer sizes. Signed-off-by: Clemens Ladisch <[email protected]> Signed-off-by: Stefan Richter <[email protected]>
1 parent 5d7db04 commit 1f8fef7

File tree

3 files changed

+84
-67
lines changed

3 files changed

+84
-67
lines changed

drivers/firewire/core-device.c

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,67 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
5959
}
6060
EXPORT_SYMBOL(fw_csr_iterator_next);
6161

62+
static u32 *search_leaf(u32 *directory, int search_key)
63+
{
64+
struct fw_csr_iterator ci;
65+
int last_key = 0, key, value;
66+
67+
fw_csr_iterator_init(&ci, directory);
68+
while (fw_csr_iterator_next(&ci, &key, &value)) {
69+
if (last_key == search_key &&
70+
key == (CSR_DESCRIPTOR | CSR_LEAF))
71+
return ci.p - 1 + value;
72+
last_key = key;
73+
}
74+
return NULL;
75+
}
76+
77+
static int textual_leaf_to_string(u32 *block, char *buf, size_t size)
78+
{
79+
unsigned int quadlets, length;
80+
81+
if (!size || !buf)
82+
return -EINVAL;
83+
84+
quadlets = min(block[0] >> 16, 256u);
85+
if (quadlets < 2)
86+
return -ENODATA;
87+
88+
if (block[1] != 0 || block[2] != 0)
89+
/* unknown language/character set */
90+
return -ENODATA;
91+
92+
block += 3;
93+
quadlets -= 2;
94+
for (length = 0; length < quadlets * 4 && length + 1 < size; length++) {
95+
char c = block[length / 4] >> (24 - 8 * (length % 4));
96+
if (c == '\0')
97+
break;
98+
buf[length] = c;
99+
}
100+
buf[length] = '\0';
101+
return length;
102+
}
103+
104+
/**
105+
* fw_csr_string - reads a string from the configuration ROM
106+
* @directory: device or unit directory;
107+
* fw_device->config_rom+5 or fw_unit->directory
108+
* @key: the key of the preceding directory entry
109+
* @buf: where to put the string
110+
* @size: size of @buf, in bytes
111+
*
112+
* Returns string length (>= 0) or error code (< 0).
113+
*/
114+
int fw_csr_string(u32 *directory, int key, char *buf, size_t size)
115+
{
116+
u32 *leaf = search_leaf(directory, key);
117+
if (!leaf)
118+
return -ENOENT;
119+
return textual_leaf_to_string(leaf, buf, size);
120+
}
121+
EXPORT_SYMBOL(fw_csr_string);
122+
62123
static bool is_fw_unit(struct device *dev);
63124

64125
static int match_unit_directory(u32 *directory, u32 match_flags,
@@ -226,10 +287,10 @@ static ssize_t show_text_leaf(struct device *dev,
226287
{
227288
struct config_rom_attribute *attr =
228289
container_of(dattr, struct config_rom_attribute, attr);
229-
struct fw_csr_iterator ci;
230-
u32 *dir, *block = NULL, *p, *end;
231-
int length, key, value, last_key = 0, ret = -ENOENT;
232-
char *b;
290+
u32 *dir;
291+
size_t bufsize;
292+
char dummy_buf[2];
293+
int ret;
233294

234295
down_read(&fw_device_rwsem);
235296

@@ -238,40 +299,23 @@ static ssize_t show_text_leaf(struct device *dev,
238299
else
239300
dir = fw_device(dev)->config_rom + 5;
240301

241-
fw_csr_iterator_init(&ci, dir);
242-
while (fw_csr_iterator_next(&ci, &key, &value)) {
243-
if (attr->key == last_key &&
244-
key == (CSR_DESCRIPTOR | CSR_LEAF))
245-
block = ci.p - 1 + value;
246-
last_key = key;
302+
if (buf) {
303+
bufsize = PAGE_SIZE - 1;
304+
} else {
305+
buf = dummy_buf;
306+
bufsize = 1;
247307
}
248308

249-
if (block == NULL)
250-
goto out;
251-
252-
length = min(block[0] >> 16, 256U);
253-
if (length < 3)
254-
goto out;
255-
256-
if (block[1] != 0 || block[2] != 0)
257-
/* Unknown encoding. */
258-
goto out;
309+
ret = fw_csr_string(dir, attr->key, buf, bufsize);
259310

260-
if (buf == NULL) {
261-
ret = length * 4;
262-
goto out;
311+
if (ret >= 0) {
312+
/* Strip trailing whitespace and add newline. */
313+
while (ret > 0 && isspace(buf[ret - 1]))
314+
ret--;
315+
strcpy(buf + ret, "\n");
316+
ret++;
263317
}
264318

265-
b = buf;
266-
end = &block[length + 1];
267-
for (p = &block[3]; p < end; p++, b += 4)
268-
* (u32 *) b = (__force u32) __cpu_to_be32(*p);
269-
270-
/* Strip trailing whitespace and add newline. */
271-
while (b--, (isspace(*b) || *b == '\0') && b > buf);
272-
strcpy(b + 1, "\n");
273-
ret = b + 2 - buf;
274-
out:
275319
up_read(&fw_device_rwsem);
276320

277321
return ret;

drivers/media/dvb/firewire/firedtv-fw.c

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -239,47 +239,18 @@ static const struct fw_address_region fcp_region = {
239239
};
240240

241241
/* Adjust the template string if models with longer names appear. */
242-
#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
243-
244-
static size_t model_name(u32 *directory, __be32 *buffer)
245-
{
246-
struct fw_csr_iterator ci;
247-
int i, length, key, value, last_key = 0;
248-
u32 *block = NULL;
249-
250-
fw_csr_iterator_init(&ci, directory);
251-
while (fw_csr_iterator_next(&ci, &key, &value)) {
252-
if (last_key == CSR_MODEL &&
253-
key == (CSR_DESCRIPTOR | CSR_LEAF))
254-
block = ci.p - 1 + value;
255-
last_key = key;
256-
}
257-
258-
if (block == NULL)
259-
return 0;
260-
261-
length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
262-
if (length <= 0)
263-
return 0;
264-
265-
/* fast-forward to text string */
266-
block += 3;
267-
268-
for (i = 0; i < length; i++)
269-
buffer[i] = cpu_to_be32(block[i]);
270-
271-
return length * 4;
272-
}
242+
#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
273243

274244
static int node_probe(struct device *dev)
275245
{
276246
struct firedtv *fdtv;
277-
__be32 name[MAX_MODEL_NAME_LEN];
247+
char name[MAX_MODEL_NAME_LEN];
278248
int name_len, err;
279249

280-
name_len = model_name(fw_unit(dev)->directory, name);
250+
name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
251+
name, sizeof(name));
281252

282-
fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
253+
fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0);
283254
if (!fdtv)
284255
return -ENOMEM;
285256

include/linux/firewire.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ struct fw_csr_iterator {
7272
void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
7373
int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value);
7474

75+
int fw_csr_string(u32 *directory, int key, char *buf, size_t size);
76+
7577
extern struct bus_type fw_bus_type;
7678

7779
struct fw_card_driver;

0 commit comments

Comments
 (0)