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