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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 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/pic16f819_impl.h> 42 43 static void *pic16f819soft_statep; 44 45 static int pic16f819_set(struct pic16f819_unit *, int, uchar_t); 46 static int pic16f819_get(struct pic16f819_unit *, int, uchar_t *, int); 47 48 49 static int pic16f819_do_attach(dev_info_t *); 50 static int pic16f819_do_detach(dev_info_t *); 51 static int pic16f819_do_resume(void); 52 static int pic16f819_do_suspend(void); 53 54 /* 55 * cb ops (only need ioctl) 56 */ 57 static int pic16f819_open(dev_t *, int, int, cred_t *); 58 static int pic16f819_close(dev_t, int, int, cred_t *); 59 static int pic16f819_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 60 61 static struct cb_ops pic16f819_cbops = { 62 pic16f819_open, /* open */ 63 pic16f819_close, /* close */ 64 nodev, /* strategy */ 65 nodev, /* print */ 66 nodev, /* dump */ 67 nodev, /* read */ 68 nodev, /* write */ 69 pic16f819_ioctl, /* ioctl */ 70 nodev, /* devmap */ 71 nodev, /* mmap */ 72 nodev, /* segmap */ 73 nochpoll, /* poll */ 74 ddi_prop_op, /* cb_prop_op */ 75 NULL, /* streamtab */ 76 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 77 CB_REV, /* rev */ 78 nodev, /* int (*cb_aread)() */ 79 nodev /* int (*cb_awrite)() */ 80 }; 81 82 /* 83 * dev ops 84 */ 85 static int pic16f819_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 86 static int pic16f819_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 87 88 static struct dev_ops pic16f819_ops = { 89 DEVO_REV, 90 0, 91 ddi_no_info, 92 nulldev, 93 nulldev, 94 pic16f819_attach, 95 pic16f819_detach, 96 nodev, 97 &pic16f819_cbops, 98 NULL 99 }; 100 101 extern struct mod_ops mod_driverops; 102 103 static struct modldrv pic16f819_modldrv = { 104 &mod_driverops, /* type of module - driver */ 105 "PIC16F819 i2c device driver: v%I%", 106 &pic16f819_ops 107 }; 108 109 static struct modlinkage pic16f819_modlinkage = { 110 MODREV_1, 111 &pic16f819_modldrv, 112 0 113 }; 114 115 116 int 117 _init(void) 118 { 119 int error; 120 121 error = mod_install(&pic16f819_modlinkage); 122 123 if (!error) 124 (void) ddi_soft_state_init(&pic16f819soft_statep, 125 sizeof (struct pic16f819_unit), 1); 126 return (error); 127 } 128 129 int 130 _fini(void) 131 { 132 int error; 133 134 error = mod_remove(&pic16f819_modlinkage); 135 if (!error) 136 ddi_soft_state_fini(&pic16f819soft_statep); 137 138 return (error); 139 } 140 141 int 142 _info(struct modinfo *modinfop) 143 { 144 return (mod_info(&pic16f819_modlinkage, modinfop)); 145 } 146 147 static int 148 pic16f819_get(struct pic16f819_unit *unitp, int reg, uchar_t *byte, int flags) 149 { 150 i2c_transfer_t *i2c_tran_pointer; 151 int err; 152 153 (void) i2c_transfer_alloc(unitp->pic16f819_hdl, &i2c_tran_pointer, 154 1, 1, flags); 155 if (i2c_tran_pointer == NULL) { 156 return (ENOMEM); 157 } 158 159 i2c_tran_pointer->i2c_flags = I2C_WR_RD; 160 i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg; 161 err = i2c_transfer(unitp->pic16f819_hdl, i2c_tran_pointer); 162 if (err) { 163 D2CMN_ERR((CE_WARN, "%s: pic16f819_get failed reg=%x", 164 unitp->pic16f819_name, reg)); 165 } else { 166 *byte = i2c_tran_pointer->i2c_rbuf[0]; 167 } 168 169 i2c_transfer_free(unitp->pic16f819_hdl, i2c_tran_pointer); 170 return (err); 171 } 172 173 static int 174 pic16f819_set(struct pic16f819_unit *unitp, int reg, uchar_t byte) 175 { 176 i2c_transfer_t *i2c_tran_pointer; 177 int err; 178 179 (void) i2c_transfer_alloc(unitp->pic16f819_hdl, &i2c_tran_pointer, 180 2, 0, I2C_SLEEP); 181 if (i2c_tran_pointer == NULL) { 182 D2CMN_ERR((CE_WARN, "%s: Failed in pic16f819_set " 183 "i2c_tran_pointer not allocated", unitp->pic16f819_name)); 184 return (ENOMEM); 185 } 186 187 i2c_tran_pointer->i2c_flags = I2C_WR; 188 i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg; 189 i2c_tran_pointer->i2c_wbuf[1] = byte; 190 D1CMN_ERR((CE_NOTE, "%s: set reg %x to %x", 191 unitp->pic16f819_name, reg, byte)); 192 193 err = i2c_transfer(unitp->pic16f819_hdl, i2c_tran_pointer); 194 if (err) { 195 D2CMN_ERR((CE_WARN, "%s: Failed in the pic16f819_set" 196 " i2c_transfer routine", unitp->pic16f819_name)); 197 } 198 i2c_transfer_free(unitp->pic16f819_hdl, i2c_tran_pointer); 199 return (err); 200 } 201 202 static int 203 pic16f819_open(dev_t *devp, int flags, int otyp, cred_t *credp) 204 { 205 _NOTE(ARGUNUSED(credp)) 206 207 struct pic16f819_unit *unitp; 208 int instance; 209 int error = 0; 210 211 instance = getminor(*devp); 212 213 if (instance < 0) { 214 return (ENXIO); 215 } 216 217 unitp = (struct pic16f819_unit *) 218 ddi_get_soft_state(pic16f819soft_statep, instance); 219 220 if (unitp == NULL) { 221 return (ENXIO); 222 } 223 224 if (otyp != OTYP_CHR) { 225 return (EINVAL); 226 } 227 228 mutex_enter(&unitp->pic16f819_mutex); 229 230 if (flags & FEXCL) { 231 if (unitp->pic16f819_oflag != 0) { 232 error = EBUSY; 233 } else { 234 unitp->pic16f819_oflag = FEXCL; 235 } 236 } else { 237 if (unitp->pic16f819_oflag == FEXCL) { 238 error = EBUSY; 239 } else { 240 unitp->pic16f819_oflag = FOPEN; 241 } 242 } 243 244 mutex_exit(&unitp->pic16f819_mutex); 245 246 return (error); 247 } 248 249 static int 250 pic16f819_close(dev_t dev, int flags, int otyp, cred_t *credp) 251 { 252 _NOTE(ARGUNUSED(flags, otyp, credp)) 253 254 struct pic16f819_unit *unitp; 255 int instance; 256 257 instance = getminor(dev); 258 259 if (instance < 0) { 260 return (ENXIO); 261 } 262 263 unitp = (struct pic16f819_unit *) 264 ddi_get_soft_state(pic16f819soft_statep, instance); 265 266 if (unitp == NULL) { 267 return (ENXIO); 268 } 269 270 mutex_enter(&unitp->pic16f819_mutex); 271 272 unitp->pic16f819_oflag = 0; 273 274 mutex_exit(&unitp->pic16f819_mutex); 275 return (DDI_SUCCESS); 276 } 277 278 static int 279 pic16f819_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 280 cred_t *credp, int *rvalp) 281 { 282 _NOTE(ARGUNUSED(credp, rvalp)) 283 284 struct pic16f819_unit *unitp; 285 int instance; 286 int err = 0; 287 i2c_reg_t ioctl_reg; 288 uchar_t val8; 289 290 if (arg == NULL) { 291 D2CMN_ERR((CE_WARN, "PIC16F819: ioctl: arg passed in to ioctl " 292 "= NULL\n")); 293 err = EINVAL; 294 return (err); 295 } 296 instance = getminor(dev); 297 unitp = (struct pic16f819_unit *) 298 ddi_get_soft_state(pic16f819soft_statep, instance); 299 300 mutex_enter(&unitp->pic16f819_mutex); 301 302 switch (cmd) { 303 304 case I2C_GET_REG: 305 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg, 306 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 307 err = EFAULT; 308 break; 309 } 310 err = pic16f819_get(unitp, ioctl_reg.reg_num, &val8, 311 I2C_SLEEP); 312 if (err != I2C_SUCCESS) { 313 break; 314 } 315 316 ioctl_reg.reg_value = val8; 317 if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg, 318 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 319 err = EFAULT; 320 } 321 break; 322 323 case I2C_SET_REG: 324 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg, 325 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 326 err = EFAULT; 327 break; 328 } 329 err = pic16f819_set(unitp, ioctl_reg.reg_num, 330 ioctl_reg.reg_value); 331 break; 332 default: 333 D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x\n", 334 unitp->pic16f819_name, cmd)); 335 err = EINVAL; 336 } 337 338 mutex_exit(&unitp->pic16f819_mutex); 339 return (err); 340 } 341 342 static int 343 pic16f819_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 344 { 345 switch (cmd) { 346 case DDI_ATTACH: 347 return (pic16f819_do_attach(dip)); 348 case DDI_RESUME: 349 return (pic16f819_do_resume()); 350 default: 351 return (DDI_FAILURE); 352 } 353 } 354 355 static int 356 pic16f819_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 357 { 358 switch (cmd) { 359 case DDI_DETACH: 360 return (pic16f819_do_detach(dip)); 361 case DDI_SUSPEND: 362 return (pic16f819_do_suspend()); 363 default: 364 return (DDI_FAILURE); 365 } 366 } 367 368 static int 369 pic16f819_do_attach(dev_info_t *dip) 370 { 371 struct pic16f819_unit *unitp; 372 int instance; 373 374 instance = ddi_get_instance(dip); 375 376 if (ddi_soft_state_zalloc(pic16f819soft_statep, instance) != 0) { 377 cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n", 378 ddi_get_name(dip), instance); 379 return (DDI_FAILURE); 380 } 381 382 unitp = ddi_get_soft_state(pic16f819soft_statep, instance); 383 384 if (unitp == NULL) { 385 cmn_err(CE_WARN, "%s%d: unitp not filled\n", 386 ddi_get_name(dip), instance); 387 return (ENOMEM); 388 } 389 390 (void) snprintf(unitp->pic16f819_name, sizeof (unitp->pic16f819_name), 391 "%s%d", ddi_node_name(dip), instance); 392 393 if (ddi_create_minor_node(dip, "fan_1", S_IFCHR, instance, 394 "ddi_i2c:pic", NULL) == DDI_FAILURE) { 395 cmn_err(CE_WARN, "%s ddi_create_minor_node failed for " 396 "%s\n", unitp->pic16f819_name, "pic16f819"); 397 ddi_soft_state_free(pic16f819soft_statep, instance); 398 399 return (DDI_FAILURE); 400 } 401 402 if (i2c_client_register(dip, &unitp->pic16f819_hdl) != I2C_SUCCESS) { 403 cmn_err(CE_WARN, "%s i2c_client_register failed\n", 404 unitp->pic16f819_name); 405 ddi_remove_minor_node(dip, NULL); 406 ddi_soft_state_free(pic16f819soft_statep, instance); 407 408 return (DDI_FAILURE); 409 } 410 411 mutex_init(&unitp->pic16f819_mutex, NULL, MUTEX_DRIVER, NULL); 412 413 return (DDI_SUCCESS); 414 } 415 416 static int 417 pic16f819_do_resume() 418 { 419 int ret = DDI_SUCCESS; 420 421 return (ret); 422 } 423 424 static int 425 pic16f819_do_suspend() 426 { 427 int ret = DDI_SUCCESS; 428 429 return (ret); 430 } 431 432 static int 433 pic16f819_do_detach(dev_info_t *dip) 434 { 435 struct pic16f819_unit *unitp; 436 int instance; 437 438 instance = ddi_get_instance(dip); 439 440 unitp = ddi_get_soft_state(pic16f819soft_statep, instance); 441 442 if (unitp == NULL) { 443 cmn_err(CE_WARN, "%s%d: unitp not filled\n", 444 ddi_get_name(dip), instance); 445 return (ENOMEM); 446 } 447 448 i2c_client_unregister(unitp->pic16f819_hdl); 449 450 ddi_remove_minor_node(dip, NULL); 451 452 mutex_destroy(&unitp->pic16f819_mutex); 453 454 ddi_soft_state_free(pic16f819soft_statep, instance); 455 456 return (DDI_SUCCESS); 457 } 458