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