1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <sys/types.h>
  28 #include <sys/byteorder.h>
  29 #include <sys/systm.h>
  30 #include <sys/ddi.h>
  31 #include <sys/sunddi.h>
  32 
  33 int pcs_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
  34 int pcs_attach(dev_info_t *, ddi_attach_cmd_t);
  35 int pcs_detach(dev_info_t *, ddi_detach_cmd_t);
  36 dev_info_t *pcs_dip;
  37 
  38 static struct dev_ops pcs_devops = {
  39         DEVO_REV,
  40         0,
  41         pcs_getinfo,
  42         nulldev,
  43         nulldev,
  44         pcs_attach,
  45         pcs_detach,
  46         nulldev,
  47         NULL,
  48         NULL,
  49         NULL,
  50         ddi_quiesce_not_needed,         /* quiesce */
  51 };
  52 /*
  53  * This is the loadable module wrapper.
  54  */
  55 #include <sys/modctl.h>
  56 
  57 extern struct mod_ops mod_driverops;
  58 
  59 static struct modldrv modldrv = {
  60         &mod_driverops,             /* Type of module. This one is a driver */
  61         "PCMCIA Socket Driver", /* Name of the module. */
  62         &pcs_devops,                /* driver ops */
  63 };
  64 
  65 static struct modlinkage modlinkage = {
  66         MODREV_1, (void *)&modldrv, NULL
  67 };
  68 
  69 struct pcs_inst {
  70         dev_info_t *dip;
  71 } *pcs_instances;
  72 
  73 int
  74 _init()
  75 {
  76         int ret;
  77         if ((ret = ddi_soft_state_init((void **)&pcs_instances,
  78             sizeof (struct pcs_inst), 1)) != 0)
  79                 return (ret);
  80         if ((ret = mod_install(&modlinkage)) != 0) {
  81                 ddi_soft_state_fini((void **)&pcs_instances);
  82         }
  83         return (ret);
  84 }
  85 
  86 int
  87 _fini()
  88 {
  89         int ret;
  90         ret = mod_remove(&modlinkage);
  91         if (ret == 0) {
  92                 ddi_soft_state_fini((void **)&pcs_instances);
  93         }
  94         return (ret);
  95 }
  96 
  97 int
  98 _info(struct modinfo *modinfop)
  99 {
 100         return (mod_info(&modlinkage, modinfop));
 101 }
 102 
 103 int
 104 pcs_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 105 {
 106         int error = DDI_SUCCESS;
 107         int inum;
 108         struct pcs_inst *inst;
 109 #ifdef lint
 110         dip = dip;
 111 #endif
 112 
 113         switch (cmd) {
 114         case DDI_INFO_DEVT2DEVINFO:
 115                 inum = getminor((dev_t)arg);
 116                 inst = (struct pcs_inst *)ddi_get_soft_state(pcs_instances,
 117                     inum);
 118                 if (inst == NULL)
 119                         error = DDI_FAILURE;
 120                 else
 121                         *result = inst->dip;
 122                 break;
 123         case DDI_INFO_DEVT2INSTANCE:
 124                 inum = getminor((dev_t)arg);
 125                 inst = (struct pcs_inst *)ddi_get_soft_state(pcs_instances,
 126                     inum);
 127                 if (inst == NULL)
 128                         error = DDI_FAILURE;
 129                 else
 130                         *result = (void *)(uintptr_t)inum;
 131                 break;
 132         default:
 133                 error = DDI_FAILURE;
 134         }
 135         return (error);
 136 }
 137 
 138 int
 139 pcs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 140 {
 141         int ret = DDI_SUCCESS;
 142         int inum;
 143         struct pcs_inst *inst;
 144 
 145         switch (cmd) {
 146         case DDI_RESUME:
 147                 return (DDI_SUCCESS);
 148         case DDI_ATTACH:
 149                 break;
 150         default:
 151                 return (DDI_FAILURE);
 152         }
 153 
 154         inum = ddi_get_instance(dip);
 155 
 156         if (ddi_soft_state_zalloc(pcs_instances, inum) == DDI_SUCCESS) {
 157                 inst = (struct pcs_inst *)ddi_get_soft_state(pcs_instances,
 158                     inum);
 159                 if (inst == NULL)
 160                         ret = DDI_FAILURE;
 161                 else
 162                         inst->dip = dip;
 163         }
 164 
 165         return (ret);
 166 }
 167 
 168 int
 169 pcs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 170 {
 171         switch (cmd) {
 172         case DDI_DETACH:
 173                 ddi_soft_state_free(pcs_instances, ddi_get_instance(dip));
 174                 return (DDI_SUCCESS);
 175 
 176         case DDI_SUSPEND:
 177         case DDI_PM_SUSPEND:
 178                 return (DDI_SUCCESS);
 179         default:
 180                 break;
 181         }
 182         return (DDI_FAILURE);
 183 }