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 /* 28 * skeleton hub driver, the actual code is in hubdi.c 29 * as it is shared between the root hub and the other hub instances 30 */ 31 #if defined(lint) && !defined(DEBUG) 32 #define DEBUG 1 33 #endif 34 35 #include <sys/usb/usba/usbai_version.h> 36 #include <sys/usb/usba.h> 37 #include <sys/usb/usba/hubdi.h> 38 #include <sys/usb/hubd/hub.h> 39 #include <sys/usb/hubd/hubdvar.h> 40 41 static int hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp); 42 static int hubd_close(dev_t dev, int flag, int otyp, cred_t *credp); 43 static int hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 44 cred_t *credp, int *rvalp); 45 static int hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 46 void *arg, void **result); 47 extern int usba_hubdi_power(dev_info_t *dip, int comp, int level); 48 49 50 static struct cb_ops hubd_cb_ops = { 51 hubd_open, /* open */ 52 hubd_close, /* close */ 53 nodev, /* strategy */ 54 nodev, /* print */ 55 nodev, /* dump */ 56 nodev, /* read */ 57 nodev, /* write */ 58 hubd_ioctl, /* ioctl */ 59 nodev, /* devmap */ 60 nodev, /* mmap */ 61 nodev, /* segmap */ 62 nochpoll, /* poll */ 63 ddi_prop_op, /* cb_prop_op */ 64 NULL, /* streamtab */ 65 D_MP /* Driver compatibility flag */ 66 }; 67 68 static struct dev_ops hubd_ops = { 69 DEVO_REV, /* devo_rev, */ 70 0, /* refcnt */ 71 hubd_info, /* info */ 72 nulldev, /* identify */ 73 nulldev, /* probe */ 74 usba_hubdi_attach, /* attach */ 75 usba_hubdi_detach, /* detach */ 76 nodev, /* reset */ 77 &hubd_cb_ops, /* driver operations */ 78 &usba_hubdi_busops, /* bus operations */ 79 usba_hubdi_power, /* power */ 80 ddi_quiesce_not_needed, /* quiesce */ 81 }; 82 83 static struct modldrv modldrv = { 84 &mod_driverops, /* Type of module. This one is a driver */ 85 "USB Hub Driver", /* Name of the module. */ 86 &hubd_ops, /* driver ops */ 87 }; 88 89 static struct modlinkage modlinkage = { 90 MODREV_1, (void *)&modldrv, NULL 91 }; 92 93 94 extern void *hubd_statep; 95 96 int 97 _init(void) 98 { 99 int rval; 100 101 /* Initialize the soft state structures */ 102 if ((rval = ddi_soft_state_init(&hubd_statep, 103 sizeof (hubd_t), HUBD_INITIAL_SOFT_SPACE)) != 0) { 104 return (rval); 105 } 106 107 if ((rval = mod_install(&modlinkage)) != 0) { 108 ddi_soft_state_fini(&hubd_statep); 109 110 return (rval); 111 } 112 113 return (rval); 114 } 115 116 117 int 118 _fini(void) 119 { 120 int rval = mod_remove(&modlinkage); 121 if (rval == 0) { 122 ddi_soft_state_fini(&hubd_statep); 123 } 124 125 return (rval); 126 } 127 128 129 int 130 _info(struct modinfo *modinfop) 131 { 132 return (mod_info(&modlinkage, modinfop)); 133 } 134 135 136 static dev_info_t * 137 hubd_get_dip(dev_t dev) 138 { 139 minor_t minor = getminor(dev); 140 int instance = (int)minor & ~HUBD_IS_ROOT_HUB; 141 hubd_t *hubd = ddi_get_soft_state(hubd_statep, instance); 142 143 if (hubd) { 144 return (hubd->h_dip); 145 } else { 146 return (NULL); 147 } 148 } 149 150 /* 151 * info handler 152 */ 153 /*ARGSUSED*/ 154 int 155 hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 156 void *arg, void **result) 157 { 158 dev_t dev; 159 int instance; 160 int error = DDI_FAILURE; 161 162 switch (infocmd) { 163 case DDI_INFO_DEVT2DEVINFO: 164 *result = (void *)hubd_get_dip((dev_t)arg); 165 if (*result != NULL) { 166 error = DDI_SUCCESS; 167 } 168 break; 169 case DDI_INFO_DEVT2INSTANCE: 170 dev = (dev_t)arg; 171 instance = HUBD_UNIT(dev); 172 *result = (void *)(intptr_t)instance; 173 error = DDI_SUCCESS; 174 break; 175 default: 176 break; 177 } 178 return (error); 179 } 180 181 static int 182 hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp) 183 { 184 dev_info_t *dip = hubd_get_dip(*devp); 185 186 return (usba_hubdi_open(dip, devp, flags, otyp, credp)); 187 } 188 189 190 static int 191 hubd_close(dev_t dev, int flag, int otyp, cred_t *credp) 192 { 193 dev_info_t *dip = hubd_get_dip(dev); 194 195 return (usba_hubdi_close(dip, dev, flag, otyp, credp)); 196 } 197 198 199 static int 200 hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 201 cred_t *credp, int *rvalp) 202 { 203 dev_info_t *dip = hubd_get_dip(dev); 204 205 return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode, 206 credp, rvalp)); 207 } 208