pcii.c revision 141123
1141121Sphk/*- 2141121Sphk * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org> 3141121Sphk * All rights reserved. 4141121Sphk * 5141121Sphk * Redistribution and use in source and binary forms, with or without 6141121Sphk * modification, are permitted provided that the following conditions 7141121Sphk * are met: 8141121Sphk * 1. Redistributions of source code must retain the above copyright 9141121Sphk * notice, this list of conditions and the following disclaimer as 10141121Sphk * the first lines of this file unmodified. 11141121Sphk * 2. Redistributions in binary form must reproduce the above copyright 12141121Sphk * notice, this list of conditions and the following disclaimer in the 13141121Sphk * documentation and/or other materials provided with the distribution. 14141121Sphk * 15141121Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16141121Sphk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17141121Sphk * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18141121Sphk * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19141121Sphk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20141121Sphk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21141121Sphk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22141121Sphk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23141121Sphk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24141121Sphk * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25141121Sphk * 26141121Sphk * Supported hardware: 27141123Sphk * PCIIA compatible cards. 28141123Sphk * 29141123Sphk * Tested and known working: 30141121Sphk * "B&C Microsystems PC488A-0" 31141121Sphk * 32141121Sphk * A whole lot of wonderful things could be written for GPIB, but for now 33141121Sphk * I have just written it such that it is possible to capture data in the 34141121Sphk * mode known as "unaddressed listen only mode". This is what many plotters 35141121Sphk * and printers do on GPIB. This is enough to capture some output from 36141121Sphk * various test instruments. 37141121Sphk * 38141121Sphk * If you are interested in working on this, send me email. 39141121Sphk */ 40141121Sphk 41141121Sphk#include <sys/cdefs.h> 42141121Sphk__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141123 2005-02-01 20:34:47Z phk $"); 43141121Sphk 44141121Sphk#include <sys/param.h> 45141121Sphk#include <sys/systm.h> 46141121Sphk#include <sys/conf.h> 47141121Sphk#include <sys/malloc.h> 48141121Sphk#include <sys/kernel.h> 49141121Sphk#include <sys/module.h> 50141121Sphk#include <sys/bus.h> 51141121Sphk#include <sys/mutex.h> 52141121Sphk#include <sys/uio.h> 53141121Sphk#include <machine/bus.h> 54141121Sphk#include <machine/resource.h> 55141121Sphk#include <sys/rman.h> 56141121Sphk 57141121Sphk/* ---> upd7210.h at some point. */ 58141121Sphk 59141121Sphkstruct upd7210 { 60141121Sphk bus_space_handle_t reg_handle[8]; 61141121Sphk bus_space_tag_t reg_tag[8]; 62141121Sphk u_int reg_offset[8]; 63141121Sphk 64141121Sphk /* private stuff */ 65141121Sphk struct mtx mutex; 66141121Sphk uint8_t rreg[8]; 67141121Sphk uint8_t wreg[8]; 68141121Sphk 69141121Sphk int busy; 70141121Sphk u_char *buf; 71141121Sphk size_t bufsize; 72141121Sphk u_int buf_wp; 73141121Sphk u_int buf_rp; 74141121Sphk struct cdev *cdev; 75141121Sphk}; 76141121Sphk 77141121Sphkstatic void upd7210intr(void *); 78141121Sphkstatic void upd7210attach(struct upd7210 *); 79141121Sphk 80141121Sphk 81141121Sphk/* ----> pcii.c */ 82141121Sphk 83141121Sphkstruct pcii_softc { 84141121Sphk int foo; 85141121Sphk struct resource *port[8]; 86141121Sphk struct resource *irq; 87141121Sphk void *intr_handler; 88141121Sphk struct upd7210 upd7210; 89141121Sphk}; 90141121Sphk 91141121Sphk#define HERE() printf("pcii HERE %s:%d\n", __FILE__, __LINE__) 92141121Sphk 93141121Sphkstatic devclass_t pcii_devclass; 94141121Sphk 95141121Sphkstatic int pcii_probe(device_t dev); 96141121Sphkstatic int pcii_attach(device_t dev); 97141121Sphk 98141121Sphkstatic device_method_t pcii_methods[] = { 99141121Sphk DEVMETHOD(device_probe, pcii_probe), 100141121Sphk DEVMETHOD(device_attach, pcii_attach), 101141121Sphk DEVMETHOD(device_suspend, bus_generic_suspend), 102141121Sphk DEVMETHOD(device_resume, bus_generic_resume), 103141121Sphk 104141121Sphk { 0, 0 } 105141121Sphk}; 106141121Sphk 107141121Sphkstatic driver_t pcii_driver = { 108141121Sphk "pcii", 109141121Sphk pcii_methods, 110141121Sphk sizeof(struct pcii_softc *), 111141121Sphk}; 112141121Sphk 113141121Sphkstatic int 114141121Sphkpcii_probe(device_t dev) 115141121Sphk{ 116141121Sphk struct resource *port; 117141121Sphk int rid; 118141121Sphk u_long start, count; 119141121Sphk int i, j, error = 0; 120141121Sphk 121141121Sphk device_set_desc(dev, "PCII IEEE-4888 controller"); 122141121Sphk 123141121Sphk rid = 0; 124141121Sphk if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) 125141121Sphk return ENXIO; 126141121Sphk if ((start & 0x3ff) != 0x2e1) 127141121Sphk return (ENXIO); 128141121Sphk count = 1; 129141121Sphk if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0) 130141121Sphk return ENXIO; 131141121Sphk for (i = 0; i < 8; i++) { 132141121Sphk j = bus_set_resource(dev, SYS_RES_IOPORT, i, 133141121Sphk start + 0x400 * i, 1); 134141121Sphk if (j) { 135141121Sphk error = ENXIO; 136141121Sphk break; 137141121Sphk } 138141121Sphk rid = i; 139141121Sphk port = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 140141121Sphk &rid, RF_ACTIVE); 141141121Sphk if (port == NULL) 142141121Sphk return (ENXIO); 143141121Sphk else 144141121Sphk bus_release_resource(dev, SYS_RES_IOPORT, i, port); 145141121Sphk } 146141121Sphk 147141121Sphk rid = 0; 148141121Sphk port = bus_alloc_resource_any(dev, 149141121Sphk SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 150141121Sphk if (port == NULL) 151141121Sphk return (ENXIO); 152141121Sphk bus_release_resource(dev, SYS_RES_IRQ, rid, port); 153141121Sphk 154141121Sphk return (error); 155141121Sphk} 156141121Sphk 157141121Sphkstatic int 158141121Sphkpcii_attach(device_t dev) 159141121Sphk{ 160141121Sphk struct pcii_softc *sc; 161141121Sphk int unit; 162141121Sphk int rid; 163141121Sphk int i, error = 0; 164141121Sphk 165141121Sphk unit = device_get_unit(dev); 166141121Sphk sc = device_get_softc(dev); 167141121Sphk memset(sc, 0, sizeof *sc); 168141121Sphk 169141121Sphk device_set_desc(dev, "PCII IEEE-4888 controller"); 170141121Sphk 171141121Sphk for (rid = 0; rid < 8; rid++) { 172141121Sphk sc->port[rid] = bus_alloc_resource_any(dev, 173141121Sphk SYS_RES_IOPORT, &rid, RF_ACTIVE); 174141121Sphk if (sc->port[rid] == NULL) { 175141121Sphk error = ENXIO; 176141121Sphk break; 177141121Sphk } 178141121Sphk sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]); 179141121Sphk sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]); 180141121Sphk } 181141121Sphk if (!error) { 182141121Sphk rid = 0; 183141121Sphk sc->irq = bus_alloc_resource_any(dev, 184141121Sphk SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 185141121Sphk if (sc->irq == NULL) { 186141121Sphk error = ENXIO; 187141121Sphk } else { 188141123Sphk error = bus_setup_intr(dev, sc->irq, 189141123Sphk INTR_TYPE_MISC | INTR_MPSAFE, 190141121Sphk upd7210intr, &sc->upd7210, &sc->intr_handler); 191141121Sphk } 192141121Sphk } 193141121Sphk if (error) { 194141121Sphkdevice_printf(dev, "error = %d\n", error); 195141121Sphk for (i = 0; i < 8; i++) { 196141121Sphk if (sc->port[i] == NULL) 197141121Sphk break; 198141121Sphk bus_release_resource(dev, SYS_RES_IOPORT, 199141121Sphk 0, sc->port[i]); 200141121Sphk } 201141121Sphk if (sc->intr_handler != NULL) 202141121Sphk bus_teardown_intr(dev, sc->irq, sc->intr_handler); 203141121Sphk if (sc->irq != NULL) 204141121Sphk bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq); 205141121Sphk } 206141121Sphk upd7210attach(&sc->upd7210); 207141121Sphk return (error); 208141121Sphk} 209141121Sphk 210141121SphkDRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0); 211141121SphkDRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0); 212141121Sphk 213141121Sphk/* ---> upd7210.c at some point */ 214141121Sphk 215141121Sphkenum upd7210_wreg { 216141121Sphk CDOR = 0, /* Command/data out */ 217141121Sphk IMR1 = 1, /* Interrupt mask 1 */ 218141121Sphk IMR2 = 2, /* Interrupt mask 2 */ 219141121Sphk SPMR = 3, /* Serial poll mode */ 220141121Sphk ADMR = 4, /* Address mode */ 221141121Sphk AUXMR = 5, /* Auxilliary mode */ 222141121Sphk ADR = 6, /* Address */ 223141121Sphk EOSR = 7, /* End-of-string */ 224141121Sphk}; 225141121Sphk 226141121Sphkenum upd7210_rreg { 227141121Sphk DIR = 0, /* Data in */ 228141121Sphk ISR1 = 1, /* Interrupt status 1 */ 229141121Sphk ISR2 = 2, /* Interrupt status 2 */ 230141121Sphk SPSR = 3, /* Serial poll status */ 231141121Sphk ADSR = 4, /* Address status */ 232141121Sphk CPTR = 5, /* Command pass though */ 233141121Sphk ADR0 = 6, /* Address 1 */ 234141121Sphk ADR1 = 7, /* Address 2 */ 235141121Sphk}; 236141121Sphk 237141121Sphk#define AUXMR_PON 0x00 238141121Sphk#define AUXMR_CRST 0x02 239141121Sphk#define AUXMR_RFD 0x03 240141121Sphk#define AUXMR_SEOI 0x06 241141121Sphk#define AUXMR_GTS 0x10 242141121Sphk#define AUXMR_TCA 0x11 243141121Sphk#define AUXMR_TCS 0x12 244141121Sphk#define AUXMR_TCSE 0x1a 245141121Sphk#define AUXMR_DSC 0x14 246141121Sphk#define AUXMR_CIFC 0x16 247141121Sphk#define AUXMR_SIFC 0x1e 248141121Sphk#define AUXMR_CREN 0x17 249141121Sphk#define AUXMR_SREN 0x1f 250141121Sphk#define AUXMR_ICTR 0x20 251141121Sphk#define AUXMR_PPR 0x60 252141121Sphk#define AUXMR_RA 0x80 253141121Sphk#define AUXMR_RB 0xa0 254141121Sphk#define AUXMR_RE 0xc0 255141121Sphk 256141121Sphk 257141121Sphk/* upd7210 generic stuff */ 258141121Sphk 259141121Sphkstatic u_int 260141121Sphkread_reg(struct upd7210 *u, enum upd7210_rreg reg) 261141121Sphk{ 262141121Sphk u_int r; 263141121Sphk 264141121Sphk r = bus_space_read_1( 265141121Sphk u->reg_tag[reg], 266141121Sphk u->reg_handle[reg], 267141121Sphk u->reg_offset[reg]); 268141121Sphk u->rreg[reg] = r; 269141121Sphk return (r); 270141121Sphk} 271141121Sphk 272141121Sphkstatic void 273141121Sphkwrite_reg(struct upd7210 *u, enum upd7210_wreg reg, u_int val) 274141121Sphk{ 275141121Sphk bus_space_write_1( 276141121Sphk u->reg_tag[reg], 277141121Sphk u->reg_handle[reg], 278141121Sphk u->reg_offset[reg], val); 279141121Sphk u->wreg[reg] = val; 280141121Sphk} 281141121Sphk 282141121Sphkstatic void 283141121Sphkupd7210intr(void *arg) 284141121Sphk{ 285141121Sphk int i; 286141121Sphk u_int isr1, isr2; 287141121Sphk struct upd7210 *u; 288141121Sphk 289141121Sphk u = arg; 290141121Sphk mtx_lock(&u->mutex); 291141121Sphk isr1 = read_reg(u, ISR1); 292141121Sphk isr2 = read_reg(u, ISR2); 293141121Sphk if (isr1 & 1) { 294141121Sphk i = read_reg(u, DIR); 295141121Sphk u->buf[u->buf_wp++] = i; 296141121Sphk u->buf_wp &= (u->bufsize - 1); 297141121Sphk i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1); 298141121Sphk if (i < 8) 299141121Sphk write_reg(u, IMR1, 0); 300141121Sphk wakeup(u->buf); 301141121Sphk } else { 302141121Sphk printf("upd7210intr [%02x %02x %02x", 303141121Sphk read_reg(u, DIR), isr1, isr2); 304141121Sphk printf(" %02x %02x %02x %02x %02x]\n", 305141121Sphk read_reg(u, SPSR), 306141121Sphk read_reg(u, ADSR), 307141121Sphk read_reg(u, CPTR), 308141121Sphk read_reg(u, ADR0), 309141121Sphk read_reg(u, ADR1)); 310141121Sphk } 311141121Sphk mtx_unlock(&u->mutex); 312141121Sphk} 313141121Sphk 314141121Sphkstatic int 315141121Sphkgpib_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 316141121Sphk{ 317141121Sphk struct upd7210 *u; 318141121Sphk 319141121Sphk u = dev->si_drv1; 320141121Sphk 321141121Sphk mtx_lock(&u->mutex); 322141121Sphk if (u->busy) 323141121Sphk return (EBUSY); 324141121Sphk u->busy = 1; 325141121Sphk mtx_unlock(&u->mutex); 326141121Sphk 327141121Sphk u->buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 328141121Sphk u->bufsize = PAGE_SIZE; 329141121Sphk u->buf_wp = 0; 330141121Sphk u->buf_rp = 0; 331141121Sphk 332141121Sphk write_reg(u, AUXMR, AUXMR_CRST); 333141121Sphk DELAY(10000); 334141121Sphk write_reg(u, AUXMR, AUXMR_ICTR | 8); 335141121Sphk DELAY(1000); 336141121Sphk write_reg(u, ADR, 0x60); 337141121Sphk write_reg(u, ADR, 0xe0); 338141121Sphk write_reg(u, ADMR, 0x70); 339141121Sphk write_reg(u, AUXMR, AUXMR_PON); 340141121Sphk write_reg(u, IMR1, 0x01); 341141121Sphk return (0); 342141121Sphk} 343141121Sphk 344141121Sphkstatic int 345141121Sphkgpib_close(struct cdev *dev, int oflags, int devtype, struct thread *td) 346141121Sphk{ 347141121Sphk struct upd7210 *u; 348141121Sphk 349141121Sphk u = dev->si_drv1; 350141121Sphk 351141121Sphk mtx_lock(&u->mutex); 352141121Sphk u->busy = 0; 353141121Sphk write_reg(u, AUXMR, AUXMR_CRST); 354141121Sphk DELAY(10000); 355141121Sphk write_reg(u, IMR1, 0x00); 356141121Sphk write_reg(u, IMR2, 0x00); 357141121Sphk free(u->buf, M_DEVBUF); 358141121Sphk u->buf = NULL; 359141121Sphk mtx_unlock(&u->mutex); 360141121Sphk return (0); 361141121Sphk} 362141121Sphk 363141121Sphkstatic int 364141121Sphkgpib_read(struct cdev *dev, struct uio *uio, int ioflag) 365141121Sphk{ 366141121Sphk struct upd7210 *u; 367141121Sphk int error; 368141121Sphk size_t z; 369141121Sphk 370141121Sphk u = dev->si_drv1; 371141121Sphk error = 0; 372141121Sphk 373141121Sphk mtx_lock(&u->mutex); 374141121Sphk while (u->buf_wp == u->buf_rp) { 375141121Sphk error = msleep(u->buf, &u->mutex, PZERO | PCATCH, 376141121Sphk "gpibrd", hz); 377141121Sphk if (error && error != EWOULDBLOCK) { 378141121Sphk mtx_unlock(&u->mutex); 379141121Sphk return (error); 380141121Sphk } 381141121Sphk } 382141121Sphk while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) { 383141121Sphk if (u->buf_wp < u->buf_rp) 384141121Sphk z = u->bufsize - u->buf_rp; 385141121Sphk else 386141121Sphk z = u->buf_wp - u->buf_rp; 387141121Sphk if (z > uio->uio_resid) 388141121Sphk z = uio->uio_resid; 389141121Sphk mtx_unlock(&u->mutex); 390141121Sphk error = uiomove(u->buf + u->buf_rp, z, uio); 391141121Sphk mtx_lock(&u->mutex); 392141121Sphk if (error) 393141121Sphk break; 394141121Sphk u->buf_rp += z; 395141121Sphk u->buf_rp &= (u->bufsize - 1); 396141121Sphk } 397141121Sphk if (u->wreg[IMR1] == 0) 398141121Sphk write_reg(u, IMR1, 0x01); 399141121Sphk mtx_unlock(&u->mutex); 400141121Sphk return (error); 401141121Sphk} 402141121Sphk 403141121Sphk 404141121Sphk 405141121Sphkstruct cdevsw gpib_cdevsw = { 406141121Sphk .d_version = D_VERSION, 407141121Sphk .d_name = "gpib", 408141121Sphk .d_open = gpib_open, 409141121Sphk .d_close = gpib_close, 410141121Sphk .d_read = gpib_read, 411141121Sphk}; 412141121Sphk 413141121Sphkstatic void 414141121Sphkupd7210attach(struct upd7210 *u) 415141121Sphk{ 416141121Sphk int unit = 0; 417141121Sphk 418141121Sphk mtx_init(&u->mutex, "gpib", NULL, MTX_DEF); 419141121Sphk u->cdev = make_dev(&gpib_cdevsw, unit, 420141121Sphk UID_ROOT, GID_WHEEL, 0444, 421141121Sphk "gpib%ul", unit); 422141121Sphk u->cdev->si_drv1 = u; 423141121Sphk} 424