amps.c revision 1.19
11.19Sdyoung/* $NetBSD: amps.c,v 1.19 2011/07/19 15:59:54 dyoung Exp $ */ 21.1Sreinoud 31.1Sreinoud/*- 41.1Sreinoud * Copyright (c) 1997 The NetBSD Foundation, Inc. 51.1Sreinoud * All rights reserved. 61.1Sreinoud * 71.1Sreinoud * This code is derived from software contributed to The NetBSD Foundation 81.1Sreinoud * by Mark Brinicombe of Causality Limited. 91.1Sreinoud * 101.1Sreinoud * Redistribution and use in source and binary forms, with or without 111.1Sreinoud * modification, are permitted provided that the following conditions 121.1Sreinoud * are met: 131.1Sreinoud * 1. Redistributions of source code must retain the above copyright 141.1Sreinoud * notice, this list of conditions and the following disclaimer. 151.1Sreinoud * 2. Redistributions in binary form must reproduce the above copyright 161.1Sreinoud * notice, this list of conditions and the following disclaimer in the 171.1Sreinoud * documentation and/or other materials provided with the distribution. 181.1Sreinoud * 191.1Sreinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.1Sreinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.1Sreinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.1Sreinoud * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.1Sreinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.1Sreinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.1Sreinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.1Sreinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.1Sreinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.1Sreinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.1Sreinoud * POSSIBILITY OF SUCH DAMAGE. 301.1Sreinoud * 311.1Sreinoud * Card driver and probe and attach functions to use generic 16550 com 321.1Sreinoud * driver for the Atomwide multiport serial podule 331.1Sreinoud */ 341.1Sreinoud 351.1Sreinoud/* 361.1Sreinoud * Thanks to Martin Coulson, Atomwide, for providing the hardware 371.1Sreinoud */ 381.9Slukem 391.9Slukem#include <sys/cdefs.h> 401.19Sdyoung__KERNEL_RCSID(0, "$NetBSD: amps.c,v 1.19 2011/07/19 15:59:54 dyoung Exp $"); 411.1Sreinoud 421.1Sreinoud#include <sys/param.h> 431.1Sreinoud#include <sys/systm.h> 441.1Sreinoud#include <sys/ioctl.h> 451.1Sreinoud#include <sys/select.h> 461.1Sreinoud#include <sys/tty.h> 471.1Sreinoud#include <sys/proc.h> 481.1Sreinoud#include <sys/conf.h> 491.1Sreinoud#include <sys/file.h> 501.1Sreinoud#include <sys/uio.h> 511.1Sreinoud#include <sys/kernel.h> 521.1Sreinoud#include <sys/syslog.h> 531.1Sreinoud#include <sys/types.h> 541.1Sreinoud#include <sys/device.h> 551.19Sdyoung#include <sys/bus.h> 561.1Sreinoud 571.2Sthorpej#include <machine/intr.h> 581.1Sreinoud#include <machine/io.h> 591.1Sreinoud#include <acorn32/podulebus/podulebus.h> 601.1Sreinoud#include <acorn32/podulebus/ampsreg.h> 611.1Sreinoud#include <dev/ic/comreg.h> 621.1Sreinoud#include <dev/ic/comvar.h> 631.1Sreinoud#include <dev/podulebus/podules.h> 641.1Sreinoud 651.1Sreinoud#include "locators.h" 661.1Sreinoud 671.1Sreinoud/* 681.1Sreinoud * Atomwide Mulit-port serial podule device. 691.1Sreinoud * 701.1Sreinoud * This probes and attaches the top level multi-port serial device to the 711.1Sreinoud * podulebus. It then configures the child com devices. 721.1Sreinoud */ 731.1Sreinoud 741.1Sreinoud/* 751.1Sreinoud * Atomwide Multi-port serial card softc structure. 761.1Sreinoud * 771.1Sreinoud * Contains the device node, podule information and global information 781.1Sreinoud * required by the driver such as the card version and the interrupt mask. 791.1Sreinoud */ 801.1Sreinoud 811.1Sreinoudstruct amps_softc { 821.1Sreinoud struct device sc_dev; /* device node */ 831.1Sreinoud podule_t *sc_podule; /* Our podule info */ 841.1Sreinoud int sc_podule_number; /* Our podule number */ 851.1Sreinoud bus_space_tag_t sc_iot; /* Bus tag */ 861.1Sreinoud}; 871.1Sreinoud 881.18Smattint amps_probe(device_t, cfdata_t, void *); 891.18Smattvoid amps_attach(device_t, device_t, void *); 901.1Sreinoud 911.5SthorpejCFATTACH_DECL(amps, sizeof(struct amps_softc), 921.6Sthorpej amps_probe, amps_attach, NULL, NULL); 931.7Schs 941.7Schsint amps_print(void *, const char *); 951.7Schsvoid amps_shutdown(void *); 961.1Sreinoud 971.1Sreinoud/* 981.1Sreinoud * Attach arguments for child devices. 991.1Sreinoud * Pass the podule details, the parent softc and the channel 1001.1Sreinoud */ 1011.1Sreinoud 1021.1Sreinoudstruct amps_attach_args { 1031.1Sreinoud bus_space_tag_t aa_iot; /* bus space tag */ 1041.1Sreinoud unsigned int aa_base; /* base address for port */ 1051.1Sreinoud int aa_port; /* serial port number */ 1061.1Sreinoud podulebus_intr_handle_t aa_irq; /* IRQ number */ 1071.1Sreinoud}; 1081.1Sreinoud 1091.1Sreinoud/* 1101.1Sreinoud * Define prototypes for custom bus space functions. 1111.1Sreinoud */ 1121.1Sreinoud 1131.1Sreinoud/* Print function used during child config */ 1141.1Sreinoud 1151.1Sreinoudint 1161.15Sdslamps_print(void *aux, const char *name) 1171.1Sreinoud{ 1181.1Sreinoud struct amps_attach_args *aa = aux; 1191.1Sreinoud 1201.1Sreinoud if (!name) 1211.8Sthorpej aprint_normal(", port %d", aa->aa_port); 1221.1Sreinoud 1231.1Sreinoud return(QUIET); 1241.1Sreinoud} 1251.1Sreinoud 1261.1Sreinoud/* 1271.1Sreinoud * Card probe function 1281.1Sreinoud * 1291.1Sreinoud * Just match the manufacturer and podule ID's 1301.1Sreinoud */ 1311.1Sreinoud 1321.1Sreinoudint 1331.18Smattamps_probe(device_t parent, cfdata_t cf, void *aux) 1341.1Sreinoud{ 1351.18Smatt struct podule_attach_args *pa = aux; 1361.1Sreinoud 1371.3Sbjh21 return (pa->pa_product == PODULE_ATOMWIDE_SERIAL); 1381.1Sreinoud} 1391.1Sreinoud 1401.1Sreinoud/* 1411.1Sreinoud * Card attach function 1421.1Sreinoud * 1431.1Sreinoud * Identify the card version and configure any children. 1441.1Sreinoud * Install a shutdown handler to kill interrupts on shutdown 1451.1Sreinoud */ 1461.1Sreinoud 1471.1Sreinoudvoid 1481.18Smattamps_attach(device_t parent, device_t self, void *aux) 1491.1Sreinoud{ 1501.18Smatt struct amps_softc *sc = device_private(self); 1511.18Smatt struct podule_attach_args *pa = aux; 1521.1Sreinoud struct amps_attach_args aa; 1531.1Sreinoud 1541.1Sreinoud /* Note the podule number and validate */ 1551.1Sreinoud 1561.1Sreinoud if (pa->pa_podule_number == -1) 1571.1Sreinoud panic("Podule has disappeared !"); 1581.1Sreinoud 1591.1Sreinoud sc->sc_podule_number = pa->pa_podule_number; 1601.1Sreinoud sc->sc_podule = pa->pa_podule; 1611.1Sreinoud podules[sc->sc_podule_number].attached = 1; 1621.1Sreinoud 1631.1Sreinoud sc->sc_iot = pa->pa_iot; 1641.1Sreinoud 1651.1Sreinoud /* Install a clean up handler to make sure IRQ's are disabled */ 1661.1Sreinoud/* if (shutdownhook_establish(amps_shutdown, (void *)sc) == NULL) 1671.1Sreinoud panic("%s: Cannot install shutdown handler", self->dv_xname);*/ 1681.1Sreinoud 1691.1Sreinoud /* Set the interrupt info for this podule */ 1701.1Sreinoud 1711.1Sreinoud/* sc->sc_podule->irq_addr = pa->pa_podule->slow_base +;*/ /* XXX */ 1721.1Sreinoud/* sc->sc_podule->irq_mask = ;*/ 1731.1Sreinoud 1741.1Sreinoud printf("\n"); 1751.1Sreinoud 1761.1Sreinoud /* Configure the children */ 1771.1Sreinoud 1781.1Sreinoud aa.aa_iot = sc->sc_iot; 1791.1Sreinoud aa.aa_base = pa->pa_podule->slow_base + AMPS_BASE_OFFSET; 1801.1Sreinoud aa.aa_base += MAX_AMPS_PORTS * AMPS_PORT_SPACING; 1811.1Sreinoud aa.aa_irq = pa->pa_podule->interrupt; 1821.1Sreinoud for (aa.aa_port = 0; aa.aa_port < MAX_AMPS_PORTS; ++aa.aa_port) { 1831.1Sreinoud aa.aa_base -= AMPS_PORT_SPACING; 1841.10Sdrochner config_found(self, &aa, amps_print); 1851.1Sreinoud } 1861.1Sreinoud} 1871.1Sreinoud 1881.1Sreinoud/* 1891.1Sreinoud * Card shutdown function 1901.1Sreinoud * 1911.1Sreinoud * Called via do_shutdown_hooks() during kernel shutdown. 1921.1Sreinoud * Clear the cards's interrupt mask to stop any podule interrupts. 1931.1Sreinoud */ 1941.1Sreinoud 1951.1Sreinoud/*void 1961.15Sdslamps_shutdown(void *arg) 1971.1Sreinoud{ 1981.1Sreinoud}*/ 1991.1Sreinoud 2001.1Sreinoud/* 2011.1Sreinoud * Atomwide Multi-Port Serial probe and attach code for the com device. 2021.1Sreinoud * 2031.1Sreinoud * This provides a different pair of probe and attach functions 2041.1Sreinoud * for attaching the com device (dev/ic/com.c) to the Atomwide serial card. 2051.1Sreinoud */ 2061.1Sreinoud 2071.1Sreinoudstruct com_amps_softc { 2081.1Sreinoud struct com_softc sc_com; /* real "com" softc */ 2091.1Sreinoud void *sc_ih; /* interrupt handler */ 2101.1Sreinoud struct evcnt sc_intrcnt; /* interrupt count */ 2111.1Sreinoud}; 2121.1Sreinoud 2131.1Sreinoud/* Prototypes for functions */ 2141.1Sreinoud 2151.13Scubestatic int com_amps_probe (device_t, cfdata_t , void *); 2161.13Scubestatic void com_amps_attach (device_t, device_t, void *); 2171.1Sreinoud 2181.1Sreinoud/* device attach structure */ 2191.1Sreinoud 2201.13ScubeCFATTACH_DECL_NEW(com_amps, sizeof(struct com_amps_softc), 2211.5Sthorpej com_amps_probe, com_amps_attach, NULL, NULL); 2221.1Sreinoud 2231.1Sreinoud/* 2241.1Sreinoud * Controller probe function 2251.1Sreinoud * 2261.1Sreinoud * Map all the required I/O space for this channel, make sure interrupts 2271.1Sreinoud * are disabled and probe the bus. 2281.1Sreinoud */ 2291.1Sreinoud 2301.1Sreinoudint 2311.13Scubecom_amps_probe(device_t parent, cfdata_t cf, void *aux) 2321.1Sreinoud{ 2331.1Sreinoud bus_space_tag_t iot; 2341.1Sreinoud bus_space_handle_t ioh; 2351.1Sreinoud int iobase; 2361.1Sreinoud int rv = 1; 2371.1Sreinoud struct amps_attach_args *aa = aux; 2381.1Sreinoud 2391.1Sreinoud iot = aa->aa_iot; 2401.1Sreinoud iobase = aa->aa_base; 2411.1Sreinoud 2421.1Sreinoud /* if it's in use as console, it's there. */ 2431.1Sreinoud if (!com_is_console(iot, iobase, 0)) { 2441.1Sreinoud if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { 2451.1Sreinoud return 0; 2461.1Sreinoud } 2471.1Sreinoud /* 2481.1Sreinoud * We don't use the generic comprobe1() function as it 2491.1Sreinoud * is not good enough to identify which ports are present. 2501.1Sreinoud * 2511.1Sreinoud * Instead test for the presence of the scratch register 2521.1Sreinoud */ 2531.1Sreinoud 2541.1Sreinoud bus_space_write_1(iot, ioh, com_scratch, 0x55); 2551.1Sreinoud bus_space_write_1(iot, ioh, com_ier, 0); 2561.1Sreinoud (void)bus_space_read_1(iot, ioh, com_data); 2571.1Sreinoud if (bus_space_read_1(iot, ioh, com_scratch) != 0x55) 2581.1Sreinoud rv = 0; 2591.1Sreinoud bus_space_write_1(iot, ioh, com_scratch, 0xaa); 2601.1Sreinoud bus_space_write_1(iot, ioh, com_ier, 0); 2611.1Sreinoud (void)bus_space_read_1(iot, ioh, com_data); 2621.1Sreinoud if (bus_space_read_1(iot, ioh, com_scratch) != 0xaa) 2631.1Sreinoud rv = 0; 2641.1Sreinoud 2651.1Sreinoud bus_space_unmap(iot, ioh, COM_NPORTS); 2661.1Sreinoud } 2671.1Sreinoud return (rv); 2681.1Sreinoud} 2691.1Sreinoud 2701.1Sreinoud/* 2711.1Sreinoud * Controller attach function 2721.1Sreinoud * 2731.1Sreinoud * Map all the required I/O space for this port and attach the driver 2741.1Sreinoud * The generic attach will probe and attach any device. 2751.1Sreinoud * Install an interrupt handler and we are ready to rock. 2761.1Sreinoud */ 2771.1Sreinoud 2781.1Sreinoudvoid 2791.13Scubecom_amps_attach(device_t parent, device_t self, void *aux) 2801.1Sreinoud{ 2811.13Scube struct com_amps_softc *asc = device_private(self); 2821.1Sreinoud struct com_softc *sc = &asc->sc_com; 2831.1Sreinoud u_int iobase; 2841.1Sreinoud bus_space_tag_t iot; 2851.12Sgdamore bus_space_handle_t ioh; 2861.1Sreinoud struct amps_attach_args *aa = aux; 2871.1Sreinoud 2881.13Scube sc->sc_dev = self; 2891.12Sgdamore iot = aa->aa_iot; 2901.12Sgdamore iobase = aa->aa_base; 2911.1Sreinoud 2921.12Sgdamore if (!com_is_console(iot, iobase, &ioh) 2931.12Sgdamore && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) 2941.12Sgdamore panic("comattach: io mapping failed"); 2951.12Sgdamore COM_INIT_REGS(sc->sc_regs, iot, ioh, iobase); 2961.1Sreinoud 2971.1Sreinoud sc->sc_frequency = AMPS_FREQ; 2981.1Sreinoud com_attach_subr(sc); 2991.1Sreinoud 3001.1Sreinoud evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 3011.13Scube device_xname(self), "intr"); 3021.1Sreinoud asc->sc_ih = podulebus_irq_establish(aa->aa_irq, IPL_SERIAL, comintr, 3031.1Sreinoud sc, &asc->sc_intrcnt); 3041.1Sreinoud} 305