xref: /illumos-gate/usr/src/uts/sun4u/io/i2c/clients/ssc100.c (revision 5422785d352a2bb398daceab3d1898a8aa64d006)
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
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
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
143 _info(struct modinfo *modinfop)
144 {
145 	return (mod_info(&ssc100_modlinkage, modinfop));
146 }
147 
148 static int
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
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
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
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
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
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
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 == 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
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
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
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", NULL) == 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
563 ssc100_do_resume()
564 {
565 	int ret = DDI_SUCCESS;
566 
567 	return (ret);
568 }
569 
570 static int
571 ssc100_do_suspend()
572 {
573 	int ret = DDI_SUCCESS;
574 
575 	return (ret);
576 }
577 
578 static int
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
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
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
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