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