1*a2a38285Sad /* $NetBSD: slhci_pcmcia.c,v 1.3 2007/10/19 12:01:06 ad Exp $ */ 23f11af64Skiyohara /* 33f11af64Skiyohara * Not (c) 2007 Matthew Orgass 43f11af64Skiyohara * This file is public domain, meaning anyone can make any use of part or all 53f11af64Skiyohara * of this file including copying into other works without credit. Any use, 63f11af64Skiyohara * modified or not, is solely the responsibility of the user. If this file is 73f11af64Skiyohara * part of a collection then use in the collection is governed by the terms of 83f11af64Skiyohara * the collection. 93f11af64Skiyohara */ 103f11af64Skiyohara 113f11af64Skiyohara /* Glue for RATOC USB HOST CF+ Card (SL811HS chip) */ 123f11af64Skiyohara 133f11af64Skiyohara #include <sys/cdefs.h> 14*a2a38285Sad __KERNEL_RCSID(0, "$NetBSD: slhci_pcmcia.c,v 1.3 2007/10/19 12:01:06 ad Exp $"); 153f11af64Skiyohara 163f11af64Skiyohara #include <sys/param.h> 173f11af64Skiyohara #include <sys/device.h> 183f11af64Skiyohara #include <sys/queue.h> 193f11af64Skiyohara #include <sys/gcq.h> 203f11af64Skiyohara #include <sys/systm.h> 213f11af64Skiyohara #include <sys/errno.h> 223f11af64Skiyohara 23*a2a38285Sad #include <sys/bus.h> 243f11af64Skiyohara #include <dev/pcmcia/pcmciareg.h> 253f11af64Skiyohara #include <dev/pcmcia/pcmciavar.h> 263f11af64Skiyohara #include <dev/pcmcia/pcmciadevs.h> 273f11af64Skiyohara 283f11af64Skiyohara #include <dev/usb/usb.h> 293f11af64Skiyohara #include <dev/usb/usb_port.h> 303f11af64Skiyohara #include <dev/usb/usbdi.h> 313f11af64Skiyohara #include <dev/usb/usbdivar.h> 323f11af64Skiyohara 333f11af64Skiyohara #include <dev/ic/sl811hsvar.h> 343f11af64Skiyohara 353f11af64Skiyohara struct slhci_pcmcia_softc { 363f11af64Skiyohara struct slhci_softc sc_slhci; 373f11af64Skiyohara 383f11af64Skiyohara struct pcmcia_function *sc_pf; 393f11af64Skiyohara void * sc_ih; 403f11af64Skiyohara int sc_flags; 413f11af64Skiyohara #define PFL_ENABLED (0x1) 423f11af64Skiyohara }; 433f11af64Skiyohara 443f11af64Skiyohara 453f11af64Skiyohara int slhci_pcmcia_probe(struct device *, struct cfdata *, void *); 463f11af64Skiyohara void slhci_pcmcia_attach(struct device *, struct device *, void *); 473f11af64Skiyohara int slhci_pcmcia_detach(struct device *, int); 483f11af64Skiyohara int slhci_pcmcia_validate_config(struct pcmcia_config_entry *); 493f11af64Skiyohara int slhci_pcmcia_enable(struct slhci_pcmcia_softc *, int); 503f11af64Skiyohara 513f11af64Skiyohara CFATTACH_DECL(slhci_pcmcia, sizeof(struct slhci_pcmcia_softc), 523f11af64Skiyohara slhci_pcmcia_probe, slhci_pcmcia_attach, slhci_pcmcia_detach, 533f11af64Skiyohara slhci_activate); 543f11af64Skiyohara 553f11af64Skiyohara /* Ratoc has two PCMCIA products with id 1. 563f11af64Skiyohara * Ratoc has a firmware update that modifies the CIS. The new CIS may 573f11af64Skiyohara * need a new entry. */ 583f11af64Skiyohara static const struct pcmcia_product slhci_pcmcia_products[] = { 593f11af64Skiyohara { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_CFU1, 603f11af64Skiyohara PCMCIA_CIS_RATOC_REX_CFU1 }, 613f11af64Skiyohara }; 623f11af64Skiyohara static const size_t slhci_pcmcia_nproducts = 633f11af64Skiyohara sizeof(slhci_pcmcia_products) / sizeof(slhci_pcmcia_products[0]); 643f11af64Skiyohara 653f11af64Skiyohara int 663f11af64Skiyohara slhci_pcmcia_probe(struct device *parent, struct cfdata *match, void *aux) 673f11af64Skiyohara { 683f11af64Skiyohara struct pcmcia_attach_args *pa = aux; 693f11af64Skiyohara 703f11af64Skiyohara if (pcmcia_product_lookup(pa, slhci_pcmcia_products, 713f11af64Skiyohara slhci_pcmcia_nproducts, sizeof(slhci_pcmcia_products[0]), NULL)) 723f11af64Skiyohara return 1; 733f11af64Skiyohara 743f11af64Skiyohara return 0; 753f11af64Skiyohara } 763f11af64Skiyohara 773f11af64Skiyohara int 783f11af64Skiyohara slhci_pcmcia_validate_config(struct pcmcia_config_entry *cfe) 793f11af64Skiyohara { 803f11af64Skiyohara if (cfe->num_iospace != 1 || cfe->num_memspace != 0) 813f11af64Skiyohara return EINVAL; 823f11af64Skiyohara return 0; 833f11af64Skiyohara } 843f11af64Skiyohara 853f11af64Skiyohara void 863f11af64Skiyohara slhci_pcmcia_attach(struct device *parent, struct device *self, void *aux) 873f11af64Skiyohara { 883f11af64Skiyohara struct slhci_pcmcia_softc *psc = (void *)self; 893f11af64Skiyohara struct pcmcia_attach_args *pa = aux; 903f11af64Skiyohara struct pcmcia_function *pf = pa->pf; 913f11af64Skiyohara 923f11af64Skiyohara psc->sc_pf = pf; 933f11af64Skiyohara psc->sc_flags = 0; 943f11af64Skiyohara 953f11af64Skiyohara slhci_pcmcia_enable(psc, 1); 963f11af64Skiyohara 973f11af64Skiyohara return; 983f11af64Skiyohara } 993f11af64Skiyohara 1003f11af64Skiyohara int 1013f11af64Skiyohara slhci_pcmcia_detach(struct device *self, int flags) 1023f11af64Skiyohara { 1033f11af64Skiyohara struct slhci_pcmcia_softc *psc = (void *)self; 1043f11af64Skiyohara 1053f11af64Skiyohara slhci_pcmcia_enable(psc, 0); 1063f11af64Skiyohara 1073f11af64Skiyohara return slhci_detach(&psc->sc_slhci, flags); 1083f11af64Skiyohara } 1093f11af64Skiyohara 1103f11af64Skiyohara int 1113f11af64Skiyohara slhci_pcmcia_enable(struct slhci_pcmcia_softc *psc, int enable) 1123f11af64Skiyohara { 1133f11af64Skiyohara struct pcmcia_function *pf; 1143f11af64Skiyohara struct pcmcia_io_handle *pioh; 1153f11af64Skiyohara struct slhci_softc *sc; 1163f11af64Skiyohara int error; 1173f11af64Skiyohara 1183f11af64Skiyohara pf = psc->sc_pf; 1193f11af64Skiyohara sc = &psc->sc_slhci; 1203f11af64Skiyohara 1213f11af64Skiyohara if (enable) { 1223f11af64Skiyohara if (psc->sc_flags & PFL_ENABLED) 1233f11af64Skiyohara return 0; 1243f11af64Skiyohara 1253f11af64Skiyohara error = pcmcia_function_configure(pf, 1263f11af64Skiyohara slhci_pcmcia_validate_config); 1273f11af64Skiyohara if (error) { 1283f11af64Skiyohara printf("%s: configure failed, error=%d\n", 1293f11af64Skiyohara SC_NAME(sc), error); 1303f11af64Skiyohara return 1; 1313f11af64Skiyohara } 1323f11af64Skiyohara 1333f11af64Skiyohara pioh = &pf->cfe->iospace[0].handle; 1343f11af64Skiyohara 1353f11af64Skiyohara /* The data port is repeated three times; using a stride of 1363f11af64Skiyohara * 2 prevents read/write errors on a Clio C-1000 hpcmips 1373f11af64Skiyohara * system. 1383f11af64Skiyohara */ 1393f11af64Skiyohara slhci_preinit(sc, NULL, pioh->iot, pioh->ioh, 100, 2); 1403f11af64Skiyohara 1413f11af64Skiyohara psc->sc_ih = pcmcia_intr_establish(pf, IPL_HARDUSB, 1423f11af64Skiyohara slhci_intr, sc); 1433f11af64Skiyohara 1443f11af64Skiyohara if (psc->sc_ih == NULL) { 1453f11af64Skiyohara printf("%s: unable to establish interrupt\n", 1463f11af64Skiyohara SC_NAME(sc)); 1473f11af64Skiyohara goto fail1; 1483f11af64Skiyohara } 1493f11af64Skiyohara 1503f11af64Skiyohara if (pcmcia_function_enable(pf)) { 1513f11af64Skiyohara printf("%s: function enable failed\n", SC_NAME(sc)); 1523f11af64Skiyohara goto fail2; 1533f11af64Skiyohara } 1543f11af64Skiyohara 1553f11af64Skiyohara if (slhci_attach(sc)) { 1563f11af64Skiyohara printf("%s: slhci_attach failed\n", SC_NAME(sc)); 1573f11af64Skiyohara goto fail3; 1583f11af64Skiyohara } 1593f11af64Skiyohara 1603f11af64Skiyohara psc->sc_flags |= PFL_ENABLED; 1613f11af64Skiyohara return 0; 1623f11af64Skiyohara } else { 1633f11af64Skiyohara if (!(psc->sc_flags & PFL_ENABLED)) 1643f11af64Skiyohara return 1; 1653f11af64Skiyohara psc->sc_flags &= ~PFL_ENABLED; 1663f11af64Skiyohara fail3: 1673f11af64Skiyohara pcmcia_function_disable(pf); 1683f11af64Skiyohara fail2: 1693f11af64Skiyohara pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 1703f11af64Skiyohara fail1: 1713f11af64Skiyohara pcmcia_function_unconfigure(pf); 1723f11af64Skiyohara 1733f11af64Skiyohara return 1; 1743f11af64Skiyohara } 1753f11af64Skiyohara } 1763f11af64Skiyohara 1773f11af64Skiyohara 178