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/stat.h> 29 #include <sys/conf.h> 30 #include <sys/modctl.h> 31 #include <sys/sunddi.h> 32 #include <sys/callb.h> 33 #include <sys/strlog.h> 34 #include <sys/file.h> 35 #include <sys/lom_io.h> 36 #include <sys/ddi.h> 37 #include <sys/time.h> 38 39 #define LOMIOCALCTL_OLD _IOW('a', 4, ts_aldata_t) 40 #define LOMIOCALSTATE_OLD _IOWR('a', 5, ts_aldata_t) 41 42 struct tsalarm_softc { 43 dev_info_t *dip; 44 kmutex_t mutex; 45 }; 46 47 #define getsoftc(minor) \ 48 ((struct tsalarm_softc *)ddi_get_soft_state(statep, (minor))) 49 /* 50 * Driver entry points 51 */ 52 53 /* dev_ops and cb_ops entry point function declarations */ 54 55 static int tsalarm_attach(dev_info_t *, ddi_attach_cmd_t); 56 static int tsalarm_detach(dev_info_t *, ddi_detach_cmd_t); 57 static int tsalarm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 58 59 static int tsalarm_open(dev_t *, int, int, cred_t *); 60 static int tsalarm_close(dev_t, int, int, cred_t *); 61 static int tsalarm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 62 63 static struct cb_ops tsalarm_cb_ops = { 64 tsalarm_open, /* open */ 65 tsalarm_close, /* close */ 66 nodev, /* strategy() */ 67 nodev, /* print() */ 68 nodev, /* dump() */ 69 nodev, /* read() */ 70 nodev, /* write() */ 71 tsalarm_ioctl, /* ioctl() */ 72 nodev, /* devmap() */ 73 nodev, /* mmap() */ 74 ddi_segmap, /* segmap() */ 75 nochpoll, /* poll() */ 76 ddi_prop_op, /* prop_op() */ 77 NULL, /* cb_str */ 78 D_NEW | D_MP /* cb_flag */ 79 }; 80 81 82 static struct dev_ops tsalarm_ops = { 83 DEVO_REV, 84 0, /* ref count */ 85 tsalarm_getinfo, /* getinfo() */ 86 nulldev, /* identify() */ 87 nulldev, /* probe() */ 88 tsalarm_attach, /* attach() */ 89 tsalarm_detach, /* detach */ 90 nodev, /* reset */ 91 &tsalarm_cb_ops, /* pointer to cb_ops structure */ 92 (struct bus_ops *)NULL, 93 nulldev, /* power() */ 94 ddi_quiesce_not_needed, /* quiesce() */ 95 }; 96 97 /* 98 * Loadable module support. 99 */ 100 extern struct mod_ops mod_driverops; 101 static void *statep; 102 103 static struct modldrv modldrv = { 104 &mod_driverops, /* Type of module. This is a driver */ 105 "tsalarm control driver", /* Name of the module */ 106 &tsalarm_ops /* pointer to the dev_ops structure */ 107 }; 108 109 static struct modlinkage modlinkage = { 110 MODREV_1, 111 &modldrv, 112 NULL 113 }; 114 115 extern int rmclomv_alarm_get(int alarm_type, int *alarm_state); 116 extern int rmclomv_alarm_set(int alarm_type, int new_state); 117 118 int 119 _init(void) 120 { 121 int e; 122 123 if (e = ddi_soft_state_init(&statep, 124 sizeof (struct tsalarm_softc), 1)) { 125 return (e); 126 } 127 128 if ((e = mod_install(&modlinkage)) != 0) { 129 ddi_soft_state_fini(&statep); 130 } 131 132 return (e); 133 } 134 135 136 int 137 _fini(void) 138 { 139 int e; 140 141 if ((e = mod_remove(&modlinkage)) != 0) { 142 return (e); 143 } 144 145 ddi_soft_state_fini(&statep); 146 147 return (DDI_SUCCESS); 148 } 149 150 151 int 152 _info(struct modinfo *modinfop) 153 { 154 return (mod_info(&modlinkage, modinfop)); 155 } 156 157 158 /* ARGSUSED */ 159 static int 160 tsalarm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 161 { 162 int inst = getminor((dev_t)arg); 163 int retval = DDI_SUCCESS; 164 struct tsalarm_softc *softc; 165 166 switch (cmd) { 167 168 case DDI_INFO_DEVT2DEVINFO: 169 if ((softc = getsoftc(inst)) == NULL) { 170 *result = (void *)NULL; 171 retval = DDI_FAILURE; 172 } else { 173 *result = (void *)softc->dip; 174 } 175 break; 176 177 case DDI_INFO_DEVT2INSTANCE: 178 *result = (void *)(uintptr_t)inst; 179 break; 180 181 default: 182 retval = DDI_FAILURE; 183 } 184 185 return (retval); 186 } 187 188 static int 189 tsalarm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 190 { 191 192 int inst; 193 struct tsalarm_softc *softc = NULL; 194 195 switch (cmd) { 196 197 case DDI_ATTACH: 198 inst = ddi_get_instance(dip); 199 /* 200 * Allocate a soft state structure for this instance. 201 */ 202 if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) 203 goto attach_failed; 204 205 softc = getsoftc(inst); 206 softc->dip = dip; 207 mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL); 208 /* 209 * Create minor node. The minor device number, inst, has no 210 * meaning. The model number above, which will be added to 211 * the device's softc, is used to direct peculiar behavior. 212 */ 213 if (ddi_create_minor_node(dip, "lom", S_IFCHR, 0, 214 DDI_PSEUDO, 0) == DDI_FAILURE) 215 goto attach_failed; 216 217 ddi_report_dev(dip); 218 return (DDI_SUCCESS); 219 220 case DDI_RESUME: 221 return (DDI_SUCCESS); 222 223 default: 224 return (DDI_FAILURE); 225 } 226 227 attach_failed: 228 /* Free soft state, if allocated. remove minor node if added earlier */ 229 if (softc) { 230 mutex_destroy(&softc->mutex); 231 ddi_soft_state_free(statep, inst); 232 } 233 234 ddi_remove_minor_node(dip, NULL); 235 236 return (DDI_FAILURE); 237 } 238 239 static int 240 tsalarm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 241 { 242 int inst; 243 struct tsalarm_softc *softc; 244 245 switch (cmd) { 246 247 case DDI_DETACH: 248 inst = ddi_get_instance(dip); 249 if ((softc = getsoftc(inst)) == NULL) 250 return (DDI_FAILURE); 251 /* 252 * Free the soft state and remove minor node added earlier. 253 */ 254 ddi_remove_minor_node(dip, NULL); 255 mutex_destroy(&softc->mutex); 256 ddi_soft_state_free(statep, inst); 257 return (DDI_SUCCESS); 258 259 case DDI_SUSPEND: 260 return (DDI_SUCCESS); 261 262 default: 263 return (DDI_FAILURE); 264 265 } 266 } 267 268 /* ARGSUSED */ 269 static int 270 tsalarm_open(dev_t *devp, int flag, int otyp, cred_t *credp) 271 { 272 int inst = getminor(*devp); 273 274 return (getsoftc(inst) == NULL ? ENXIO : 0); 275 } 276 277 278 /* ARGSUSED */ 279 static int 280 tsalarm_close(dev_t dev, int flag, int otyp, cred_t *credp) 281 { 282 int inst = getminor(dev); 283 284 return (getsoftc(inst) == NULL ? ENXIO : 0); 285 } 286 287 288 /* ARGSUSED */ 289 static int 290 tsalarm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 291 cred_t *credp, int *rvalp) 292 { 293 int inst = getminor(dev); 294 struct tsalarm_softc *softc; 295 int retval = 0; 296 ts_aldata_t ts_alinfo; 297 int alarm_type, alarm_state = 0; 298 299 if ((softc = getsoftc(inst)) == NULL) 300 return (ENXIO); 301 302 mutex_enter(&softc->mutex); 303 304 switch (cmd) { 305 306 case LOMIOCALSTATE: 307 case LOMIOCALSTATE_OLD: 308 { 309 if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo, 310 sizeof (ts_aldata_t), mode) != 0) { 311 retval = EFAULT; 312 goto end; 313 } 314 315 alarm_type = ts_alinfo.alarm_no; 316 if ((alarm_type < ALARM_CRITICAL) || 317 (alarm_type > ALARM_USER)) { 318 retval = EINVAL; 319 goto end; 320 } 321 322 retval = rmclomv_alarm_get(alarm_type, &alarm_state); 323 324 if (retval != 0) 325 goto end; 326 327 if ((alarm_state != 0) && (alarm_state != 1)) { 328 retval = EIO; 329 goto end; 330 } 331 332 ts_alinfo.alarm_state = alarm_state; 333 if (ddi_copyout((caddr_t)&ts_alinfo, (caddr_t)arg, 334 sizeof (ts_aldata_t), mode) != 0) { 335 retval = EFAULT; 336 goto end; 337 } 338 339 } 340 break; 341 342 case LOMIOCALCTL: 343 case LOMIOCALCTL_OLD: 344 { 345 if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo, 346 sizeof (ts_aldata_t), mode) != 0) { 347 retval = EFAULT; 348 goto end; 349 } 350 351 alarm_type = ts_alinfo.alarm_no; 352 alarm_state = ts_alinfo.alarm_state; 353 354 if ((alarm_type < ALARM_CRITICAL) || 355 (alarm_type > ALARM_USER)) { 356 retval = EINVAL; 357 goto end; 358 } 359 if ((alarm_state < ALARM_OFF) || 360 (alarm_state > ALARM_ON)) { 361 retval = EINVAL; 362 goto end; 363 } 364 365 retval = rmclomv_alarm_set(alarm_type, alarm_state); 366 } 367 break; 368 369 default: 370 retval = EINVAL; 371 break; 372 } 373 374 end: 375 mutex_exit(&softc->mutex); 376 377 return (retval); 378 } 379