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