4 * Copyright (c) 2011 Hans Petter Selasky. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/queue.h>
38 #include "bus_sections.h"
43 typedef TAILQ_HEAD(,format_info) format_info_head_t;
44 typedef TAILQ_ENTRY(format_info) format_info_entry_t;
46 static format_info_head_t format_head = TAILQ_HEAD_INITIALIZER(format_head);
49 format_info_entry_t entry;
50 format_info_head_t fields;
51 char name[MAX_STRING];
56 static struct format_info *
57 format_info_new(char *pstr, uint16_t bo, uint16_t bs)
59 struct format_info *pfi;
61 pfi = malloc(sizeof(*pfi));
63 errx(EX_SOFTWARE, "Out of memory.");
65 memset(pfi, 0, sizeof(*pfi));
67 TAILQ_INIT(&pfi->fields);
69 strlcpy(pfi->name, pstr, sizeof(pfi->name));
75 static const struct format_info *
76 format_get_section(const char *section)
78 const struct format_info *psub;
79 static const struct format_info *psub_last;
80 static const char *psub_cache;
82 if (psub_cache && strcmp(psub_cache, section) == 0)
85 TAILQ_FOREACH(psub, &format_head, entry) {
86 if (strcmp(section, psub->name) == 0) {
92 warnx("Section '%s' not found", section);
99 format_get_section_size(const char *section)
101 const struct format_info *pfi;
103 pfi = format_get_section(section);
107 return ((pfi->bit_offset + 7) / 8);
112 format_get_field(const char *section, const char *field,
113 const uint8_t *ptr, uint16_t size)
115 const struct format_info *pfi;
116 const struct format_info *psub;
121 pfi = format_get_section(section);
125 /* skip until we find the fields */
126 while (pfi && TAILQ_FIRST(&pfi->fields) == NULL)
127 pfi = TAILQ_NEXT(pfi, entry);
132 TAILQ_FOREACH(psub, &pfi->fields, entry) {
133 if (strcmp(field, psub->name) == 0) {
136 if (((psub->bit_offset + psub->bit_size) / 8) > size)
139 /* compute byte offset */
140 rem = psub->bit_offset & 7;
141 off = psub->bit_offset / 8;
144 /* extract bit-field */
145 return ((ptr[off] >> rem) & ((1 << sz) - 1));
148 warnx("Field '%s' not found in '%s'", field, pfi->name);
153 format_parse_entries(const uint8_t *ptr, uint32_t len)
155 static const char *command_list = "012345678:";
157 struct format_info *pfi;
158 struct format_info *pfi_last = NULL;
159 char linebuf[3][MAX_STRING];
161 uint16_t bit_offset = 0;
167 * The format we are parsing:
168 * <string>{string,string}<next_string>{...}
173 /* skip some characters */
174 if (c == 0 || c == '\n' || c == '\r' || c == ' ' || c == '\t')
177 /* accumulate non-field delimiters */
178 if (strchr("{,}", c) == NULL) {
179 if (off < (MAX_STRING - 1)) {
180 linebuf[state][off] = c;
186 linebuf[state][off] = 0;
190 /* check for command in command list */
191 cmd = strchr(command_list, linebuf[2][0]);
193 cmd_index = cmd - command_list;
198 * Check for new field, format is:
200 * <field_name>{bit_offset_xor, bit_size}
202 if (cmd_index < 9 && pfi_last != NULL) {
203 pfi = format_info_new(linebuf[0], bit_offset ^
204 atoi(linebuf[1]), cmd_index);
205 TAILQ_INSERT_TAIL(&pfi_last->fields, pfi, entry);
206 bit_offset += cmd_index;
209 * Check for new section, format is:
211 * <section_name>{section_bit_size, :}
213 if (cmd_index == 9) {
214 pfi_last = format_info_new(linebuf[0],
215 atoi(linebuf[1]), cmd_index);
216 TAILQ_INSERT_TAIL(&format_head, pfi_last, entry);