pcii.c revision 141121
1254721Semaste/*- 2254721Semaste * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org> 3254721Semaste * All rights reserved. 4254721Semaste * 5254721Semaste * Redistribution and use in source and binary forms, with or without 6254721Semaste * modification, are permitted provided that the following conditions 7254721Semaste * are met: 8254721Semaste * 1. Redistributions of source code must retain the above copyright 9254721Semaste * notice, this list of conditions and the following disclaimer as 10254721Semaste * the first lines of this file unmodified. 11254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 12254721Semaste * notice, this list of conditions and the following disclaimer in the 13254721Semaste * documentation and/or other materials provided with the distribution. 14254721Semaste * 15254721Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16254721Semaste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17254721Semaste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18254721Semaste * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19254721Semaste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20254721Semaste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21254721Semaste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22254721Semaste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23254721Semaste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24254721Semaste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25254721Semaste * 26254721Semaste * Supported hardware: 27254721Semaste * "B&C Microsystems PC488A-0" 28254721Semaste * 29254721Semaste * A whole lot of wonderful things could be written for GPIB, but for now 30254721Semaste * I have just written it such that it is possible to capture data in the 31254721Semaste * mode known as "unaddressed listen only mode". This is what many plotters 32254721Semaste * and printers do on GPIB. This is enough to capture some output from 33254721Semaste * various test instruments. 34254721Semaste * 35254721Semaste * If you are interested in working on this, send me email. 36254721Semaste */ 37254721Semaste 38254721Semaste#include <sys/cdefs.h> 39254721Semaste__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141121 2005-02-01 16:59:23Z phk $"); 40254721Semaste 41254721Semaste#include <sys/param.h> 42254721Semaste#include <sys/systm.h> 43254721Semaste#include <sys/conf.h> 44254721Semaste#include <sys/malloc.h> 45254721Semaste#include <sys/kernel.h> 46254721Semaste#include <sys/module.h> 47254721Semaste#include <sys/bus.h> 48254721Semaste#include <sys/mutex.h> 49254721Semaste#include <sys/uio.h> 50254721Semaste#include <machine/bus.h> 51254721Semaste#include <machine/resource.h> 52254721Semaste#include <sys/rman.h> 53254721Semaste 54254721Semaste/* ---> upd7210.h at some point. */ 55254721Semaste 56254721Semastestruct upd7210 { 57254721Semaste bus_space_handle_t reg_handle[8]; 58254721Semaste bus_space_tag_t reg_tag[8]; 59254721Semaste u_int reg_offset[8]; 60254721Semaste 61254721Semaste /* private stuff */ 62254721Semaste struct mtx mutex; 63254721Semaste uint8_t rreg[8]; 64254721Semaste uint8_t wreg[8]; 65254721Semaste 66254721Semaste int busy; 67254721Semaste u_char *buf; 68254721Semaste size_t bufsize; 69254721Semaste u_int buf_wp; 70254721Semaste u_int buf_rp; 71254721Semaste struct cdev *cdev; 72254721Semaste}; 73254721Semaste 74254721Semastestatic void upd7210intr(void *); 75254721Semastestatic void upd7210attach(struct upd7210 *); 76254721Semaste 77254721Semaste 78254721Semaste/* ----> pcii.c */ 79254721Semaste 80254721Semastestruct pcii_softc { 81254721Semaste int foo; 82254721Semaste struct resource *port[8]; 83254721Semaste struct resource *irq; 84254721Semaste void *intr_handler; 85254721Semaste struct upd7210 upd7210; 86254721Semaste}; 87254721Semaste 88254721Semaste#define HERE() printf("pcii HERE %s:%d\n", __FILE__, __LINE__) 89254721Semaste 90254721Semastestatic devclass_t pcii_devclass; 91254721Semaste 92254721Semastestatic int pcii_probe(device_t dev); 93254721Semastestatic int pcii_attach(device_t dev); 94254721Semaste 95254721Semastestatic device_method_t pcii_methods[] = { 96254721Semaste DEVMETHOD(device_probe, pcii_probe), 97254721Semaste DEVMETHOD(device_attach, pcii_attach), 98254721Semaste DEVMETHOD(device_suspend, bus_generic_suspend), 99254721Semaste DEVMETHOD(device_resume, bus_generic_resume), 100254721Semaste 101254721Semaste { 0, 0 } 102254721Semaste}; 103254721Semaste 104254721Semastestatic driver_t pcii_driver = { 105254721Semaste "pcii", 106254721Semaste pcii_methods, 107254721Semaste sizeof(struct pcii_softc *), 108254721Semaste}; 109254721Semaste 110254721Semastestatic int 111254721Semastepcii_probe(device_t dev) 112254721Semaste{ 113254721Semaste struct resource *port; 114254721Semaste int rid; 115254721Semaste u_long start, count; 116254721Semaste int i, j, error = 0; 117254721Semaste 118254721Semaste device_set_desc(dev, "PCII IEEE-4888 controller"); 119254721Semaste 120254721Semaste rid = 0; 121254721Semaste if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) 122254721Semaste return ENXIO; 123254721Semaste if ((start & 0x3ff) != 0x2e1) 124254721Semaste return (ENXIO); 125254721Semaste count = 1; 126254721Semaste if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0) 127254721Semaste return ENXIO; 128254721Semaste for (i = 0; i < 8; i++) { 129254721Semaste j = bus_set_resource(dev, SYS_RES_IOPORT, i, 130254721Semaste start + 0x400 * i, 1); 131254721Semaste if (j) { 132254721Semaste error = ENXIO; 133254721Semaste break; 134254721Semaste } 135254721Semaste rid = i; 136254721Semaste port = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 137254721Semaste &rid, RF_ACTIVE); 138254721Semaste if (port == NULL) 139254721Semaste return (ENXIO); 140254721Semaste else 141254721Semaste bus_release_resource(dev, SYS_RES_IOPORT, i, port); 142254721Semaste } 143254721Semaste 144254721Semaste rid = 0; 145254721Semaste port = bus_alloc_resource_any(dev, 146254721Semaste SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 147254721Semaste if (port == NULL) 148254721Semaste return (ENXIO); 149254721Semaste bus_release_resource(dev, SYS_RES_IRQ, rid, port); 150254721Semaste 151254721Semaste return (error); 152254721Semaste} 153254721Semaste 154254721Semastestatic int 155254721Semastepcii_attach(device_t dev) 156254721Semaste{ 157254721Semaste struct pcii_softc *sc; 158254721Semaste int unit; 159254721Semaste int rid; 160254721Semaste int i, error = 0; 161254721Semaste 162254721Semaste unit = device_get_unit(dev); 163254721Semaste sc = device_get_softc(dev); 164254721Semaste memset(sc, 0, sizeof *sc); 165254721Semaste 166254721Semaste device_set_desc(dev, "PCII IEEE-4888 controller"); 167254721Semaste 168254721Semaste for (rid = 0; rid < 8; rid++) { 169254721Semaste sc->port[rid] = bus_alloc_resource_any(dev, 170254721Semaste SYS_RES_IOPORT, &rid, RF_ACTIVE); 171254721Semaste if (sc->port[rid] == NULL) { 172254721Semaste error = ENXIO; 173254721Semaste break; 174254721Semaste } 175254721Semaste sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]); 176254721Semaste sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]); 177254721Semaste } 178254721Semaste if (!error) { 179254721Semaste rid = 0; 180254721Semaste sc->irq = bus_alloc_resource_any(dev, 181254721Semaste SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 182254721Semaste if (sc->irq == NULL) { 183254721Semaste error = ENXIO; 184254721Semaste } else { 185254721Semaste error = bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC, 186254721Semaste upd7210intr, &sc->upd7210, &sc->intr_handler); 187254721Semaste } 188254721Semaste } 189254721Semaste if (error) { 190254721Semastedevice_printf(dev, "error = %d\n", error); 191254721Semaste for (i = 0; i < 8; i++) { 192254721Semaste if (sc->port[i] == NULL) 193254721Semaste break; 194254721Semaste bus_release_resource(dev, SYS_RES_IOPORT, 195254721Semaste 0, sc->port[i]); 196254721Semaste } 197254721Semaste if (sc->intr_handler != NULL) 198254721Semaste bus_teardown_intr(dev, sc->irq, sc->intr_handler); 199254721Semaste if (sc->irq != NULL) 200254721Semaste bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq); 201254721Semaste } 202254721Semaste upd7210attach(&sc->upd7210); 203254721Semaste return (error); 204254721Semaste} 205254721Semaste 206254721SemasteDRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0); 207254721SemasteDRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0); 208254721Semaste 209254721Semaste/* ---> upd7210.c at some point */ 210254721Semaste 211254721Semasteenum upd7210_wreg { 212254721Semaste CDOR = 0, /* Command/data out */ 213254721Semaste IMR1 = 1, /* Interrupt mask 1 */ 214254721Semaste IMR2 = 2, /* Interrupt mask 2 */ 215254721Semaste SPMR = 3, /* Serial poll mode */ 216254721Semaste ADMR = 4, /* Address mode */ 217254721Semaste AUXMR = 5, /* Auxilliary mode */ 218254721Semaste ADR = 6, /* Address */ 219254721Semaste EOSR = 7, /* End-of-string */ 220254721Semaste}; 221254721Semaste 222254721Semasteenum upd7210_rreg { 223254721Semaste DIR = 0, /* Data in */ 224254721Semaste ISR1 = 1, /* Interrupt status 1 */ 225254721Semaste ISR2 = 2, /* Interrupt status 2 */ 226254721Semaste SPSR = 3, /* Serial poll status */ 227254721Semaste ADSR = 4, /* Address status */ 228254721Semaste CPTR = 5, /* Command pass though */ 229254721Semaste ADR0 = 6, /* Address 1 */ 230254721Semaste ADR1 = 7, /* Address 2 */ 231254721Semaste}; 232254721Semaste 233254721Semaste#define AUXMR_PON 0x00 234254721Semaste#define AUXMR_CRST 0x02 235254721Semaste#define AUXMR_RFD 0x03 236254721Semaste#define AUXMR_SEOI 0x06 237254721Semaste#define AUXMR_GTS 0x10 238254721Semaste#define AUXMR_TCA 0x11 239254721Semaste#define AUXMR_TCS 0x12 240254721Semaste#define AUXMR_TCSE 0x1a 241254721Semaste#define AUXMR_DSC 0x14 242254721Semaste#define AUXMR_CIFC 0x16 243254721Semaste#define AUXMR_SIFC 0x1e 244254721Semaste#define AUXMR_CREN 0x17 245254721Semaste#define AUXMR_SREN 0x1f 246254721Semaste#define AUXMR_ICTR 0x20 247254721Semaste#define AUXMR_PPR 0x60 248254721Semaste#define AUXMR_RA 0x80 249254721Semaste#define AUXMR_RB 0xa0 250254721Semaste#define AUXMR_RE 0xc0 251254721Semaste 252254721Semaste 253254721Semaste/* upd7210 generic stuff */ 254254721Semaste 255254721Semastestatic u_int 256254721Semasteread_reg(struct upd7210 *u, enum upd7210_rreg reg) 257254721Semaste{ 258254721Semaste u_int r; 259254721Semaste 260254721Semaste r = bus_space_read_1( 261254721Semaste u->reg_tag[reg], 262254721Semaste u->reg_handle[reg], 263254721Semaste u->reg_offset[reg]); 264254721Semaste u->rreg[reg] = r; 265254721Semaste return (r); 266254721Semaste} 267254721Semaste 268254721Semastestatic void 269254721Semastewrite_reg(struct upd7210 *u, enum upd7210_wreg reg, u_int val) 270254721Semaste{ 271254721Semaste bus_space_write_1( 272254721Semaste u->reg_tag[reg], 273254721Semaste u->reg_handle[reg], 274254721Semaste u->reg_offset[reg], val); 275254721Semaste u->wreg[reg] = val; 276254721Semaste} 277254721Semaste 278254721Semastestatic void 279254721Semasteupd7210intr(void *arg) 280254721Semaste{ 281254721Semaste int i; 282254721Semaste u_int isr1, isr2; 283254721Semaste struct upd7210 *u; 284254721Semaste 285254721Semaste u = arg; 286254721Semaste mtx_lock(&u->mutex); 287254721Semaste isr1 = read_reg(u, ISR1); 288254721Semaste isr2 = read_reg(u, ISR2); 289254721Semaste if (isr1 & 1) { 290254721Semaste i = read_reg(u, DIR); 291254721Semaste u->buf[u->buf_wp++] = i; 292254721Semaste u->buf_wp &= (u->bufsize - 1); 293254721Semaste i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1); 294254721Semaste if (i < 8) 295254721Semaste write_reg(u, IMR1, 0); 296254721Semaste wakeup(u->buf); 297254721Semaste } else { 298254721Semaste printf("upd7210intr [%02x %02x %02x", 299254721Semaste read_reg(u, DIR), isr1, isr2); 300254721Semaste printf(" %02x %02x %02x %02x %02x]\n", 301254721Semaste read_reg(u, SPSR), 302254721Semaste read_reg(u, ADSR), 303254721Semaste read_reg(u, CPTR), 304254721Semaste read_reg(u, ADR0), 305254721Semaste read_reg(u, ADR1)); 306254721Semaste } 307254721Semaste mtx_unlock(&u->mutex); 308254721Semaste} 309254721Semaste 310254721Semastestatic int 311254721Semastegpib_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 312254721Semaste{ 313254721Semaste struct upd7210 *u; 314254721Semaste 315254721Semaste u = dev->si_drv1; 316254721Semaste 317254721Semaste mtx_lock(&u->mutex); 318254721Semaste if (u->busy) 319254721Semaste return (EBUSY); 320254721Semaste u->busy = 1; 321254721Semaste mtx_unlock(&u->mutex); 322254721Semaste 323254721Semaste u->buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 324254721Semaste u->bufsize = PAGE_SIZE; 325254721Semaste u->buf_wp = 0; 326254721Semaste u->buf_rp = 0; 327254721Semaste 328254721Semaste write_reg(u, AUXMR, AUXMR_CRST); 329254721Semaste DELAY(10000); 330254721Semaste write_reg(u, AUXMR, AUXMR_ICTR | 8); 331254721Semaste DELAY(1000); 332254721Semaste write_reg(u, ADR, 0x60); 333254721Semaste write_reg(u, ADR, 0xe0); 334254721Semaste write_reg(u, ADMR, 0x70); 335254721Semaste write_reg(u, AUXMR, AUXMR_PON); 336254721Semaste write_reg(u, IMR1, 0x01); 337254721Semaste return (0); 338254721Semaste} 339254721Semaste 340254721Semastestatic int 341254721Semastegpib_close(struct cdev *dev, int oflags, int devtype, struct thread *td) 342254721Semaste{ 343254721Semaste struct upd7210 *u; 344254721Semaste 345254721Semaste u = dev->si_drv1; 346254721Semaste 347254721Semaste mtx_lock(&u->mutex); 348254721Semaste u->busy = 0; 349254721Semaste write_reg(u, AUXMR, AUXMR_CRST); 350254721Semaste DELAY(10000); 351254721Semaste write_reg(u, IMR1, 0x00); 352254721Semaste write_reg(u, IMR2, 0x00); 353254721Semaste free(u->buf, M_DEVBUF); 354254721Semaste u->buf = NULL; 355254721Semaste mtx_unlock(&u->mutex); 356254721Semaste return (0); 357254721Semaste} 358254721Semaste 359254721Semastestatic int 360254721Semastegpib_read(struct cdev *dev, struct uio *uio, int ioflag) 361254721Semaste{ 362254721Semaste struct upd7210 *u; 363254721Semaste int error; 364254721Semaste size_t z; 365254721Semaste 366254721Semaste u = dev->si_drv1; 367254721Semaste error = 0; 368254721Semaste 369254721Semaste mtx_lock(&u->mutex); 370254721Semaste while (u->buf_wp == u->buf_rp) { 371254721Semaste error = msleep(u->buf, &u->mutex, PZERO | PCATCH, 372254721Semaste "gpibrd", hz); 373254721Semaste if (error && error != EWOULDBLOCK) { 374254721Semaste mtx_unlock(&u->mutex); 375254721Semaste return (error); 376254721Semaste } 377254721Semaste } 378254721Semaste while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) { 379254721Semaste if (u->buf_wp < u->buf_rp) 380254721Semaste z = u->bufsize - u->buf_rp; 381254721Semaste else 382254721Semaste z = u->buf_wp - u->buf_rp; 383254721Semaste if (z > uio->uio_resid) 384254721Semaste z = uio->uio_resid; 385254721Semaste mtx_unlock(&u->mutex); 386254721Semaste error = uiomove(u->buf + u->buf_rp, z, uio); 387254721Semaste mtx_lock(&u->mutex); 388254721Semaste if (error) 389254721Semaste break; 390254721Semaste u->buf_rp += z; 391254721Semaste u->buf_rp &= (u->bufsize - 1); 392254721Semaste } 393254721Semaste if (u->wreg[IMR1] == 0) 394254721Semaste write_reg(u, IMR1, 0x01); 395254721Semaste mtx_unlock(&u->mutex); 396254721Semaste return (error); 397254721Semaste} 398254721Semaste 399254721Semaste 400254721Semaste 401254721Semastestruct cdevsw gpib_cdevsw = { 402254721Semaste .d_version = D_VERSION, 403254721Semaste .d_name = "gpib", 404254721Semaste .d_open = gpib_open, 405254721Semaste .d_close = gpib_close, 406254721Semaste .d_read = gpib_read, 407254721Semaste}; 408254721Semaste 409254721Semastestatic void 410254721Semasteupd7210attach(struct upd7210 *u) 411254721Semaste{ 412254721Semaste int unit = 0; 413254721Semaste 414254721Semaste mtx_init(&u->mutex, "gpib", NULL, MTX_DEF); 415254721Semaste u->cdev = make_dev(&gpib_cdevsw, unit, 416254721Semaste UID_ROOT, GID_WHEEL, 0444, 417254721Semaste "gpib%ul", unit); 418254721Semaste u->cdev->si_drv1 = u; 419254721Semaste} 420254721Semaste