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 #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */
27 #include <sys/modctl.h> /* for modldrv */
28 #include <sys/open.h> /* for open params. */
29 #include <sys/types.h>
30 #include <sys/kmem.h>
31 #include <sys/sunddi.h>
32 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */
33 #include <sys/ddi.h>
34 #include <sys/file.h>
35 #include <sys/note.h>
36
37 #include <sys/i2c/clients/ssc100_impl.h>
38
39 static void *ssc100soft_statep;
40
41 static int ssc100_do_attach(dev_info_t *);
42 static int ssc100_do_detach(dev_info_t *);
43 static int ssc100_do_resume(void);
44 static int ssc100_do_suspend(void);
45 static int ssc100_get(struct ssc100_unit *, uchar_t *);
46 static int ssc100_set(struct ssc100_unit *, uchar_t);
47 static int ssc100_get_reg(struct ssc100_unit *, uchar_t *, uchar_t);
48 static int ssc100_common(struct ssc100_unit *, uchar_t *, uchar_t, int8_t);
49 static int ssc100_read(dev_t, struct uio *, cred_t *);
50 static int ssc100_write(dev_t, struct uio *, cred_t *);
51 static int ssc100_io(dev_t, struct uio *, int);
52
53 /*
54 * cb ops (only need ioctl)
55 */
56 static int ssc100_open(dev_t *, int, int, cred_t *);
57 static int ssc100_close(dev_t, int, int, cred_t *);
58 static int ssc100_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
59
60 static struct cb_ops ssc100_cbops = {
61 ssc100_open, /* open */
62 ssc100_close, /* close */
63 nodev, /* strategy */
64 nodev, /* print */
65 nodev, /* dump */
66 ssc100_read, /* read */
67 ssc100_write, /* write */
68 ssc100_ioctl, /* ioctl */
69 nodev, /* devmap */
70 nodev, /* mmap */
71 nodev, /* segmap */
72 nochpoll, /* poll */
73 ddi_prop_op, /* cb_prop_op */
74 NULL, /* streamtab */
75 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */
76 CB_REV, /* rev */
77 nodev, /* int (*cb_aread)() */
78 nodev /* int (*cb_awrite)() */
79 };
80
81 /*
82 * dev ops
83 */
84 static int ssc100_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
85 static int ssc100_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
86
87 static struct dev_ops ssc100_ops = {
88 DEVO_REV,
89 0,
90 ddi_getinfo_1to1,
91 nulldev,
92 nulldev,
93 ssc100_attach,
94 ssc100_detach,
95 nodev,
96 &ssc100_cbops,
97 NULL,
98 NULL,
99 ddi_quiesce_not_needed, /* quiesce */
100 };
101
102 extern struct mod_ops mod_driverops;
103
104 static struct modldrv ssc100_modldrv = {
105 &mod_driverops, /* type of module - driver */
106 "SSC100 i2c device driver",
107 &ssc100_ops
108 };
109
110 static struct modlinkage ssc100_modlinkage = {
111 MODREV_1,
112 &ssc100_modldrv,
113 0
114 };
115
116
117 int
_init(void)118 _init(void)
119 {
120 int error;
121
122 error = mod_install(&ssc100_modlinkage);
123
124 if (!error)
125 (void) ddi_soft_state_init(&ssc100soft_statep,
126 sizeof (struct ssc100_unit), 1);
127 return (error);
128 }
129
130 int
_fini(void)131 _fini(void)
132 {
133 int error;
134
135 error = mod_remove(&ssc100_modlinkage);
136 if (!error)
137 ddi_soft_state_fini(&ssc100soft_statep);
138
139 return (error);
140 }
141
142 int
_info(struct modinfo * modinfop)143 _info(struct modinfo *modinfop)
144 {
145 return (mod_info(&ssc100_modlinkage, modinfop));
146 }
147
148 static int
ssc100_open(dev_t * devp,int flags,int otyp,cred_t * credp)149 ssc100_open(dev_t *devp, int flags, int otyp, cred_t *credp)
150 {
151 _NOTE(ARGUNUSED(credp))
152
153 struct ssc100_unit *unitp;
154 int instance;
155 int error = 0;
156
157 instance = getminor(*devp);
158
159 if (instance < 0) {
160 return (ENXIO);
161 }
162
163 unitp = (struct ssc100_unit *)
164 ddi_get_soft_state(ssc100soft_statep, instance);
165
166 if (unitp == NULL) {
167 return (ENXIO);
168 }
169
170 if (otyp != OTYP_CHR) {
171 return (EINVAL);
172 }
173
174 mutex_enter(&unitp->ssc100_mutex);
175
176 if (flags & FEXCL) {
177 if (unitp->ssc100_oflag != 0) {
178 error = EBUSY;
179 } else {
180 unitp->ssc100_oflag = FEXCL;
181 }
182 } else {
183 if (unitp->ssc100_oflag == FEXCL) {
184 error = EBUSY;
185 } else {
186 unitp->ssc100_oflag = FOPEN;
187 }
188 }
189
190 mutex_exit(&unitp->ssc100_mutex);
191
192 return (error);
193 }
194
195 static int
ssc100_close(dev_t dev,int flags,int otyp,cred_t * credp)196 ssc100_close(dev_t dev, int flags, int otyp, cred_t *credp)
197 {
198 _NOTE(ARGUNUSED(flags, otyp, credp))
199
200 struct ssc100_unit *unitp;
201 int instance;
202
203 instance = getminor(dev);
204
205 if (instance < 0) {
206 return (ENXIO);
207 }
208 unitp = (struct ssc100_unit *)
209 ddi_get_soft_state(ssc100soft_statep, instance);
210
211 if (unitp == NULL) {
212 return (ENXIO);
213 }
214
215 mutex_enter(&unitp->ssc100_mutex);
216
217 unitp->ssc100_oflag = 0;
218
219 mutex_exit(&unitp->ssc100_mutex);
220 return (DDI_SUCCESS);
221 }
222
223 static int
ssc100_common(struct ssc100_unit * unitp,uchar_t * byte,uchar_t input,int8_t flag)224 ssc100_common(struct ssc100_unit *unitp, uchar_t *byte, uchar_t input,
225 int8_t flag)
226 {
227 i2c_transfer_t *i2c_tran_pointer;
228 int err = I2C_SUCCESS;
229
230 (void) i2c_transfer_alloc(unitp->ssc100_hdl, &i2c_tran_pointer,
231 1, 1, I2C_SLEEP);
232 if (i2c_tran_pointer == NULL) {
233 D2CMN_ERR((CE_WARN, "%s: Failed in SSC100_COMMON "
234 "i2c_tran_pointer not allocated",
235 unitp->ssc100_name));
236 return (ENOMEM);
237 }
238
239 i2c_tran_pointer->i2c_flags = flag;
240 if (flag != I2C_RD) {
241 i2c_tran_pointer->i2c_wbuf[0] = input;
242 }
243
244 err = i2c_transfer(unitp->ssc100_hdl, i2c_tran_pointer);
245 if (err) {
246 D2CMN_ERR((CE_WARN, "%s: Failed in SSC100_COMMON "
247 "i2c_transfer routine", unitp->ssc100_name));
248 } else if (flag != I2C_WR) {
249 *byte = i2c_tran_pointer->i2c_rbuf[0];
250 }
251
252 i2c_transfer_free(unitp->ssc100_hdl, i2c_tran_pointer);
253 return (err);
254 }
255
256 static int
ssc100_get_reg(struct ssc100_unit * unitp,uchar_t * byte,uchar_t reg)257 ssc100_get_reg(struct ssc100_unit *unitp, uchar_t *byte, uchar_t reg)
258 {
259 int err = I2C_SUCCESS;
260
261 err = ssc100_common(unitp, byte, reg, I2C_WR_RD);
262 if (err) {
263 D2CMN_ERR((CE_WARN, "%s: Failed in SSC100_GET_REG "
264 "i2c_common routine", unitp->ssc100_name));
265 }
266 return (err);
267 }
268
269 static int
ssc100_get(struct ssc100_unit * unitp,uchar_t * byte)270 ssc100_get(struct ssc100_unit *unitp, uchar_t *byte)
271 {
272 int err = I2C_SUCCESS;
273
274 err = ssc100_common(unitp, byte, 0, I2C_RD);
275 if (err) {
276 D2CMN_ERR((CE_WARN, "%s: Failed in SSC100_GET "
277 "i2c_common routine", unitp->ssc100_name));
278 }
279 return (err);
280 }
281
282 static int
ssc100_set(struct ssc100_unit * unitp,uchar_t byte)283 ssc100_set(struct ssc100_unit *unitp, uchar_t byte)
284 {
285 int err = I2C_SUCCESS;
286
287 err = ssc100_common(unitp, NULL, byte, I2C_WR);
288 if (err) {
289 D2CMN_ERR((CE_WARN, "%s: Failed in SSC100_SET "
290 "i2c_common routine", unitp->ssc100_name));
291 }
292 return (err);
293 }
294
295 static int
ssc100_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)296 ssc100_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
297 cred_t *credp, int *rvalp)
298 {
299 _NOTE(ARGUNUSED(credp, rvalp))
300
301 struct ssc100_unit *unitp;
302 int instance;
303 int err = 0;
304 i2c_bit_t ioctl_bit;
305 i2c_port_t ioctl_port;
306 i2c_reg_t ioctl_reg;
307 uchar_t byte;
308
309 if (arg == (intptr_t)NULL) {
310 D2CMN_ERR((CE_WARN, "SSC100: ioctl: arg passed in to ioctl "
311 "= NULL"));
312 err = EINVAL;
313 return (err);
314 }
315
316 instance = getminor(dev);
317 unitp = (struct ssc100_unit *)
318 ddi_get_soft_state(ssc100soft_statep, instance);
319 if (unitp == NULL) {
320 cmn_err(CE_WARN, "SSC100: ioctl: unitp not filled");
321 return (ENOMEM);
322 }
323
324 mutex_enter(&unitp->ssc100_mutex);
325
326 switch (cmd) {
327 case I2C_GET_PORT:
328 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_port,
329 sizeof (i2c_port_t), mode) != DDI_SUCCESS) {
330 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_PORT"
331 " ddi_copyin routine", unitp->ssc100_name));
332 err = EFAULT;
333 break;
334 }
335
336 err = ssc100_get(unitp, &byte);
337 if (err != I2C_SUCCESS) {
338 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_PORT"
339 " ssc100_get routine", unitp->ssc100_name));
340 break;
341 }
342
343 ioctl_port.value = byte;
344 if (ddi_copyout((caddr_t)&ioctl_port, (caddr_t)arg,
345 sizeof (i2c_port_t), mode) != DDI_SUCCESS) {
346 D2CMN_ERR((CE_WARN, "%s: Failed in I2C_GET_PORT "
347 "ddi_copyout routine", unitp->ssc100_name));
348 err = EFAULT;
349 }
350
351 D1CMN_ERR((CE_NOTE, "%s: contains %x", unitp->ssc100_name,
352 byte));
353 break;
354
355 case I2C_SET_PORT:
356 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_port,
357 sizeof (uint8_t), mode) != DDI_SUCCESS) {
358 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_PORT"
359 "ddi_cpoyin routine", unitp->ssc100_name));
360 err = EFAULT;
361 break;
362 }
363
364 err = ssc100_set(unitp, ioctl_port.value);
365 if (err != I2C_SUCCESS) {
366 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_PORT"
367 " ssc100_set routine", unitp->ssc100_name));
368 break;
369 }
370 break;
371
372 case I2C_GET_BIT:
373 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_bit,
374 sizeof (i2c_bit_t), mode) != DDI_SUCCESS) {
375 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_BIT"
376 " ddi_copyin routine", unitp->ssc100_name));
377 err = EFAULT;
378 break;
379 }
380
381 if (ioctl_bit.bit_num > 7) {
382 D2CMN_ERR((CE_WARN, "%s: In I2C_GET_BIT bit num"
383 " was not between 0 and 7",
384 unitp->ssc100_name));
385 err = EIO;
386 break;
387 }
388
389 err = ssc100_get(unitp, &byte);
390 if (err != I2C_SUCCESS) {
391 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_BIT"
392 " ssc100_get routine", unitp->ssc100_name));
393 break;
394 }
395
396 D1CMN_ERR((CE_NOTE, "%s: byte returned from device is %x",
397 unitp->ssc100_name, byte));
398 ioctl_bit.bit_value = (boolean_t)SSC100_BIT_READ_MASK(byte,
399 ioctl_bit.bit_num);
400 D1CMN_ERR((CE_NOTE, "%s: byte now contains %x",
401 unitp->ssc100_name, byte));
402
403 if (ddi_copyout((caddr_t)&ioctl_bit, (caddr_t)arg,
404 sizeof (i2c_bit_t), mode) != DDI_SUCCESS) {
405 D2CMN_ERR((CE_WARN, "%s: Failed in I2C_GET_BIT"
406 " ddi_copyout routine", unitp->ssc100_name));
407 err = EFAULT;
408 }
409 break;
410
411 case I2C_SET_BIT:
412 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_bit,
413 sizeof (i2c_bit_t), mode) != DDI_SUCCESS) {
414 D2CMN_ERR((CE_WARN, "%s: Failed in I2C_SET_BIT"
415 " ddi_copyin routine", unitp->ssc100_name));
416 err = EFAULT;
417 break;
418 }
419
420 if (ioctl_bit.bit_num > 7) {
421 D2CMN_ERR((CE_WARN, "%s: I2C_SET_BIT: bit_num sent"
422 " in was not between 0 and 7",
423 unitp->ssc100_name));
424 err = EIO;
425 break;
426 }
427
428 err = ssc100_get(unitp, &byte);
429 if (err != I2C_SUCCESS) {
430 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_BIT"
431 " ssc100_get routine", unitp->ssc100_name));
432 break;
433 }
434
435 D1CMN_ERR((CE_NOTE, "%s: byte returned from device is %x",
436 unitp->ssc100_name, byte));
437 byte = SSC100_BIT_WRITE_MASK(byte, ioctl_bit.bit_num,
438 ioctl_bit.bit_value);
439 D1CMN_ERR((CE_NOTE, "%s: byte after shifting is %x",
440 unitp->ssc100_name, byte));
441
442 err = ssc100_set(unitp, byte);
443 if (err != I2C_SUCCESS) {
444 D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_BIT"
445 " ssc100_set routine", unitp->ssc100_name));
446 break;
447 }
448 break;
449
450 case I2C_GET_REG:
451 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
452 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
453 D2CMN_ERR((CE_WARN, "%s: Failed in I2C_GET_REG "
454 "ddi_copyin routine", unitp->ssc100_name));
455 err = EFAULT;
456 break;
457 }
458
459 err = ssc100_get_reg(unitp, &byte, ioctl_reg.reg_num);
460
461 ioctl_reg.reg_value = byte;
462 if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg,
463 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
464 D2CMN_ERR((CE_WARN, "%s: Failed in I2C_GET_REG "
465 "ddi_copyout routine", unitp->ssc100_name));
466 err = EFAULT;
467 }
468 break;
469
470 default:
471 D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x",
472 unitp->ssc100_name, cmd));
473 err = EINVAL;
474 }
475
476 mutex_exit(&unitp->ssc100_mutex);
477 return (err);
478 }
479
480 static int
ssc100_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)481 ssc100_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
482 {
483 switch (cmd) {
484 case DDI_ATTACH:
485 return (ssc100_do_attach(dip));
486 case DDI_RESUME:
487 return (ssc100_do_resume());
488 default:
489 return (DDI_FAILURE);
490 }
491 }
492
493 static int
ssc100_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)494 ssc100_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
495 {
496 switch (cmd) {
497 case DDI_DETACH:
498 return (ssc100_do_detach(dip));
499 case DDI_SUSPEND:
500 return (ssc100_do_suspend());
501 default:
502 return (DDI_FAILURE);
503 }
504 }
505
506 static int
ssc100_do_attach(dev_info_t * dip)507 ssc100_do_attach(dev_info_t *dip)
508 {
509 struct ssc100_unit *unitp;
510 int instance;
511
512 instance = ddi_get_instance(dip);
513
514 if (ddi_soft_state_zalloc(ssc100soft_statep, instance) != 0) {
515 cmn_err(CE_WARN, "%s%d: failed to zalloc softstate",
516 ddi_get_name(dip), instance);
517 return (DDI_FAILURE);
518 }
519
520 unitp = ddi_get_soft_state(ssc100soft_statep, instance);
521
522 if (unitp == NULL) {
523 cmn_err(CE_WARN, "%s%d: unitp not filled",
524 ddi_get_name(dip), instance);
525 return (ENOMEM);
526 }
527
528 (void) snprintf(unitp->ssc100_name, sizeof (unitp->ssc100_name),
529 "%s%d", ddi_node_name(dip), instance);
530
531 if (ddi_create_minor_node(dip, "ssc100", S_IFCHR, instance,
532 "ddi_i2c:ioexp", 0) == DDI_FAILURE) {
533 cmn_err(CE_WARN, "%s ddi_create_minor_node failed for "
534 "%s", unitp->ssc100_name, "ssc100");
535 ddi_soft_state_free(ssc100soft_statep, instance);
536
537 return (DDI_FAILURE);
538 }
539
540 /*
541 * If we had different sizes in the future, this could be read
542 * from a property.
543 */
544 unitp->ssc100_size = SSC100_SIZE;
545
546 (void) ddi_prop_create(DDI_DEV_T_NONE, dip,
547 DDI_PROP_CANSLEEP, "size",
548 (caddr_t)&unitp->ssc100_size, sizeof (unitp->ssc100_size));
549
550 if (i2c_client_register(dip, &unitp->ssc100_hdl) != I2C_SUCCESS) {
551 ddi_remove_minor_node(dip, NULL);
552 ddi_soft_state_free(ssc100soft_statep, instance);
553
554 return (DDI_FAILURE);
555 }
556
557 mutex_init(&unitp->ssc100_mutex, NULL, MUTEX_DRIVER, NULL);
558
559 return (DDI_SUCCESS);
560 }
561
562 static int
ssc100_do_resume()563 ssc100_do_resume()
564 {
565 int ret = DDI_SUCCESS;
566
567 return (ret);
568 }
569
570 static int
ssc100_do_suspend()571 ssc100_do_suspend()
572 {
573 int ret = DDI_SUCCESS;
574
575 return (ret);
576 }
577
578 static int
ssc100_do_detach(dev_info_t * dip)579 ssc100_do_detach(dev_info_t *dip)
580 {
581 struct ssc100_unit *unitp;
582 int instance;
583
584 instance = ddi_get_instance(dip);
585
586 unitp = ddi_get_soft_state(ssc100soft_statep, instance);
587
588 i2c_client_unregister(unitp->ssc100_hdl);
589
590 ddi_remove_minor_node(dip, NULL);
591
592 mutex_destroy(&unitp->ssc100_mutex);
593
594 ddi_soft_state_free(ssc100soft_statep, instance);
595
596 return (DDI_SUCCESS);
597
598 }
599
600 static int
ssc100_read(dev_t dev,struct uio * uiop,cred_t * cred_p)601 ssc100_read(dev_t dev, struct uio *uiop, cred_t *cred_p)
602 {
603 _NOTE(ARGUNUSED(cred_p))
604
605 return (ssc100_io(dev, uiop, B_READ));
606 }
607
608 static int
ssc100_write(dev_t dev,struct uio * uiop,cred_t * cred_p)609 ssc100_write(dev_t dev, struct uio *uiop, cred_t *cred_p)
610 {
611 _NOTE(ARGUNUSED(cred_p))
612
613 return (ssc100_io(dev, uiop, B_WRITE));
614 }
615
616 static int
ssc100_io(dev_t dev,struct uio * uiop,int rw)617 ssc100_io(dev_t dev, struct uio *uiop, int rw)
618 {
619 struct ssc100_unit *unitp;
620 int instance = getminor(dev);
621 int ssc100_addr;
622 int bytes_to_rw;
623 int err = 0;
624 int current_xfer_len;
625 i2c_transfer_t *i2ctp = NULL;
626
627 if (instance < 0) {
628 return (ENXIO);
629 }
630
631 unitp = (struct ssc100_unit *)
632 ddi_get_soft_state(ssc100soft_statep, instance);
633
634
635 if (unitp == NULL) {
636 return (ENXIO);
637 }
638
639 if (uiop->uio_offset >= unitp->ssc100_size) {
640 /*
641 * Exceeded ssc100 size.
642 */
643 if (rw == B_WRITE) {
644
645 return (ENOSPC);
646 }
647 return (0);
648 }
649
650 ssc100_addr = uiop->uio_offset;
651
652 if (uiop->uio_resid == 0) {
653 return (0);
654 }
655
656 bytes_to_rw = min(uiop->uio_resid,
657 unitp->ssc100_size - uiop->uio_offset);
658 current_xfer_len = bytes_to_rw;
659
660 if (rw == B_WRITE) {
661 (void) i2c_transfer_alloc(unitp->ssc100_hdl, &i2ctp,
662 current_xfer_len+1, 0, I2C_SLEEP);
663 if (i2ctp == NULL) {
664 D2CMN_ERR((CE_WARN, "%s: Failed in ssc100_io WRITE "
665 "i2c_tran_pointer not allocated",
666 unitp->ssc100_name));
667 return (ENOMEM);
668 }
669 i2ctp->i2c_version = I2C_XFER_REV;
670 i2ctp->i2c_flags = I2C_WR;
671 i2ctp->i2c_wbuf[0] = (uchar_t)ssc100_addr;
672 if ((err = uiomove(&i2ctp->i2c_wbuf[1], current_xfer_len,
673 UIO_WRITE, uiop)) != 0) {
674 D2CMN_ERR((CE_WARN, "%s: Failed in ssc100_io WRITE "
675 "uiomove failed", unitp->ssc100_name));
676 goto end;
677 }
678
679 if ((err = i2c_transfer(unitp->ssc100_hdl, i2ctp)) !=
680 I2C_SUCCESS) {
681 D2CMN_ERR((CE_WARN, "%s: Failed in ssc100_io WRITE "
682 "i2c_transfer failed", unitp->ssc100_name));
683 goto end;
684 }
685 } else {
686 /*
687 * SSC100 read. We need to first write out the address
688 * that we wish to read.
689 */
690 (void) i2c_transfer_alloc(unitp->ssc100_hdl, &i2ctp, 1,
691 current_xfer_len, I2C_SLEEP);
692 if (i2ctp == NULL) {
693 D2CMN_ERR((CE_WARN, "%s: Failed in ssc100_io READ "
694 "i2c_tran_pointer not allocated",
695 unitp->ssc100_name));
696 return (ENOMEM);
697 }
698 i2ctp->i2c_version = I2C_XFER_REV;
699 i2ctp->i2c_wbuf[0] = (uchar_t)ssc100_addr;
700 i2ctp->i2c_flags = I2C_WR_RD;
701
702 if ((err = i2c_transfer(unitp->ssc100_hdl, i2ctp)) !=
703 I2C_SUCCESS) {
704 D2CMN_ERR((CE_WARN, "%s: Failed in ssc100_io READ "
705 "i2c_transfer failed", unitp->ssc100_name));
706 goto end;
707 }
708
709 if ((err = uiomove(i2ctp->i2c_rbuf, current_xfer_len,
710 UIO_READ, uiop)) != 0) {
711 D2CMN_ERR((CE_WARN, "%s: Failed in ssc100_io READ "
712 "uiomove failed", unitp->ssc100_name));
713 goto end;
714 }
715 }
716
717 end:
718 i2c_transfer_free(unitp->ssc100_hdl, i2ctp);
719 return (err);
720 }
721