1ed381522SMike Smith /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 40f210c92SNicolas Souchu * Copyright (c) 1997, 1998, 1999 Nicolas Souchu, Michael Smith 5ed381522SMike Smith * All rights reserved. 6ed381522SMike Smith * 7ed381522SMike Smith * Redistribution and use in source and binary forms, with or without 8ed381522SMike Smith * modification, are permitted provided that the following conditions 9ed381522SMike Smith * are met: 10ed381522SMike Smith * 1. Redistributions of source code must retain the above copyright 11ed381522SMike Smith * notice, this list of conditions and the following disclaimer. 12ed381522SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 13ed381522SMike Smith * notice, this list of conditions and the following disclaimer in the 14ed381522SMike Smith * documentation and/or other materials provided with the distribution. 15ed381522SMike Smith * 16ed381522SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17ed381522SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18ed381522SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ed381522SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20ed381522SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21ed381522SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22ed381522SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23ed381522SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24ed381522SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25ed381522SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26ed381522SMike Smith * SUCH DAMAGE. 27ed381522SMike Smith * 28ed381522SMike Smith * 29ed381522SMike Smith */ 30aad970f1SDavid E. O'Brien 31aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 330f210c92SNicolas Souchu #include "opt_ppb_1284.h" 340f210c92SNicolas Souchu 35ed381522SMike Smith #include <sys/param.h> 36ed381522SMike Smith #include <sys/systm.h> 370f210c92SNicolas Souchu #include <sys/module.h> 380f210c92SNicolas Souchu #include <sys/bus.h> 39ed381522SMike Smith #include <sys/conf.h> 40ed381522SMike Smith #include <sys/kernel.h> 412067d312SJohn Baldwin #include <sys/lock.h> 422067d312SJohn Baldwin #include <sys/sx.h> 43bc35c174SNicolas Souchu #include <sys/uio.h> 446f34dba9SMike Smith #include <sys/fcntl.h> 45ed381522SMike Smith 460f210c92SNicolas Souchu #include <machine/bus.h> 470f210c92SNicolas Souchu #include <machine/resource.h> 480f210c92SNicolas Souchu #include <sys/rman.h> 49bc35c174SNicolas Souchu 50ed381522SMike Smith #include <dev/ppbus/ppbconf.h> 51bc35c174SNicolas Souchu #include <dev/ppbus/ppb_msq.h> 52bc35c174SNicolas Souchu 53bc35c174SNicolas Souchu #ifdef PERIPH_1284 542067d312SJohn Baldwin #include <sys/malloc.h> 55bc35c174SNicolas Souchu #include <dev/ppbus/ppb_1284.h> 56bc35c174SNicolas Souchu #endif 57bc35c174SNicolas Souchu 586f34dba9SMike Smith #include <dev/ppbus/ppi.h> 596f34dba9SMike Smith 600f210c92SNicolas Souchu #include "ppbus_if.h" 610f210c92SNicolas Souchu 620f210c92SNicolas Souchu #include <dev/ppbus/ppbio.h> 630f210c92SNicolas Souchu 64bc35c174SNicolas Souchu #define BUFSIZE 512 65ed381522SMike Smith 66e51b0386SMike Smith struct ppi_data { 67ae6b868aSJohn Baldwin device_t ppi_device; 68ae6b868aSJohn Baldwin struct cdev *ppi_cdev; 692067d312SJohn Baldwin struct sx ppi_lock; 706f34dba9SMike Smith int ppi_flags; 716f34dba9SMike Smith #define HAVE_PPBUS (1<<0) 72bc35c174SNicolas Souchu 73bc35c174SNicolas Souchu int ppi_mode; /* IEEE1284 mode */ 74bc35c174SNicolas Souchu char ppi_buffer[BUFSIZE]; 75e51b0386SMike Smith 76c47eb96cSNick Hibma #ifdef PERIPH_1284 770f210c92SNicolas Souchu struct resource *intr_resource; /* interrupt resource */ 780f210c92SNicolas Souchu void *intr_cookie; /* interrupt registration cookie */ 79c47eb96cSNick Hibma #endif /* PERIPH_1284 */ 80e51b0386SMike Smith }; 81e51b0386SMike Smith 820f210c92SNicolas Souchu #define DEVTOSOFTC(dev) \ 830f210c92SNicolas Souchu ((struct ppi_data *)device_get_softc(dev)) 84ed381522SMike Smith 850f210c92SNicolas Souchu static devclass_t ppi_devclass; 86ed381522SMike Smith 872067d312SJohn Baldwin #ifdef PERIPH_1284 882067d312SJohn Baldwin static void ppiintr(void *arg); 892067d312SJohn Baldwin #endif 902067d312SJohn Baldwin 91ed381522SMike Smith static d_open_t ppiopen; 92ed381522SMike Smith static d_close_t ppiclose; 93ed381522SMike Smith static d_ioctl_t ppiioctl; 94bc35c174SNicolas Souchu static d_write_t ppiwrite; 95bc35c174SNicolas Souchu static d_read_t ppiread; 96ed381522SMike Smith 974e2f199eSPoul-Henning Kamp static struct cdevsw ppi_cdevsw = { 98dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 997ac40f5fSPoul-Henning Kamp .d_open = ppiopen, 1007ac40f5fSPoul-Henning Kamp .d_close = ppiclose, 1017ac40f5fSPoul-Henning Kamp .d_read = ppiread, 1027ac40f5fSPoul-Henning Kamp .d_write = ppiwrite, 1037ac40f5fSPoul-Henning Kamp .d_ioctl = ppiioctl, 1047ac40f5fSPoul-Henning Kamp .d_name = "ppi", 1054e2f199eSPoul-Henning Kamp }; 106ed381522SMike Smith 107bc35c174SNicolas Souchu #ifdef PERIPH_1284 108bc35c174SNicolas Souchu 109bc35c174SNicolas Souchu static void 1100f210c92SNicolas Souchu ppi_enable_intr(device_t ppidev) 111bc35c174SNicolas Souchu { 112bc35c174SNicolas Souchu char r; 1130f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 114bc35c174SNicolas Souchu 1150f210c92SNicolas Souchu r = ppb_rctr(ppbus); 1160f210c92SNicolas Souchu ppb_wctr(ppbus, r | IRQENABLE); 117bc35c174SNicolas Souchu 118bc35c174SNicolas Souchu return; 119bc35c174SNicolas Souchu } 120bc35c174SNicolas Souchu 121bc35c174SNicolas Souchu static void 1220f210c92SNicolas Souchu ppi_disable_intr(device_t ppidev) 123bc35c174SNicolas Souchu { 124bc35c174SNicolas Souchu char r; 1250f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 126bc35c174SNicolas Souchu 1270f210c92SNicolas Souchu r = ppb_rctr(ppbus); 1280f210c92SNicolas Souchu ppb_wctr(ppbus, r & ~IRQENABLE); 129bc35c174SNicolas Souchu 130bc35c174SNicolas Souchu return; 131bc35c174SNicolas Souchu } 132bc35c174SNicolas Souchu 133bc35c174SNicolas Souchu #endif /* PERIPH_1284 */ 134bc35c174SNicolas Souchu 1350f063508SPeter Wemm static void 1360f063508SPeter Wemm ppi_identify(driver_t *driver, device_t parent) 1370f063508SPeter Wemm { 1380f063508SPeter Wemm 139a5c7e3bbSGuido van Rooij device_t dev; 140a5c7e3bbSGuido van Rooij 14157fb5e60SJohn Baldwin dev = device_find_child(parent, "ppi", -1); 142a5c7e3bbSGuido van Rooij if (!dev) 143338cad62SBernd Walter BUS_ADD_CHILD(parent, 0, "ppi", -1); 1440f063508SPeter Wemm } 1450f063508SPeter Wemm 146ed381522SMike Smith /* 1470f210c92SNicolas Souchu * ppi_probe() 148ed381522SMike Smith */ 1490f210c92SNicolas Souchu static int 1500f210c92SNicolas Souchu ppi_probe(device_t dev) 151ed381522SMike Smith { 152ed381522SMike Smith struct ppi_data *ppi; 1532447bec8SPoul-Henning Kamp 1540f210c92SNicolas Souchu /* probe is always ok */ 1550f210c92SNicolas Souchu device_set_desc(dev, "Parallel I/O"); 1560f210c92SNicolas Souchu 1570f210c92SNicolas Souchu ppi = DEVTOSOFTC(dev); 158ed381522SMike Smith 1590f210c92SNicolas Souchu return (0); 160ed381522SMike Smith } 161ed381522SMike Smith 162ed381522SMike Smith /* 1630f210c92SNicolas Souchu * ppi_attach() 164ed381522SMike Smith */ 1650f210c92SNicolas Souchu static int 1660f210c92SNicolas Souchu ppi_attach(device_t dev) 1670f210c92SNicolas Souchu { 168ae6b868aSJohn Baldwin struct ppi_data *ppi = DEVTOSOFTC(dev); 169c47eb96cSNick Hibma #ifdef PERIPH_1284 1702067d312SJohn Baldwin int error, rid = 0; 171ed381522SMike Smith 1720f210c92SNicolas Souchu /* declare our interrupt handler */ 173ca3d3795SJohn Baldwin ppi->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 174ca3d3795SJohn Baldwin RF_ACTIVE); 1752067d312SJohn Baldwin if (ppi->intr_resource) { 1762067d312SJohn Baldwin /* register our interrupt handler */ 1772067d312SJohn Baldwin error = bus_setup_intr(dev, ppi->intr_resource, 1782067d312SJohn Baldwin INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppiintr, dev, 1792067d312SJohn Baldwin &ppi->intr_cookie); 1802067d312SJohn Baldwin if (error) { 1812067d312SJohn Baldwin bus_release_resource(dev, SYS_RES_IRQ, rid, 1822067d312SJohn Baldwin ppi->intr_resource); 1832067d312SJohn Baldwin device_printf(dev, 1842067d312SJohn Baldwin "Unable to register interrupt handler\n"); 1852067d312SJohn Baldwin return (error); 1862067d312SJohn Baldwin } 1872067d312SJohn Baldwin } 188c47eb96cSNick Hibma #endif /* PERIPH_1284 */ 1890f210c92SNicolas Souchu 1902067d312SJohn Baldwin sx_init(&ppi->ppi_lock, "ppi"); 191ae6b868aSJohn Baldwin ppi->ppi_cdev = make_dev(&ppi_cdevsw, device_get_unit(dev), 1920f210c92SNicolas Souchu UID_ROOT, GID_WHEEL, 1930f210c92SNicolas Souchu 0600, "ppi%d", device_get_unit(dev)); 194ae6b868aSJohn Baldwin if (ppi->ppi_cdev == NULL) { 195f32b2a16SJohn Baldwin device_printf(dev, "Failed to create character device\n"); 196ae6b868aSJohn Baldwin return (ENXIO); 197ae6b868aSJohn Baldwin } 198ae6b868aSJohn Baldwin ppi->ppi_cdev->si_drv1 = ppi; 199ae6b868aSJohn Baldwin ppi->ppi_device = dev; 2000f210c92SNicolas Souchu 2010f210c92SNicolas Souchu return (0); 202ed381522SMike Smith } 203ed381522SMike Smith 2042067d312SJohn Baldwin static int 2052067d312SJohn Baldwin ppi_detach(device_t dev) 2062067d312SJohn Baldwin { 2072067d312SJohn Baldwin struct ppi_data *ppi = DEVTOSOFTC(dev); 2082067d312SJohn Baldwin 2092067d312SJohn Baldwin destroy_dev(ppi->ppi_cdev); 2102067d312SJohn Baldwin #ifdef PERIPH_1284 2112067d312SJohn Baldwin if (ppi->intr_resource != NULL) { 2122067d312SJohn Baldwin bus_teardown_intr(dev, ppi->intr_resource, ppi->intr_cookie); 2132067d312SJohn Baldwin bus_release_resource(dev, SYS_RES_IRQ, 0, ppi->intr_resource); 2142067d312SJohn Baldwin } 2152067d312SJohn Baldwin #endif 2162067d312SJohn Baldwin sx_destroy(&ppi->ppi_lock); 2172067d312SJohn Baldwin return (0); 2182067d312SJohn Baldwin } 2192067d312SJohn Baldwin 220c47eb96cSNick Hibma #ifdef PERIPH_1284 221bc35c174SNicolas Souchu /* 222bc35c174SNicolas Souchu * Cable 223bc35c174SNicolas Souchu * ----- 224bc35c174SNicolas Souchu * 225bc35c174SNicolas Souchu * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks: 226bc35c174SNicolas Souchu * 227bc35c174SNicolas Souchu * nStrobe <-> nAck 1 <-> 10 228bc35c174SNicolas Souchu * nAutofd <-> Busy 11 <-> 14 229bc35c174SNicolas Souchu * nSelectin <-> Select 17 <-> 13 230bc35c174SNicolas Souchu * nInit <-> nFault 15 <-> 16 231bc35c174SNicolas Souchu * 232bc35c174SNicolas Souchu */ 233ed381522SMike Smith static void 2340f210c92SNicolas Souchu ppiintr(void *arg) 235ed381522SMike Smith { 2360f210c92SNicolas Souchu device_t ppidev = (device_t)arg; 2370f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 2380f210c92SNicolas Souchu struct ppi_data *ppi = DEVTOSOFTC(ppidev); 239bc35c174SNicolas Souchu 2402067d312SJohn Baldwin ppb_assert_locked(ppbus); 2410f210c92SNicolas Souchu ppi_disable_intr(ppidev); 242bc35c174SNicolas Souchu 2430f210c92SNicolas Souchu switch (ppb_1284_get_state(ppbus)) { 244bc35c174SNicolas Souchu 245d64ada50SJens Schweikhardt /* accept IEEE1284 negotiation then wakeup a waiting process to 246d64ada50SJens Schweikhardt * continue negotiation at process level */ 247bc35c174SNicolas Souchu case PPB_FORWARD_IDLE: 248bc35c174SNicolas Souchu /* Event 1 */ 2490f210c92SNicolas Souchu if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) == 250bc35c174SNicolas Souchu (SELECT | nBUSY)) { 251d64ada50SJens Schweikhardt /* IEEE1284 negotiation */ 252bc35c174SNicolas Souchu #ifdef DEBUG_1284 253bc35c174SNicolas Souchu printf("N"); 254bc35c174SNicolas Souchu #endif 255bc35c174SNicolas Souchu 256bc35c174SNicolas Souchu /* Event 2 - prepare for reading the ext. value */ 2570f210c92SNicolas Souchu ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN); 258bc35c174SNicolas Souchu 2590f210c92SNicolas Souchu ppb_1284_set_state(ppbus, PPB_NEGOCIATION); 260bc35c174SNicolas Souchu 261bc35c174SNicolas Souchu } else { 262bc35c174SNicolas Souchu #ifdef DEBUG_1284 2630f210c92SNicolas Souchu printf("0x%x", ppb_rstr(ppbus)); 264bc35c174SNicolas Souchu #endif 2650f210c92SNicolas Souchu ppb_peripheral_terminate(ppbus, PPB_DONTWAIT); 266bc35c174SNicolas Souchu break; 267bc35c174SNicolas Souchu } 268bc35c174SNicolas Souchu 269d64ada50SJens Schweikhardt /* wake up any process waiting for negotiation from 270bc35c174SNicolas Souchu * remote master host */ 271bc35c174SNicolas Souchu 272bc35c174SNicolas Souchu /* XXX should set a variable to warn the process about 273bc35c174SNicolas Souchu * the interrupt */ 274bc35c174SNicolas Souchu 275bc35c174SNicolas Souchu wakeup(ppi); 276bc35c174SNicolas Souchu break; 277bc35c174SNicolas Souchu default: 278bc35c174SNicolas Souchu #ifdef DEBUG_1284 27999904c75SPeter Wemm printf("?%d", ppb_1284_get_state(ppbus)); 280bc35c174SNicolas Souchu #endif 2810f210c92SNicolas Souchu ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE); 2820f210c92SNicolas Souchu ppb_set_mode(ppbus, PPB_COMPATIBLE); 283bc35c174SNicolas Souchu break; 284bc35c174SNicolas Souchu } 285bc35c174SNicolas Souchu 2860f210c92SNicolas Souchu ppi_enable_intr(ppidev); 287bc35c174SNicolas Souchu 288ed381522SMike Smith return; 289ed381522SMike Smith } 290c47eb96cSNick Hibma #endif /* PERIPH_1284 */ 291ed381522SMike Smith 292ed381522SMike Smith static int 29389c9c53dSPoul-Henning Kamp ppiopen(struct cdev *dev, int flags, int fmt, struct thread *td) 294ed381522SMike Smith { 295ae6b868aSJohn Baldwin struct ppi_data *ppi = dev->si_drv1; 296ae6b868aSJohn Baldwin device_t ppidev = ppi->ppi_device; 2970f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 2986f34dba9SMike Smith int res; 299e51b0386SMike Smith 3002067d312SJohn Baldwin sx_xlock(&ppi->ppi_lock); 301bc35c174SNicolas Souchu if (!(ppi->ppi_flags & HAVE_PPBUS)) { 3022067d312SJohn Baldwin ppb_lock(ppbus); 3032067d312SJohn Baldwin res = ppb_request_bus(ppbus, ppidev, 3042067d312SJohn Baldwin (flags & O_NONBLOCK) ? PPB_DONTWAIT : PPB_WAIT | PPB_INTR); 3052067d312SJohn Baldwin ppb_unlock(ppbus); 3062067d312SJohn Baldwin if (res) { 3072067d312SJohn Baldwin sx_xunlock(&ppi->ppi_lock); 3086f34dba9SMike Smith return (res); 3092067d312SJohn Baldwin } 310e51b0386SMike Smith 3116f34dba9SMike Smith ppi->ppi_flags |= HAVE_PPBUS; 312bc35c174SNicolas Souchu } 3132067d312SJohn Baldwin sx_xunlock(&ppi->ppi_lock); 314bc35c174SNicolas Souchu 3156f34dba9SMike Smith return (0); 316ed381522SMike Smith } 317ed381522SMike Smith 318ed381522SMike Smith static int 31989c9c53dSPoul-Henning Kamp ppiclose(struct cdev *dev, int flags, int fmt, struct thread *td) 320ed381522SMike Smith { 321ae6b868aSJohn Baldwin struct ppi_data *ppi = dev->si_drv1; 322ae6b868aSJohn Baldwin device_t ppidev = ppi->ppi_device; 3230f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 3246f34dba9SMike Smith 3252067d312SJohn Baldwin sx_xlock(&ppi->ppi_lock); 3262067d312SJohn Baldwin ppb_lock(ppbus); 327bc35c174SNicolas Souchu #ifdef PERIPH_1284 3280f210c92SNicolas Souchu switch (ppb_1284_get_state(ppbus)) { 329bc35c174SNicolas Souchu case PPB_PERIPHERAL_IDLE: 3300f210c92SNicolas Souchu ppb_peripheral_terminate(ppbus, 0); 331bc35c174SNicolas Souchu break; 332bc35c174SNicolas Souchu case PPB_REVERSE_IDLE: 333bc35c174SNicolas Souchu case PPB_EPP_IDLE: 334bc35c174SNicolas Souchu case PPB_ECP_FORWARD_IDLE: 335bc35c174SNicolas Souchu default: 3360f210c92SNicolas Souchu ppb_1284_terminate(ppbus); 337bc35c174SNicolas Souchu break; 338bc35c174SNicolas Souchu } 339bc35c174SNicolas Souchu #endif /* PERIPH_1284 */ 340bc35c174SNicolas Souchu 3410f210c92SNicolas Souchu /* unregistration of interrupt forced by release */ 3420f210c92SNicolas Souchu ppb_release_bus(ppbus, ppidev); 3432067d312SJohn Baldwin ppb_unlock(ppbus); 3440f210c92SNicolas Souchu 3456f34dba9SMike Smith ppi->ppi_flags &= ~HAVE_PPBUS; 3462067d312SJohn Baldwin sx_xunlock(&ppi->ppi_lock); 347bc35c174SNicolas Souchu 3486f34dba9SMike Smith return (0); 349ed381522SMike Smith } 350ed381522SMike Smith 351bc35c174SNicolas Souchu /* 352bc35c174SNicolas Souchu * ppiread() 353bc35c174SNicolas Souchu * 354bc35c174SNicolas Souchu * IEEE1284 compliant read. 355bc35c174SNicolas Souchu * 356d64ada50SJens Schweikhardt * First, try negotiation to BYTE then NIBBLE mode 357bc35c174SNicolas Souchu * If no data is available, wait for it otherwise transfer as much as possible 358bc35c174SNicolas Souchu */ 359bc35c174SNicolas Souchu static int 36089c9c53dSPoul-Henning Kamp ppiread(struct cdev *dev, struct uio *uio, int ioflag) 361bc35c174SNicolas Souchu { 362bc35c174SNicolas Souchu #ifdef PERIPH_1284 363ae6b868aSJohn Baldwin struct ppi_data *ppi = dev->si_drv1; 364ae6b868aSJohn Baldwin device_t ppidev = ppi->ppi_device; 3650f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 366bc35c174SNicolas Souchu int len, error = 0; 3672067d312SJohn Baldwin char *buffer; 368bc35c174SNicolas Souchu 3692067d312SJohn Baldwin buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); 3702067d312SJohn Baldwin 3712067d312SJohn Baldwin ppb_lock(ppbus); 3720f210c92SNicolas Souchu switch (ppb_1284_get_state(ppbus)) { 373bc35c174SNicolas Souchu case PPB_PERIPHERAL_IDLE: 3740f210c92SNicolas Souchu ppb_peripheral_terminate(ppbus, 0); 37593b0017fSPhilippe Charnier /* FALLTHROUGH */ 376bc35c174SNicolas Souchu 377bc35c174SNicolas Souchu case PPB_FORWARD_IDLE: 378d64ada50SJens Schweikhardt /* if can't negotiate NIBBLE mode then try BYTE mode, 379bc35c174SNicolas Souchu * the peripheral may be a computer 380bc35c174SNicolas Souchu */ 3810f210c92SNicolas Souchu if ((ppb_1284_negociate(ppbus, 382bc35c174SNicolas Souchu ppi->ppi_mode = PPB_NIBBLE, 0))) { 383bc35c174SNicolas Souchu 384bc35c174SNicolas Souchu /* XXX Wait 2 seconds to let the remote host some 385bc35c174SNicolas Souchu * time to terminate its interrupt 386bc35c174SNicolas Souchu */ 3872067d312SJohn Baldwin ppb_sleep(ppbus, ppi, PPBPRI, "ppiread", 2 * hz); 388bc35c174SNicolas Souchu 3890f210c92SNicolas Souchu if ((error = ppb_1284_negociate(ppbus, 3902067d312SJohn Baldwin ppi->ppi_mode = PPB_BYTE, 0))) { 3912067d312SJohn Baldwin ppb_unlock(ppbus); 3922067d312SJohn Baldwin free(buffer, M_DEVBUF); 393bc35c174SNicolas Souchu return (error); 394bc35c174SNicolas Souchu } 3952067d312SJohn Baldwin } 396bc35c174SNicolas Souchu break; 397bc35c174SNicolas Souchu 398bc35c174SNicolas Souchu case PPB_REVERSE_IDLE: 399bc35c174SNicolas Souchu case PPB_EPP_IDLE: 400bc35c174SNicolas Souchu case PPB_ECP_FORWARD_IDLE: 401bc35c174SNicolas Souchu default: 402bc35c174SNicolas Souchu break; 403bc35c174SNicolas Souchu } 404bc35c174SNicolas Souchu 405bc35c174SNicolas Souchu #ifdef DEBUG_1284 406bc35c174SNicolas Souchu printf("N"); 407bc35c174SNicolas Souchu #endif 408bc35c174SNicolas Souchu /* read data */ 409bc35c174SNicolas Souchu len = 0; 410bc35c174SNicolas Souchu while (uio->uio_resid) { 4112067d312SJohn Baldwin error = ppb_1284_read(ppbus, ppi->ppi_mode, 4122067d312SJohn Baldwin buffer, min(BUFSIZE, uio->uio_resid), &len); 4132067d312SJohn Baldwin ppb_unlock(ppbus); 4142067d312SJohn Baldwin if (error) 415bc35c174SNicolas Souchu goto error; 416bc35c174SNicolas Souchu 417bc35c174SNicolas Souchu if (!len) 418bc35c174SNicolas Souchu goto error; /* no more data */ 419bc35c174SNicolas Souchu 420bc35c174SNicolas Souchu #ifdef DEBUG_1284 421bc35c174SNicolas Souchu printf("d"); 422bc35c174SNicolas Souchu #endif 4232067d312SJohn Baldwin if ((error = uiomove(buffer, len, uio))) 424bc35c174SNicolas Souchu goto error; 4252067d312SJohn Baldwin ppb_lock(ppbus); 426bc35c174SNicolas Souchu } 4272067d312SJohn Baldwin ppb_unlock(ppbus); 428bc35c174SNicolas Souchu 429bc35c174SNicolas Souchu error: 4302067d312SJohn Baldwin free(buffer, M_DEVBUF); 431bc35c174SNicolas Souchu #else /* PERIPH_1284 */ 432bc35c174SNicolas Souchu int error = ENODEV; 433bc35c174SNicolas Souchu #endif 434bc35c174SNicolas Souchu 435bc35c174SNicolas Souchu return (error); 436bc35c174SNicolas Souchu } 437bc35c174SNicolas Souchu 438bc35c174SNicolas Souchu /* 439bc35c174SNicolas Souchu * ppiwrite() 440bc35c174SNicolas Souchu * 441bc35c174SNicolas Souchu * IEEE1284 compliant write 442bc35c174SNicolas Souchu * 443bc35c174SNicolas Souchu * Actually, this is the peripheral side of a remote IEEE1284 read 444bc35c174SNicolas Souchu * 445d64ada50SJens Schweikhardt * The first part of the negotiation (IEEE1284 device detection) is 446bc35c174SNicolas Souchu * done at interrupt level, then the remaining is done by the writing 447bc35c174SNicolas Souchu * process 448bc35c174SNicolas Souchu * 449d64ada50SJens Schweikhardt * Once negotiation done, transfer data 450bc35c174SNicolas Souchu */ 451bc35c174SNicolas Souchu static int 45289c9c53dSPoul-Henning Kamp ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) 453bc35c174SNicolas Souchu { 454bc35c174SNicolas Souchu #ifdef PERIPH_1284 455ae6b868aSJohn Baldwin struct ppi_data *ppi = dev->si_drv1; 456ae6b868aSJohn Baldwin device_t ppidev = ppi->ppi_device; 4570f210c92SNicolas Souchu device_t ppbus = device_get_parent(ppidev); 458bc35c174SNicolas Souchu int len, error = 0, sent; 4592067d312SJohn Baldwin char *buffer; 460bc35c174SNicolas Souchu 461bc35c174SNicolas Souchu #if 0 462bc35c174SNicolas Souchu int ret; 463bc35c174SNicolas Souchu 464bc35c174SNicolas Souchu #define ADDRESS MS_PARAM(0, 0, MS_TYP_PTR) 465bc35c174SNicolas Souchu #define LENGTH MS_PARAM(0, 1, MS_TYP_INT) 466bc35c174SNicolas Souchu 467bc35c174SNicolas Souchu struct ppb_microseq msq[] = { 468bc35c174SNicolas Souchu { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } }, 469bc35c174SNicolas Souchu MS_RET(0) 470bc35c174SNicolas Souchu }; 471bc35c174SNicolas Souchu 4722067d312SJohn Baldwin buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); 4732067d312SJohn Baldwin ppb_lock(ppbus); 4742067d312SJohn Baldwin 475d64ada50SJens Schweikhardt /* negotiate ECP mode */ 4760f210c92SNicolas Souchu if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) { 477d64ada50SJens Schweikhardt printf("ppiwrite: ECP negotiation failed\n"); 478bc35c174SNicolas Souchu } 479bc35c174SNicolas Souchu 480bc35c174SNicolas Souchu while (!error && (len = min(uio->uio_resid, BUFSIZE))) { 4812067d312SJohn Baldwin ppb_unlock(ppbus); 4822067d312SJohn Baldwin uiomove(buffer, len, uio); 483bc35c174SNicolas Souchu 4842067d312SJohn Baldwin ppb_MS_init_msq(msq, 2, ADDRESS, buffer, LENGTH, len); 485bc35c174SNicolas Souchu 4862067d312SJohn Baldwin ppb_lock(ppbus); 4870f210c92SNicolas Souchu error = ppb_MS_microseq(ppbus, msq, &ret); 488bc35c174SNicolas Souchu } 4892067d312SJohn Baldwin #else 4902067d312SJohn Baldwin buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); 4912067d312SJohn Baldwin ppb_lock(ppbus); 492bc35c174SNicolas Souchu #endif 493bc35c174SNicolas Souchu 494bc35c174SNicolas Souchu /* we have to be peripheral to be able to send data, so 495bc35c174SNicolas Souchu * wait for the appropriate state 496bc35c174SNicolas Souchu */ 497bdcee5cfSNicolas Souchu if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION) 4980f210c92SNicolas Souchu ppb_1284_terminate(ppbus); 499bc35c174SNicolas Souchu 500bdcee5cfSNicolas Souchu while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) { 501bc35c174SNicolas Souchu /* XXX should check a variable before sleeping */ 502bc35c174SNicolas Souchu #ifdef DEBUG_1284 503bc35c174SNicolas Souchu printf("s"); 504bc35c174SNicolas Souchu #endif 505bc35c174SNicolas Souchu 5060f210c92SNicolas Souchu ppi_enable_intr(ppidev); 507bc35c174SNicolas Souchu 508d64ada50SJens Schweikhardt /* sleep until IEEE1284 negotiation starts */ 5092067d312SJohn Baldwin error = ppb_sleep(ppbus, ppi, PCATCH | PPBPRI, "ppiwrite", 0); 510bc35c174SNicolas Souchu 511bc35c174SNicolas Souchu switch (error) { 512bc35c174SNicolas Souchu case 0: 513d64ada50SJens Schweikhardt /* negotiate peripheral side with BYTE mode */ 5140f210c92SNicolas Souchu ppb_peripheral_negociate(ppbus, PPB_BYTE, 0); 515bc35c174SNicolas Souchu break; 516bc35c174SNicolas Souchu case EWOULDBLOCK: 517bc35c174SNicolas Souchu break; 518bc35c174SNicolas Souchu default: 519bc35c174SNicolas Souchu goto error; 520bc35c174SNicolas Souchu } 521bc35c174SNicolas Souchu } 522bc35c174SNicolas Souchu #ifdef DEBUG_1284 523bc35c174SNicolas Souchu printf("N"); 524bc35c174SNicolas Souchu #endif 525bc35c174SNicolas Souchu 526d64ada50SJens Schweikhardt /* negotiation done, write bytes to master host */ 527d254af07SMatthew Dillon while ((len = min(uio->uio_resid, BUFSIZE)) != 0) { 5282067d312SJohn Baldwin ppb_unlock(ppbus); 5292067d312SJohn Baldwin uiomove(buffer, len, uio); 5302067d312SJohn Baldwin ppb_lock(ppbus); 5310f210c92SNicolas Souchu if ((error = byte_peripheral_write(ppbus, 5322067d312SJohn Baldwin buffer, len, &sent))) 533bc35c174SNicolas Souchu goto error; 534bc35c174SNicolas Souchu #ifdef DEBUG_1284 535bc35c174SNicolas Souchu printf("d"); 536bc35c174SNicolas Souchu #endif 537bc35c174SNicolas Souchu } 538bc35c174SNicolas Souchu 539bc35c174SNicolas Souchu error: 5402067d312SJohn Baldwin ppb_unlock(ppbus); 5412067d312SJohn Baldwin free(buffer, M_DEVBUF); 542bc35c174SNicolas Souchu #else /* PERIPH_1284 */ 543bc35c174SNicolas Souchu int error = ENODEV; 544bc35c174SNicolas Souchu #endif 545bc35c174SNicolas Souchu 546bc35c174SNicolas Souchu return (error); 547bc35c174SNicolas Souchu } 548bc35c174SNicolas Souchu 549ed381522SMike Smith static int 55089c9c53dSPoul-Henning Kamp ppiioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) 551ed381522SMike Smith { 552ae6b868aSJohn Baldwin struct ppi_data *ppi = dev->si_drv1; 553ae6b868aSJohn Baldwin device_t ppidev = ppi->ppi_device; 554f32b2a16SJohn Baldwin device_t ppbus = device_get_parent(ppidev); 5556f34dba9SMike Smith int error = 0; 5566f34dba9SMike Smith u_int8_t *val = (u_int8_t *)data; 5576f34dba9SMike Smith 5582067d312SJohn Baldwin ppb_lock(ppbus); 5596f34dba9SMike Smith switch (cmd) { 5606f34dba9SMike Smith 5616f34dba9SMike Smith case PPIGDATA: /* get data register */ 5620f210c92SNicolas Souchu *val = ppb_rdtr(ppbus); 5636f34dba9SMike Smith break; 5646f34dba9SMike Smith case PPIGSTATUS: /* get status bits */ 5650f210c92SNicolas Souchu *val = ppb_rstr(ppbus); 5666f34dba9SMike Smith break; 5676f34dba9SMike Smith case PPIGCTRL: /* get control bits */ 5680f210c92SNicolas Souchu *val = ppb_rctr(ppbus); 5696f34dba9SMike Smith break; 57020240fa3SNicolas Souchu case PPIGEPPD: /* get EPP data bits */ 5710f210c92SNicolas Souchu *val = ppb_repp_D(ppbus); 5726f34dba9SMike Smith break; 5736f34dba9SMike Smith case PPIGECR: /* get ECP bits */ 5740f210c92SNicolas Souchu *val = ppb_recr(ppbus); 5756f34dba9SMike Smith break; 5766f34dba9SMike Smith case PPIGFIFO: /* read FIFO */ 5770f210c92SNicolas Souchu *val = ppb_rfifo(ppbus); 5786f34dba9SMike Smith break; 5796f34dba9SMike Smith case PPISDATA: /* set data register */ 5800f210c92SNicolas Souchu ppb_wdtr(ppbus, *val); 5816f34dba9SMike Smith break; 5826f34dba9SMike Smith case PPISSTATUS: /* set status bits */ 5830f210c92SNicolas Souchu ppb_wstr(ppbus, *val); 5846f34dba9SMike Smith break; 5856f34dba9SMike Smith case PPISCTRL: /* set control bits */ 5860f210c92SNicolas Souchu ppb_wctr(ppbus, *val); 5876f34dba9SMike Smith break; 58820240fa3SNicolas Souchu case PPISEPPD: /* set EPP data bits */ 5890f210c92SNicolas Souchu ppb_wepp_D(ppbus, *val); 5906f34dba9SMike Smith break; 5916f34dba9SMike Smith case PPISECR: /* set ECP bits */ 5920f210c92SNicolas Souchu ppb_wecr(ppbus, *val); 5936f34dba9SMike Smith break; 5946f34dba9SMike Smith case PPISFIFO: /* write FIFO */ 5950f210c92SNicolas Souchu ppb_wfifo(ppbus, *val); 5966f34dba9SMike Smith break; 59720240fa3SNicolas Souchu case PPIGEPPA: /* get EPP address bits */ 5980f210c92SNicolas Souchu *val = ppb_repp_A(ppbus); 59920240fa3SNicolas Souchu break; 60020240fa3SNicolas Souchu case PPISEPPA: /* set EPP address bits */ 6010f210c92SNicolas Souchu ppb_wepp_A(ppbus, *val); 60220240fa3SNicolas Souchu break; 6036f34dba9SMike Smith default: 6046f34dba9SMike Smith error = ENOTTY; 6056f34dba9SMike Smith break; 6066f34dba9SMike Smith } 6072067d312SJohn Baldwin ppb_unlock(ppbus); 6086f34dba9SMike Smith 6096f34dba9SMike Smith return (error); 610ed381522SMike Smith } 611ed381522SMike Smith 6120f063508SPeter Wemm static device_method_t ppi_methods[] = { 6130f063508SPeter Wemm /* device interface */ 6140f063508SPeter Wemm DEVMETHOD(device_identify, ppi_identify), 6150f063508SPeter Wemm DEVMETHOD(device_probe, ppi_probe), 6160f063508SPeter Wemm DEVMETHOD(device_attach, ppi_attach), 6172067d312SJohn Baldwin DEVMETHOD(device_detach, ppi_detach), 6180f210c92SNicolas Souchu 6190f063508SPeter Wemm { 0, 0 } 6200f063508SPeter Wemm }; 6210f063508SPeter Wemm 6220f063508SPeter Wemm static driver_t ppi_driver = { 6230f063508SPeter Wemm "ppi", 6240f063508SPeter Wemm ppi_methods, 6250f063508SPeter Wemm sizeof(struct ppi_data), 6260f063508SPeter Wemm }; 6270f063508SPeter Wemm DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0); 628f5fd5611SRuslan Ermilov MODULE_DEPEND(ppi, ppbus, 1, 1, 1); 629