Line data Source code
1 : /* $OpenBSD: cardbus_exrom.c,v 1.7 2015/08/28 00:03:53 deraadt Exp $ */
2 : /* $NetBSD: cardbus_exrom.c,v 1.4 2000/02/03 06:47:31 thorpej Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1999 The NetBSD Foundation, Inc.
6 : * All rights reserved.
7 : *
8 : * This code is derived from software contributed to
9 : * The NetBSD Foundation by Johan Danielsson.
10 : *
11 : * Redistribution and use in source and binary forms, with or without
12 : * modification, are permitted provided that the following conditions
13 : * are met:
14 : *
15 : * 1. Redistributions of source code must retain the above copyright
16 : * notice, this list of conditions and the following disclaimer.
17 : *
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : *
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 : * POSSIBILITY OF SUCH DAMAGE.
34 : */
35 :
36 : #include <sys/param.h>
37 : #include <sys/systm.h>
38 : #include <sys/queue.h>
39 : #include <sys/malloc.h>
40 :
41 : #include <machine/bus.h>
42 :
43 : #include <dev/cardbus/cardbus_exrom.h>
44 :
45 : #if defined(CARDBUS_DEBUG)
46 : #define DPRINTF(a) printf a
47 : #else
48 : #define DPRINTF(a)
49 : #endif
50 :
51 : #define READ_INT16(T, H, O) \
52 : (bus_space_read_1((T), (H), (O)) | \
53 : (bus_space_read_1((T), (H), (O) + 1) << 8))
54 :
55 : /*
56 : * A PCI ROM is divided into a number of images. Each image has two
57 : * data structures, a header located at the start of the image, and a
58 : * `data structure' at some offset into it.
59 : *
60 : * The header is a 26 byte structure:
61 : *
62 : * Offset Length Description
63 : * 0x00 1 signature byte 1 (0x55)
64 : * 0x01 1 signature byte 2 (0xAA)
65 : * 0x02 22 processor architecture data
66 : * 0x18 2 pointer to the data structure
67 : *
68 : * The data structure is a 24 byte structure:
69 : *
70 : * Offset Length Description
71 : * 0x00 4 signature (PCIR)
72 : * 0x04 2 vendor id
73 : * 0x06 2 device id
74 : * 0x08 2 reserved
75 : * 0x0A 2 data structure length
76 : * 0x0C 1 data structure revision (0)
77 : * 0x0D 3 class code
78 : * 0x10 2 image length (in 512 byte blocks)
79 : * 0x12 2 code revision level
80 : * 0x14 1 code type
81 : * 0x15 1 indicator (bit 7 indicates final image)
82 : * 0x16 2 reserved
83 : *
84 : */
85 :
86 : /*
87 : * Scan through a PCI expansion ROM, and create subregions for each
88 : * ROM image. This function assumes that the ROM is mapped at
89 : * (tag,handle), and that the expansion ROM address decoder is
90 : * enabled. The PCI specification requires that no other BAR should
91 : * be accessed while the ROM is enabled, so interrupts should be
92 : * disabled.
93 : *
94 : * XXX This routine is way too pessimistic and returns as soon as it encounters
95 : * a problem, although not being able to malloc or read a particular image
96 : * may not prevent further images from being read successfully.
97 : */
98 : int
99 0 : cardbus_read_exrom(bus_space_tag_t romt, bus_space_handle_t romh,
100 : struct cardbus_rom_image_head *head)
101 : {
102 : size_t addr = 0; /* offset of current rom image */
103 : size_t dataptr;
104 : unsigned int rom_image = 0;
105 : size_t image_size;
106 : struct cardbus_rom_image *image;
107 : u_int16_t val;
108 :
109 0 : SIMPLEQ_INIT(head);
110 0 : do {
111 0 : val = READ_INT16(romt, romh, addr + CARDBUS_EXROM_SIGNATURE);
112 0 : if (val != 0xaa55) {
113 : DPRINTF(("%s: bad header signature in ROM image "
114 : "%u: 0x%04x\n", __func__, rom_image, val));
115 0 : return (1);
116 : }
117 0 : dataptr = addr + READ_INT16(romt, romh,
118 : addr + CARDBUS_EXROM_DATA_PTR);
119 :
120 : /* get the ROM image size, in blocks */
121 0 : image_size = READ_INT16(romt, romh,
122 : dataptr + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
123 : /* XXX
124 : * Some ROMs seem to have this as zero, can we assume
125 : * this means 1 block?
126 : */
127 0 : if (image_size == 0)
128 : image_size = 1;
129 0 : image_size <<= 9;
130 :
131 0 : image = malloc(sizeof(*image), M_DEVBUF, M_NOWAIT);
132 0 : if (image == NULL) {
133 : DPRINTF(("%s: out of memory\n", __func__));
134 0 : return (1);
135 : }
136 0 : image->rom_image = rom_image;
137 0 : image->image_size = image_size;
138 0 : image->romt = romt;
139 0 : if (bus_space_subregion(romt, romh, addr,
140 0 : image_size, &image->romh)) {
141 : DPRINTF(("%s: bus_space_subregion failed", __func__));
142 0 : free(image, M_DEVBUF, sizeof(*image));
143 0 : return (1);
144 : }
145 0 : SIMPLEQ_INSERT_TAIL(head, image, next);
146 0 : addr += image_size;
147 0 : rom_image++;
148 0 : } while ((bus_space_read_1(romt, romh,
149 0 : dataptr + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0);
150 :
151 0 : return (0);
152 0 : }
|