xref: /freebsd/sys/dev/firewire/fwcrom.c (revision 7ddbf617b10ab40edb1231ac1ec966d7fb187298)
1b018dcd1SHidetoshi Shimokawa /*
2b018dcd1SHidetoshi Shimokawa  * Copyright (C) 2002
3b018dcd1SHidetoshi Shimokawa  * 	Hidetoshi Shimokawa. All rights reserved.
4b018dcd1SHidetoshi Shimokawa  *
5b018dcd1SHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
6b018dcd1SHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
7b018dcd1SHidetoshi Shimokawa  * are met:
8b018dcd1SHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
9b018dcd1SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
10b018dcd1SHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
11b018dcd1SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
12b018dcd1SHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
13b018dcd1SHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
14b018dcd1SHidetoshi Shimokawa  *    must display the following acknowledgement:
15b018dcd1SHidetoshi Shimokawa  *
16b018dcd1SHidetoshi Shimokawa  *	This product includes software developed by Hidetoshi Shimokawa.
17b018dcd1SHidetoshi Shimokawa  *
18b018dcd1SHidetoshi Shimokawa  * 4. Neither the name of the author nor the names of its contributors
19b018dcd1SHidetoshi Shimokawa  *    may be used to endorse or promote products derived from this software
20b018dcd1SHidetoshi Shimokawa  *    without specific prior written permission.
21b018dcd1SHidetoshi Shimokawa  *
22b018dcd1SHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23b018dcd1SHidetoshi Shimokawa  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24b018dcd1SHidetoshi Shimokawa  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25b018dcd1SHidetoshi Shimokawa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26b018dcd1SHidetoshi Shimokawa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27b018dcd1SHidetoshi Shimokawa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28b018dcd1SHidetoshi Shimokawa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29b018dcd1SHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30b018dcd1SHidetoshi Shimokawa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31b018dcd1SHidetoshi Shimokawa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32b018dcd1SHidetoshi Shimokawa  * SUCH DAMAGE.
33b018dcd1SHidetoshi Shimokawa  *
34b018dcd1SHidetoshi Shimokawa  * $FreeBSD$
35b018dcd1SHidetoshi Shimokawa  */
36b018dcd1SHidetoshi Shimokawa 
37b018dcd1SHidetoshi Shimokawa #include <sys/param.h>
38b018dcd1SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
39b018dcd1SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
40b018dcd1SHidetoshi Shimokawa #ifdef _KERNEL
41b018dcd1SHidetoshi Shimokawa #include <sys/systm.h>
42b018dcd1SHidetoshi Shimokawa #include <sys/kernel.h>
43b018dcd1SHidetoshi Shimokawa #else
44b018dcd1SHidetoshi Shimokawa #include <netinet/in.h>
45b018dcd1SHidetoshi Shimokawa #include <fcntl.h>
46b018dcd1SHidetoshi Shimokawa #include <stdio.h>
47b018dcd1SHidetoshi Shimokawa #include <err.h>
48b018dcd1SHidetoshi Shimokawa #include <stdlib.h>
49b018dcd1SHidetoshi Shimokawa #include <string.h>
50b018dcd1SHidetoshi Shimokawa #endif
51b018dcd1SHidetoshi Shimokawa 
52b018dcd1SHidetoshi Shimokawa void
53b018dcd1SHidetoshi Shimokawa crom_init_context(struct crom_context *cc, u_int32_t *p)
54b018dcd1SHidetoshi Shimokawa {
55b018dcd1SHidetoshi Shimokawa 	struct csrhdr *hdr;
56b018dcd1SHidetoshi Shimokawa 
57b018dcd1SHidetoshi Shimokawa 	hdr = (struct csrhdr *)p;
58b018dcd1SHidetoshi Shimokawa 	if (hdr->info_len == 1) {
59b018dcd1SHidetoshi Shimokawa 		/* minimum ROM */
60b018dcd1SHidetoshi Shimokawa 		cc->depth = -1;
61b018dcd1SHidetoshi Shimokawa 	}
62b018dcd1SHidetoshi Shimokawa 	p += 1 + hdr->info_len;
63b018dcd1SHidetoshi Shimokawa 	cc->depth = 0;
64b018dcd1SHidetoshi Shimokawa 	cc->stack[0].dir = (struct csrdirectory *)p;
65b018dcd1SHidetoshi Shimokawa 	cc->stack[0].index = 0;
66b018dcd1SHidetoshi Shimokawa }
67b018dcd1SHidetoshi Shimokawa 
68b018dcd1SHidetoshi Shimokawa struct csrreg *
69b018dcd1SHidetoshi Shimokawa crom_get(struct crom_context *cc)
70b018dcd1SHidetoshi Shimokawa {
71b018dcd1SHidetoshi Shimokawa 	struct crom_ptr *ptr;
72b018dcd1SHidetoshi Shimokawa 
73b018dcd1SHidetoshi Shimokawa 	ptr = &cc->stack[cc->depth];
74b018dcd1SHidetoshi Shimokawa 	return (&ptr->dir->entry[ptr->index]);
75b018dcd1SHidetoshi Shimokawa }
76b018dcd1SHidetoshi Shimokawa 
77b018dcd1SHidetoshi Shimokawa void
78b018dcd1SHidetoshi Shimokawa crom_next(struct crom_context *cc)
79b018dcd1SHidetoshi Shimokawa {
80b018dcd1SHidetoshi Shimokawa 	struct crom_ptr *ptr;
81b018dcd1SHidetoshi Shimokawa 	struct csrreg *reg;
82b018dcd1SHidetoshi Shimokawa 
83b018dcd1SHidetoshi Shimokawa 	if (cc->depth < 0)
84b018dcd1SHidetoshi Shimokawa 		return;
85b018dcd1SHidetoshi Shimokawa 	reg = crom_get(cc);
86b018dcd1SHidetoshi Shimokawa 	if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
87b018dcd1SHidetoshi Shimokawa 		cc->depth ++;
88b018dcd1SHidetoshi Shimokawa 		if (cc->depth > CROM_MAX_DEPTH) {
89b018dcd1SHidetoshi Shimokawa 			printf("crom_next: too deep\n");
90b018dcd1SHidetoshi Shimokawa 			cc->depth --;
91b018dcd1SHidetoshi Shimokawa 			goto again;
92b018dcd1SHidetoshi Shimokawa 		}
937ddbf617SHidetoshi Shimokawa 		ptr = &cc->stack[cc->depth];
947ddbf617SHidetoshi Shimokawa 		ptr->dir = (struct csrdirectory *) (reg + reg->val);
957ddbf617SHidetoshi Shimokawa 		ptr->index = 0;
967ddbf617SHidetoshi Shimokawa 		goto check;
97b018dcd1SHidetoshi Shimokawa 	}
98b018dcd1SHidetoshi Shimokawa again:
99b018dcd1SHidetoshi Shimokawa 	ptr = &cc->stack[cc->depth];
100b018dcd1SHidetoshi Shimokawa 	ptr->index ++;
1017ddbf617SHidetoshi Shimokawa check:
102b018dcd1SHidetoshi Shimokawa 	if (ptr->index < ptr->dir->crc_len)
103b018dcd1SHidetoshi Shimokawa 		return;
104b018dcd1SHidetoshi Shimokawa 	if (cc->depth > 0) {
105b018dcd1SHidetoshi Shimokawa 		cc->depth--;
106b018dcd1SHidetoshi Shimokawa 		goto again;
107b018dcd1SHidetoshi Shimokawa 	}
108b018dcd1SHidetoshi Shimokawa 	/* no more data */
109b018dcd1SHidetoshi Shimokawa 	cc->depth = -1;
110b018dcd1SHidetoshi Shimokawa }
111b018dcd1SHidetoshi Shimokawa 
112b018dcd1SHidetoshi Shimokawa 
113b018dcd1SHidetoshi Shimokawa struct csrreg *
114b018dcd1SHidetoshi Shimokawa crom_search_key(struct crom_context *cc, u_int8_t key)
115b018dcd1SHidetoshi Shimokawa {
116b018dcd1SHidetoshi Shimokawa 	struct csrreg *reg;
117b018dcd1SHidetoshi Shimokawa 
118b018dcd1SHidetoshi Shimokawa 	while(cc->depth >= 0) {
119b018dcd1SHidetoshi Shimokawa 		reg = crom_get(cc);
120b018dcd1SHidetoshi Shimokawa 		if (reg->key == key)
121b018dcd1SHidetoshi Shimokawa 			return reg;
122b018dcd1SHidetoshi Shimokawa 		crom_next(cc);
123b018dcd1SHidetoshi Shimokawa 	}
124b018dcd1SHidetoshi Shimokawa 	return NULL;
125b018dcd1SHidetoshi Shimokawa }
126b018dcd1SHidetoshi Shimokawa 
127b018dcd1SHidetoshi Shimokawa void
128b018dcd1SHidetoshi Shimokawa crom_parse_text(struct crom_context *cc, char *buf, int len)
129b018dcd1SHidetoshi Shimokawa {
130b018dcd1SHidetoshi Shimokawa 	struct csrreg *reg;
131b018dcd1SHidetoshi Shimokawa 	struct csrtext *textleaf;
132b018dcd1SHidetoshi Shimokawa 	u_int32_t *bp;
133b018dcd1SHidetoshi Shimokawa 	int i, qlen;
134b018dcd1SHidetoshi Shimokawa 	static char *nullstr = "(null)";
135b018dcd1SHidetoshi Shimokawa 
136b018dcd1SHidetoshi Shimokawa 	reg = crom_get(cc);
137b018dcd1SHidetoshi Shimokawa 	if (reg->key != CROM_TEXTLEAF) {
138b018dcd1SHidetoshi Shimokawa 		strncpy(buf, nullstr, len);
139b018dcd1SHidetoshi Shimokawa 		return;
140b018dcd1SHidetoshi Shimokawa 	}
141b018dcd1SHidetoshi Shimokawa 	textleaf = (struct csrtext *)(reg + reg->val);
142b018dcd1SHidetoshi Shimokawa 
143b018dcd1SHidetoshi Shimokawa 	/* XXX should check spec and type */
144b018dcd1SHidetoshi Shimokawa 
145b018dcd1SHidetoshi Shimokawa 	bp = (u_int32_t *)&buf[0];
146b018dcd1SHidetoshi Shimokawa 	qlen = textleaf->crc_len - 2;
147b018dcd1SHidetoshi Shimokawa 	if (len < qlen * 4)
148b018dcd1SHidetoshi Shimokawa 		qlen = len/4;
149b018dcd1SHidetoshi Shimokawa 	for (i = 0; i < qlen; i ++)
150b018dcd1SHidetoshi Shimokawa 		*bp++ = ntohl(textleaf->text[i]);
151b018dcd1SHidetoshi Shimokawa 	/* make sure to terminate the string */
152b018dcd1SHidetoshi Shimokawa 	if (len <= qlen * 4)
153b018dcd1SHidetoshi Shimokawa 		buf[len - 1] = 0;
154b018dcd1SHidetoshi Shimokawa 	else
155b018dcd1SHidetoshi Shimokawa 		buf[qlen * 4] = 0;
156b018dcd1SHidetoshi Shimokawa }
157b018dcd1SHidetoshi Shimokawa 
158b018dcd1SHidetoshi Shimokawa u_int16_t
159b018dcd1SHidetoshi Shimokawa crom_crc(u_int32_t *ptr, int len)
160b018dcd1SHidetoshi Shimokawa {
161b018dcd1SHidetoshi Shimokawa 	int i, shift;
162b018dcd1SHidetoshi Shimokawa 	u_int32_t data, sum, crc = 0;
163b018dcd1SHidetoshi Shimokawa 
164b018dcd1SHidetoshi Shimokawa 	for (i = 0; i < len; i++) {
165b018dcd1SHidetoshi Shimokawa 		data = ptr[i];
166b018dcd1SHidetoshi Shimokawa 		for (shift = 28; shift >= 0; shift -= 4) {
167b018dcd1SHidetoshi Shimokawa 			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
168b018dcd1SHidetoshi Shimokawa 			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
169b018dcd1SHidetoshi Shimokawa 		}
170b018dcd1SHidetoshi Shimokawa 		crc &= 0xffff;
171b018dcd1SHidetoshi Shimokawa 	}
172b018dcd1SHidetoshi Shimokawa 	return((u_int16_t) crc);
173b018dcd1SHidetoshi Shimokawa }
174b018dcd1SHidetoshi Shimokawa 
175b018dcd1SHidetoshi Shimokawa #ifndef _KERNEL
176b018dcd1SHidetoshi Shimokawa char *
177b018dcd1SHidetoshi Shimokawa crom_desc(struct crom_context *cc, char *buf, int len)
178b018dcd1SHidetoshi Shimokawa {
179b018dcd1SHidetoshi Shimokawa 	struct csrreg *reg;
180b018dcd1SHidetoshi Shimokawa 	struct csrdirectory *dir;
181b018dcd1SHidetoshi Shimokawa 	char *desc;
182b018dcd1SHidetoshi Shimokawa 
183b018dcd1SHidetoshi Shimokawa 	reg = crom_get(cc);
184b018dcd1SHidetoshi Shimokawa 	switch (reg->key & CSRTYPE_MASK) {
185b018dcd1SHidetoshi Shimokawa 	case CSRTYPE_I:
186b018dcd1SHidetoshi Shimokawa 		snprintf(buf, len, "%d", reg->val);
187b018dcd1SHidetoshi Shimokawa 		break;
188b018dcd1SHidetoshi Shimokawa 	case CSRTYPE_L:
189b018dcd1SHidetoshi Shimokawa 	case CSRTYPE_C:
190b018dcd1SHidetoshi Shimokawa 		snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val);
191b018dcd1SHidetoshi Shimokawa 		break;
192b018dcd1SHidetoshi Shimokawa 	case CSRTYPE_D:
193b018dcd1SHidetoshi Shimokawa 		dir = (struct csrdirectory *) (reg + reg->val);
194b018dcd1SHidetoshi Shimokawa 		snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x",
195b018dcd1SHidetoshi Shimokawa 			dir->crc_len, dir->crc_len, dir->crc);
196b018dcd1SHidetoshi Shimokawa 	}
197b018dcd1SHidetoshi Shimokawa 	switch (reg->key) {
198b018dcd1SHidetoshi Shimokawa 	case 0x03:
199b018dcd1SHidetoshi Shimokawa 		desc = "module_vendor_ID";
200b018dcd1SHidetoshi Shimokawa 		break;
201b018dcd1SHidetoshi Shimokawa 	case 0x04:
202b018dcd1SHidetoshi Shimokawa 		desc = "hardware_version";
203b018dcd1SHidetoshi Shimokawa 		break;
204b018dcd1SHidetoshi Shimokawa 	case 0x0c:
205b018dcd1SHidetoshi Shimokawa 		desc = "node_capabilities";
206b018dcd1SHidetoshi Shimokawa 		break;
207b018dcd1SHidetoshi Shimokawa 	case 0x12:
208b018dcd1SHidetoshi Shimokawa 		desc = "unit_spec_ID";
209b018dcd1SHidetoshi Shimokawa 		break;
210b018dcd1SHidetoshi Shimokawa 	case 0x13:
211b018dcd1SHidetoshi Shimokawa 		desc = "unit_sw_version";
212b018dcd1SHidetoshi Shimokawa 		break;
213b018dcd1SHidetoshi Shimokawa 	case 0x14:
214b018dcd1SHidetoshi Shimokawa 		desc = "logical_unit_number";
215b018dcd1SHidetoshi Shimokawa 		break;
216b018dcd1SHidetoshi Shimokawa 	case 0x17:
217b018dcd1SHidetoshi Shimokawa 		desc = "model_ID";
218b018dcd1SHidetoshi Shimokawa 		break;
219b018dcd1SHidetoshi Shimokawa 	case 0x38:
220b018dcd1SHidetoshi Shimokawa 		desc = "command_set_spec_ID";
221b018dcd1SHidetoshi Shimokawa 		break;
222b018dcd1SHidetoshi Shimokawa 	case 0x39:
223b018dcd1SHidetoshi Shimokawa 		desc = "command_set";
224b018dcd1SHidetoshi Shimokawa 		break;
225b018dcd1SHidetoshi Shimokawa 	case 0x3a:
226b018dcd1SHidetoshi Shimokawa 		desc = "unit_characteristics";
227b018dcd1SHidetoshi Shimokawa 		break;
228b018dcd1SHidetoshi Shimokawa 	case 0x3b:
229b018dcd1SHidetoshi Shimokawa 		desc = "command_set_revision";
230b018dcd1SHidetoshi Shimokawa 		break;
231b018dcd1SHidetoshi Shimokawa 	case 0x3c:
232b018dcd1SHidetoshi Shimokawa 		desc = "firmware_revision";
233b018dcd1SHidetoshi Shimokawa 		break;
234b018dcd1SHidetoshi Shimokawa 	case 0x3d:
235b018dcd1SHidetoshi Shimokawa 		desc = "reconnect_timeout";
236b018dcd1SHidetoshi Shimokawa 		break;
237b018dcd1SHidetoshi Shimokawa 	case 0x54:
238b018dcd1SHidetoshi Shimokawa 		desc = "management_agent";
239b018dcd1SHidetoshi Shimokawa 		break;
240b018dcd1SHidetoshi Shimokawa 	case 0x81:
241b018dcd1SHidetoshi Shimokawa 		desc = "text_leaf";
242b018dcd1SHidetoshi Shimokawa 		crom_parse_text(cc, buf, len);
243b018dcd1SHidetoshi Shimokawa 		break;
244b018dcd1SHidetoshi Shimokawa 	case 0xd1:
245b018dcd1SHidetoshi Shimokawa 		desc = "unit_directory";
246b018dcd1SHidetoshi Shimokawa 		break;
247b018dcd1SHidetoshi Shimokawa 	case 0xd4:
248b018dcd1SHidetoshi Shimokawa 		desc = "logical_unit_directory";
249b018dcd1SHidetoshi Shimokawa 		break;
250b018dcd1SHidetoshi Shimokawa 	default:
251b018dcd1SHidetoshi Shimokawa 		desc = "unknown";
252b018dcd1SHidetoshi Shimokawa 	}
253b018dcd1SHidetoshi Shimokawa 	return desc;
254b018dcd1SHidetoshi Shimokawa }
255b018dcd1SHidetoshi Shimokawa #endif
256