1150362Simp/*- 2150362Simp * Copyright (c) 2005, M. Warner Losh 3150362Simp * All rights reserved. 4150362Simp * 5150362Simp * Redistribution and use in source and binary forms, with or without 6150362Simp * modification, are permitted provided that the following conditions 7150362Simp * are met: 8150362Simp * 1. Redistributions of source code must retain the above copyright 9150362Simp * notice unmodified, this list of conditions, and the following 10150362Simp * disclaimer. 11150362Simp * 2. Redistributions in binary form must reproduce the above copyright 12150362Simp * notice, this list of conditions and the following disclaimer in the 13150362Simp * documentation and/or other materials provided with the distribution. 14150362Simp * 15150362Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16150362Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17150362Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18150362Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19150362Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20150362Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21150362Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22150362Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23150362Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24150362Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25150362Simp * SUCH DAMAGE. 26150362Simp * 27150362Simp */ 28150362Simp#include <sys/cdefs.h> 29150362Simp__FBSDID("$FreeBSD$"); 30150362Simp 31150362Simp#include <sys/param.h> 32150362Simp#include <sys/conf.h> 33150362Simp#include <sys/malloc.h> 34150362Simp#include <sys/systm.h> 35150362Simp#include <sys/uio.h> 36150362Simp 37150362Simp#include <sys/bus.h> 38150362Simp#include <machine/bus.h> 39150362Simp#include <sys/rman.h> 40150362Simp#include <machine/resource.h> 41150362Simp 42150362Simp#include <dev/pccard/pccardreg.h> 43150362Simp#include <dev/pccard/pccardvar.h> 44150362Simp#include <dev/pccard/pccardvarp.h> 45150362Simp#include <dev/pccard/pccard_cis.h> 46150362Simp 47150362Simpstatic d_open_t pccard_open; 48150362Simpstatic d_close_t pccard_close; 49150362Simpstatic d_read_t pccard_read; 50150362Simpstatic d_ioctl_t pccard_ioctl; 51150362Simp 52150362Simpstatic struct cdevsw pccard_cdevsw = { 53150362Simp .d_version = D_VERSION, 54150362Simp .d_open = pccard_open, 55150362Simp .d_close = pccard_close, 56150362Simp .d_read = pccard_read, 57150362Simp .d_ioctl = pccard_ioctl, 58150362Simp .d_name = "pccard" 59150362Simp}; 60150362Simp 61150362Simpint 62150362Simppccard_device_create(struct pccard_softc *sc) 63150362Simp{ 64150400Simp uint32_t minor; 65150400Simp 66150400Simp minor = device_get_unit(sc->dev) << 16; 67150400Simp sc->cisdev = make_dev(&pccard_cdevsw, minor, 0, 0, 0666, 68150400Simp "pccard%u.cis", device_get_unit(sc->dev)); 69150362Simp sc->cisdev->si_drv1 = sc; 70150362Simp return (0); 71150362Simp} 72150362Simp 73150362Simpint 74150362Simppccard_device_destroy(struct pccard_softc *sc) 75150362Simp{ 76150400Simp if (sc->cisdev) 77150400Simp destroy_dev(sc->cisdev); 78150362Simp return (0); 79150362Simp} 80150362Simp 81150362Simpstatic int 82150362Simppccard_build_cis(const struct pccard_tuple *tuple, void *argp) 83150362Simp{ 84150362Simp struct cis_buffer *cis; 85150362Simp int i; 86150362Simp uint8_t ch; 87150362Simp 88150362Simp cis = (struct cis_buffer *)argp; 89150362Simp /* 90150362Simp * CISTPL_END is a special case, it has no length field. 91150362Simp */ 92150362Simp if (tuple->code == CISTPL_END) { 93150362Simp if (cis->len + 1 > sizeof(cis->buffer)) 94150362Simp return (ENOSPC); 95150362Simp cis->buffer[cis->len++] = tuple->code; 96150362Simp return (0); 97150362Simp } 98150432Simp if (cis->len + 2 + tuple->length > sizeof(cis->buffer)) 99150362Simp return (ENOSPC); 100150362Simp cis->buffer[cis->len++] = tuple->code; 101150362Simp cis->buffer[cis->len++] = tuple->length; 102150362Simp for (i = 0; i < tuple->length; i++) { 103150362Simp ch = pccard_tuple_read_1(tuple, i); 104150362Simp cis->buffer[cis->len++] = ch; 105150362Simp } 106150362Simp return (0); 107150362Simp} 108150362Simp 109150362Simpstatic int 110150362Simppccard_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 111150362Simp{ 112150362Simp device_t parent, child; 113150362Simp device_t *kids; 114150362Simp int cnt, err; 115150362Simp struct pccard_softc *sc; 116150362Simp 117150362Simp sc = dev->si_drv1; 118150362Simp if (sc->cis_open) 119150362Simp return (EBUSY); 120150362Simp parent = sc->dev; 121150362Simp err = device_get_children(parent, &kids, &cnt); 122150362Simp if (err) 123150362Simp return err; 124150362Simp if (cnt == 0) { 125150362Simp free(kids, M_TEMP); 126150362Simp sc->cis_open++; 127150362Simp sc->cis = NULL; 128150362Simp return (0); 129150362Simp } 130150362Simp child = kids[0]; 131150362Simp free(kids, M_TEMP); 132150362Simp sc->cis = malloc(sizeof(*sc->cis), M_TEMP, M_ZERO | M_WAITOK); 133150362Simp err = pccard_scan_cis(parent, child, pccard_build_cis, sc->cis); 134150362Simp if (err) { 135150362Simp free(sc->cis, M_TEMP); 136150362Simp sc->cis = NULL; 137150362Simp return (err); 138150362Simp } 139150362Simp sc->cis_open++; 140150362Simp return (0); 141150362Simp} 142150362Simp 143150362Simpstatic int 144150362Simppccard_close(struct cdev *dev, int fflags, int devtype, struct thread *td) 145150362Simp{ 146150362Simp struct pccard_softc *sc; 147150362Simp 148150362Simp sc = dev->si_drv1; 149150362Simp free(sc->cis, M_TEMP); 150150362Simp sc->cis = NULL; 151150362Simp sc->cis_open = 0; 152150362Simp return (0); 153150362Simp} 154150362Simp 155150362Simpstatic int 156150362Simppccard_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 157150362Simp struct thread *td) 158150362Simp{ 159150362Simp return (ENOTTY); 160150362Simp} 161150362Simp 162150362Simpstatic int 163150362Simppccard_read(struct cdev *dev, struct uio *uio, int ioflag) 164150362Simp{ 165150362Simp struct pccard_softc *sc; 166150362Simp 167150362Simp sc = dev->si_drv1; 168150362Simp /* EOF */ 169150362Simp if (sc->cis == NULL || uio->uio_offset > sc->cis->len) 170150362Simp return (0); 171150362Simp return (uiomove(sc->cis->buffer + uio->uio_offset, 172150362Simp MIN(uio->uio_resid, sc->cis->len - uio->uio_offset), uio)); 173150362Simp} 174