1153811Simp/*-
2185015Simp * Copyright (c) 2005-2008, M. Warner Losh
3153811Simp * All rights reserved.
4153811Simp *
5153811Simp * Redistribution and use in source and binary forms, with or without
6153811Simp * modification, are permitted provided that the following conditions
7153811Simp * are met:
8153811Simp * 1. Redistributions of source code must retain the above copyright
9153811Simp *    notice unmodified, this list of conditions, and the following
10153811Simp *    disclaimer.
11153811Simp * 2. Redistributions in binary form must reproduce the above copyright
12153811Simp *    notice, this list of conditions and the following disclaimer in the
13153811Simp *    documentation and/or other materials provided with the distribution.
14153811Simp *
15153811Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16153811Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17153811Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18153811Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19153811Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20153811Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21153811Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22153811Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23153811Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24153811Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25153811Simp * SUCH DAMAGE.
26153811Simp *
27153811Simp */
28153811Simp#include <sys/cdefs.h>
29153811Simp__FBSDID("$FreeBSD$");
30153811Simp
31153811Simp#include <sys/param.h>
32153811Simp#include <sys/conf.h>
33153811Simp#include <sys/malloc.h>
34153811Simp#include <sys/systm.h>
35153811Simp#include <sys/uio.h>
36153811Simp
37153811Simp#include <sys/bus.h>
38153811Simp#include <machine/bus.h>
39153811Simp#include <sys/rman.h>
40153811Simp#include <machine/resource.h>
41153811Simp
42153811Simp#include <sys/pciio.h>
43153811Simp#include <dev/pci/pcivar.h>
44153811Simp#include <dev/pci/pcireg.h>
45153811Simp#include <dev/pci/pci_private.h>
46153811Simp
47153811Simp#include <dev/cardbus/cardbusreg.h>
48153811Simp#include <dev/cardbus/cardbusvar.h>
49153811Simp#include <dev/cardbus/cardbus_cis.h>
50153811Simp#include <dev/pccard/pccard_cis.h>
51153811Simp
52153811Simpstatic	d_open_t	cardbus_open;
53153811Simpstatic	d_close_t	cardbus_close;
54153811Simpstatic	d_read_t	cardbus_read;
55153811Simpstatic	d_ioctl_t	cardbus_ioctl;
56153811Simp
57153811Simpstatic struct cdevsw cardbus_cdevsw = {
58153811Simp	.d_version =	D_VERSION,
59153811Simp	.d_open =	cardbus_open,
60153811Simp	.d_close =	cardbus_close,
61153811Simp	.d_read =	cardbus_read,
62153811Simp	.d_ioctl =	cardbus_ioctl,
63153811Simp	.d_name =	"cardbus"
64153811Simp};
65153811Simp
66153811Simpstatic int
67153811Simpcardbus_build_cis(device_t cbdev, device_t child, int id,
68153811Simp    int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
69153811Simp    struct tuple_callbacks *info, void *argp)
70153811Simp{
71153811Simp	struct cis_buffer *cis;
72153811Simp	int i;
73153811Simp
74153811Simp	cis = (struct cis_buffer *)argp;
75153811Simp	/*
76153811Simp	 * CISTPL_END is a special case, it has no length field.
77153811Simp	 */
78153811Simp	if (id == CISTPL_END) {
79184981Simp		if (cis->len + 1 > sizeof(cis->buffer)) {
80184981Simp			cis->len = 0;
81153811Simp			return (ENOSPC);
82184981Simp		}
83153811Simp		cis->buffer[cis->len++] = id;
84153811Simp		return (0);
85153811Simp	}
86184981Simp	if (cis->len + 2 + len > sizeof(cis->buffer)) {
87184981Simp		cis->len = 0;
88153811Simp		return (ENOSPC);
89184981Simp	}
90153811Simp	cis->buffer[cis->len++] = id;
91153811Simp	cis->buffer[cis->len++] = len;
92153811Simp	for (i = 0; i < len; i++)
93153811Simp		cis->buffer[cis->len++] = tupledata[i];
94153811Simp	return (0);
95153811Simp}
96153811Simp
97184981Simpstatic int
98185015Simpcardbus_device_buffer_cis(device_t parent, device_t child,
99185015Simp    struct cis_buffer *cbp)
100184981Simp{
101184981Simp	struct tuple_callbacks cb[] = {
102184981Simp		{CISTPL_GENERIC, "GENERIC", cardbus_build_cis}
103184981Simp	};
104184981Simp
105185015Simp	return (cardbus_parse_cis(parent, child, cb, cbp));
106184981Simp}
107184981Simp
108185015Simpint
109185015Simpcardbus_device_create(struct cardbus_softc *sc, struct cardbus_devinfo *devi,
110185015Simp    device_t parent, device_t child)
111185015Simp{
112185015Simp	uint32_t minor;
113185545Simp	int unit;
114185015Simp
115185015Simp	cardbus_device_buffer_cis(parent, child, &devi->sc_cis);
116185015Simp	minor = (device_get_unit(sc->sc_dev) << 8) + devi->pci.cfg.func;
117185545Simp	unit = device_get_unit(sc->sc_dev);
118185015Simp	devi->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666,
119185545Simp	    "cardbus%d.%d.cis", unit, devi->pci.cfg.func);
120185140Simp	if (devi->pci.cfg.func == 0)
121185545Simp		make_dev_alias(devi->sc_cisdev, "cardbus%d.cis", unit);
122185015Simp	devi->sc_cisdev->si_drv1 = devi;
123185015Simp	return (0);
124185015Simp}
125185015Simp
126185015Simpint
127185015Simpcardbus_device_destroy(struct cardbus_devinfo *devi)
128185015Simp{
129185015Simp	if (devi->sc_cisdev)
130185015Simp		destroy_dev(devi->sc_cisdev);
131185015Simp	return (0);
132185015Simp}
133185015Simp
134153811Simpstatic	int
135153811Simpcardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
136153811Simp{
137153811Simp
138153811Simp	return (0);
139153811Simp}
140153811Simp
141153811Simpstatic	int
142153811Simpcardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
143153811Simp{
144153811Simp
145153811Simp	return (0);
146153811Simp}
147153811Simp
148153811Simpstatic	int
149153811Simpcardbus_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
150153811Simp    struct thread *td)
151153811Simp{
152153811Simp	return (ENOTTY);
153153811Simp}
154153811Simp
155153811Simpstatic	int
156153811Simpcardbus_read(struct cdev *dev, struct uio *uio, int ioflag)
157153811Simp{
158185015Simp	struct cardbus_devinfo *devi;
159153811Simp
160185015Simp	devi = dev->si_drv1;
161153811Simp	/* EOF */
162185015Simp	if (uio->uio_offset >= devi->sc_cis.len)
163153811Simp		return (0);
164185015Simp	return (uiomove(devi->sc_cis.buffer + uio->uio_offset,
165185015Simp	  MIN(uio->uio_resid, devi->sc_cis.len - uio->uio_offset), uio));
166153811Simp}
167