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