pcii.c revision 141123
1/*- 2 * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * Supported hardware: 27 * PCIIA compatible cards. 28 * 29 * Tested and known working: 30 * "B&C Microsystems PC488A-0" 31 * 32 * A whole lot of wonderful things could be written for GPIB, but for now 33 * I have just written it such that it is possible to capture data in the 34 * mode known as "unaddressed listen only mode". This is what many plotters 35 * and printers do on GPIB. This is enough to capture some output from 36 * various test instruments. 37 * 38 * If you are interested in working on this, send me email. 39 */ 40 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141123 2005-02-01 20:34:47Z phk $"); 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/conf.h> 47#include <sys/malloc.h> 48#include <sys/kernel.h> 49#include <sys/module.h> 50#include <sys/bus.h> 51#include <sys/mutex.h> 52#include <sys/uio.h> 53#include <machine/bus.h> 54#include <machine/resource.h> 55#include <sys/rman.h> 56 57/* ---> upd7210.h at some point. */ 58 59struct upd7210 { 60 bus_space_handle_t reg_handle[8]; 61 bus_space_tag_t reg_tag[8]; 62 u_int reg_offset[8]; 63 64 /* private stuff */ 65 struct mtx mutex; 66 uint8_t rreg[8]; 67 uint8_t wreg[8]; 68 69 int busy; 70 u_char *buf; 71 size_t bufsize; 72 u_int buf_wp; 73 u_int buf_rp; 74 struct cdev *cdev; 75}; 76 77static void upd7210intr(void *); 78static void upd7210attach(struct upd7210 *); 79 80 81/* ----> pcii.c */ 82 83struct pcii_softc { 84 int foo; 85 struct resource *port[8]; 86 struct resource *irq; 87 void *intr_handler; 88 struct upd7210 upd7210; 89}; 90 91#define HERE() printf("pcii HERE %s:%d\n", __FILE__, __LINE__) 92 93static devclass_t pcii_devclass; 94 95static int pcii_probe(device_t dev); 96static int pcii_attach(device_t dev); 97 98static device_method_t pcii_methods[] = { 99 DEVMETHOD(device_probe, pcii_probe), 100 DEVMETHOD(device_attach, pcii_attach), 101 DEVMETHOD(device_suspend, bus_generic_suspend), 102 DEVMETHOD(device_resume, bus_generic_resume), 103 104 { 0, 0 } 105}; 106 107static driver_t pcii_driver = { 108 "pcii", 109 pcii_methods, 110 sizeof(struct pcii_softc *), 111}; 112 113static int 114pcii_probe(device_t dev) 115{ 116 struct resource *port; 117 int rid; 118 u_long start, count; 119 int i, j, error = 0; 120 121 device_set_desc(dev, "PCII IEEE-4888 controller"); 122 123 rid = 0; 124 if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) 125 return ENXIO; 126 if ((start & 0x3ff) != 0x2e1) 127 return (ENXIO); 128 count = 1; 129 if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0) 130 return ENXIO; 131 for (i = 0; i < 8; i++) { 132 j = bus_set_resource(dev, SYS_RES_IOPORT, i, 133 start + 0x400 * i, 1); 134 if (j) { 135 error = ENXIO; 136 break; 137 } 138 rid = i; 139 port = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 140 &rid, RF_ACTIVE); 141 if (port == NULL) 142 return (ENXIO); 143 else 144 bus_release_resource(dev, SYS_RES_IOPORT, i, port); 145 } 146 147 rid = 0; 148 port = bus_alloc_resource_any(dev, 149 SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 150 if (port == NULL) 151 return (ENXIO); 152 bus_release_resource(dev, SYS_RES_IRQ, rid, port); 153 154 return (error); 155} 156 157static int 158pcii_attach(device_t dev) 159{ 160 struct pcii_softc *sc; 161 int unit; 162 int rid; 163 int i, error = 0; 164 165 unit = device_get_unit(dev); 166 sc = device_get_softc(dev); 167 memset(sc, 0, sizeof *sc); 168 169 device_set_desc(dev, "PCII IEEE-4888 controller"); 170 171 for (rid = 0; rid < 8; rid++) { 172 sc->port[rid] = bus_alloc_resource_any(dev, 173 SYS_RES_IOPORT, &rid, RF_ACTIVE); 174 if (sc->port[rid] == NULL) { 175 error = ENXIO; 176 break; 177 } 178 sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]); 179 sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]); 180 } 181 if (!error) { 182 rid = 0; 183 sc->irq = bus_alloc_resource_any(dev, 184 SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 185 if (sc->irq == NULL) { 186 error = ENXIO; 187 } else { 188 error = bus_setup_intr(dev, sc->irq, 189 INTR_TYPE_MISC | INTR_MPSAFE, 190 upd7210intr, &sc->upd7210, &sc->intr_handler); 191 } 192 } 193 if (error) { 194device_printf(dev, "error = %d\n", error); 195 for (i = 0; i < 8; i++) { 196 if (sc->port[i] == NULL) 197 break; 198 bus_release_resource(dev, SYS_RES_IOPORT, 199 0, sc->port[i]); 200 } 201 if (sc->intr_handler != NULL) 202 bus_teardown_intr(dev, sc->irq, sc->intr_handler); 203 if (sc->irq != NULL) 204 bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq); 205 } 206 upd7210attach(&sc->upd7210); 207 return (error); 208} 209 210DRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0); 211DRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0); 212 213/* ---> upd7210.c at some point */ 214 215enum upd7210_wreg { 216 CDOR = 0, /* Command/data out */ 217 IMR1 = 1, /* Interrupt mask 1 */ 218 IMR2 = 2, /* Interrupt mask 2 */ 219 SPMR = 3, /* Serial poll mode */ 220 ADMR = 4, /* Address mode */ 221 AUXMR = 5, /* Auxilliary mode */ 222 ADR = 6, /* Address */ 223 EOSR = 7, /* End-of-string */ 224}; 225 226enum upd7210_rreg { 227 DIR = 0, /* Data in */ 228 ISR1 = 1, /* Interrupt status 1 */ 229 ISR2 = 2, /* Interrupt status 2 */ 230 SPSR = 3, /* Serial poll status */ 231 ADSR = 4, /* Address status */ 232 CPTR = 5, /* Command pass though */ 233 ADR0 = 6, /* Address 1 */ 234 ADR1 = 7, /* Address 2 */ 235}; 236 237#define AUXMR_PON 0x00 238#define AUXMR_CRST 0x02 239#define AUXMR_RFD 0x03 240#define AUXMR_SEOI 0x06 241#define AUXMR_GTS 0x10 242#define AUXMR_TCA 0x11 243#define AUXMR_TCS 0x12 244#define AUXMR_TCSE 0x1a 245#define AUXMR_DSC 0x14 246#define AUXMR_CIFC 0x16 247#define AUXMR_SIFC 0x1e 248#define AUXMR_CREN 0x17 249#define AUXMR_SREN 0x1f 250#define AUXMR_ICTR 0x20 251#define AUXMR_PPR 0x60 252#define AUXMR_RA 0x80 253#define AUXMR_RB 0xa0 254#define AUXMR_RE 0xc0 255 256 257/* upd7210 generic stuff */ 258 259static u_int 260read_reg(struct upd7210 *u, enum upd7210_rreg reg) 261{ 262 u_int r; 263 264 r = bus_space_read_1( 265 u->reg_tag[reg], 266 u->reg_handle[reg], 267 u->reg_offset[reg]); 268 u->rreg[reg] = r; 269 return (r); 270} 271 272static void 273write_reg(struct upd7210 *u, enum upd7210_wreg reg, u_int val) 274{ 275 bus_space_write_1( 276 u->reg_tag[reg], 277 u->reg_handle[reg], 278 u->reg_offset[reg], val); 279 u->wreg[reg] = val; 280} 281 282static void 283upd7210intr(void *arg) 284{ 285 int i; 286 u_int isr1, isr2; 287 struct upd7210 *u; 288 289 u = arg; 290 mtx_lock(&u->mutex); 291 isr1 = read_reg(u, ISR1); 292 isr2 = read_reg(u, ISR2); 293 if (isr1 & 1) { 294 i = read_reg(u, DIR); 295 u->buf[u->buf_wp++] = i; 296 u->buf_wp &= (u->bufsize - 1); 297 i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1); 298 if (i < 8) 299 write_reg(u, IMR1, 0); 300 wakeup(u->buf); 301 } else { 302 printf("upd7210intr [%02x %02x %02x", 303 read_reg(u, DIR), isr1, isr2); 304 printf(" %02x %02x %02x %02x %02x]\n", 305 read_reg(u, SPSR), 306 read_reg(u, ADSR), 307 read_reg(u, CPTR), 308 read_reg(u, ADR0), 309 read_reg(u, ADR1)); 310 } 311 mtx_unlock(&u->mutex); 312} 313 314static int 315gpib_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 316{ 317 struct upd7210 *u; 318 319 u = dev->si_drv1; 320 321 mtx_lock(&u->mutex); 322 if (u->busy) 323 return (EBUSY); 324 u->busy = 1; 325 mtx_unlock(&u->mutex); 326 327 u->buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 328 u->bufsize = PAGE_SIZE; 329 u->buf_wp = 0; 330 u->buf_rp = 0; 331 332 write_reg(u, AUXMR, AUXMR_CRST); 333 DELAY(10000); 334 write_reg(u, AUXMR, AUXMR_ICTR | 8); 335 DELAY(1000); 336 write_reg(u, ADR, 0x60); 337 write_reg(u, ADR, 0xe0); 338 write_reg(u, ADMR, 0x70); 339 write_reg(u, AUXMR, AUXMR_PON); 340 write_reg(u, IMR1, 0x01); 341 return (0); 342} 343 344static int 345gpib_close(struct cdev *dev, int oflags, int devtype, struct thread *td) 346{ 347 struct upd7210 *u; 348 349 u = dev->si_drv1; 350 351 mtx_lock(&u->mutex); 352 u->busy = 0; 353 write_reg(u, AUXMR, AUXMR_CRST); 354 DELAY(10000); 355 write_reg(u, IMR1, 0x00); 356 write_reg(u, IMR2, 0x00); 357 free(u->buf, M_DEVBUF); 358 u->buf = NULL; 359 mtx_unlock(&u->mutex); 360 return (0); 361} 362 363static int 364gpib_read(struct cdev *dev, struct uio *uio, int ioflag) 365{ 366 struct upd7210 *u; 367 int error; 368 size_t z; 369 370 u = dev->si_drv1; 371 error = 0; 372 373 mtx_lock(&u->mutex); 374 while (u->buf_wp == u->buf_rp) { 375 error = msleep(u->buf, &u->mutex, PZERO | PCATCH, 376 "gpibrd", hz); 377 if (error && error != EWOULDBLOCK) { 378 mtx_unlock(&u->mutex); 379 return (error); 380 } 381 } 382 while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) { 383 if (u->buf_wp < u->buf_rp) 384 z = u->bufsize - u->buf_rp; 385 else 386 z = u->buf_wp - u->buf_rp; 387 if (z > uio->uio_resid) 388 z = uio->uio_resid; 389 mtx_unlock(&u->mutex); 390 error = uiomove(u->buf + u->buf_rp, z, uio); 391 mtx_lock(&u->mutex); 392 if (error) 393 break; 394 u->buf_rp += z; 395 u->buf_rp &= (u->bufsize - 1); 396 } 397 if (u->wreg[IMR1] == 0) 398 write_reg(u, IMR1, 0x01); 399 mtx_unlock(&u->mutex); 400 return (error); 401} 402 403 404 405struct cdevsw gpib_cdevsw = { 406 .d_version = D_VERSION, 407 .d_name = "gpib", 408 .d_open = gpib_open, 409 .d_close = gpib_close, 410 .d_read = gpib_read, 411}; 412 413static void 414upd7210attach(struct upd7210 *u) 415{ 416 int unit = 0; 417 418 mtx_init(&u->mutex, "gpib", NULL, MTX_DEF); 419 u->cdev = make_dev(&gpib_cdevsw, unit, 420 UID_ROOT, GID_WHEEL, 0444, 421 "gpib%ul", unit); 422 u->cdev->si_drv1 = u; 423} 424