amps.c revision 1.15
11.15Sdsl/* $NetBSD: amps.c,v 1.15 2009/03/14 15:35:58 dsl 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.15Sdsl__KERNEL_RCSID(0, "$NetBSD: amps.c,v 1.15 2009/03/14 15:35:58 dsl 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/user.h> 491.1Sreinoud#include <sys/conf.h> 501.1Sreinoud#include <sys/file.h> 511.1Sreinoud#include <sys/uio.h> 521.1Sreinoud#include <sys/kernel.h> 531.1Sreinoud#include <sys/syslog.h> 541.1Sreinoud#include <sys/types.h> 551.1Sreinoud#include <sys/device.h> 561.1Sreinoud 571.2Sthorpej#include <machine/intr.h> 581.1Sreinoud#include <machine/io.h> 591.1Sreinoud#include <machine/bus.h> 601.1Sreinoud#include <acorn32/podulebus/podulebus.h> 611.1Sreinoud#include <acorn32/podulebus/ampsreg.h> 621.1Sreinoud#include <dev/ic/comreg.h> 631.1Sreinoud#include <dev/ic/comvar.h> 641.1Sreinoud#include <dev/podulebus/podules.h> 651.1Sreinoud 661.1Sreinoud#include "locators.h" 671.1Sreinoud 681.1Sreinoud/* 691.1Sreinoud * Atomwide Mulit-port serial podule device. 701.1Sreinoud * 711.1Sreinoud * This probes and attaches the top level multi-port serial device to the 721.1Sreinoud * podulebus. It then configures the child com devices. 731.1Sreinoud */ 741.1Sreinoud 751.1Sreinoud/* 761.1Sreinoud * Atomwide Multi-port serial card softc structure. 771.1Sreinoud * 781.1Sreinoud * Contains the device node, podule information and global information 791.1Sreinoud * required by the driver such as the card version and the interrupt mask. 801.1Sreinoud */ 811.1Sreinoud 821.1Sreinoudstruct amps_softc { 831.1Sreinoud struct device sc_dev; /* device node */ 841.1Sreinoud podule_t *sc_podule; /* Our podule info */ 851.1Sreinoud int sc_podule_number; /* Our podule number */ 861.1Sreinoud bus_space_tag_t sc_iot; /* Bus tag */ 871.1Sreinoud}; 881.1Sreinoud 891.7Schsint amps_probe(struct device *, struct cfdata *, void *); 901.7Schsvoid amps_attach(struct device *, struct device *, void *); 911.1Sreinoud 921.5SthorpejCFATTACH_DECL(amps, sizeof(struct amps_softc), 931.6Sthorpej amps_probe, amps_attach, NULL, NULL); 941.7Schs 951.7Schsint amps_print(void *, const char *); 961.7Schsvoid amps_shutdown(void *); 971.1Sreinoud 981.1Sreinoud/* 991.1Sreinoud * Attach arguments for child devices. 1001.1Sreinoud * Pass the podule details, the parent softc and the channel 1011.1Sreinoud */ 1021.1Sreinoud 1031.1Sreinoudstruct amps_attach_args { 1041.1Sreinoud bus_space_tag_t aa_iot; /* bus space tag */ 1051.1Sreinoud unsigned int aa_base; /* base address for port */ 1061.1Sreinoud int aa_port; /* serial port number */ 1071.1Sreinoud podulebus_intr_handle_t aa_irq; /* IRQ number */ 1081.1Sreinoud}; 1091.1Sreinoud 1101.1Sreinoud/* 1111.1Sreinoud * Define prototypes for custom bus space functions. 1121.1Sreinoud */ 1131.1Sreinoud 1141.1Sreinoud/* Print function used during child config */ 1151.1Sreinoud 1161.1Sreinoudint 1171.15Sdslamps_print(void *aux, const char *name) 1181.1Sreinoud{ 1191.1Sreinoud struct amps_attach_args *aa = aux; 1201.1Sreinoud 1211.1Sreinoud if (!name) 1221.8Sthorpej aprint_normal(", port %d", aa->aa_port); 1231.1Sreinoud 1241.1Sreinoud return(QUIET); 1251.1Sreinoud} 1261.1Sreinoud 1271.1Sreinoud/* 1281.1Sreinoud * Card probe function 1291.1Sreinoud * 1301.1Sreinoud * Just match the manufacturer and podule ID's 1311.1Sreinoud */ 1321.1Sreinoud 1331.1Sreinoudint 1341.15Sdslamps_probe(struct device *parent, struct cfdata *cf, void *aux) 1351.1Sreinoud{ 1361.1Sreinoud struct podule_attach_args *pa = (void *)aux; 1371.1Sreinoud 1381.3Sbjh21 return (pa->pa_product == PODULE_ATOMWIDE_SERIAL); 1391.1Sreinoud} 1401.1Sreinoud 1411.1Sreinoud/* 1421.1Sreinoud * Card attach function 1431.1Sreinoud * 1441.1Sreinoud * Identify the card version and configure any children. 1451.1Sreinoud * Install a shutdown handler to kill interrupts on shutdown 1461.1Sreinoud */ 1471.1Sreinoud 1481.1Sreinoudvoid 1491.1Sreinoudamps_attach(parent, self, aux) 1501.1Sreinoud struct device *parent, *self; 1511.1Sreinoud void *aux; 1521.1Sreinoud{ 1531.1Sreinoud struct amps_softc *sc = (void *)self; 1541.1Sreinoud struct podule_attach_args *pa = (void *)aux; 1551.1Sreinoud struct amps_attach_args aa; 1561.1Sreinoud 1571.1Sreinoud /* Note the podule number and validate */ 1581.1Sreinoud 1591.1Sreinoud if (pa->pa_podule_number == -1) 1601.1Sreinoud panic("Podule has disappeared !"); 1611.1Sreinoud 1621.1Sreinoud sc->sc_podule_number = pa->pa_podule_number; 1631.1Sreinoud sc->sc_podule = pa->pa_podule; 1641.1Sreinoud podules[sc->sc_podule_number].attached = 1; 1651.1Sreinoud 1661.1Sreinoud sc->sc_iot = pa->pa_iot; 1671.1Sreinoud 1681.1Sreinoud /* Install a clean up handler to make sure IRQ's are disabled */ 1691.1Sreinoud/* if (shutdownhook_establish(amps_shutdown, (void *)sc) == NULL) 1701.1Sreinoud panic("%s: Cannot install shutdown handler", self->dv_xname);*/ 1711.1Sreinoud 1721.1Sreinoud /* Set the interrupt info for this podule */ 1731.1Sreinoud 1741.1Sreinoud/* sc->sc_podule->irq_addr = pa->pa_podule->slow_base +;*/ /* XXX */ 1751.1Sreinoud/* sc->sc_podule->irq_mask = ;*/ 1761.1Sreinoud 1771.1Sreinoud printf("\n"); 1781.1Sreinoud 1791.1Sreinoud /* Configure the children */ 1801.1Sreinoud 1811.1Sreinoud aa.aa_iot = sc->sc_iot; 1821.1Sreinoud aa.aa_base = pa->pa_podule->slow_base + AMPS_BASE_OFFSET; 1831.1Sreinoud aa.aa_base += MAX_AMPS_PORTS * AMPS_PORT_SPACING; 1841.1Sreinoud aa.aa_irq = pa->pa_podule->interrupt; 1851.1Sreinoud for (aa.aa_port = 0; aa.aa_port < MAX_AMPS_PORTS; ++aa.aa_port) { 1861.1Sreinoud aa.aa_base -= AMPS_PORT_SPACING; 1871.10Sdrochner config_found(self, &aa, amps_print); 1881.1Sreinoud } 1891.1Sreinoud} 1901.1Sreinoud 1911.1Sreinoud/* 1921.1Sreinoud * Card shutdown function 1931.1Sreinoud * 1941.1Sreinoud * Called via do_shutdown_hooks() during kernel shutdown. 1951.1Sreinoud * Clear the cards's interrupt mask to stop any podule interrupts. 1961.1Sreinoud */ 1971.1Sreinoud 1981.1Sreinoud/*void 1991.15Sdslamps_shutdown(void *arg) 2001.1Sreinoud{ 2011.1Sreinoud}*/ 2021.1Sreinoud 2031.1Sreinoud/* 2041.1Sreinoud * Atomwide Multi-Port Serial probe and attach code for the com device. 2051.1Sreinoud * 2061.1Sreinoud * This provides a different pair of probe and attach functions 2071.1Sreinoud * for attaching the com device (dev/ic/com.c) to the Atomwide serial card. 2081.1Sreinoud */ 2091.1Sreinoud 2101.1Sreinoudstruct com_amps_softc { 2111.1Sreinoud struct com_softc sc_com; /* real "com" softc */ 2121.1Sreinoud void *sc_ih; /* interrupt handler */ 2131.1Sreinoud struct evcnt sc_intrcnt; /* interrupt count */ 2141.1Sreinoud}; 2151.1Sreinoud 2161.1Sreinoud/* Prototypes for functions */ 2171.1Sreinoud 2181.13Scubestatic int com_amps_probe (device_t, cfdata_t , void *); 2191.13Scubestatic void com_amps_attach (device_t, device_t, void *); 2201.1Sreinoud 2211.1Sreinoud/* device attach structure */ 2221.1Sreinoud 2231.13ScubeCFATTACH_DECL_NEW(com_amps, sizeof(struct com_amps_softc), 2241.5Sthorpej com_amps_probe, com_amps_attach, NULL, NULL); 2251.1Sreinoud 2261.1Sreinoud/* 2271.1Sreinoud * Controller probe function 2281.1Sreinoud * 2291.1Sreinoud * Map all the required I/O space for this channel, make sure interrupts 2301.1Sreinoud * are disabled and probe the bus. 2311.1Sreinoud */ 2321.1Sreinoud 2331.1Sreinoudint 2341.13Scubecom_amps_probe(device_t parent, cfdata_t cf, void *aux) 2351.1Sreinoud{ 2361.1Sreinoud bus_space_tag_t iot; 2371.1Sreinoud bus_space_handle_t ioh; 2381.1Sreinoud int iobase; 2391.1Sreinoud int rv = 1; 2401.1Sreinoud struct amps_attach_args *aa = aux; 2411.1Sreinoud 2421.1Sreinoud iot = aa->aa_iot; 2431.1Sreinoud iobase = aa->aa_base; 2441.1Sreinoud 2451.1Sreinoud /* if it's in use as console, it's there. */ 2461.1Sreinoud if (!com_is_console(iot, iobase, 0)) { 2471.1Sreinoud if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { 2481.1Sreinoud return 0; 2491.1Sreinoud } 2501.1Sreinoud /* 2511.1Sreinoud * We don't use the generic comprobe1() function as it 2521.1Sreinoud * is not good enough to identify which ports are present. 2531.1Sreinoud * 2541.1Sreinoud * Instead test for the presence of the scratch register 2551.1Sreinoud */ 2561.1Sreinoud 2571.1Sreinoud bus_space_write_1(iot, ioh, com_scratch, 0x55); 2581.1Sreinoud bus_space_write_1(iot, ioh, com_ier, 0); 2591.1Sreinoud (void)bus_space_read_1(iot, ioh, com_data); 2601.1Sreinoud if (bus_space_read_1(iot, ioh, com_scratch) != 0x55) 2611.1Sreinoud rv = 0; 2621.1Sreinoud bus_space_write_1(iot, ioh, com_scratch, 0xaa); 2631.1Sreinoud bus_space_write_1(iot, ioh, com_ier, 0); 2641.1Sreinoud (void)bus_space_read_1(iot, ioh, com_data); 2651.1Sreinoud if (bus_space_read_1(iot, ioh, com_scratch) != 0xaa) 2661.1Sreinoud rv = 0; 2671.1Sreinoud 2681.1Sreinoud bus_space_unmap(iot, ioh, COM_NPORTS); 2691.1Sreinoud } 2701.1Sreinoud return (rv); 2711.1Sreinoud} 2721.1Sreinoud 2731.1Sreinoud/* 2741.1Sreinoud * Controller attach function 2751.1Sreinoud * 2761.1Sreinoud * Map all the required I/O space for this port and attach the driver 2771.1Sreinoud * The generic attach will probe and attach any device. 2781.1Sreinoud * Install an interrupt handler and we are ready to rock. 2791.1Sreinoud */ 2801.1Sreinoud 2811.1Sreinoudvoid 2821.13Scubecom_amps_attach(device_t parent, device_t self, void *aux) 2831.1Sreinoud{ 2841.13Scube struct com_amps_softc *asc = device_private(self); 2851.1Sreinoud struct com_softc *sc = &asc->sc_com; 2861.1Sreinoud u_int iobase; 2871.1Sreinoud bus_space_tag_t iot; 2881.12Sgdamore bus_space_handle_t ioh; 2891.1Sreinoud struct amps_attach_args *aa = aux; 2901.1Sreinoud 2911.13Scube sc->sc_dev = self; 2921.12Sgdamore iot = aa->aa_iot; 2931.12Sgdamore iobase = aa->aa_base; 2941.1Sreinoud 2951.12Sgdamore if (!com_is_console(iot, iobase, &ioh) 2961.12Sgdamore && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) 2971.12Sgdamore panic("comattach: io mapping failed"); 2981.12Sgdamore COM_INIT_REGS(sc->sc_regs, iot, ioh, iobase); 2991.1Sreinoud 3001.1Sreinoud sc->sc_frequency = AMPS_FREQ; 3011.1Sreinoud com_attach_subr(sc); 3021.1Sreinoud 3031.1Sreinoud evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 3041.13Scube device_xname(self), "intr"); 3051.1Sreinoud asc->sc_ih = podulebus_irq_establish(aa->aa_irq, IPL_SERIAL, comintr, 3061.1Sreinoud sc, &asc->sc_intrcnt); 3071.1Sreinoud} 308