This source file includes following definitions.
- wdc_pcmcia_disk_device_interface_callback
 
- wdc_pcmcia_disk_device_interface
 
- wdc_pcmcia_lookup
 
- wdc_pcmcia_match
 
- wdc_pcmcia_attach
 
- wdc_pcmcia_detach
 
- wdc_pcmcia_activate
 
- wdc_pcmcia_enable
 
    1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
   10 
   11 
   12 
   13 
   14 
   15 
   16 
   17 
   18 
   19 
   20 
   21 
   22 
   23 
   24 
   25 
   26 
   27 
   28 
   29 
   30 
   31 
   32 
   33 
   34 
   35 
   36 
   37 
   38 
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/conf.h>
   44 #include <sys/file.h>
   45 #include <sys/stat.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/buf.h>
   48 #include <sys/uio.h>
   49 #include <sys/malloc.h>
   50 #include <sys/device.h>
   51 #include <sys/disklabel.h>
   52 #include <sys/disk.h>
   53 #include <sys/syslog.h>
   54 #include <sys/proc.h>
   55 
   56 #include <uvm/uvm_extern.h>
   57 
   58 #include <machine/cpu.h>
   59 #include <machine/intr.h>
   60 #include <machine/bus.h>
   61 
   62 #include <dev/pcmcia/pcmciareg.h>
   63 #include <dev/pcmcia/pcmciavar.h>
   64 #include <dev/pcmcia/pcmciadevs.h>
   65 
   66 #include <dev/ata/atavar.h>
   67 #include <dev/ic/wdcvar.h>
   68 
   69 #define WDC_PCMCIA_REG_NPORTS      8
   70 #define WDC_PCMCIA_AUXREG_OFFSET   (WDC_PCMCIA_REG_NPORTS + 6)
   71 #define WDC_PCMCIA_AUXREG_NPORTS   2
   72 
   73 struct wdc_pcmcia_softc {
   74         struct wdc_softc sc_wdcdev;
   75         struct channel_softc *wdc_chanptr;
   76         struct channel_softc wdc_channel;
   77         struct pcmcia_io_handle sc_pioh;
   78         struct pcmcia_io_handle sc_auxpioh;
   79         int sc_iowindow;
   80         int sc_auxiowindow;
   81         void *sc_ih;
   82         struct pcmcia_function *sc_pf;
   83         int sc_flags;
   84 #define WDC_PCMCIA_ATTACH       0x0001
   85 };
   86 
   87 static int wdc_pcmcia_match(struct device *, void *, void *);
   88 static void wdc_pcmcia_attach(struct device *, struct device *, void *);
   89 int    wdc_pcmcia_detach(struct device *, int);
   90 int    wdc_pcmcia_activate(struct device *, enum devact);
   91 
   92 struct cfattach wdc_pcmcia_ca = {
   93         sizeof(struct wdc_pcmcia_softc), wdc_pcmcia_match, wdc_pcmcia_attach,
   94         wdc_pcmcia_detach, wdc_pcmcia_activate
   95 };
   96 
   97 struct wdc_pcmcia_product {
   98         u_int16_t       wpp_vendor;     
   99         u_int16_t       wpp_product;    
  100         int             wpp_quirk_flag; 
  101 #define WDC_PCMCIA_FORCE_16BIT_IO       0x01 
  102 #define WDC_PCMCIA_NO_EXTRA_RESETS      0x02 
  103         const char      *wpp_cis_info[4];       
  104 } wdc_pcmcia_pr[] = {
  105 
  106         {  0x0100,
  107           PCMCIA_PRODUCT_DIGITAL_MOBILE_MEDIA_CDROM,
  108           0, { NULL, "Digital Mobile Media CD-ROM", NULL, NULL }, },
  109 
  110         { PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_PORTABLE_CDROM,
  111           0, { NULL, "Portable CD-ROM Drive", NULL, NULL }, },
  112 
  113         { PCMCIA_VENDOR_HAGIWARASYSCOM, PCMCIA_PRODUCT_INVALID, 
  114           WDC_PCMCIA_FORCE_16BIT_IO, { NULL, NULL, NULL, NULL }, },
  115 
  116         
  117         { PCMCIA_VENDOR_TEAC, PCMCIA_PRODUCT_TEAC_IDECARDII,
  118           WDC_PCMCIA_NO_EXTRA_RESETS, PCMCIA_CIS_TEAC_IDECARDII },
  119 
  120         
  121 
  122 
  123 
  124         { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
  125           0, PCMCIA_CIS_EXP_EXPMULTIMEDIA },
  126 
  127         
  128         { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
  129           0, PCMCIA_CIS_SHUTTLE_IDE_ATAPI },
  130 
  131         
  132         { PCMCIA_VENDOR_ARCHOS, PCMCIA_PRODUCT_ARCHOS_ARC_ATAPI,
  133           0, PCMCIA_CIS_ARCHOS_ARC_ATAPI },
  134 };
  135 
  136 struct wdc_pcmcia_disk_device_interface_args {
  137         int ddi_type;           
  138         int ddi_reqfn;          
  139         int ddi_curfn;          
  140 };
  141 
  142 int     wdc_pcmcia_disk_device_interface_callback(struct pcmcia_tuple *,
  143             void *);
  144 int     wdc_pcmcia_disk_device_interface(struct pcmcia_function *);
  145 struct wdc_pcmcia_product *
  146         wdc_pcmcia_lookup(struct pcmcia_attach_args *);
  147 
  148 int     wdc_pcmcia_enable(void *, int);
  149 
  150 int
  151 wdc_pcmcia_disk_device_interface_callback(tuple, arg)
  152         struct pcmcia_tuple *tuple;
  153         void *arg;
  154 {
  155         struct wdc_pcmcia_disk_device_interface_args *ddi = arg;
  156 
  157         switch (tuple->code) {
  158         case PCMCIA_CISTPL_FUNCID:
  159                 ddi->ddi_curfn++;
  160                 break;
  161 
  162         case PCMCIA_CISTPL_FUNCE:
  163                 if (ddi->ddi_reqfn != ddi->ddi_curfn)
  164                         break;
  165 
  166                 
  167                 if (tuple->length < 2)
  168                         break;
  169 
  170                 
  171                 if (pcmcia_tuple_read_1(tuple, 0) !=
  172                     PCMCIA_TPLFE_TYPE_DISK_DEVICE_INTERFACE)
  173                         break;
  174 
  175                 ddi->ddi_type = pcmcia_tuple_read_1(tuple, 1);
  176                 return (1);
  177         }
  178         return (0);
  179 }
  180 
  181 int
  182 wdc_pcmcia_disk_device_interface(pf)
  183         struct pcmcia_function *pf;
  184 {
  185         struct wdc_pcmcia_disk_device_interface_args ddi;
  186 
  187         ddi.ddi_reqfn = pf->number;
  188         ddi.ddi_curfn = -1;
  189         if (pcmcia_scan_cis((struct device *)pf->sc,
  190             wdc_pcmcia_disk_device_interface_callback, &ddi) > 0)
  191                 return (ddi.ddi_type);
  192         else
  193                 return (-1);
  194 }
  195 
  196 struct wdc_pcmcia_product *
  197 wdc_pcmcia_lookup(pa)
  198         struct pcmcia_attach_args *pa;
  199 {
  200         struct wdc_pcmcia_product *wpp;
  201         int i, cis_match;
  202 
  203         for (wpp = wdc_pcmcia_pr;
  204             wpp < &wdc_pcmcia_pr[sizeof(wdc_pcmcia_pr)/sizeof(wdc_pcmcia_pr[0])];
  205             wpp++)
  206                 if ((wpp->wpp_vendor == PCMCIA_VENDOR_INVALID ||
  207                      pa->manufacturer == wpp->wpp_vendor) &&
  208                     (wpp->wpp_product == PCMCIA_PRODUCT_INVALID ||
  209                      pa->product == wpp->wpp_product)) {
  210                         cis_match = 1;
  211                         for (i = 0; i < 4; i++) {
  212                                 if (!(wpp->wpp_cis_info[i] == NULL ||
  213                                       (pa->card->cis1_info[i] != NULL &&
  214                                        strcmp(pa->card->cis1_info[i],
  215                                               wpp->wpp_cis_info[i]) == 0)))
  216                                         cis_match = 0;
  217                         }
  218                         if (cis_match)
  219                                 return (wpp);
  220                 }
  221 
  222         return (NULL);
  223 }
  224 
  225 static int
  226 wdc_pcmcia_match(parent, match, aux)
  227         struct device *parent;
  228         void *match, *aux;
  229 {
  230         struct pcmcia_attach_args *pa = aux;
  231         struct pcmcia_softc *sc;
  232         int iftype;
  233 
  234         if (wdc_pcmcia_lookup(pa) != NULL)
  235                 return (1);
  236 
  237         if (pa->pf->function == PCMCIA_FUNCTION_DISK) {
  238                 sc = pa->pf->sc;
  239 
  240                 pcmcia_chip_socket_enable(sc->pct, sc->pch);
  241                 iftype = wdc_pcmcia_disk_device_interface(pa->pf);
  242                 pcmcia_chip_socket_disable(sc->pct, sc->pch);
  243 
  244                 if (iftype == PCMCIA_TPLFE_DDI_PCCARD_ATA)
  245                         return (1);
  246         }
  247 
  248         return (0);
  249 }
  250 
  251 static void
  252 wdc_pcmcia_attach(parent, self, aux)
  253         struct device *parent;
  254         struct device *self;
  255         void *aux;
  256 {
  257         struct wdc_pcmcia_softc *sc = (void *)self;
  258         struct pcmcia_attach_args *pa = aux;
  259         struct pcmcia_config_entry *cfe;
  260         struct wdc_pcmcia_product *wpp;
  261         const char *intrstr;
  262         int quirks;
  263 
  264         sc->sc_pf = pa->pf;
  265 
  266         for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL;
  267             cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
  268                 if (cfe->num_iospace != 1 && cfe->num_iospace != 2)
  269                         continue;
  270 
  271                 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
  272                     cfe->iospace[0].length,
  273                     cfe->iospace[0].start == 0 ? cfe->iospace[0].length : 0,
  274                     &sc->sc_pioh))
  275                         continue;
  276 
  277                 if (cfe->num_iospace == 2) {
  278                         if (!pcmcia_io_alloc(pa->pf, cfe->iospace[1].start,
  279                             cfe->iospace[1].length, 0, &sc->sc_auxpioh))
  280                                 break;
  281                 } else  {
  282                         sc->sc_auxpioh.iot = sc->sc_pioh.iot;
  283                         if (!bus_space_subregion(sc->sc_pioh.iot,
  284                             sc->sc_pioh.ioh, WDC_PCMCIA_AUXREG_OFFSET,
  285                             WDC_PCMCIA_AUXREG_NPORTS, &sc->sc_auxpioh.ioh))
  286                                 break;
  287                 }
  288                 pcmcia_io_free(pa->pf, &sc->sc_pioh);
  289         }
  290 
  291         if (cfe == NULL) {
  292                 printf(": can't handle card info\n");
  293                 goto no_config_entry;
  294         }
  295 
  296         
  297         pcmcia_function_init(pa->pf, cfe);
  298         if (pcmcia_function_enable(pa->pf)) {
  299                 printf(": function enable failed\n");
  300                 goto enable_failed;
  301         }
  302 
  303         
  304 
  305 
  306 
  307 
  308 
  309 
  310         wpp = wdc_pcmcia_lookup(pa);
  311         if (wpp != NULL)
  312                 quirks = wpp->wpp_quirk_flag;
  313         else
  314                 quirks = 0;
  315 
  316         if (pcmcia_io_map(pa->pf, quirks & WDC_PCMCIA_FORCE_16BIT_IO ?
  317             PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO, 0,
  318             sc->sc_pioh.size, &sc->sc_pioh, &sc->sc_iowindow)) {
  319                 printf(": can't map first I/O space\n");
  320                 goto iomap_failed;
  321         } 
  322 
  323         
  324 
  325 
  326 
  327 
  328         if (cfe->num_iospace <= 1)
  329                 sc->sc_auxiowindow = -1;
  330         else if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0,
  331             sc->sc_auxpioh.size, &sc->sc_auxpioh, &sc->sc_auxiowindow)) {
  332                 printf(": can't map second I/O space\n");
  333                 goto iomapaux_failed;
  334         }
  335 
  336         printf(" port 0x%lx/%lu",
  337             sc->sc_pioh.addr, (u_long)sc->sc_pioh.size);
  338         if (cfe->num_iospace > 1 && sc->sc_auxpioh.size > 0)
  339                 printf(",0x%lx/%lu",
  340                     sc->sc_auxpioh.addr, (u_long)sc->sc_auxpioh.size);
  341 
  342         sc->wdc_channel.cmd_iot = sc->sc_pioh.iot;
  343         sc->wdc_channel.cmd_ioh = sc->sc_pioh.ioh;
  344         sc->wdc_channel.ctl_iot = sc->sc_auxpioh.iot;
  345         sc->wdc_channel.ctl_ioh = sc->sc_auxpioh.ioh;
  346         sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot;
  347         sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh;
  348         sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
  349         sc->sc_wdcdev.PIO_cap = 0;
  350         sc->wdc_chanptr = &sc->wdc_channel;
  351         sc->sc_wdcdev.channels = &sc->wdc_chanptr;
  352         sc->sc_wdcdev.nchannels = 1;
  353         sc->wdc_channel.channel = 0;
  354         sc->wdc_channel.wdc = &sc->sc_wdcdev;
  355         sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
  356             M_DEVBUF, M_NOWAIT);
  357         if (sc->wdc_channel.ch_queue == NULL) {
  358                 printf("can't allocate memory for command queue\n");
  359                 goto ch_queue_alloc_failed;
  360         }
  361         if (quirks & WDC_PCMCIA_NO_EXTRA_RESETS)
  362                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
  363 
  364 #ifdef notyet
  365         
  366         sc->sc_wdcdev.sc_atapi_adapter.scsipi_enable = wdc_pcmcia_enable;
  367 
  368         
  369 
  370 
  371 
  372         pcmcia_function_disable(pa->pf);
  373 #else
  374         
  375         sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr,
  376             &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
  377         intrstr = pcmcia_intr_string(sc->sc_pf, sc->sc_ih);
  378         if (*intrstr)
  379                 printf(": %s", intrstr);
  380 #endif
  381 
  382         printf("\n");
  383 
  384         sc->sc_flags |= WDC_PCMCIA_ATTACH;
  385         wdcattach(&sc->wdc_channel);
  386         wdc_print_current_modes(&sc->wdc_channel);
  387         sc->sc_flags &= ~WDC_PCMCIA_ATTACH;
  388         return;
  389 
  390  ch_queue_alloc_failed:
  391         
  392         if (sc->sc_auxiowindow != -1)
  393                 pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
  394 
  395  iomapaux_failed:
  396         
  397         pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
  398 
  399  iomap_failed:
  400         
  401         pcmcia_function_disable(sc->sc_pf);
  402 
  403  enable_failed:
  404         
  405         pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
  406         if (cfe->num_iospace == 2)
  407                 pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
  408 
  409  no_config_entry:
  410         sc->sc_iowindow = -1;
  411 }
  412 
  413 int
  414 wdc_pcmcia_detach(self, flags)
  415         struct device *self;
  416         int  flags;
  417 {
  418         struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
  419         int error;
  420 
  421         if (sc->sc_iowindow == -1)
  422                 
  423                 return (0);
  424         
  425         if ((error = wdcdetach(&sc->wdc_channel, flags)) != 0) 
  426                 return (error);
  427 
  428         if (sc->wdc_channel.ch_queue != NULL)
  429                 free(sc->wdc_channel.ch_queue, M_DEVBUF);
  430 
  431         
  432         pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
  433         pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
  434         if (sc->sc_auxiowindow != -1) {
  435                 pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
  436                 pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
  437         }
  438 
  439         return (0);
  440 }
  441 
  442 int
  443 wdc_pcmcia_activate(self, act)
  444         struct device *self;
  445         enum devact act;
  446 {
  447         struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
  448         int rv = 0, s;
  449 
  450         s = splbio();
  451         switch (act) {
  452         case DVACT_ACTIVATE:
  453                 if (pcmcia_function_enable(sc->sc_pf)) {
  454                         printf("%s: couldn't enable PCMCIA function\n",
  455                             sc->sc_wdcdev.sc_dev.dv_xname);
  456                         rv = EIO;
  457                         break;
  458                 }
  459 
  460                 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
  461                     wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
  462                 if (sc->sc_ih == NULL) {
  463                         printf("%s: "
  464                             "couldn't establish interrupt handler\n",
  465                             sc->sc_wdcdev.sc_dev.dv_xname);
  466                         pcmcia_function_disable(sc->sc_pf);
  467                         rv = EIO;
  468                         break;
  469                 }
  470 
  471                 wdcreset(&sc->wdc_channel, VERBOSE);
  472                 rv = wdcactivate(self, act);
  473                 break;
  474 
  475         case DVACT_DEACTIVATE:
  476                 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  477                 pcmcia_function_disable(sc->sc_pf);
  478                 rv = wdcactivate(self, act);
  479                 break;
  480         }
  481         splx(s);
  482         return (rv);
  483 }
  484 
  485 #if 0
  486 int
  487 wdc_pcmcia_enable(arg, onoff)
  488         void *arg;
  489         int onoff;
  490 {
  491         struct wdc_pcmcia_softc *sc = arg;
  492 
  493         if (onoff) {
  494                 if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) {
  495                         if (pcmcia_function_enable(sc->sc_pf)) {
  496                                 printf("%s: couldn't enable PCMCIA function\n",
  497                                     sc->sc_wdcdev.sc_dev.dv_xname);
  498                                 return (EIO);
  499                         }
  500 
  501                         sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
  502                             wdcintr, &sc->wdc_channel, sc->sc_dev.dv_xname);
  503                         if (sc->sc_ih == NULL) {
  504                                 printf("%s: "
  505                                     "couldn't establish interrupt handler\n",
  506                                     sc->sc_wdcdev.sc_dev.dv_xname);
  507                                 pcmcia_function_disable(sc->sc_pf);
  508                                 return (EIO);
  509                         }
  510 
  511                         wdcreset(&sc->wdc_channel, VERBOSE);
  512                 }
  513         } else {
  514                 if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0)
  515                         pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  516                 pcmcia_function_disable(sc->sc_pf);
  517         }
  518 
  519         return (0);
  520 }
  521 #endif