11844Swollman/* $NetBSD: fdc_pcmcia.c,v 1.19 2008/03/16 00:58:56 cube Exp $ */ 250476Speter 31638Srgrimes/*- 494940Sru * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. 51638Srgrimes * All rights reserved. 6103713Smarkm * 71638Srgrimes * This code is derived from software contributed to The NetBSD Foundation 82827Sjkh * by Christos Zoulas. 9117034Sgordon * 101638Srgrimes * Redistribution and use in source and binary forms, with or without 112827Sjkh * modification, are permitted provided that the following conditions 121638Srgrimes * are met: 132827Sjkh * 1. Redistributions of source code must retain the above copyright 141638Srgrimes * notice, this list of conditions and the following disclaimer. 1527028Spst * 2. Redistributions in binary form must reproduce the above copyright 161844Swollman * notice, this list of conditions and the following disclaimer in the 171844Swollman * documentation and/or other materials provided with the distribution. 181638Srgrimes * 1994424Sru * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2094424Sru * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2194424Sru * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2294424Sru * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231638Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241638Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251638Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2636054Sbde * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2736054Sbde * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2836054Sbde * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2936054Sbde * POSSIBILITY OF SUCH DAMAGE. 3036054Sbde */ 3136054Sbde 321844Swollman#include <sys/cdefs.h> 331638Srgrimes__KERNEL_RCSID(0, "$NetBSD: fdc_pcmcia.c,v 1.19 2008/03/16 00:58:56 cube Exp $"); 3494518Sru 3594518Sru#include <sys/param.h> 3694518Sru#include <sys/systm.h> 3794518Sru#include <sys/conf.h> 3894518Sru#include <sys/device.h> 3994518Sru#include <sys/disk.h> 4094518Sru#include <sys/buf.h> 418321Sbde 421844Swollman#include <sys/bus.h> 4394518Sru#include <sys/intr.h> 4494424Sru 4594424Sru#include <dev/pcmcia/pcmciareg.h> 4694424Sru#include <dev/pcmcia/pcmciavar.h> 472351Sbde#include <dev/pcmcia/pcmciadevs.h> 4894424Sru 491638Srgrimes#include <dev/isa/isavar.h> 502351Sbde 512351Sbde#include <dev/isa/fdreg.h> 522351Sbde#include <dev/isa/fdcvar.h> 532351Sbde 542351Sbdestruct fdc_pcmcia_softc { 552351Sbde struct fdc_softc sc_fdc; /* real "fdc" softc */ 5633624Seivind 5734081Sbde struct pcmcia_function *sc_pf; /* our PCMCIA function */ 5894497Sru}; 5994497Sru 6094497Sruint fdc_pcmcia_match(device_t, cfdata_t, void *); 6194410Sruint fdc_pcmcia_validate_config(struct pcmcia_config_entry *); 6233624Seivindvoid fdc_pcmcia_attach(device_t, device_t, void *); 6394518Srustatic void fdc_conf(struct fdc_softc *); 641638Srgrimes 651638SrgrimesCFATTACH_DECL_NEW(fdc_pcmcia, sizeof(struct fdc_pcmcia_softc), 661638Srgrimes fdc_pcmcia_match, fdc_pcmcia_attach, NULL, NULL); 6774806Sru 6874806Sruconst struct pcmcia_product fdc_pcmcia_products[] = { 691638Srgrimes { PCMCIA_VENDOR_YEDATA, PCMCIA_PRODUCT_YEDATA_EXTERNAL_FDD, 7058493Sru PCMCIA_CIS_YEDATA_EXTERNAL_FDD }, 7174806Sru}; 7274941Sruconst size_t fdc_pcmcia_nproducts = 7374941Sru sizeof(fdc_pcmcia_products) / sizeof(fdc_pcmcia_products[0]); 741638Srgrimes 751638Srgrimesstatic void 761638Srgrimesfdc_conf(struct fdc_softc *fdc) 7797769Sru{ 7874806Sru bus_space_tag_t iot = fdc->sc_iot; 7996164Sru bus_space_handle_t ioh = fdc->sc_ioh; 8074806Sru int n; 811638Srgrimes 8233816Sbde /* Figure out what we have */ 831638Srgrimes if (out_fdc_cmd(iot, ioh, FDC_CMD_VERSION) == -1 || 8455670Sbde (n = fdcresult(fdc, 1)) != 1) 8524750Sbde return; 8646541Sbde 8794497Sru /* Nec765 or equivalent */ 8894497Sru if (FDC_ST0(fdc->sc_status[0]) == FDC_ST0_INVL) 8924750Sbde return; 9028945Speter 9124750Sbde#if 0 921638Srgrimes /* ns8477 check */ 931638Srgrimes if (out_fdc_cmd(iot, ioh, FDC_CMD_NSC) == -1 || 9449328Shoek (n = fdcresult(fdc, 1)) != 1) { 9549328Shoek printf("NSC command failed\n"); 9649328Shoek return; 9749328Shoek } 9849328Shoek else 9995734Sru printf("Version %x\n", fdc->sc_status[0]); 10096163Sru#endif 10199343Sru 10296163Sru if (out_fdc_cmd(iot, ioh, FDC_CMD_DUMPREG) == -1 || 1031638Srgrimes (n = fdcresult(fdc, -1)) == -1) 10475083Sru return; 105100872Sru 10675083Sru /* 10775083Sru * Expect 10 bytes of status; one means that it did not 108100872Sru * understand the command 10949328Shoek */ 1101638Srgrimes if (n == 1) 11175083Sru return; 11295734Sru 1131638Srgrimes /* 11475284Sru * Configure controller to use FIFO and 8 bytes of FIFO threshold 11575284Sru */ 11699343Sru (void)out_fdc_cmd(iot, ioh, FDC_CMD_CONFIGURE); 11775284Sru (void)out_fdc(iot, ioh, 0x00); /* doc says 0 */ 11875284Sru (void)out_fdc(iot, ioh, 8); /* FIFO is active low. */ 11975284Sru (void)out_fdc(iot, ioh, fdc->sc_status[9]); /* same comp */ 12075284Sru /* No result phase */ 12175284Sru 12275284Sru /* Lock this configuration */ 12375284Sru if (out_fdc_cmd(iot, ioh, FDC_CMD_LOCK(FDC_CMD_FLAGS_LOCK)) == -1 || 12475284Sru fdcresult(fdc, 1) != 1) 12575284Sru return; 12675284Sru} 12775284Sru 12875284Sruint 12975284Srufdc_pcmcia_match(device_t parent, cfdata_t match, void *aux) 13075284Sru{ 13175284Sru struct pcmcia_attach_args *pa = aux; 13275284Sru 13388055Sru if (pcmcia_product_lookup(pa, fdc_pcmcia_products, fdc_pcmcia_nproducts, 13488055Sru sizeof(fdc_pcmcia_products[0]), NULL)) 135100872Sru return (1); 13675284Sru return (0); 13794954Sru} 13875284Sru 13975284Sruvoid 14075284Srufdc_pcmcia_attach(device_t parent, device_t self, void *aux) 14175284Sru{ 14299257Sru struct fdc_pcmcia_softc *psc = device_private(self); 14399257Sru struct fdc_softc *fdc = &psc->sc_fdc; 14499257Sru struct pcmcia_attach_args *pa = aux; 14597769Sru struct pcmcia_config_entry *cfe; 14696668Sru struct pcmcia_function *pf = pa->pf; 14799256Sru struct fdc_attach_args fa; 14896462Sru int error; 14996163Sru 15096164Sru fdc->sc_dev = self; 15199343Sru psc->sc_pf = pf; 15296163Sru 15396163Sru error = pcmcia_function_configure(pf, fdc_pcmcia_validate_config); 1541844Swollman if (error) { 1551638Srgrimes aprint_error_dev(self, "configure failed, error=%d\n", error); 1561638Srgrimes return; 157103713Smarkm } 1581638Srgrimes 159103713Smarkm cfe = pf->cfe; 1601638Srgrimes fdc->sc_iot = cfe->iospace[0].handle.iot; 1611638Srgrimes fdc->sc_iot = cfe->iospace[0].handle.ioh; 1621638Srgrimes 1631638Srgrimes if (pcmcia_function_enable(pf)) 1641638Srgrimes goto fail; 16574842Sru 1661844Swollman fdc->sc_flags = FDC_HEADSETTLE; 16728945Speter fdc->sc_state = DEVIDLE; 16828945Speter TAILQ_INIT(&fdc->sc_drives); 1691844Swollman 17034081Sbde if (!fdcfind(fdc->sc_iot, fdc->sc_ioh, 1)) 17194113Sru aprint_error_dev(self, "coundn't find fdc\n"); 17234087Sbde 17334081Sbde fdc_conf(fdc); 17434081Sbde 17516663Sjkh /* Establish the interrupt handler. */ 17676861Skris fdc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_BIO, fdchwintr, fdc); 17776861Skris if (!fdc->sc_ih) 178 goto fail; 179 180 /* physical limit: four drives per controller. */ 181 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 182 if (fa.fa_drive < 2) 183 fa.fa_deftype = &fd_types[0]; 184 else 185 fa.fa_deftype = NULL; /* unknown */ 186 (void)config_found(self, (void *)&fa, fdprint); 187 } 188 189 return; 190 191fail: 192 pcmcia_function_unconfigure(pf); 193} 194