xref: /freebsd/sys/dev/cardbus/cardbus_device.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
147147ce7SWarner Losh /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4f86e6000SWarner Losh  * Copyright (c) 2005-2008 M. Warner Losh <imp@FreeBSD.org>
547147ce7SWarner Losh  *
647147ce7SWarner Losh  * Redistribution and use in source and binary forms, with or without
747147ce7SWarner Losh  * modification, are permitted provided that the following conditions
847147ce7SWarner Losh  * are met:
947147ce7SWarner Losh  * 1. Redistributions of source code must retain the above copyright
1047147ce7SWarner Losh  *    notice unmodified, this list of conditions, and the following
1147147ce7SWarner Losh  *    disclaimer.
1247147ce7SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
1347147ce7SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
1447147ce7SWarner Losh  *    documentation and/or other materials provided with the distribution.
1547147ce7SWarner Losh  *
1647147ce7SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1747147ce7SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1847147ce7SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1947147ce7SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2047147ce7SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2147147ce7SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2247147ce7SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2347147ce7SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2447147ce7SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2547147ce7SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2647147ce7SWarner Losh  * SUCH DAMAGE.
2747147ce7SWarner Losh  *
2847147ce7SWarner Losh  */
29*fdafd315SWarner Losh 
3047147ce7SWarner Losh #include <sys/param.h>
3147147ce7SWarner Losh #include <sys/conf.h>
3247147ce7SWarner Losh #include <sys/malloc.h>
3347147ce7SWarner Losh #include <sys/systm.h>
3447147ce7SWarner Losh #include <sys/uio.h>
3547147ce7SWarner Losh 
3647147ce7SWarner Losh #include <sys/bus.h>
3747147ce7SWarner Losh #include <machine/bus.h>
3847147ce7SWarner Losh #include <sys/rman.h>
3947147ce7SWarner Losh #include <machine/resource.h>
4047147ce7SWarner Losh 
4147147ce7SWarner Losh #include <sys/pciio.h>
4247147ce7SWarner Losh #include <dev/pci/pcivar.h>
4347147ce7SWarner Losh #include <dev/pci/pcireg.h>
4447147ce7SWarner Losh #include <dev/pci/pci_private.h>
4547147ce7SWarner Losh 
4647147ce7SWarner Losh #include <dev/cardbus/cardbusreg.h>
4747147ce7SWarner Losh #include <dev/cardbus/cardbusvar.h>
4847147ce7SWarner Losh #include <dev/cardbus/cardbus_cis.h>
4947147ce7SWarner Losh #include <dev/pccard/pccard_cis.h>
5047147ce7SWarner Losh 
5147147ce7SWarner Losh static	d_open_t	cardbus_open;
5247147ce7SWarner Losh static	d_close_t	cardbus_close;
5347147ce7SWarner Losh static	d_read_t	cardbus_read;
5447147ce7SWarner Losh static	d_ioctl_t	cardbus_ioctl;
5547147ce7SWarner Losh 
5647147ce7SWarner Losh static struct cdevsw cardbus_cdevsw = {
5747147ce7SWarner Losh 	.d_version =	D_VERSION,
5847147ce7SWarner Losh 	.d_open =	cardbus_open,
5947147ce7SWarner Losh 	.d_close =	cardbus_close,
6047147ce7SWarner Losh 	.d_read =	cardbus_read,
6147147ce7SWarner Losh 	.d_ioctl =	cardbus_ioctl,
6247147ce7SWarner Losh 	.d_name =	"cardbus"
6347147ce7SWarner Losh };
6447147ce7SWarner Losh 
6547147ce7SWarner Losh static int
cardbus_build_cis(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info,void * argp)6647147ce7SWarner Losh cardbus_build_cis(device_t cbdev, device_t child, int id,
6747147ce7SWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
6847147ce7SWarner Losh     struct tuple_callbacks *info, void *argp)
6947147ce7SWarner Losh {
7047147ce7SWarner Losh 	struct cis_buffer *cis;
7147147ce7SWarner Losh 	int i;
7247147ce7SWarner Losh 
7347147ce7SWarner Losh 	cis = (struct cis_buffer *)argp;
7447147ce7SWarner Losh 	/*
7547147ce7SWarner Losh 	 * CISTPL_END is a special case, it has no length field.
7647147ce7SWarner Losh 	 */
7747147ce7SWarner Losh 	if (id == CISTPL_END) {
78e371fa45SWarner Losh 		if (cis->len + 1 > sizeof(cis->buffer)) {
79e371fa45SWarner Losh 			cis->len = 0;
8047147ce7SWarner Losh 			return (ENOSPC);
81e371fa45SWarner Losh 		}
8247147ce7SWarner Losh 		cis->buffer[cis->len++] = id;
8347147ce7SWarner Losh 		return (0);
8447147ce7SWarner Losh 	}
85e371fa45SWarner Losh 	if (cis->len + 2 + len > sizeof(cis->buffer)) {
86e371fa45SWarner Losh 		cis->len = 0;
8747147ce7SWarner Losh 		return (ENOSPC);
88e371fa45SWarner Losh 	}
8947147ce7SWarner Losh 	cis->buffer[cis->len++] = id;
9047147ce7SWarner Losh 	cis->buffer[cis->len++] = len;
9147147ce7SWarner Losh 	for (i = 0; i < len; i++)
9247147ce7SWarner Losh 		cis->buffer[cis->len++] = tupledata[i];
9347147ce7SWarner Losh 	return (0);
9447147ce7SWarner Losh }
9547147ce7SWarner Losh 
9647147ce7SWarner Losh static int
cardbus_device_buffer_cis(device_t parent,device_t child,struct cis_buffer * cbp)97a7de0b74SWarner Losh cardbus_device_buffer_cis(device_t parent, device_t child,
98a7de0b74SWarner Losh     struct cis_buffer *cbp)
99e371fa45SWarner Losh {
100e371fa45SWarner Losh 	struct tuple_callbacks cb[] = {
101e371fa45SWarner Losh 		{CISTPL_GENERIC, "GENERIC", cardbus_build_cis}
102e371fa45SWarner Losh 	};
103e371fa45SWarner Losh 
104a7de0b74SWarner Losh 	return (cardbus_parse_cis(parent, child, cb, cbp));
105a7de0b74SWarner Losh }
106a7de0b74SWarner Losh 
107a7de0b74SWarner Losh int
cardbus_device_create(struct cardbus_softc * sc,struct cardbus_devinfo * devi,device_t parent,device_t child)108a7de0b74SWarner Losh cardbus_device_create(struct cardbus_softc *sc, struct cardbus_devinfo *devi,
109a7de0b74SWarner Losh     device_t parent, device_t child)
110a7de0b74SWarner Losh {
111a7de0b74SWarner Losh 	uint32_t minor;
1127d0fb1f7SWarner Losh 	int unit;
113a7de0b74SWarner Losh 
114a7de0b74SWarner Losh 	cardbus_device_buffer_cis(parent, child, &devi->sc_cis);
115a7de0b74SWarner Losh 	minor = (device_get_unit(sc->sc_dev) << 8) + devi->pci.cfg.func;
1167d0fb1f7SWarner Losh 	unit = device_get_unit(sc->sc_dev);
117a7de0b74SWarner Losh 	devi->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666,
1187d0fb1f7SWarner Losh 	    "cardbus%d.%d.cis", unit, devi->pci.cfg.func);
119db8deb42SWarner Losh 	if (devi->pci.cfg.func == 0)
1207d0fb1f7SWarner Losh 		make_dev_alias(devi->sc_cisdev, "cardbus%d.cis", unit);
121a7de0b74SWarner Losh 	devi->sc_cisdev->si_drv1 = devi;
122a7de0b74SWarner Losh 	return (0);
123a7de0b74SWarner Losh }
124a7de0b74SWarner Losh 
125a7de0b74SWarner Losh int
cardbus_device_destroy(struct cardbus_devinfo * devi)126a7de0b74SWarner Losh cardbus_device_destroy(struct cardbus_devinfo *devi)
127a7de0b74SWarner Losh {
128a7de0b74SWarner Losh 	if (devi->sc_cisdev)
129a7de0b74SWarner Losh 		destroy_dev(devi->sc_cisdev);
130a7de0b74SWarner Losh 	return (0);
131e371fa45SWarner Losh }
132e371fa45SWarner Losh 
133e371fa45SWarner Losh static	int
cardbus_open(struct cdev * dev,int oflags,int devtype,struct thread * td)13447147ce7SWarner Losh cardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
13547147ce7SWarner Losh {
13647147ce7SWarner Losh 
13747147ce7SWarner Losh 	return (0);
13847147ce7SWarner Losh }
13947147ce7SWarner Losh 
14047147ce7SWarner Losh static	int
cardbus_close(struct cdev * dev,int fflags,int devtype,struct thread * td)14147147ce7SWarner Losh cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
14247147ce7SWarner Losh {
14347147ce7SWarner Losh 
14447147ce7SWarner Losh 	return (0);
14547147ce7SWarner Losh }
14647147ce7SWarner Losh 
14747147ce7SWarner Losh static	int
cardbus_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)14847147ce7SWarner Losh cardbus_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
14947147ce7SWarner Losh     struct thread *td)
15047147ce7SWarner Losh {
15147147ce7SWarner Losh 	return (ENOTTY);
15247147ce7SWarner Losh }
15347147ce7SWarner Losh 
15447147ce7SWarner Losh static	int
cardbus_read(struct cdev * dev,struct uio * uio,int ioflag)15547147ce7SWarner Losh cardbus_read(struct cdev *dev, struct uio *uio, int ioflag)
15647147ce7SWarner Losh {
157a7de0b74SWarner Losh 	struct cardbus_devinfo *devi;
15847147ce7SWarner Losh 
159a7de0b74SWarner Losh 	devi = dev->si_drv1;
16047147ce7SWarner Losh 	/* EOF */
161a7de0b74SWarner Losh 	if (uio->uio_offset >= devi->sc_cis.len)
16247147ce7SWarner Losh 		return (0);
163a7de0b74SWarner Losh 	return (uiomove(devi->sc_cis.buffer + uio->uio_offset,
164a7de0b74SWarner Losh 	  MIN(uio->uio_resid, devi->sc_cis.len - uio->uio_offset), uio));
16547147ce7SWarner Losh }
166