1 /* $NetBSD: fwnode.c,v 1.19 2003/01/01 00:10:19 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2001,2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by James Chacon.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: fwnode.c,v 1.19 2003/01/01 00:10:19 thorpej Exp $");
41
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/systm.h>
46 #include <sys/malloc.h>
47
48 #include <machine/bus.h>
49
50 #include <dev/std/ieee1212var.h>
51 #include <dev/std/ieee1212reg.h>
52
53 #include <dev/ieee1394/ieee1394reg.h>
54 #include <dev/ieee1394/fwnodereg.h>
55
56 #include <dev/ieee1394/ieee1394var.h>
57 #include <dev/ieee1394/fwnodevar.h>
58
59 static const char * const ieee1394_speeds[] = { IEEE1394_SPD_STRINGS };
60
61 int fwnode_match(struct device *, struct cfdata *, void *);
62 void fwnode_attach(struct device *, struct device *, void *);
63 int fwnode_detach(struct device *, int);
64 static void fwnode_configrom_input(struct ieee1394_abuf *, int);
65 static int fwnode_print(void *, const char *);
66 #ifdef FWNODE_DEBUG
67 static void fwnode_dump_rom(struct fwnode_softc *,u_int32_t *, u_int32_t);
68 #endif
69
70 #ifdef FWNODE_DEBUG
71 #define DPRINTF(x) if (fwnodedebug) printf x
72 #define DPRINTFN(n,x) if (fwnodedebug>(n)) printf x
73 int fwnodedebug = 1;
74 #else
75 #define DPRINTF(x)
76 #define DPRINTFN(n,x)
77 #endif
78
79 CFATTACH_DECL(fwnode, sizeof(struct fwnode_softc),
80 fwnode_match, fwnode_attach, fwnode_detach, NULL);
81
82 int
83 fwnode_match(struct device *parent, struct cfdata *match, void *aux)
84 {
85 struct ieee1394_attach_args *fwa = aux;
86
87 if (strcmp(fwa->name, "fwnode") == 0)
88 return 1;
89 return 0;
90 }
91
92 void
93 fwnode_attach(struct device *parent, struct device *self, void *aux)
94 {
95 struct fwnode_softc *sc = (struct fwnode_softc *)self;
96 struct ieee1394_softc *psc = (struct ieee1394_softc *)parent;
97 struct ieee1394_attach_args *fwa = aux;
98 struct ieee1394_abuf *ab;
99
100 ab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK|M_ZERO);
101 ab->ab_data = malloc(4, M_1394DATA, M_WAITOK);
102 ab->ab_data[0] = 0;
103
104 sc->sc_sc1394.sc1394_node_id = fwa->nodeid;
105 memcpy(sc->sc_sc1394.sc1394_guid, fwa->uid, 8);
106 sc->sc_sc1394.sc1394_callback.sc1394_read =
107 psc->sc1394_callback.sc1394_read;
108 sc->sc_sc1394.sc1394_callback.sc1394_write =
109 psc->sc1394_callback.sc1394_write;
110 sc->sc_sc1394.sc1394_callback.sc1394_inreg =
111 psc->sc1394_callback.sc1394_inreg;
112 sc->sc_sc1394.sc1394_callback.sc1394_unreg =
113 psc->sc1394_callback.sc1394_unreg;
114
115 /* XXX. Fix the fw code to use the generic routines. */
116 sc->sc_sc1394.sc1394_ifinreg = psc->sc1394_ifinreg;
117 sc->sc_sc1394.sc1394_ifoutput = psc->sc1394_ifoutput;
118
119 printf(" Node %d: UID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
120 sc->sc_sc1394.sc1394_node_id,
121 sc->sc_sc1394.sc1394_guid[0], sc->sc_sc1394.sc1394_guid[1],
122 sc->sc_sc1394.sc1394_guid[2], sc->sc_sc1394.sc1394_guid[3],
123 sc->sc_sc1394.sc1394_guid[4], sc->sc_sc1394.sc1394_guid[5],
124 sc->sc_sc1394.sc1394_guid[6], sc->sc_sc1394.sc1394_guid[7]);
125 ab->ab_req = (struct ieee1394_softc *)sc;
126 ab->ab_addr = CSR_BASE + CSR_CONFIG_ROM;
127 ab->ab_length = 4;
128 ab->ab_retlen = 0;
129 ab->ab_cbarg = NULL;
130 ab->ab_cb = fwnode_configrom_input;
131 sc->sc_sc1394.sc1394_callback.sc1394_read(ab);
132 }
133
134 int
135 fwnode_detach(struct device *self, int flags)
136 {
137 struct fwnode_softc *sc = (struct fwnode_softc *)self;
138 struct device **children;
139
140 if (sc->sc_children) {
141 children = sc->sc_children;
142 do {
143 config_detach(*children, 0);
144 } while (*(++children));
145 free(sc->sc_children, M_DEVBUF);
146 }
147
148 if (sc->sc_sc1394.sc1394_configrom &&
149 sc->sc_sc1394.sc1394_configrom_len)
150 free(sc->sc_sc1394.sc1394_configrom, M_1394DATA);
151
152 if (sc->sc_configrom)
153 p1212_free(sc->sc_configrom);
154 return 0;
155 }
156
157 /*
158 * This code is trying to build a complete image of the ROM in memory.
159 * This is done all here to keep the bus_read logic/callback for the ROM in one
160 * place since reading the whole ROM may require lots of small reads up front
161 * and building separate callback handlers for each step would be even worse.
162 */
163
164 static void
165 fwnode_configrom_input(struct ieee1394_abuf *ab, int rcode)
166 {
167 struct fwnode_softc *sc = (struct fwnode_softc *)ab->ab_req;
168 u_int32_t val;
169
170 if (rcode != IEEE1394_RCODE_COMPLETE) {
171 DPRINTF(("Aborting configrom input, rcode: %d\n", rcode));
172 #ifdef FWNODE_DEBUG
173 fwnode_dump_rom(sc, ab->ab_data, ab->ab_retlen);
174 #endif
175 free(ab->ab_data, M_1394DATA);
176 free(ab, M_1394DATA);
177 return;
178 }
179
180 if (ab->ab_cbarg)
181 panic("Got an invalid abuf on callback");
182
183 if (ab->ab_length != ab->ab_retlen) {
184 DPRINTF(("%s: config rom short read. Expected :%d, received: "
185 "%d. Not attaching\n", sc->sc_sc1394.sc1394_dev.dv_xname,
186 ab->ab_length, ab->ab_retlen));
187 free(ab->ab_data, M_1394DATA);
188 free(ab, M_1394DATA);
189 return;
190 }
191 if (ab->ab_retlen % 4) {
192 DPRINTF(("%s: configrom read of invalid length: %d\n",
193 sc->sc_sc1394.sc1394_dev.dv_xname, ab->ab_retlen));
194 free(ab->ab_data, M_1394DATA);
195 free(ab, M_1394DATA);
196 return;
197 }
198
199 ab->ab_retlen = ab->ab_retlen / 4;
200 if (p1212_iscomplete(ab->ab_data, &ab->ab_retlen) == -1) {
201 DPRINTF(("%s: configrom parse error\n",
202 sc->sc_sc1394.sc1394_dev.dv_xname));
203 free(ab->ab_data, M_1394DATA);
204 free(ab, M_1394DATA);
205 return;
206 }
207
208 #ifdef DIAGNOSTIC
209 if (ab->ab_retlen < (ab->ab_length / 4))
210 panic("Configrom shrank during iscomplete check?");
211 #endif
212
213 if (ab->ab_retlen > (ab->ab_length / 4)) {
214
215 free(ab->ab_data, M_1394DATA);
216 ab->ab_data = malloc(ab->ab_retlen * 4, M_1394DATA,
217 M_WAITOK|M_ZERO);
218
219 ab->ab_addr = CSR_BASE + CSR_CONFIG_ROM;
220 ab->ab_length = ab->ab_retlen * 4;
221 ab->ab_retlen = 0;
222 ab->ab_cbarg = NULL;
223 ab->ab_cb = fwnode_configrom_input;
224 sc->sc_sc1394.sc1394_callback.sc1394_read(ab);
225 return;
226 } else {
227 sc->sc_sc1394.sc1394_configrom_len = ab->ab_retlen;
228 sc->sc_sc1394.sc1394_configrom = ab->ab_data;
229 ab->ab_data = NULL;
230
231 free(ab, M_1394DATA);
232
233 /*
234 * Set P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE and
235 * P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE as some protocols
236 * such as SBP2 need it.
237 */
238
239 val = P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE;
240 val |= P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE;
241 val |= P1212_ALLOW_VENDOR_DIRECTORY_TYPE;
242 sc->sc_configrom =
243 p1212_parse(sc->sc_sc1394.sc1394_configrom,
244 sc->sc_sc1394.sc1394_configrom_len, val);
245 if ((sc->sc_configrom == NULL) ||
246 (sc->sc_configrom->len != IEEE1394_BUSINFO_LEN)) {
247 #ifdef FWNODE_DEBUG
248 DPRINTF(("Parse error with config rom\n"));
249 fwnode_dump_rom(sc, sc->sc_sc1394.sc1394_configrom,
250 sc->sc_sc1394.sc1394_configrom_len);
251 #endif
252 if (sc->sc_configrom)
253 p1212_free(sc->sc_configrom);
254 free(sc->sc_sc1394.sc1394_configrom, M_1394DATA);
255 sc->sc_sc1394.sc1394_configrom = NULL;
256 sc->sc_sc1394.sc1394_configrom_len = 0;
257 return;
258 }
259
260 val = htonl(IEEE1394_SIGNATURE);
261 if (memcmp(sc->sc_configrom->name, &val, 4)) {
262 DPRINTF(("Invalid signature found in bus info block: "
263 "%s\n", sc->sc_configrom->name));
264 p1212_free(sc->sc_configrom);
265 sc->sc_sc1394.sc1394_configrom = NULL;
266 sc->sc_sc1394.sc1394_configrom_len = 0;
267 return;
268 }
269
270 sc->sc_sc1394.sc1394_max_receive =
271 IEEE1394_GET_MAX_REC(ntohl(sc->sc_configrom->data[0]));
272 sc->sc_sc1394.sc1394_link_speed =
273 IEEE1394_GET_LINK_SPD(ntohl(sc->sc_configrom->data[0]));
274 printf("%s: Link Speed: %s, max_rec: %d bytes\n",
275 sc->sc_sc1394.sc1394_dev.dv_xname,
276 ieee1394_speeds[sc->sc_sc1394.sc1394_link_speed],
277 IEEE1394_MAX_REC(sc->sc_sc1394.sc1394_max_receive));
278 sc->sc_children = p1212_match_units(&sc->sc_sc1394.sc1394_dev,
279 sc->sc_configrom->root, fwnode_print);
280 #ifdef FWNODE_DEBUG
281 fwnode_dump_rom(sc, sc->sc_sc1394.sc1394_configrom,
282 sc->sc_sc1394.sc1394_configrom_len);
283 p1212_print(sc->sc_configrom->root);
284 #endif
285 }
286 }
287
288 static int
289 fwnode_print(void *aux, const char *pnp)
290 {
291 if (pnp)
292 aprint_normal("Unknown device at %s", pnp);
293
294 return UNCONF;
295 }
296
297 #ifdef FWNODE_DEBUG
298 static void
299 fwnode_dump_rom(struct fwnode_softc *sc, u_int32_t *t, u_int32_t len)
300 {
301 int i;
302 printf("%s: Config rom dump:\n", sc->sc_sc1394.sc1394_dev.dv_xname);
303 for (i = 0; i < len; i++) {
304 if ((i % 4) == 0) {
305 if (i)
306 printf("\n");
307 printf("%s: 0x%02hx: ",
308 sc->sc_sc1394.sc1394_dev.dv_xname, (short)(4 * i));
309 }
310 printf("0x%08x ", ntohl(t[i]));
311 }
312 printf("\n");
313 }
314 #endif
Cache object: 04c60baac39b7aa73f3a1b373bfe6641
|