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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2000-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 30 #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */ 31 #include <sys/modctl.h> /* for modldrv */ 32 #include <sys/open.h> /* for open params. */ 33 #include <sys/types.h> 34 #include <sys/kmem.h> 35 #include <sys/sunddi.h> 36 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 37 #include <sys/ddi.h> 38 #include <sys/file.h> 39 #include <sys/note.h> 40 41 #include <sys/i2c/clients/ltc1427_impl.h> 42 43 static void *ltc1427soft_statep; 44 45 46 static int ltc1427_do_attach(dev_info_t *); 47 static int ltc1427_do_detach(dev_info_t *); 48 static int ltc1427_do_resume(void); 49 static int ltc1427_do_suspend(void); 50 51 /* 52 * cb ops (only need ioctl) 53 */ 54 static int ltc1427_open(dev_t *, int, int, cred_t *); 55 static int ltc1427_close(dev_t, int, int, cred_t *); 56 static int ltc1427_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 57 58 static struct cb_ops ltc1427_cbops = { 59 ltc1427_open, /* open */ 60 ltc1427_close, /* close */ 61 nodev, /* strategy */ 62 nodev, /* print */ 63 nodev, /* dump */ 64 nodev, /* read */ 65 nodev, /* write */ 66 ltc1427_ioctl, /* ioctl */ 67 nodev, /* devmap */ 68 nodev, /* mmap */ 69 nodev, /* segmap */ 70 nochpoll, /* poll */ 71 ddi_prop_op, /* cb_prop_op */ 72 NULL, /* streamtab */ 73 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 74 CB_REV, /* rev */ 75 nodev, /* int (*cb_aread)() */ 76 nodev /* int (*cb_awrite)() */ 77 }; 78 79 /* 80 * dev ops 81 */ 82 static int ltc1427_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 83 static int ltc1427_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 84 85 static struct dev_ops ltc1427_ops = { 86 DEVO_REV, 87 0, 88 ddi_getinfo_1to1, 89 nulldev, 90 nulldev, 91 ltc1427_attach, 92 ltc1427_detach, 93 nodev, 94 <c1427_cbops, 95 NULL 96 }; 97 98 extern struct mod_ops mod_driverops; 99 100 static struct modldrv ltc1427_modldrv = { 101 &mod_driverops, /* type of module - driver */ 102 "LTC1427 i2c device driver: v%I%", 103 <c1427_ops 104 }; 105 106 static struct modlinkage ltc1427_modlinkage = { 107 MODREV_1, 108 <c1427_modldrv, 109 0 110 }; 111 112 113 int 114 _init(void) 115 { 116 int error; 117 118 error = mod_install(<c1427_modlinkage); 119 120 if (!error) 121 (void) ddi_soft_state_init(<c1427soft_statep, 122 sizeof (struct ltc1427_unit), 1); 123 return (error); 124 } 125 126 int 127 _fini(void) 128 { 129 int error; 130 131 error = mod_remove(<c1427_modlinkage); 132 if (!error) 133 ddi_soft_state_fini(<c1427soft_statep); 134 135 return (error); 136 } 137 138 int 139 _info(struct modinfo *modinfop) 140 { 141 return (mod_info(<c1427_modlinkage, modinfop)); 142 } 143 144 static int 145 ltc1427_open(dev_t *devp, int flags, int otyp, cred_t *credp) 146 { 147 _NOTE(ARGUNUSED(credp)) 148 149 struct ltc1427_unit *unitp; 150 int instance; 151 int error = 0; 152 153 instance = getminor(*devp); 154 155 if (instance < 0) { 156 return (ENXIO); 157 } 158 159 unitp = (struct ltc1427_unit *) 160 ddi_get_soft_state(ltc1427soft_statep, instance); 161 162 if (unitp == NULL) { 163 return (ENXIO); 164 } 165 166 if (otyp != OTYP_CHR) { 167 return (EINVAL); 168 } 169 170 mutex_enter(&unitp->ltc1427_mutex); 171 172 if (flags & FEXCL) { 173 if (unitp->ltc1427_oflag != 0) { 174 error = EBUSY; 175 } else { 176 unitp->ltc1427_oflag = FEXCL; 177 } 178 } else { 179 if (unitp->ltc1427_oflag == FEXCL) { 180 error = EBUSY; 181 } else { 182 unitp->ltc1427_oflag = FOPEN; 183 } 184 } 185 186 mutex_exit(&unitp->ltc1427_mutex); 187 188 return (error); 189 } 190 191 static int 192 ltc1427_close(dev_t dev, int flags, int otyp, cred_t *credp) 193 { 194 _NOTE(ARGUNUSED(flags, otyp, credp)) 195 196 struct ltc1427_unit *unitp; 197 int instance; 198 199 instance = getminor(dev); 200 201 if (instance < 0) { 202 return (ENXIO); 203 } 204 205 unitp = (struct ltc1427_unit *) 206 ddi_get_soft_state(ltc1427soft_statep, instance); 207 208 if (unitp == NULL) { 209 return (ENXIO); 210 } 211 212 mutex_enter(&unitp->ltc1427_mutex); 213 214 unitp->ltc1427_oflag = 0; 215 216 mutex_exit(&unitp->ltc1427_mutex); 217 return (DDI_SUCCESS); 218 } 219 220 static int 221 ltc1427_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 222 cred_t *credp, int *rvalp) 223 { 224 _NOTE(ARGUNUSED(credp, rvalp)) 225 226 struct ltc1427_unit *unitp; 227 int instance; 228 int err = 0; 229 i2c_transfer_t *i2c_tran_pointer; 230 int32_t fan_speed; 231 232 if (arg == NULL) { 233 D2CMN_ERR((CE_WARN, "LTC1427: ioctl: arg passed in to ioctl " 234 "= NULL\n")); 235 err = EINVAL; 236 return (err); 237 } 238 instance = getminor(dev); 239 unitp = (struct ltc1427_unit *) 240 ddi_get_soft_state(ltc1427soft_statep, instance); 241 242 mutex_enter(&unitp->ltc1427_mutex); 243 244 switch (cmd) { 245 case I2C_GET_OUTPUT: 246 D1CMN_ERR((CE_NOTE, "current_set_flag = %d\n", 247 unitp->current_set_flag)); 248 if (unitp->current_set_flag == 0) { 249 err = EIO; 250 break; 251 } else { 252 if (ddi_copyout((caddr_t)&unitp->current_value, 253 (caddr_t)arg, sizeof (int32_t), 254 mode) != DDI_SUCCESS) { 255 D2CMN_ERR((CE_WARN, 256 "%s: Failed in I2C_GET_OUTPUT " 257 "ddi_copyout routine\n", 258 unitp->ltc1427_name)); 259 err = EFAULT; 260 break; 261 } 262 } 263 break; 264 265 case I2C_SET_OUTPUT: 266 if (ddi_copyin((caddr_t)arg, (caddr_t)&fan_speed, 267 sizeof (int32_t), mode) != DDI_SUCCESS) { 268 D2CMN_ERR((CE_WARN, 269 "%s: Failed in I2C_SET_OUTPUT " 270 "ioctl before switch\n", 271 unitp->ltc1427_name)); 272 err = EFAULT; 273 break; 274 } 275 276 (void) i2c_transfer_alloc(unitp->ltc1427_hdl, 277 &i2c_tran_pointer, 2, 0, I2C_SLEEP); 278 if (i2c_tran_pointer == NULL) { 279 D2CMN_ERR((CE_WARN, 280 "%s: Failed in I2C_SET_OUTPUT " 281 "i2c_transfer_pointer not allocated\n", 282 unitp->ltc1427_name)); 283 err = ENOMEM; 284 break; 285 } 286 i2c_tran_pointer->i2c_flags = I2C_WR; 287 i2c_tran_pointer->i2c_wbuf[0] = 288 (uchar_t)((fan_speed >> 8) & 0x03); 289 i2c_tran_pointer->i2c_wbuf[1] = 290 (uchar_t)((fan_speed) & 0x000000ff); 291 292 err = i2c_transfer(unitp->ltc1427_hdl, i2c_tran_pointer); 293 if (!err) { 294 unitp->current_value = fan_speed; 295 unitp->current_set_flag = 1; 296 } 297 i2c_transfer_free(unitp->ltc1427_hdl, i2c_tran_pointer); 298 break; 299 300 default: 301 D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x\n", 302 unitp->ltc1427_name, cmd)); 303 err = EINVAL; 304 } 305 306 mutex_exit(&unitp->ltc1427_mutex); 307 return (err); 308 } 309 310 static int 311 ltc1427_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 312 { 313 switch (cmd) { 314 case DDI_ATTACH: 315 return (ltc1427_do_attach(dip)); 316 case DDI_RESUME: 317 return (ltc1427_do_resume()); 318 default: 319 return (DDI_FAILURE); 320 } 321 } 322 323 static int 324 ltc1427_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 325 { 326 switch (cmd) { 327 case DDI_DETACH: 328 return (ltc1427_do_detach(dip)); 329 case DDI_SUSPEND: 330 return (ltc1427_do_suspend()); 331 default: 332 return (DDI_FAILURE); 333 } 334 } 335 336 static int 337 ltc1427_do_attach(dev_info_t *dip) 338 { 339 struct ltc1427_unit *unitp; 340 int instance; 341 342 instance = ddi_get_instance(dip); 343 344 if (ddi_soft_state_zalloc(ltc1427soft_statep, instance) != 0) { 345 cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n", 346 ddi_get_name(dip), instance); 347 return (DDI_FAILURE); 348 } 349 350 unitp = ddi_get_soft_state(ltc1427soft_statep, instance); 351 352 if (unitp == NULL) { 353 cmn_err(CE_WARN, "%s%d: unitp not filled\n", 354 ddi_get_name(dip), instance); 355 return (ENOMEM); 356 } 357 358 (void) snprintf(unitp->ltc1427_name, sizeof (unitp->ltc1427_name), 359 "%s%d", ddi_node_name(dip), instance); 360 361 if (ddi_create_minor_node(dip, "ltc1427", S_IFCHR, instance, 362 "ddi_i2c:adio", NULL) == DDI_FAILURE) { 363 cmn_err(CE_WARN, "%s ddi_create_minor_node failed for " 364 "%s\n", unitp->ltc1427_name, "ltc1427"); 365 ddi_soft_state_free(ltc1427soft_statep, instance); 366 367 return (DDI_FAILURE); 368 } 369 370 if (i2c_client_register(dip, &unitp->ltc1427_hdl) != I2C_SUCCESS) { 371 ddi_remove_minor_node(dip, NULL); 372 ddi_soft_state_free(ltc1427soft_statep, instance); 373 374 return (DDI_FAILURE); 375 } 376 377 mutex_init(&unitp->ltc1427_mutex, NULL, MUTEX_DRIVER, NULL); 378 379 return (DDI_SUCCESS); 380 } 381 382 static int 383 ltc1427_do_resume() 384 { 385 int ret = DDI_SUCCESS; 386 387 return (ret); 388 } 389 390 static int 391 ltc1427_do_suspend() 392 { 393 int ret = DDI_SUCCESS; 394 395 return (ret); 396 } 397 398 static int 399 ltc1427_do_detach(dev_info_t *dip) 400 { 401 struct ltc1427_unit *unitp; 402 int instance; 403 404 instance = ddi_get_instance(dip); 405 406 unitp = ddi_get_soft_state(ltc1427soft_statep, instance); 407 408 if (unitp == NULL) { 409 cmn_err(CE_WARN, "%s%d: unitp not filled\n", 410 ddi_get_name(dip), instance); 411 return (ENOMEM); 412 } 413 414 i2c_client_unregister(unitp->ltc1427_hdl); 415 416 ddi_remove_minor_node(dip, NULL); 417 418 mutex_destroy(&unitp->ltc1427_mutex); 419 420 ddi_soft_state_free(ltc1427soft_statep, instance); 421 422 return (DDI_SUCCESS); 423 } 424