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 */
98int
99cardbus_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	SIMPLEQ_INIT(head);
110	do {
111		val = READ_INT16(romt, romh, addr + CARDBUS_EXROM_SIGNATURE);
112		if (val != 0xaa55) {
113			DPRINTF(("%s: bad header signature in ROM image "
114			    "%u: 0x%04x\n", __func__, rom_image, val));
115			return (1);
116		}
117		dataptr = addr + READ_INT16(romt, romh,
118		    addr + CARDBUS_EXROM_DATA_PTR);
119
120		/* get the ROM image size, in blocks */
121		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		if (image_size == 0)
128			image_size = 1;
129		image_size <<= 9;
130
131		image = malloc(sizeof(*image), M_DEVBUF, M_NOWAIT);
132		if (image == NULL) {
133			DPRINTF(("%s: out of memory\n", __func__));
134			return (1);
135		}
136		image->rom_image = rom_image;
137		image->image_size = image_size;
138		image->romt = romt;
139		if (bus_space_subregion(romt, romh, addr,
140		    image_size, &image->romh)) {
141			DPRINTF(("%s: bus_space_subregion failed", __func__));
142			free(image, M_DEVBUF, sizeof(*image));
143			return (1);
144		}
145		SIMPLEQ_INSERT_TAIL(head, image, next);
146		addr += image_size;
147		rom_image++;
148	} while ((bus_space_read_1(romt, romh,
149	    dataptr + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0);
150
151	return (0);
152}
153