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
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * This file consists of routines to manage objects in the
31 * "Platform Environment Services Framework". The classes
32 * and subclasses are defined by attributes and methods.
33 * The objects, and their initial, static, attribute values are
34 * specified in a configuration file, "psvcobj.conf".
35 * psvc_init() reads the configuration file and creates a repository
36 * of environmental objects in memory. A client application may manipulate
37 * these objects by invoking the psvc_get_attr(), and psvc_set_attr()
38 * routines with the object's string ID specified as an argument.
39 */
40#include <stdio.h>
41#include <math.h>
42#include <stdlib.h>
43#include <unistd.h>
44#include <stropts.h>
45#include <string.h>
46#include <errno.h>
47#include <fcntl.h>
48#include <pthread.h>
49#include <syslog.h>
50#include <stdarg.h>
51#include <pthread.h>
52#include <sys/systeminfo.h>
53
54#define	LIBRARY_BUILD 1
55#include <psvc_objects.h>
56#include <psvc_objects_class.h>
57#include <sys/i2c/clients/i2c_client.h>
58
59/* Mutex used for Daktari Fan speed reading */
60pthread_mutex_t fan_mutex = PTHREAD_MUTEX_INITIALIZER;
61
62/*LINTLIBRARY*/
63
64#define	ENV_DEBUG(str, id) printf("%s id %s\n", (str), (id))
65
66#define	BUFSZ  512
67
68#define	CLASS_MAX	12
69#define	SUBCLASS_MAX	10
70
71static int32_t i_psvc_constructor_0_0(EHdl_t *, char *, EObj_t **);
72static int32_t i_psvc_constructor_0_1(EHdl_t *, char *, EObj_t **);
73static int32_t i_psvc_constructor_1_0(EHdl_t *, char *, EObj_t **);
74static int32_t i_psvc_constructor_2_0(EHdl_t *, char *, EObj_t **);
75static int32_t i_psvc_constructor_2_1(EHdl_t *, char *, EObj_t **);
76static int32_t i_psvc_constructor_2_2(EHdl_t *, char *, EObj_t **);
77static int32_t i_psvc_constructor_3_0(EHdl_t *, char *, EObj_t **);
78static int32_t i_psvc_constructor_4_0(EHdl_t *, char *, EObj_t **);
79static int32_t i_psvc_constructor_5_0(EHdl_t *, char *, EObj_t **);
80static int32_t i_psvc_constructor_6_0(EHdl_t *, char *, EObj_t **);
81static int32_t i_psvc_constructor_7_0(EHdl_t *, char *, EObj_t **);
82static int32_t i_psvc_constructor_8_0(EHdl_t *, char *, EObj_t **);
83static int32_t i_psvc_constructor_9_0(EHdl_t *, char *, EObj_t **);
84static int32_t i_psvc_constructor_10_0(EHdl_t *, char *, EObj_t **);
85static int32_t i_psvc_constructor_10_1(EHdl_t *, char *, EObj_t **);
86static int32_t i_psvc_constructor_11_0(EHdl_t *, char *, EObj_t **);
87static int32_t i_psvc_constructor_11_1(EHdl_t *, char *, EObj_t **);
88static int32_t i_psvc_constructor_11_2(EHdl_t *, char *, EObj_t **);
89static int32_t i_psvc_constructor_11_3(EHdl_t *, char *, EObj_t **);
90static int32_t i_psvc_constructor_11_4(EHdl_t *, char *, EObj_t **);
91static int32_t i_psvc_constructor_11_5(EHdl_t *, char *, EObj_t **);
92static int32_t i_psvc_constructor_11_6(EHdl_t *, char *, EObj_t **);
93static int32_t i_psvc_constructor_11_7(EHdl_t *, char *, EObj_t **);
94static int32_t i_psvc_constructor_11_8(EHdl_t *, char *, EObj_t **);
95static int32_t i_psvc_constructor_11_9(EHdl_t *, char *, EObj_t **);
96
97static int32_t i_psvc_get_obj(EHdl_t *, char *, EObj_t **);
98static int32_t i_psvc_destructor(EHdl_t *, char *, void *);
99static int32_t i_psvc_get_devpath(EHdl_t *, uint64_t, char *);
100static int32_t i_psvc_get_attr_generic(EHdl_t *, EObj_t *, int32_t, void *);
101static int32_t i_psvc_get_attr_6_0(EHdl_t *, EObj_t *, int32_t, void *);
102static int32_t i_psvc_get_reg_11_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id,
103    void *attrp);
104static int32_t i_psvc_get_attr_10_1(EHdl_t *, EObj_t *, int32_t, void *);
105static int32_t psvc_get_str_key(char *object);
106
107int32_t ioctl_retry(int fp, int request, void * arg_pointer);
108
109/*
110 * Method lookup tables
111 * Update when adding classes or subclasses.
112 */
113
114
115/* Lookup method by class, subclass, used when calling method */
116static int32_t (*i_psvc_constructor[CLASS_MAX][SUBCLASS_MAX])(EHdl_t *,
117	char *, EObj_t **) = {
118{i_psvc_constructor_0_0, i_psvc_constructor_0_1, 0, 0, 0, 0, 0, 0, 0, 0},
119	{i_psvc_constructor_1_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
120{i_psvc_constructor_2_0, i_psvc_constructor_2_1, i_psvc_constructor_2_2,
121		0, 0, 0, 0, 0, 0, 0},
122	{i_psvc_constructor_3_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
123	{i_psvc_constructor_4_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
124	{i_psvc_constructor_5_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
125	{i_psvc_constructor_6_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
126	{i_psvc_constructor_7_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
127	{i_psvc_constructor_8_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
128	{i_psvc_constructor_9_0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
129{i_psvc_constructor_10_0, i_psvc_constructor_10_1, 0, 0, 0, 0, 0, 0, 0, 0},
130{i_psvc_constructor_11_0, i_psvc_constructor_11_1, i_psvc_constructor_11_2,
131	i_psvc_constructor_11_3, i_psvc_constructor_11_4,
132	i_psvc_constructor_11_5, i_psvc_constructor_11_6,
133	i_psvc_constructor_11_7, i_psvc_constructor_11_8,
134	i_psvc_constructor_11_9},
135};
136
137static int32_t i_psvc_cell_size[8] = {1, 1, 2, 2, 4, 4, 8, 8};
138
139static struct bits {
140	uint64_t	bit;
141	char		*label;
142} feature_bits[] = {
143{PSVC_DEV_PERM, "PERM="},
144{PSVC_DEV_HOTPLUG, "HOTPLUG="},
145{PSVC_DEV_OPTION, "OPTION="},
146{PSVC_DEV_PRIMARY, "PRIMARY="},
147{PSVC_DEV_SECONDARY, "SECONDARY="},
148{PSVC_DEV_RDONLY, "RDONLY="},
149{PSVC_DEV_RDWR, "RDWR="},
150{PSVC_DEV_FRU, "FRU="},
151{PSVC_LOW_WARN, "LO_WARN_MASK="},
152{PSVC_LOW_SHUT, "LO_SHUT_MASK="},
153{PSVC_HIGH_WARN, "HI_WARN_MASK="},
154{PSVC_HIGH_SHUT, "HI_SHUT_MASK="},
155{PSVC_CONVERSION_TABLE, "CONV_TABLE="},
156{PSVC_OPT_TEMP, "OPT_TEMP_MASK="},
157{PSVC_HW_LOW_SHUT, "HW_LO_MASK="},
158{PSVC_HW_HIGH_SHUT, "HW_HI_MASK="},
159{PSVC_FAN_DRIVE_PR, "FAN_DRIVE_PR="},
160{PSVC_TEMP_DRIVEN, "TEMP_DRIVEN="},
161{PSVC_SPEED_CTRL_PR, "SPEED_CTRL_PR="},
162{PSVC_FAN_ON_OFF, "FAN_ON_OFF="},
163{PSVC_CLOSED_LOOP_CTRL, "CLOSED_LOOP_CTRL="},
164{PSVC_FAN_DRIVE_TABLE_PR, "FAN_DRIVE_TABLE_PR="},
165{PSVC_DIE_TEMP, "DIE_TEMP="},
166{PSVC_AMB_TEMP, "AMB_TEMP="},
167{PSVC_DIGI_SENSOR, "DIGI_SENSOR="},
168{PSVC_BI_STATE, "BI_STATE="},
169{PSVC_TRI_STATE, "TRI_STATE="},
170{PSVC_GREEN, "GREEN="},
171{PSVC_AMBER, "AMBER="},
172{PSVC_OUTPUT, "OUTPUT="},
173{PSVC_INPUT, "INPUT="},
174{PSVC_BIDIR, "BIDIR="},
175{PSVC_BIT_POS, "BIT_POS="},
176{PSVC_VAL_POS, "VAL_POS="},
177{PSVC_NORMAL_POS_AV, "NORMAL_POS_AV="},
178{PSVC_DIAG_POS_AV, "DIAG_POS_AV="},
179{PSVC_LOCK_POS_AV, "LOCK_POS_AV="},
180{PSVC_OFF_POS_AV, "OFF_POS_AV="},
181{PSVC_GPIO_PORT, "GPIO_PORT="},
182{PSVC_GPIO_REG, "GPIO_REG="}
183};
184
185#define	ASSOC_STR_TAB_SIZE 33
186static char *assoc_str_tab[] = {
187	"PSVC_PRESENCE_SENSOR",			/* 0 */
188	"PSVC_FAN_ONOFF_SENSOR",		/* 1 */
189	"PSVC_FAN_SPEED_TACHOMETER",		/* 2 */
190	"PSVC_FAN_PRIM_SEC_SELECTOR",		/* 3 */
191	"PSVC_DEV_TEMP_SENSOR",			/* 4 */
192	"PSVC_FAN_DRIVE_CONTROL",		/* 5 */
193	"PSVC_KS_NORMAL_POS_SENSOR",		/* 6 */
194	"PSVC_KS_DIAG_POS_SENSOR",		/* 7 */
195	"PSVC_KS_LOCK_POS_SENSOR",		/* 8 */
196	"PSVC_KS_OFF_POS_SENSOR",		/* 9 */
197	"PSVC_SLOT_FAULT_LED",			/* 10 */
198	"PSVC_SLOT_REMOVE_LED",			/* 11 */
199	"PSVC_TS_OVERTEMP_LED",			/* 12 */
200	"PSVC_PS_I_SENSOR",			/* 13 */
201	"PSVC_DEV_FAULT_SENSOR",		/* 14 */
202	"PSVC_DEV_FAULT_LED",			/* 15 */
203	"PSVC_TABLE",				/* 16 */
204	"PSVC_PARENT",				/* 17 */
205	"PSVC_CPU",				/* 18 */
206	"PSVC_ALTERNATE",			/* 19 */
207	"PSVC_HOTPLUG_ENABLE_SWITCH",		/* 20 */
208	"PSVC_PS",				/* 21 */
209	"PSVC_FAN",				/* 22 */
210	"PSVC_TS",				/* 23 */
211	"PSVC_DISK",				/* 24 */
212	"PSVC_LED",				/* 25 */
213	"PSVC_FSP_LED",				/* 26 */
214	"PSVC_KEYSWITCH",			/* 27 */
215	"PSVC_PCI_CARD",			/* 28 */
216	"PSVC_PHYSICAL_DEVICE",			/* 29 */
217	"PSVC_DEV_TYPE_SENSOR",			/* 30 */
218	"PSVC_FAN_TRAY_FANS",			/* 31 */
219	"PSVC_FRU"				/* 32 */
220};
221
222#define	FEATURE_BITS (sizeof (feature_bits) / sizeof (struct bits))
223
224static struct bitfield {
225	int8_t shift;
226	char   *label;
227	char   *format;
228} addr_fields[] =
229{
230{PSVC_VERSION_SHIFT, "VERSION=", "%d"},
231{PSVC_ACTIVE_LOW_SHIFT, "ACTIVE_LOW=", "%d"},
232{PSVC_BIT_NUM_SHIFT, "BIT_NUM=", "%d"},
233{PSVC_INVERT_SHIFT, "INVERT=", "%d"},
234{PSVC_PORT_SHIFT, "PORT=", "%d"},
235{PSVC_BITSHIFT_SHIFT, "BITSHIFT=", "%d"},
236{PSVC_BYTEMASK_SHIFT, "BYTEMASK=", "%x"},
237{PSVC_REG_SHIFT, "REG=", "%d"},
238{PSVC_TYPE_SHIFT, "TYPE=", "%d"},
239{PSVC_BUSADDR_SHIFT, "BUSADDR=", "%x"},
240{PSVC_BUSNUM_SHIFT, "BUSNUM=", "%d"},
241{PSVC_CNTLR_SHIFT, "CNTLR=", "%d"},
242};
243#define	ADDR_BITFIELDS (sizeof (addr_fields) / sizeof (struct bitfield))
244
245/*
246 * record format is:
247 * pathname label1=val1,label2=val2,label3=val3
248 * Must be a space after the pathname and a comma between variables.
249 */
250
251static char *
252find_label(char *str, char *label)
253{
254	char *start;
255
256	start = strchr(str, ' ');
257	if (start == NULL)
258		return (start);
259
260	do {
261		++start;
262		if (strncmp(start, label, strlen(label)) == 0)
263			return (start);
264
265		start = strchr(start, ',');
266	} while (start != NULL);
267
268	return (NULL);
269}
270
271static int32_t
272i_psvc_value(char *buf, int32_t attr_id, void *attrp)
273{
274	char *val;
275	uint32_t temp32;
276	uint64_t temp64;
277	uint64_t result;
278	int32_t i;
279	int32_t found;
280	char label[64];
281	int val_size;
282	int label_size;
283
284
285	switch (attr_id) {
286	case PSVC_CLASS_ATTR:
287	case PSVC_SUBCLASS_ATTR:
288	case PSVC_INSTANCE_ATTR:
289	case PSVC_LO_WARN_ATTR:
290	case PSVC_LO_SHUT_ATTR:
291	case PSVC_HI_WARN_ATTR:
292	case PSVC_HI_SHUT_ATTR:
293	case PSVC_HW_HI_SHUT_ATTR:
294	case PSVC_HW_LO_SHUT_ATTR:
295	case PSVC_OPTIMAL_TEMP_ATTR:
296		snprintf(label, sizeof (label), "%s=", attr_str_tab[attr_id]);
297		val = find_label(buf, label);
298		if (val == NULL) {
299			errno = EINVAL;
300			return (PSVC_FAILURE);
301		}
302		found = sscanf(val + strlen(label),
303			"%d", (int32_t *)attrp);
304		if (found == 0)
305			*(int32_t *)attrp = 0;
306		break;
307	case PSVC_SETPOINT_ATTR:
308	case PSVC_HYSTERESIS_ATTR:
309	case PSVC_LOOPGAIN_ATTR:
310	case PSVC_LOOPBIAS_ATTR:
311		snprintf(label, sizeof (label), "%s=", attr_str_tab[attr_id]);
312		val = find_label(buf, label);
313		if (val == NULL) {
314			errno = EINVAL;
315			return (PSVC_FAILURE);
316		}
317
318		found = sscanf(val + strlen(label), "%hd", (int16_t *)attrp);
319		if (found == 0)
320			*(int16_t *)attrp = 0;
321		break;
322	case PSVC_LED_COLOR_ATTR:
323	case PSVC_LED_IS_LOCATOR_ATTR:
324	case PSVC_LED_LOCATOR_NAME_ATTR:
325		snprintf(label, sizeof (label), "%s=", attr_str_tab[attr_id]);
326		val = find_label(buf, label);
327		if (val == NULL) {
328			errno = EINVAL;
329			return (PSVC_FAILURE);
330		}
331		val_size = strlen(val);
332		label_size = strlen(label);
333
334		for (i = 0; i < val_size && val[i] != ','; i++);
335		if (i < strlen(val) - 1) {
336			strncpy((char *)attrp, val+label_size,
337				i - label_size);
338		} else
339		found = sscanf(val + label_size, "%s", (char *)attrp);
340		if (found == 0)
341			strcpy((char *)attrp, "");
342		break;
343	case PSVC_FEATURES_ATTR:
344		result = 0;
345		for (i = 0; i < FEATURE_BITS; ++i) {
346			val = find_label(buf, feature_bits[i].label);
347			if (val == NULL)
348				continue;
349			found = sscanf(val + strlen(feature_bits[i].label),
350				"%d", &temp32);
351			if (found != 0) {
352				if (temp32 == 1)
353					result |= feature_bits[i].bit;
354			}
355		}
356		*(uint64_t *)attrp = result;
357		break;
358	case PSVC_ADDR_SPEC_ATTR:
359		result = 0;
360		for (i = 0; i < ADDR_BITFIELDS; ++i) {
361			val = find_label(buf, addr_fields[i].label);
362			if (val == NULL)
363				continue;
364			found = sscanf(val + strlen(addr_fields[i].label),
365				addr_fields[i].format, &temp32);
366			if (found != 0) {
367				temp64 = temp32;
368				temp64 <<= addr_fields[i].shift;
369				result |= temp64;
370			}
371		}
372		*(uint64_t *)attrp = result;
373		break;
374	default:
375		errno = EINVAL;
376		return (PSVC_FAILURE);
377	}
378	return (PSVC_SUCCESS);
379}
380
381/* determine number of records in file section */
382static int32_t
383i_psvc_count_records(FILE *fp, char *end, uint32_t *countp)
384{
385	long first_record;
386	char *ret;
387	char buf[BUFSZ];
388	uint32_t count = 0;
389
390	first_record = ftell(fp);
391
392	while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
393		if (strncmp(end, buf, strlen(end)) == 0)
394			break;
395		++count;
396	}
397
398	if (ret == NULL) {
399		errno = EINVAL;
400		return (PSVC_FAILURE);
401	}
402
403	fseek(fp, first_record, SEEK_SET);
404	*countp = count;
405	return (PSVC_SUCCESS);
406}
407
408/* determine number of records in file section */
409static int32_t
410i_psvc_count_tables_associations(FILE *fp, uint32_t *countp, char *end)
411{
412	long first_record;
413	char *ret;
414	char buf[BUFSZ];
415	uint32_t count = 0;
416
417	first_record = ftell(fp);
418
419	while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
420		if (strncmp(end, buf, strlen(end)) == 0)
421			++count;
422	}
423#ifdef	lint
424	ret = ret;
425#endif
426
427	fseek(fp, first_record, SEEK_SET);
428	*countp = count;
429	return (PSVC_SUCCESS);
430}
431
432/* determine number of records in a table */
433static int32_t
434i_psvc_count_table_records(FILE *fp, char *end, uint32_t *countp)
435{
436	long first_record;
437	int ret;
438	char string[BUFSZ];
439	uint32_t count = 0;
440
441	first_record = ftell(fp);
442
443	while ((ret = fscanf(fp, "%s", string)) == 1) {
444		if (strncmp(end, string, strlen(end)) == 0)
445			break;
446		++count;
447	}
448
449	if (ret != 1) {
450		errno = EINVAL;
451		return (PSVC_FAILURE);
452	}
453
454	fseek(fp, first_record, SEEK_SET);
455	*countp = count;
456	return (PSVC_SUCCESS);
457}
458
459/*
460 * Find number of matches to an antecedent_id of a certain
461 * association type.
462 */
463static int32_t
464i_psvc_get_assoc_matches(EHdl_t *hdlp, char *antecedent, int32_t assoc_id,
465	int32_t *matches)
466{
467	int i;
468	int32_t key;
469	EAssocList_t *ap = hdlp->assoc_tbl + assoc_id;
470
471	*matches = 0;
472
473	if (ap->table == 0) {
474		errno = EINVAL;
475		return (PSVC_FAILURE);
476	}
477
478	key = psvc_get_str_key(antecedent);
479
480	for (i = 0; i < ap->count; ++i) {
481		if (ap->table[i].ant_key == key) {
482			if (strcmp(ap->table[i].antecedent_id, antecedent)
483			    == 0)
484				++*matches;
485		}
486	}
487	return (PSVC_SUCCESS);
488}
489
490/*
491 * Find 1st m matches to an antecedent_id of a certain
492 * association type.
493 * Returns zero for success, -1 for failure.
494 */
495static int32_t
496i_psvc_get_assoc_id(EHdl_t *hdlp, char *antecedent, int32_t assoc_id,
497	int32_t match, char **id_list)
498{
499	int i;
500	int found = 0;
501	int32_t key;
502	EAssocList_t *ap = &hdlp->assoc_tbl[assoc_id];
503
504	if (ap->table == 0) {
505		errno = EINVAL;
506		return (-1);
507	}
508
509	key = psvc_get_str_key(antecedent);
510
511	for (i = 0; i < ap->count; ++i) {
512		if (ap->table[i].ant_key == key) {
513			if (strcmp(ap->table[i].antecedent_id, antecedent)
514			    == 0) {
515				if (found == match) {
516					*id_list = ap->table[i].dependent_id;
517					return (0);
518				}
519				++found;
520			}
521		}
522	}
523
524	errno = EINVAL;
525	return (-1);
526}
527
528static int32_t
529i_psvc_get_table_value(EHdl_t *hdlp, char *table_id, uint32_t index,
530	void *value)
531{
532	int32_t i;
533	ETable_t *tblp;
534	ETable_Array *tbl_arr;
535	int32_t key, array;
536
537	key = psvc_get_str_key(table_id);
538	array = key % PSVC_MAX_TABLE_ARRAYS;
539	tbl_arr = &(hdlp->tbl_arry[array]);
540
541	for (i = 0; i < tbl_arr->obj_count; ++i) {
542		if (key == tbl_arr->obj_tbl[i].key) {
543			if (strcmp(tbl_arr->obj_tbl[i].name,
544				table_id) == 0)
545				break;
546		}
547	}
548
549	if (tbl_arr->obj_tbl[i].type != PSVC_TBL)
550		return (PSVC_FAILURE);
551
552	tblp = (ETable_t *)tbl_arr->obj_tbl[i].objp;
553
554	if (tblp->table == NULL)
555		return (PSVC_FAILURE);
556
557	if (index >= tblp->size)
558		return (PSVC_FAILURE);
559
560	switch (tblp->cell_type) {
561		case 0:
562			*(int8_t *)value = *((int8_t *)tblp->table + index);
563			break;
564		case 1:
565			*(uint8_t *)value = *((uint8_t *)tblp->table + index);
566			break;
567		case 2:
568			*(int16_t *)value = *((int16_t *)tblp->table + index);
569			break;
570		case 3:
571			*(uint16_t *)value = *((uint16_t *)tblp->table + index);
572			break;
573		case 4:
574			*(int32_t *)value = *((int32_t *)tblp->table + index);
575			break;
576		case 5:
577			*(uint32_t *)value = *((uint32_t *)tblp->table + index);
578			break;
579		case 6:
580			*(int64_t *)value = *((int64_t *)tblp->table + index);
581			break;
582		case 7:
583			*(uint64_t *)value = *((uint64_t *)tblp->table + index);
584			break;
585		default:
586			return (PSVC_FAILURE);
587	}
588
589	return (PSVC_SUCCESS);
590}
591
592int32_t
593psvc_get_attr(EHdl_t *hdlp, char *name, int32_t attr_id, void *attr_valuep, ...)
594{
595	EObj_t *objp;
596	int32_t status = PSVC_SUCCESS;
597	int32_t arg1, arg2;
598	va_list ap;
599
600	pthread_mutex_lock(&hdlp->mutex);
601
602	if (attr_valuep == NULL) {
603		errno = EFAULT;
604		pthread_mutex_unlock(&hdlp->mutex);
605		return (PSVC_FAILURE);
606	}
607
608	switch (attr_id) {
609	case PSVC_TABLE_VALUE_ATTR:
610		va_start(ap, attr_valuep);
611		status = i_psvc_get_table_value(hdlp, name,
612			va_arg(ap, uint32_t), attr_valuep);
613		va_end(ap);
614		break;
615	case PSVC_ASSOC_MATCHES_ATTR:
616		va_start(ap, attr_valuep);
617		status = i_psvc_get_assoc_matches(hdlp, name,
618			va_arg(ap, int32_t), attr_valuep);
619		va_end(ap);
620		break;
621	case PSVC_ASSOC_ID_ATTR:
622		va_start(ap, attr_valuep);
623		arg1 = va_arg(ap, int32_t);
624		arg2 = va_arg(ap, int32_t);
625		status = i_psvc_get_assoc_id(hdlp, name,
626		    arg1, arg2, attr_valuep);
627		va_end(ap);
628		break;
629	default:
630		status = i_psvc_get_obj(hdlp, name, &objp);
631		if (status != PSVC_SUCCESS) {
632			pthread_mutex_unlock(&hdlp->mutex);
633			return (status);
634		}
635		status = (*objp->get_attr)(hdlp, objp, attr_id,
636			attr_valuep);
637	}
638
639	if (status != PSVC_SUCCESS) {
640		pthread_mutex_unlock(&hdlp->mutex);
641		return (status);
642	}
643
644	pthread_mutex_unlock(&hdlp->mutex);
645	return (status);
646}
647
648int32_t
649psvc_set_attr(EHdl_t *hdlp, char *name, int32_t attr_id, void *attr_valuep)
650{
651	EObj_t *objp;
652	int32_t status = PSVC_SUCCESS;
653
654	pthread_mutex_lock(&hdlp->mutex);
655	status = i_psvc_get_obj(hdlp, name, &objp);
656	if (status != PSVC_SUCCESS) {
657		pthread_mutex_unlock(&hdlp->mutex);
658		return (status);
659	}
660
661	if (attr_valuep == NULL) {
662		errno = EFAULT;
663		pthread_mutex_unlock(&hdlp->mutex);
664		return (PSVC_FAILURE);
665	}
666
667	status = (*objp->set_attr)(hdlp, objp, attr_id, attr_valuep);
668	if (status != PSVC_SUCCESS) {
669		pthread_mutex_unlock(&hdlp->mutex);
670		return (status);
671	}
672
673	pthread_mutex_unlock(&hdlp->mutex);
674	return (status);
675}
676
677
678static int32_t
679i_psvc_get_presence(EHdl_t *hdlp, EObj_t *objp, boolean_t *pr)
680{
681	EObj_t *pobjp, *mobjp;
682	int32_t matches;
683	char *mid;
684	char *parent_id;
685	int32_t status = PSVC_SUCCESS;
686	uint8_t value_8bit, value_8bit_inv;
687	boolean_t active_low, value;
688
689	if (strcmp(objp->label, PSVC_CHASSIS) == 0) {
690		*pr = PSVC_PRESENT;
691		objp->present = PSVC_PRESENT;
692		return (PSVC_SUCCESS);
693	}
694
695	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PARENT, 0,
696		&parent_id);
697	if (status != PSVC_SUCCESS)
698		return (status);
699
700	if (strcmp(parent_id, PSVC_CHASSIS)) {
701		status = i_psvc_get_obj(hdlp, parent_id, &pobjp);
702		if (status != PSVC_SUCCESS)
703			return (status);
704		if (!pobjp->present) {
705			pobjp->get_attr(hdlp, pobjp, PSVC_PRESENCE_ATTR, pr);
706			*pr = pobjp->present;
707			objp->present = pobjp->present;
708			return (status);
709		}
710	}
711
712	(void) i_psvc_get_assoc_matches(hdlp, objp->label,
713		PSVC_PRESENCE_SENSOR, &matches);
714
715	if (matches != 0) {
716		status = i_psvc_get_assoc_id(hdlp, objp->label,
717		    PSVC_PRESENCE_SENSOR, 0, &mid);
718		if (status != PSVC_SUCCESS)
719			return (status);
720		status = i_psvc_get_obj(hdlp, mid, &mobjp);
721		if (status != PSVC_SUCCESS)
722			return (status);
723
724		active_low = PSVC_IS_ACTIVE_LOW(mobjp->addr_spec);
725
726		if (mobjp->class == PSVC_BOOLEAN_GPIO_CLASS) {
727			status = mobjp->get_attr(hdlp, mobjp,
728				PSVC_GPIO_VALUE_ATTR, &value);
729			if (status != PSVC_SUCCESS)
730				return (status);
731			if (active_low)
732				if (value == 0)
733					*pr = PSVC_PRESENT;
734				else
735					*pr = PSVC_ABSENT;
736			else
737				if (value == 0)
738					*pr = PSVC_ABSENT;
739				else
740					*pr = PSVC_PRESENT;
741		} else if (mobjp->class == PSVC_8BIT_GPIO_CLASS) {
742			uint8_t bitshift, bytemask;
743
744			status = mobjp->get_attr(hdlp, mobjp,
745				PSVC_GPIO_VALUE_ATTR, &value_8bit);
746			if (status != PSVC_SUCCESS)
747				return (status);
748			if (PSVC_HP_INVERT(mobjp->addr_spec))
749				value_8bit_inv = ~value_8bit;
750			else
751				value_8bit_inv = value_8bit;
752			bitshift = PSVC_GET_ASPEC_BITSHIFT(mobjp->addr_spec);
753			bytemask = PSVC_GET_ASPEC_BYTEMASK(mobjp->addr_spec);
754			value_8bit_inv =
755				value_8bit_inv & (bytemask >> bitshift);
756			if (active_low)
757				if (value_8bit_inv == 0)
758					*pr = PSVC_PRESENT;
759				else
760					*pr = PSVC_ABSENT;
761			else
762				if (value_8bit_inv == 0)
763					*pr = PSVC_ABSENT;
764				else
765					*pr = PSVC_PRESENT;
766		} else {
767			errno = EINVAL;
768			return (PSVC_FAILURE);
769		}
770	} else {
771		*pr = PSVC_PRESENT;
772	}
773
774	objp->present = *pr;
775
776	return (status);
777}
778
779static int32_t
780i_psvc_get_device_value_0_0(EHdl_t *hdlp, EObj_t *objp, int32_t *temp)
781{
782	int32_t status = PSVC_SUCCESS, m;
783	char *tid;
784	int16_t temp16;
785	char *physid;
786	EObj_t *physobjp;
787
788	if (objp->present != PSVC_PRESENT) {
789		errno = ENODEV;
790		return (PSVC_FAILURE);
791	}
792
793	status = i_psvc_get_assoc_id(
794		hdlp, objp->label, PSVC_PHYSICAL_DEVICE, 0, &physid);
795	if (status != PSVC_SUCCESS) {
796		return (status);
797	}
798	status = i_psvc_get_obj(hdlp, physid, &physobjp);
799	if (status != PSVC_SUCCESS) {
800		return (status);
801	}
802
803	status = ((EPhysDev_t *)physobjp)->get_temperature(hdlp,
804		objp->addr_spec, temp);
805	if (status != PSVC_SUCCESS) {
806		return (status);
807	}
808
809	if (objp->features & PSVC_CONVERSION_TABLE) {
810		status = i_psvc_get_assoc_matches(hdlp, objp->label,
811		    PSVC_TABLE, &m);
812		if ((status != PSVC_SUCCESS) || (m != 1)) {
813			return (status);
814		}
815
816		(void) i_psvc_get_assoc_id(hdlp, objp->label, PSVC_TABLE, 0,
817			&tid);
818
819		status = i_psvc_get_table_value(hdlp, tid, *temp, &temp16);
820		*temp = temp16;
821	}
822	return (status);
823}
824
825static int32_t
826i_psvc_get_device_value_0_1(EHdl_t *hdlp, EObj_t *objp, int32_t *temp)
827{
828	int32_t status = PSVC_SUCCESS, m;
829	char *tid;
830	int16_t temp16;
831	char *physid;
832	EObj_t *physobjp;
833
834	if (objp->present != PSVC_PRESENT) {
835		errno = ENODEV;
836		return (PSVC_FAILURE);
837	}
838
839	status = i_psvc_get_assoc_id(
840		hdlp, objp->label, PSVC_PHYSICAL_DEVICE, 0, &physid);
841	if (status != PSVC_SUCCESS) {
842		return (status);
843	}
844	status = i_psvc_get_obj(hdlp, physid, &physobjp);
845	if (status != PSVC_SUCCESS) {
846		return (status);
847	}
848
849	status = ((EPhysDev_t *)physobjp)->get_temperature(hdlp,
850		objp->addr_spec, temp);
851	if (status != PSVC_SUCCESS) {
852		return (status);
853	}
854
855	if (objp->features & PSVC_CONVERSION_TABLE) {
856		status = i_psvc_get_assoc_matches(hdlp, objp->label,
857		    PSVC_TABLE, &m);
858		if ((status != PSVC_SUCCESS) || (m != 1)) {
859			return (status);
860		}
861
862		(void) i_psvc_get_assoc_id(hdlp, objp->label, PSVC_TABLE, 0,
863			&tid);
864
865		status = i_psvc_get_table_value(hdlp, tid, *temp, &temp16);
866		*temp = temp16;
867	}
868	return (status);
869}
870
871static int32_t
872i_psvc_get_device_value_4_0(EHdl_t *hdlp, EObj_t *objp, int32_t *value)
873{
874	int32_t status = PSVC_SUCCESS;
875	char *physid;
876	EObj_t *physobjp;
877
878	if (objp->present != PSVC_PRESENT) {
879		errno = ENODEV;
880		return (PSVC_FAILURE);
881	}
882
883	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
884		0, &physid);
885	if (status != PSVC_SUCCESS)
886		return (status);
887	status = i_psvc_get_obj(hdlp, physid, &physobjp);
888	if (status != PSVC_SUCCESS)
889		return (status);
890
891	status = ((EPhysDev_t *)physobjp)->get_input(hdlp, objp->addr_spec,
892		value);
893	if (status != PSVC_SUCCESS)
894		return (status);
895
896	if (objp->features & PSVC_CONVERSION_TABLE) {
897		int32_t m;
898		char *tid;
899		int16_t temp16;
900
901		status = i_psvc_get_assoc_matches(hdlp, objp->label,
902		    PSVC_TABLE, &m);
903		if ((status != PSVC_SUCCESS) || (m != 1)) {
904			return (status);
905		}
906
907		(void) i_psvc_get_assoc_id(hdlp, objp->label, PSVC_TABLE, 0,
908			&tid);
909
910		status = i_psvc_get_table_value(hdlp, tid, *value, &temp16);
911		*value = temp16;
912	}
913
914	return (status);
915}
916
917static int32_t
918i_psvc_set_device_value_5_0(EHdl_t *hdlp, EObj_t *objp, int32_t *value)
919{
920	int32_t status = PSVC_SUCCESS;
921	char *physid;
922	EObj_t *physobjp;
923
924	if (objp->present != PSVC_PRESENT) {
925		errno = ENODEV;
926		return (PSVC_FAILURE);
927	}
928
929	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
930		0, &physid);
931	if (status != PSVC_SUCCESS)
932		return (status);
933	status = i_psvc_get_obj(hdlp, physid, &physobjp);
934	if (status != PSVC_SUCCESS)
935		return (status);
936	status = ((EPhysDev_t *)physobjp)->set_output(hdlp, objp->addr_spec,
937		*value);
938	if (status != PSVC_SUCCESS)
939		return (status);
940
941	return (status);
942}
943
944static int32_t
945i_psvc_get_device_value_5_0(EHdl_t *hdlp, EObj_t *objp, int32_t *value)
946{
947	int32_t status = PSVC_SUCCESS;
948	char *physid;
949	EObj_t *physobjp;
950
951	if (objp->present != PSVC_PRESENT) {
952		errno = ENODEV;
953		return (PSVC_FAILURE);
954	}
955
956	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
957		0, &physid);
958	if (status != PSVC_SUCCESS)
959		return (status);
960	status = i_psvc_get_obj(hdlp, physid, &physobjp);
961	if (status != PSVC_SUCCESS)
962		return (status);
963
964	status = ((EPhysDev_t *)physobjp)->get_output(hdlp, objp->addr_spec,
965		value);
966	if (status != PSVC_SUCCESS)
967		return (status);
968
969	if (objp->features & PSVC_CONVERSION_TABLE) {
970		int32_t m;
971		char *tid;
972		int16_t temp16;
973
974		status = i_psvc_get_assoc_matches(hdlp, objp->label,
975		    PSVC_TABLE, &m);
976		if ((status != PSVC_SUCCESS) || (m != 1)) {
977			return (status);
978		}
979
980		(void) i_psvc_get_assoc_id(hdlp, objp->label, PSVC_TABLE, 0,
981			&tid);
982
983		status = i_psvc_get_table_value(hdlp, tid, *value, &temp16);
984		*value = temp16;
985	}
986	return (status);
987}
988
989static int32_t
990i_psvc_get_device_value_6_0(EHdl_t *hdlp, EObj_t *objp, boolean_t *value)
991{
992	int32_t status = PSVC_SUCCESS;
993	int32_t bit_value;
994	char *physid;
995	EObj_t *physobjp;
996
997	if (objp->present != PSVC_PRESENT) {
998		errno = ENODEV;
999		return (PSVC_FAILURE);
1000	}
1001
1002	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1003		0, &physid);
1004	if (status != PSVC_SUCCESS)
1005		return (status);
1006	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1007	if (status != PSVC_SUCCESS)
1008		return (status);
1009
1010	status = ((EPhysDev_t *)physobjp)->get_bit(hdlp, objp->addr_spec,
1011		&bit_value);
1012	if (status != PSVC_SUCCESS)
1013		return (status);
1014
1015	*value = bit_value;
1016
1017	return (status);
1018}
1019
1020static int32_t
1021i_psvc_set_device_value_6_0(EHdl_t *hdlp, EObj_t *objp, boolean_t *value)
1022{
1023	int32_t status = PSVC_SUCCESS;
1024	int32_t bit_value;
1025	char *physid;
1026	EObj_t *physobjp;
1027
1028	if (objp->present != PSVC_PRESENT) {
1029		errno = ENODEV;
1030		return (PSVC_FAILURE);
1031	}
1032
1033	bit_value = *value;
1034	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1035		0, &physid);
1036	if (status != PSVC_SUCCESS)
1037		return (status);
1038	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1039	if (status != PSVC_SUCCESS)
1040		return (status);
1041
1042	status = ((EPhysDev_t *)physobjp)->set_bit(hdlp, objp->addr_spec,
1043		bit_value);
1044	if (status != PSVC_SUCCESS)
1045		return (status);
1046
1047	return (status);
1048}
1049
1050static int32_t
1051i_psvc_get_device_value_1_0(EHdl_t *hdlp, EObj_t *objp, int32_t *fan_speed)
1052{
1053	int32_t status = PSVC_SUCCESS;
1054	EObj_t *ftobjp;
1055	char *fan_tach;
1056
1057	if (objp->present != PSVC_PRESENT) {
1058		errno = ENODEV;
1059		return (PSVC_FAILURE);
1060	}
1061
1062	status = i_psvc_get_assoc_id(hdlp, objp->label,
1063		PSVC_FAN_SPEED_TACHOMETER, 0, &fan_tach);
1064	if (status != PSVC_SUCCESS)
1065		return (status);
1066
1067	status = i_psvc_get_obj(hdlp, fan_tach, &ftobjp);
1068	if (status != PSVC_SUCCESS)
1069		return (status);
1070
1071	status = ftobjp->get_attr(hdlp, ftobjp, PSVC_SENSOR_VALUE_ATTR,
1072		fan_speed);
1073	if (status != PSVC_SUCCESS)
1074		return (status);
1075
1076	return (status);
1077}
1078
1079static int32_t
1080i_psvc_get_device_value_7_0(EHdl_t *hdlp, EObj_t *objp, int32_t *fan_speed)
1081{
1082	char *physid;
1083	EObj_t *physobjp;
1084	int32_t status = PSVC_SUCCESS;
1085
1086	if (objp->present != PSVC_PRESENT) {
1087		errno = ENODEV;
1088		return (PSVC_FAILURE);
1089	}
1090
1091	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1092		0, &physid);
1093	if (status != PSVC_SUCCESS)
1094		return (status);
1095	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1096	if (status != PSVC_SUCCESS)
1097		return (status);
1098
1099	status = ((EPhysDev_t *)physobjp)->get_fanspeed(hdlp, objp->addr_spec,
1100		fan_speed);
1101	if (status != PSVC_SUCCESS)
1102		return (status);
1103
1104	if (objp->features & PSVC_CONVERSION_TABLE) {
1105		int32_t m;
1106		char *tid;
1107		int16_t temp16;
1108
1109		status = i_psvc_get_assoc_matches(hdlp, objp->label,
1110		    PSVC_TABLE, &m);
1111		if ((status != PSVC_SUCCESS) || (m != 1)) {
1112			return (status);
1113		}
1114
1115		(void) i_psvc_get_assoc_id(hdlp, objp->label, PSVC_TABLE, 0,
1116			&tid);
1117
1118		status = i_psvc_get_table_value(hdlp, tid, *fan_speed, &temp16);
1119		*fan_speed = temp16;
1120	}
1121	return (status);
1122}
1123
1124static int32_t
1125i_psvc_get_device_state_2_0(EHdl_t *hdlp, EObj_t *objp, char *led_state)
1126{
1127	int32_t status = PSVC_SUCCESS;
1128	int32_t bit_value;
1129	boolean_t active_low;
1130	char *physid;
1131	EObj_t *physobjp;
1132
1133	if (objp->present != PSVC_PRESENT) {
1134		errno = ENODEV;
1135		return (PSVC_FAILURE);
1136	}
1137
1138	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1139		0, &physid);
1140	if (status != PSVC_SUCCESS)
1141		return (status);
1142	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1143	if (status != PSVC_SUCCESS)
1144		return (status);
1145
1146	status = ((EPhysDev_t *)physobjp)->get_bit(hdlp, objp->addr_spec,
1147		&bit_value);
1148	if (status != PSVC_SUCCESS)
1149		return (status);
1150
1151	active_low = PSVC_IS_ACTIVE_LOW(objp->addr_spec);
1152	if (active_low)
1153		if (bit_value == 0)
1154			strcpy(led_state, PSVC_LED_ON);
1155		else
1156			strcpy(led_state, PSVC_LED_OFF);
1157	else
1158		if (bit_value == 0)
1159			strcpy(led_state, PSVC_LED_OFF);
1160		else
1161			strcpy(led_state, PSVC_LED_ON);
1162
1163	return (status);
1164}
1165
1166static int32_t
1167i_psvc_set_device_state_2_0(EHdl_t *hdlp, EObj_t *objp, char *led_state)
1168{
1169	int32_t status = PSVC_SUCCESS;
1170	boolean_t active_low;
1171	int32_t bit_value;
1172	char *physid;
1173	EObj_t *physobjp;
1174
1175	if (objp->present != PSVC_PRESENT) {
1176		errno = ENODEV;
1177		return (PSVC_FAILURE);
1178	}
1179
1180	if (strcmp(((ELed_t *)objp)->is_locator, PSVC_LOCATOR_TRUE) != 0) {
1181		/*
1182		 * For Locator LEDs we ignore lit_count.  RSC may have
1183		 * altered the LED state underneath us, So we should
1184		 * always just do what the user asked instead of trying
1185		 * to be smart.
1186		 */
1187
1188		if (strcmp(led_state, PSVC_LED_ON) == 0)
1189			((ELed_t *)objp)->lit_count++;
1190		else if (strcmp(led_state, PSVC_LED_OFF) == 0) {
1191			if (--((ELed_t *)objp)->lit_count > 0) {
1192				return (PSVC_SUCCESS);
1193			} else if (((ELed_t *)objp)->lit_count < 0)
1194				((ELed_t *)objp)->lit_count = 0;
1195			/* Fall through case is when lit_count is 0 */
1196		}
1197	}
1198
1199	strcpy(objp->previous_state, objp->state);
1200	strcpy(objp->state, led_state);
1201
1202	bit_value = (strcmp(led_state, PSVC_LED_ON) == 0);
1203
1204	/*
1205	 * Flip the bit if necessary (for active_low devices,
1206	 * O ==> ON; 1 ==> OFF.
1207	 */
1208	active_low = PSVC_IS_ACTIVE_LOW(objp->addr_spec);
1209	bit_value ^= active_low;
1210
1211	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1212		0, &physid);
1213	if (status != PSVC_SUCCESS)
1214		return (status);
1215	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1216	if (status != PSVC_SUCCESS)
1217		return (status);
1218
1219	status = ((EPhysDev_t *)physobjp)->set_bit(hdlp, objp->addr_spec,
1220		bit_value);
1221	return (status);
1222}
1223
1224static int32_t
1225i_psvc_get_device_state_2_1(EHdl_t *hdlp, EObj_t *objp, char *led_state)
1226{
1227	int32_t status = PSVC_SUCCESS;
1228	uint8_t value;
1229	char *physid;
1230	EObj_t *physobjp;
1231
1232	if (objp->present != PSVC_PRESENT) {
1233		errno = ENODEV;
1234		return (PSVC_FAILURE);
1235	}
1236
1237	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1238		0, &physid);
1239	if (status != PSVC_SUCCESS)
1240		return (status);
1241	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1242	if (status != PSVC_SUCCESS)
1243		return (status);
1244
1245	status = ((EPhysDev_t *)physobjp)->get_reg(hdlp, objp->addr_spec,
1246		&value);
1247	if (status != PSVC_SUCCESS)
1248		return (status);
1249
1250	switch (value) {
1251	case 0:
1252		strcpy(led_state, PSVC_LED_OFF);
1253		break;
1254	case 1:
1255		strcpy(led_state, PSVC_LED_SLOW_BLINK);
1256		break;
1257	case 2:
1258		strcpy(led_state, PSVC_LED_FAST_BLINK);
1259		break;
1260	case 3:
1261		strcpy(led_state, PSVC_LED_ON);
1262		break;
1263	}
1264
1265	return (status);
1266}
1267
1268static int32_t
1269i_psvc_set_device_state_2_1(EHdl_t *hdlp, EObj_t *objp, char *led_state)
1270{
1271	int32_t status = PSVC_SUCCESS;
1272	uint8_t value;
1273	char *physid;
1274	EObj_t *physobjp;
1275
1276	if (objp->present != PSVC_PRESENT) {
1277		errno = ENODEV;
1278		return (PSVC_FAILURE);
1279	}
1280
1281	if (strcmp(led_state, PSVC_LED_ON) == 0)
1282		((ELed_t *)objp)->lit_count++;
1283	else if (strcmp(led_state, PSVC_LED_OFF) == 0) {
1284		if (--((ELed_t *)objp)->lit_count > 0) {
1285			return (PSVC_SUCCESS);
1286		} else if (((ELed_t *)objp)->lit_count < 0)
1287			((ELed_t *)objp)->lit_count = 0;
1288
1289		/* Fall through case is when lit_count is 0 */
1290	}
1291
1292	strcpy(objp->previous_state, objp->state);
1293	strcpy(objp->state, led_state);
1294
1295	if (strcmp(led_state, PSVC_LED_OFF) == 0)
1296		value = 0;
1297	else if (strcmp(led_state, PSVC_LED_SLOW_BLINK) == 0)
1298		value = 1;
1299	else if (strcmp(led_state, PSVC_LED_FAST_BLINK) == 0)
1300		value = 2;
1301	else if (strcmp(led_state, PSVC_LED_ON) == 0)
1302		value = 3;
1303
1304	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1305		0, &physid);
1306	if (status != PSVC_SUCCESS)
1307		return (status);
1308	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1309	if (status != PSVC_SUCCESS)
1310		return (status);
1311
1312	status = ((EPhysDev_t *)physobjp)->set_reg(hdlp, objp->addr_spec,
1313		value);
1314
1315	return (status);
1316}
1317
1318static int32_t
1319i_psvc_get_device_state_9_0(EHdl_t *hdlp, EObj_t *objp, char *pos)
1320{
1321	int32_t status = PSVC_SUCCESS, matches;
1322	char *sensorid;
1323	EObj_t *sensorp;
1324	char state[32];
1325
1326	if (objp->present != PSVC_PRESENT) {
1327		errno = ENODEV;
1328		return (PSVC_FAILURE);
1329	}
1330
1331	if (objp->features & PSVC_NORMAL_POS_AV) {
1332		(void) i_psvc_get_assoc_matches(hdlp, objp->label,
1333		    PSVC_KS_NORMAL_POS_SENSOR, &matches);
1334		if (matches == 1) {
1335			status = i_psvc_get_assoc_id(hdlp, objp->label,
1336				PSVC_KS_NORMAL_POS_SENSOR, 0, &sensorid);
1337			if (status != PSVC_SUCCESS)
1338				return (status);
1339
1340			status = i_psvc_get_obj(hdlp, sensorid, &sensorp);
1341			if (status != PSVC_SUCCESS)
1342				return (status);
1343
1344			status = sensorp->get_attr(hdlp, sensorp,
1345				PSVC_SWITCH_STATE_ATTR, state);
1346			if (status != PSVC_SUCCESS)
1347				return (status);
1348
1349			if (strcmp(state, PSVC_SWITCH_ON) == 0) {
1350				strcpy(pos, PSVC_NORMAL_POS);
1351				return (PSVC_SUCCESS);
1352			}
1353		}
1354	}
1355
1356	if (objp->features & PSVC_DIAG_POS_AV) {
1357		(void) i_psvc_get_assoc_matches(hdlp, objp->label,
1358		    PSVC_KS_DIAG_POS_SENSOR, &matches);
1359		if (matches == 1) {
1360			status = i_psvc_get_assoc_id(hdlp, objp->label,
1361			    PSVC_KS_DIAG_POS_SENSOR, 0, &sensorid);
1362			if (status != PSVC_SUCCESS)
1363				return (status);
1364
1365			status = i_psvc_get_obj(hdlp, sensorid, &sensorp);
1366			if (status != PSVC_SUCCESS)
1367				return (status);
1368
1369			status = sensorp->get_attr(hdlp, sensorp,
1370				PSVC_SWITCH_STATE_ATTR, state);
1371			if (status != PSVC_SUCCESS)
1372				return (status);
1373
1374			if (strcmp(state, PSVC_SWITCH_ON) == 0) {
1375				strcpy(pos, PSVC_DIAG_POS);
1376				return (PSVC_SUCCESS);
1377			}
1378		}
1379	}
1380
1381	if (objp->features & PSVC_LOCK_POS_AV) {
1382		(void) i_psvc_get_assoc_matches(hdlp, objp->label,
1383		    PSVC_KS_LOCK_POS_SENSOR, &matches);
1384		if (matches == 1) {
1385			status = i_psvc_get_assoc_id(hdlp, objp->label,
1386			    PSVC_KS_LOCK_POS_SENSOR, 0, &sensorid);
1387			if (status != PSVC_SUCCESS)
1388				return (status);
1389
1390			status = i_psvc_get_obj(hdlp, sensorid, &sensorp);
1391			if (status != PSVC_SUCCESS)
1392				return (status);
1393
1394			status = sensorp->get_attr(hdlp, sensorp,
1395				PSVC_SWITCH_STATE_ATTR, state);
1396			if (status != PSVC_SUCCESS)
1397				return (status);
1398
1399			if (strcmp(state, PSVC_SWITCH_ON) == 0) {
1400				strcpy(pos, PSVC_LOCKED_POS);
1401				return (PSVC_SUCCESS);
1402			}
1403		}
1404	}
1405
1406	if (objp->features & PSVC_OFF_POS_AV) {
1407		(void) i_psvc_get_assoc_matches(hdlp, objp->label,
1408		    PSVC_KS_OFF_POS_SENSOR, &matches);
1409		if (matches == 1) {
1410			status = i_psvc_get_assoc_id(hdlp, objp->label,
1411			    PSVC_KS_OFF_POS_SENSOR, 0, &sensorid);
1412			if (status != PSVC_SUCCESS)
1413				return (status);
1414
1415			status = i_psvc_get_obj(hdlp, sensorid, &sensorp);
1416			if (status != PSVC_SUCCESS)
1417				return (status);
1418
1419			status = sensorp->get_attr(hdlp, sensorp,
1420				PSVC_SWITCH_STATE_ATTR, state);
1421			if (status != PSVC_SUCCESS)
1422				return (status);
1423
1424			if (strcmp(state, PSVC_SWITCH_ON) == 0) {
1425				strcpy(pos, PSVC_OFF_POS);
1426				return (PSVC_SUCCESS);
1427			}
1428		}
1429	}
1430	/* If we have fallen through till here, something's wrong */
1431	errno = EINVAL;
1432	return (PSVC_FAILURE);
1433}
1434
1435
1436static int32_t
1437i_psvc_get_device_value_10_0(EHdl_t *hdlp, EObj_t *objp, uint8_t *value)
1438{
1439	int32_t status = PSVC_SUCCESS;
1440	char *physid;
1441	EObj_t *physobjp;
1442
1443	if (objp->present != PSVC_PRESENT) {
1444		errno = ENODEV;
1445		return (PSVC_FAILURE);
1446	}
1447
1448	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1449		0, &physid);
1450	if (status != PSVC_SUCCESS)
1451		return (status);
1452	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1453	if (status != PSVC_SUCCESS)
1454		return (status);
1455
1456	status = ((EPhysDev_t *)physobjp)->get_reg(hdlp, objp->addr_spec,
1457		value);
1458	if (status != PSVC_SUCCESS)
1459		return (status);
1460
1461	if (objp->features & PSVC_CONVERSION_TABLE) {
1462		int32_t m;
1463		char *tid;
1464		uint8_t temp8;
1465
1466		status = i_psvc_get_assoc_matches(hdlp, objp->label,
1467		    PSVC_TABLE, &m);
1468		if ((status != PSVC_SUCCESS) || (m != 1)) {
1469			return (status);
1470		}
1471
1472		(void) i_psvc_get_assoc_id(hdlp, objp->label,
1473			PSVC_TABLE, 0, &tid);
1474
1475		status = i_psvc_get_table_value(hdlp, tid, *value, &temp8);
1476		*value = temp8;
1477	}
1478	return (status);
1479}
1480
1481static int32_t
1482i_psvc_get_device_value_10_1(EHdl_t *hdlp, EObj_t *objp, uint8_t *value)
1483{
1484	int32_t status = PSVC_SUCCESS;
1485	char *physid;
1486	EObj_t *physobjp;
1487
1488	if (objp->present != PSVC_PRESENT) {
1489		errno = ENODEV;
1490		return (PSVC_FAILURE);
1491	}
1492
1493	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1494		0, &physid);
1495	if (status != PSVC_SUCCESS)
1496		return (status);
1497	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1498	if (status != PSVC_SUCCESS)
1499		return (status);
1500
1501	status = ((EPhysDev_t *)physobjp)->get_port(hdlp, objp->addr_spec,
1502		value);
1503	if (status != PSVC_SUCCESS)
1504		return (status);
1505
1506	return (status);
1507}
1508
1509static int32_t
1510i_psvc_set_device_value_10_0(EHdl_t *hdlp, EObj_t *objp, uint8_t *value)
1511{
1512	int32_t status = PSVC_SUCCESS;
1513	char *physid;
1514	EObj_t *physobjp;
1515
1516	if (objp->present != PSVC_PRESENT) {
1517		errno = ENODEV;
1518		return (PSVC_FAILURE);
1519	}
1520
1521	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1522		0, &physid);
1523	if (status != PSVC_SUCCESS)
1524		return (status);
1525	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1526	if (status != PSVC_SUCCESS)
1527		return (status);
1528
1529	status = ((EPhysDev_t *)physobjp)->set_reg(hdlp, objp->addr_spec,
1530		*value);
1531	return (status);
1532}
1533
1534static int32_t
1535i_psvc_set_device_value_10_1(EHdl_t *hdlp, EObj_t *objp, uint8_t *value)
1536{
1537	int32_t status = PSVC_SUCCESS;
1538	char *physid;
1539	EObj_t *physobjp;
1540
1541	if (objp->present != PSVC_PRESENT) {
1542		errno = ENODEV;
1543		return (PSVC_FAILURE);
1544	}
1545
1546	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1547		0, &physid);
1548	if (status != PSVC_SUCCESS)
1549		return (status);
1550	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1551	if (status != PSVC_SUCCESS)
1552		return (status);
1553
1554	status = ((EPhysDev_t *)physobjp)->set_port(hdlp, objp->addr_spec,
1555		*value);
1556	return (status);
1557}
1558
1559static int32_t
1560i_psvc_get_device_state_8_0(EHdl_t *hdlp, EObj_t *objp, char *sw_state)
1561{
1562	int32_t status = PSVC_SUCCESS;
1563	boolean_t active_low;
1564	int32_t bit_value;
1565	char *physid;
1566	EObj_t *physobjp;
1567
1568	if (objp->present != PSVC_PRESENT) {
1569		errno = ENODEV;
1570		return (PSVC_FAILURE);
1571	}
1572
1573	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1574		0, &physid);
1575	if (status != PSVC_SUCCESS)
1576		return (status);
1577	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1578	if (status != PSVC_SUCCESS)
1579		return (status);
1580
1581	status = ((EPhysDev_t *)physobjp)->get_bit(hdlp, objp->addr_spec,
1582		&bit_value);
1583	if (status != PSVC_SUCCESS)
1584		return (status);
1585
1586	active_low = PSVC_IS_ACTIVE_LOW(objp->addr_spec);
1587	if (active_low)
1588		if (bit_value == 0)
1589			strcpy(sw_state, PSVC_SWITCH_ON);
1590		else
1591			strcpy(sw_state, PSVC_SWITCH_OFF);
1592	else
1593		if (bit_value == 0)
1594			strcpy(sw_state, PSVC_SWITCH_OFF);
1595		else
1596			strcpy(sw_state, PSVC_SWITCH_ON);
1597
1598	return (status);
1599}
1600
1601static int32_t
1602i_psvc_set_device_state_8_0(EHdl_t *hdlp, EObj_t *objp, char *sw_state)
1603{
1604	int32_t status = PSVC_SUCCESS;
1605	boolean_t active_low;
1606	int32_t bit_value;
1607	char *physid;
1608	EObj_t *physobjp;
1609
1610	if (objp->present != PSVC_PRESENT) {
1611		errno = ENODEV;
1612		return (PSVC_FAILURE);
1613	}
1614
1615	strcpy(objp->previous_state, objp->state);
1616	strcpy(objp->state, sw_state);
1617
1618	active_low = PSVC_IS_ACTIVE_LOW(objp->addr_spec);
1619
1620	if (active_low)
1621		if (strcmp(sw_state, PSVC_SWITCH_ON) == 0)
1622			bit_value = 0;
1623		else
1624			bit_value = 1;
1625	else
1626		if (strcmp(sw_state, PSVC_SWITCH_ON) == 0)
1627			bit_value = 1;
1628		else
1629			bit_value = 0;
1630
1631	status = i_psvc_get_assoc_id(hdlp, objp->label, PSVC_PHYSICAL_DEVICE,
1632		0, &physid);
1633	if (status != PSVC_SUCCESS)
1634		return (status);
1635	status = i_psvc_get_obj(hdlp, physid, &physobjp);
1636	if (status != PSVC_SUCCESS)
1637		return (status);
1638
1639	status = ((EPhysDev_t *)physobjp)->set_bit(hdlp, objp->addr_spec,
1640		bit_value);
1641	return (status);
1642}
1643
1644/* LM75 */
1645static int32_t
1646i_psvc_get_temperature_11_2(EHdl_t *hdlp, uint64_t aspec, int32_t *temp)
1647{
1648	int32_t status = PSVC_SUCCESS;
1649	char path[1024];
1650	int32_t fp;
1651	int16_t temp16;
1652
1653	status = i_psvc_get_devpath(hdlp, aspec, path);
1654	if (status != PSVC_SUCCESS)
1655		return (status);
1656
1657	fp = open(path, O_RDWR);
1658	if (fp == -1)
1659		return (PSVC_FAILURE);
1660
1661	status = ioctl_retry(fp, I2C_GET_TEMPERATURE, (void *)&temp16);
1662	if (status == -1) {
1663		close(fp);
1664		errno = EIO;
1665		return (PSVC_FAILURE);
1666	}
1667	*temp = temp16;
1668
1669	close(fp);
1670
1671	return (status);
1672}
1673
1674/* MAX1617 */
1675static int32_t
1676i_psvc_get_temperature_11_4(EHdl_t *hdlp, uint64_t aspec, int32_t *temp)
1677{
1678	int32_t status = PSVC_SUCCESS;
1679	char path[1024];
1680	int32_t fp;
1681	int16_t temp16;
1682
1683	status = i_psvc_get_devpath(hdlp, aspec, path);
1684	if (status != PSVC_SUCCESS)
1685		return (status);
1686
1687	fp = open(path, O_RDWR);
1688	if (fp == -1)
1689		return (PSVC_FAILURE);
1690
1691	status = ioctl_retry(fp, I2C_GET_TEMPERATURE, (void *)&temp16);
1692	if (status == -1) {
1693		close(fp);
1694		errno = EIO;
1695		return (PSVC_FAILURE);
1696	}
1697	*temp = temp16;
1698
1699	close(fp);
1700
1701	return (status);
1702}
1703
1704/* PCF8591 */
1705static int32_t
1706i_psvc_get_temperature_11_6(EHdl_t *hdlp, uint64_t aspec, int32_t *temp)
1707{
1708	int32_t status = PSVC_SUCCESS;
1709	char path[1024];
1710	int32_t fp;
1711
1712	status = i_psvc_get_devpath(hdlp, aspec, path);
1713	if (status != PSVC_SUCCESS)
1714		return (status);
1715
1716	fp = open(path, O_RDWR);
1717	if (fp == -1)
1718		return (PSVC_FAILURE);
1719
1720	status = ioctl_retry(fp, I2C_GET_INPUT, (void *)temp);
1721	if (status == -1) {
1722		close(fp);
1723		errno = EIO;
1724		return (-1);
1725	}
1726
1727	close(fp);
1728
1729	return (status);
1730}
1731
1732/* SSC050 */
1733static int32_t
1734i_psvc_get_fanspeed_11_7(EHdl_t *hdlp, uint64_t aspec, int32_t *fan_speed)
1735{
1736	int32_t ret, status = PSVC_SUCCESS;
1737	char path[1024];
1738	int32_t fp;
1739
1740	status = i_psvc_get_devpath(hdlp, aspec, path);
1741	if (status != PSVC_SUCCESS)
1742		return (status);
1743
1744	fp = open(path, O_RDWR);
1745	if (fp == -1)
1746		return (PSVC_FAILURE);
1747
1748	ret = ioctl_retry(fp, I2C_GET_FAN_SPEED, (void *)fan_speed);
1749	if (ret == -1) {
1750		close(fp);
1751		errno = EIO;
1752		return (-1);
1753	}
1754
1755	close(fp);
1756
1757	return (status);
1758}
1759
1760/* PCF8591 */
1761static int32_t
1762i_psvc_get_input_11_6(EHdl_t *hdlp, uint64_t aspec, int32_t *value)
1763{
1764	int32_t ret, status = PSVC_SUCCESS;
1765	char path[1024];
1766	int32_t fp;
1767
1768	status = i_psvc_get_devpath(hdlp, aspec, path);
1769	if (status != PSVC_SUCCESS)
1770		return (status);
1771
1772	fp = open(path, O_RDWR);
1773	if (fp == -1)
1774		return (PSVC_FAILURE);
1775
1776	ret = ioctl_retry(fp, I2C_GET_INPUT, (void *)value);
1777	if (ret == -1) {
1778		close(fp);
1779		errno = EIO;
1780		return (-1);
1781	}
1782
1783	close(fp);
1784
1785	return (status);
1786}
1787
1788/* LTC1427 */
1789static int32_t
1790i_psvc_get_output_11_3(EHdl_t *hdlp, uint64_t aspec, int32_t *value)
1791{
1792	int32_t ret, status = PSVC_SUCCESS;
1793	char path[1024];
1794	int32_t fp;
1795
1796	status = i_psvc_get_devpath(hdlp, aspec, path);
1797	if (status != PSVC_SUCCESS)
1798		return (status);
1799
1800	fp = open(path, O_RDWR);
1801	if (fp == -1)
1802		return (PSVC_FAILURE);
1803
1804	ret = ioctl_retry(fp, I2C_GET_OUTPUT, (void *)value);
1805	if (ret == -1) {
1806		close(fp);
1807		errno = EIO;
1808		return (PSVC_FAILURE);
1809	}
1810
1811	close(fp);
1812
1813	return (status);
1814}
1815
1816/* PCF8591 */
1817static int32_t
1818i_psvc_get_output_11_6(EHdl_t *hdlp, uint64_t aspec, int32_t *value)
1819{
1820	int32_t ret, status = PSVC_SUCCESS;
1821	char path[1024];
1822	int32_t fp;
1823
1824	status = i_psvc_get_devpath(hdlp, aspec, path);
1825	if (status != PSVC_SUCCESS)
1826		return (status);
1827
1828	fp = open(path, O_RDWR);
1829	if (fp == -1)
1830		return (PSVC_FAILURE);
1831
1832	ret = ioctl_retry(fp, I2C_GET_OUTPUT, (void *)value);
1833	if (ret == -1) {
1834		close(fp);
1835		errno = EIO;
1836		return (PSVC_FAILURE);
1837	}
1838
1839	close(fp);
1840
1841	return (status);
1842}
1843
1844/* TDA8444 */
1845static int32_t
1846i_psvc_get_output_11_8(EHdl_t *hdlp, uint64_t aspec, int32_t *value)
1847{
1848	int32_t ret, status = PSVC_SUCCESS;
1849	char path[1024];
1850	int32_t fp;
1851	int8_t buf;
1852
1853	status = i_psvc_get_devpath(hdlp, aspec, path);
1854	if (status != PSVC_SUCCESS)
1855		return (status);
1856
1857	fp = open(path, O_RDWR);
1858	if (fp == -1)
1859		return (PSVC_FAILURE);
1860
1861	ret = read(fp, &buf, 1);
1862	if (ret == -1) {
1863		close(fp);
1864		errno = EIO;
1865		return (PSVC_FAILURE);
1866	}
1867	*value = buf;
1868
1869	close(fp);
1870
1871	return (status);
1872}
1873
1874/* LTC1427 */
1875static int32_t
1876i_psvc_set_output_11_3(EHdl_t *hdlp, uint64_t aspec, int32_t value)
1877{
1878	int32_t ret, status = PSVC_SUCCESS;
1879	char path[1024];
1880	int32_t fp;
1881
1882	status = i_psvc_get_devpath(hdlp, aspec, path);
1883	if (status != PSVC_SUCCESS)
1884		return (status);
1885
1886	fp = open(path, O_RDWR);
1887	if (fp == -1)
1888		return (PSVC_FAILURE);
1889
1890	ret = ioctl_retry(fp, I2C_SET_OUTPUT, (void *)&value);
1891	if (ret == -1) {
1892		close(fp);
1893		errno = EIO;
1894		return (PSVC_FAILURE);
1895	}
1896
1897	close(fp);
1898
1899	return (status);
1900}
1901
1902/* PCF8591 */
1903static int32_t
1904i_psvc_set_output_11_6(EHdl_t *hdlp, uint64_t aspec, int32_t value)
1905{
1906	int32_t ret, status = PSVC_SUCCESS;
1907	char path[1024];
1908	int32_t fp;
1909
1910	status = i_psvc_get_devpath(hdlp, aspec, path);
1911	if (status != PSVC_SUCCESS)
1912		return (status);
1913
1914	fp = open(path, O_RDWR);
1915	if (fp == -1)
1916		return (PSVC_FAILURE);
1917
1918	ret = ioctl_retry(fp, I2C_SET_OUTPUT, (void *)&value);
1919	if (ret == -1) {
1920		close(fp);
1921		errno = EIO;
1922		return (PSVC_FAILURE);
1923	}
1924
1925	close(fp);
1926
1927	return (status);
1928}
1929
1930/* TDA8444 */
1931static int32_t
1932i_psvc_set_output_11_8(EHdl_t *hdlp, uint64_t aspec, int32_t value)
1933{
1934	int32_t ret, status = PSVC_SUCCESS;
1935	char path[1024];
1936	int32_t fp;
1937	int8_t buf;
1938
1939	status = i_psvc_get_devpath(hdlp, aspec, path);
1940	if (status != PSVC_SUCCESS)
1941		return (status);
1942
1943	fp = open(path, O_RDWR);
1944	if (fp == -1)
1945		return (PSVC_FAILURE);
1946
1947	buf = value;
1948	ret = write(fp, &buf, 1);
1949	if (ret == -1) {
1950		close(fp);
1951		errno = EIO;
1952		return (PSVC_FAILURE);
1953	}
1954
1955	close(fp);
1956
1957	return (status);
1958}
1959
1960/* HPC3130 */
1961static int32_t
1962i_psvc_get_reg_11_1(EHdl_t *hdlp, uint64_t aspec, uint8_t *value)
1963{
1964	int32_t ret, status = PSVC_SUCCESS;
1965	uint8_t bitshift, bytemask;
1966	char path[1024];
1967	i2c_reg_t i2cregarg;
1968	int32_t fp;
1969
1970	status = i_psvc_get_devpath(hdlp, aspec, path);
1971	if (status != PSVC_SUCCESS)
1972		return (status);
1973	fp = open(path, O_RDWR);
1974	if (fp == -1)
1975		return (PSVC_FAILURE);
1976
1977	i2cregarg.reg_num = PSVC_GET_ASPEC_REG(aspec);
1978	ret = ioctl_retry(fp, I2C_GET_REG, (void *)&i2cregarg);
1979	if (ret == -1) {
1980		close(fp);
1981		errno = EIO;
1982		return (-1);
1983	}
1984
1985	bitshift = PSVC_GET_ASPEC_BITSHIFT(aspec);
1986	bytemask = PSVC_GET_ASPEC_BYTEMASK(aspec);
1987	if (value != NULL)
1988		*value = (i2cregarg.reg_value & bytemask) >> bitshift;
1989	close(fp);
1990
1991	return (status);
1992}
1993
1994/* SSC050 */
1995static int32_t
1996i_psvc_get_reg_11_7(EHdl_t *hdlp, uint64_t aspec, uint8_t *value)
1997{
1998	int32_t ret, status = PSVC_SUCCESS;
1999	uint8_t bitshift, bytemask;
2000	char path[1024];
2001	i2c_reg_t i2cregarg;
2002	int32_t fp;
2003
2004	status = i_psvc_get_devpath(hdlp, aspec, path);
2005	if (status != PSVC_SUCCESS)
2006		return (status);
2007
2008	fp = open(path, O_RDWR);
2009	if (fp == -1)
2010		return (PSVC_FAILURE);
2011
2012	i2cregarg.reg_num = PSVC_GET_ASPEC_REG(aspec);
2013	ret = ioctl_retry(fp, I2C_GET_REG, (void *)&i2cregarg);
2014	if (ret == -1) {
2015		close(fp);
2016		errno = EIO;
2017		return (-1);
2018	}
2019
2020	bitshift = PSVC_GET_ASPEC_BITSHIFT(aspec);
2021	bytemask = PSVC_GET_ASPEC_BYTEMASK(aspec);
2022	if (value != NULL)
2023		*value = (i2cregarg.reg_value & bytemask) >> bitshift;
2024
2025	close(fp);
2026
2027	return (status);
2028}
2029
2030/* HPC3130 */
2031static int32_t
2032i_psvc_set_reg_11_1(EHdl_t *hdlp, uint64_t aspec, int32_t value)
2033{
2034	int32_t ret, status = PSVC_SUCCESS;
2035	char path[1024];
2036	i2c_reg_t i2cregarg;
2037	int8_t tval;
2038	uint8_t bitshift, bytemask;
2039	int32_t fp;
2040
2041	status = i_psvc_get_devpath(hdlp, aspec, path);
2042	if (status != PSVC_SUCCESS)
2043		return (status);
2044
2045	bitshift = PSVC_GET_ASPEC_BITSHIFT(aspec);
2046	bytemask = PSVC_GET_ASPEC_BYTEMASK(aspec);
2047	value = value << bitshift;
2048
2049	fp = open(path, O_RDWR);
2050	if (fp == -1)
2051		return (PSVC_FAILURE);
2052
2053	i2cregarg.reg_num = PSVC_GET_ASPEC_REG(aspec);
2054	if (bytemask != 0xFF) {
2055		ret = ioctl_retry(fp, I2C_GET_REG, (void *)&i2cregarg);
2056		if (ret == -1) {
2057			close(fp);
2058			errno = EIO;
2059			return (-1);
2060		}
2061		tval = i2cregarg.reg_value;
2062		tval = tval & ~bytemask;
2063	} else
2064		tval = 0;
2065
2066	value = tval | value;
2067	i2cregarg.reg_value = value;
2068	ret = ioctl_retry(fp, I2C_SET_REG, (void *)&i2cregarg);
2069	if (ret == -1) {
2070		close(fp);
2071		errno = EIO;
2072		return (-1);
2073	}
2074
2075	close(fp);
2076
2077	return (status);
2078}
2079
2080/* SSC050 */
2081static int32_t
2082i_psvc_set_reg_11_7(EHdl_t *hdlp, uint64_t aspec, int32_t value)
2083{
2084	int32_t ret, status = PSVC_SUCCESS;
2085	char path[1024];
2086	i2c_reg_t i2cregarg;
2087	int8_t tval;
2088	uint8_t bitshift, bytemask;
2089	int32_t fp;
2090
2091	status = i_psvc_get_devpath(hdlp, aspec, path);
2092	if (status != PSVC_SUCCESS)
2093		return (status);
2094
2095	bitshift = PSVC_GET_ASPEC_BITSHIFT(aspec);
2096	bytemask = PSVC_GET_ASPEC_BYTEMASK(aspec);
2097	value = value << bitshift;
2098
2099	fp = open(path, O_RDWR);
2100	if (fp == -1)
2101		return (PSVC_FAILURE);
2102
2103	i2cregarg.reg_num = PSVC_GET_ASPEC_REG(aspec);
2104	if (bytemask != 0xFF) {
2105		ret = ioctl_retry(fp, I2C_GET_REG, (void *)&i2cregarg);
2106		if (ret == -1) {
2107			close(fp);
2108			errno = EIO;
2109			return (-1);
2110		}
2111		tval = i2cregarg.reg_value;
2112		tval = tval & ~bytemask;
2113	} else
2114		tval = 0;
2115
2116	value = tval | value;
2117	i2cregarg.reg_value = value;
2118	ret = ioctl_retry(fp, I2C_SET_REG, (void *)&i2cregarg);
2119	if (ret == -1) {
2120		close(fp);
2121		errno = EIO;
2122		return (-1);
2123	}
2124
2125	close(fp);
2126
2127	return (status);
2128}
2129
2130/* PCF8574 */
2131static int32_t
2132i_psvc_get_bit_11_5(EHdl_t *hdlp, uint64_t aspec, int32_t *value)
2133{
2134	int32_t ret, status = PSVC_SUCCESS;
2135	char path[1024];
2136	i2c_bit_t bitarg;
2137	int32_t fp;
2138
2139	status = i_psvc_get_devpath(hdlp, aspec, path);
2140	if (status != PSVC_SUCCESS)
2141		return (status);
2142
2143	bitarg.bit_num = PSVC_GET_BIT_NUM(aspec);
2144	bitarg.direction = DIR_NO_CHANGE;
2145
2146	fp = open(path, O_RDWR);
2147	if (fp == -1)
2148		return (PSVC_FAILURE);
2149
2150	ret = ioctl_retry(fp, I2C_GET_BIT, (void *)&bitarg);
2151	if (ret == -1) {
2152		close(fp);
2153		errno = EIO;
2154		return (-1);
2155	}
2156
2157	*value = bitarg.bit_value;
2158
2159	close(fp);
2160
2161	return (status);
2162}
2163
2164/* PCF8574 */
2165static int32_t
2166i_psvc_get_port_11_5(EHdl_t *hdlp, uint64_t aspec, uint8_t *value)
2167{
2168	int32_t ret, status = PSVC_SUCCESS;
2169	char path[1024];
2170	i2c_port_t port;
2171	int32_t fp;
2172
2173	status = i_psvc_get_devpath(hdlp, aspec, path);
2174	if (status != PSVC_SUCCESS)
2175		return (status);
2176
2177	port.direction = DIR_NO_CHANGE;
2178
2179	fp = open(path, O_RDWR);
2180	if (fp == -1)
2181		return (PSVC_FAILURE);
2182
2183	ret = ioctl_retry(fp, I2C_GET_PORT, (void *)&port);
2184	if (ret == -1) {
2185		close(fp);
2186		errno = EIO;
2187		return (-1);
2188	}
2189
2190	*value = port.value;
2191
2192	close(fp);
2193
2194	return (status);
2195}
2196
2197/* SSC050 */
2198static int32_t
2199i_psvc_get_bit_11_7(EHdl_t *hdlp, uint64_t aspec, int32_t *value)
2200{
2201	int32_t ret, status = PSVC_SUCCESS;
2202	char path[1024];
2203	i2c_bit_t bitarg;
2204	int32_t fp;
2205
2206	status = i_psvc_get_devpath(hdlp, aspec, path);
2207	if (status != PSVC_SUCCESS)
2208		return (status);
2209
2210	bitarg.bit_num = PSVC_GET_BIT_NUM(aspec);
2211	bitarg.direction = DIR_NO_CHANGE;
2212
2213	fp = open(path, O_RDWR);
2214	if (fp == -1)
2215		return (PSVC_FAILURE);
2216
2217	ret = ioctl_retry(fp, I2C_GET_BIT, (void *)&bitarg);
2218	if (ret == -1) {
2219		close(fp);
2220		errno = EIO;
2221		return (-1);
2222	}
2223
2224	*value = bitarg.bit_value;
2225
2226	close(fp);
2227
2228	return (status);
2229}
2230
2231/* PCF8574 */
2232static int32_t
2233i_psvc_set_bit_11_5(EHdl_t *hdlp, uint64_t aspec, int32_t value)
2234{
2235	int32_t ret, status = PSVC_SUCCESS;
2236	char path[1024];
2237	i2c_bit_t bitarg;
2238	int32_t fp;
2239
2240	status = i_psvc_get_devpath(hdlp, aspec, path);
2241	if (status != PSVC_SUCCESS)
2242		return (status);
2243
2244	bitarg.bit_value = value;
2245	bitarg.bit_num = PSVC_GET_BIT_NUM(aspec);
2246	bitarg.direction = DIR_OUTPUT;
2247	fp = open(path, O_RDWR);
2248	if (fp == -1)
2249		return (PSVC_FAILURE);
2250
2251	ret = ioctl_retry(fp, I2C_SET_BIT, (void *)&bitarg);
2252	if (ret == -1) {
2253		close(fp);
2254		errno = EIO;
2255		return (-1);
2256	}
2257
2258	close(fp);
2259
2260	return (status);
2261}
2262
2263/* PCF8574 */
2264static int32_t
2265i_psvc_set_port_11_5(EHdl_t *hdlp, uint64_t aspec, int32_t value)
2266{
2267	int32_t ret, status = PSVC_SUCCESS;
2268	char path[1024];
2269	i2c_port_t port;
2270	int32_t fp;
2271
2272	status = i_psvc_get_devpath(hdlp, aspec, path);
2273	if (status != PSVC_SUCCESS)
2274		return (status);
2275
2276	port.value = (uint8_t)value;
2277	port.direction = DIR_NO_CHANGE;
2278	fp = open(path, O_RDWR);
2279	if (fp == -1)
2280		return (PSVC_FAILURE);
2281
2282	ret = ioctl_retry(fp, I2C_SET_PORT, (void *)&port);
2283	if (ret == -1) {
2284		close(fp);
2285		errno = EIO;
2286		return (-1);
2287	}
2288
2289	close(fp);
2290
2291	return (status);
2292}
2293
2294/* SSC050 */
2295static int32_t
2296i_psvc_set_bit_11_7(EHdl_t *hdlp, uint64_t aspec, int32_t value)
2297{
2298	int32_t ret, status = PSVC_SUCCESS;
2299	char path[1024];
2300	i2c_bit_t bitarg;
2301	int32_t fp;
2302
2303	status = i_psvc_get_devpath(hdlp, aspec, path);
2304	if (status != PSVC_SUCCESS)
2305		return (status);
2306
2307	bitarg.bit_value = value;
2308	bitarg.bit_num = PSVC_GET_BIT_NUM(aspec);
2309	bitarg.direction = DIR_OUTPUT;
2310
2311	fp = open(path, O_RDWR);
2312	if (fp == -1)
2313		return (PSVC_FAILURE);
2314
2315	ret = ioctl_retry(fp, I2C_SET_BIT, (void *)&bitarg);
2316	if (ret == -1) {
2317		close(fp);
2318		errno = EIO;
2319		return (-1);
2320	}
2321
2322	close(fp);
2323
2324	return (status);
2325}
2326
2327/* AT24 */
2328static int32_t
2329i_psvc_probe_11_0(EHdl_t *hdlp, EObj_t *objp)
2330{
2331	int32_t ret, status = PSVC_SUCCESS;
2332	uint8_t value;
2333	char path[1024];
2334	int32_t fp;
2335
2336	if (objp->present != PSVC_PRESENT) {
2337		errno = ENODEV;
2338		return (PSVC_FAILURE);
2339	}
2340
2341	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2342	if (status != PSVC_SUCCESS) {
2343		return (status);
2344	}
2345
2346	fp = open(path, O_RDWR);
2347	if (fp == -1) {
2348		return (PSVC_FAILURE);
2349	}
2350
2351	ret = read(fp, &value, 1);
2352	if (ret == -1) {
2353		close(fp);
2354		errno = EIO;
2355		return (-1);
2356	}
2357
2358	close(fp);
2359
2360	return (status);
2361}
2362
2363/* HPC3130 */
2364static int32_t
2365i_psvc_probe_11_1(EHdl_t *hdlp, EObj_t *objp)
2366{
2367	int32_t ret, status = PSVC_SUCCESS;
2368	char path[1024];
2369	i2c_reg_t reg;
2370	int32_t fp;
2371
2372	if (objp->present != PSVC_PRESENT) {
2373		errno = ENODEV;
2374		return (PSVC_FAILURE);
2375	}
2376
2377	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2378	if (status != PSVC_SUCCESS)
2379		return (status);
2380
2381	fp = open(path, O_RDWR);
2382	if (fp == -1)
2383		return (PSVC_FAILURE);
2384
2385	reg.reg_num = 0;
2386	ret = ioctl_retry(fp, I2C_GET_REG, (void *)&reg);
2387	if (ret == -1) {
2388		close(fp);
2389		errno = EIO;
2390		return (-1);
2391	}
2392
2393	close(fp);
2394
2395	return (status);
2396}
2397
2398/* LM75 */
2399static int32_t
2400i_psvc_probe_11_2(EHdl_t *hdlp, EObj_t *objp)
2401{
2402	int32_t ret, status = PSVC_SUCCESS;
2403	char path[1024];
2404	int32_t fp;
2405	int16_t temp16;
2406
2407	if (objp->present != PSVC_PRESENT) {
2408		errno = ENODEV;
2409		return (PSVC_FAILURE);
2410	}
2411
2412	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2413	if (status != PSVC_SUCCESS) {
2414		return (status);
2415	}
2416
2417	fp = open(path, O_RDWR);
2418	if (fp == -1) {
2419		return (PSVC_FAILURE);
2420	}
2421
2422	ret = ioctl_retry(fp, I2C_GET_TEMPERATURE, (void *)&temp16);
2423	if (ret == -1) {
2424		close(fp);
2425		errno = EIO;
2426		return (-1);
2427	}
2428
2429	close(fp);
2430
2431	return (status);
2432}
2433
2434/* LTC1427 */
2435static int32_t
2436i_psvc_probe_11_3(EHdl_t *hdlp, EObj_t *objp)
2437{
2438	int32_t ret, status = PSVC_SUCCESS;
2439	int32_t value;
2440	char path[1024];
2441	int32_t fp;
2442
2443	if (objp->present != PSVC_PRESENT) {
2444		errno = ENODEV;
2445		return (PSVC_FAILURE);
2446	}
2447
2448	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2449	if (status != PSVC_SUCCESS) {
2450		return (status);
2451	}
2452
2453	fp = open(path, O_RDWR);
2454	if (fp == -1) {
2455		return (PSVC_FAILURE);
2456	}
2457
2458	ret = ioctl_retry(fp, I2C_GET_OUTPUT, (void *)&value);
2459	if (ret == -1) {
2460		close(fp);
2461		errno = EINVAL;
2462		return (-1);
2463	}
2464
2465	ret = ioctl_retry(fp, I2C_SET_OUTPUT, (void *)&value);
2466	if (ret == -1) {
2467		close(fp);
2468		errno = EIO;
2469		return (-1);
2470	}
2471
2472	close(fp);
2473	return (status);
2474}
2475
2476/* MAX1617 */
2477static int32_t
2478i_psvc_probe_11_4(EHdl_t *hdlp, EObj_t *objp)
2479{
2480	int32_t ret, status = PSVC_SUCCESS;
2481	char path[1024];
2482	int32_t fp;
2483	int16_t temp16;
2484
2485	if (objp->present != PSVC_PRESENT) {
2486		errno = ENODEV;
2487		return (PSVC_FAILURE);
2488	}
2489
2490	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2491	if (status != PSVC_SUCCESS) {
2492		return (status);
2493	}
2494
2495	fp = open(path, O_RDWR);
2496	if (fp == -1) {
2497		return (PSVC_FAILURE);
2498	}
2499
2500	ret = ioctl_retry(fp, I2C_GET_TEMPERATURE, (void *)&temp16);
2501	if (ret == -1) {
2502		close(fp);
2503		errno = EIO;
2504		return (-1);
2505	}
2506
2507	close(fp);
2508
2509	return (status);
2510}
2511
2512/* PCF8574 */
2513static int32_t
2514i_psvc_probe_11_5(EHdl_t *hdlp, EObj_t *objp)
2515{
2516	int32_t ret, status = PSVC_SUCCESS;
2517	char path[1024];
2518	i2c_port_t port;
2519	int32_t fp;
2520
2521	if (objp->present != PSVC_PRESENT) {
2522		errno = ENODEV;
2523		return (PSVC_FAILURE);
2524	}
2525
2526	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2527	if (status != PSVC_SUCCESS) {
2528		return (status);
2529	}
2530
2531	port.direction = DIR_NO_CHANGE;
2532
2533	fp = open(path, O_RDWR);
2534	if (fp == -1) {
2535		return (PSVC_FAILURE);
2536	}
2537
2538	ret = ioctl_retry(fp, I2C_GET_PORT, (void *)&port);
2539	if (ret == -1) {
2540		close(fp);
2541		errno = EIO;
2542		return (-1);
2543	}
2544
2545	close(fp);
2546
2547	return (status);
2548}
2549
2550/* PCF8591 */
2551static int32_t
2552i_psvc_probe_11_6(EHdl_t *hdlp, EObj_t *objp)
2553{
2554	int32_t ret, status = PSVC_SUCCESS;
2555	char path[1024];
2556	int32_t arg;
2557	int32_t fp;
2558
2559	if (objp->present != PSVC_PRESENT) {
2560		errno = ENODEV;
2561		return (PSVC_FAILURE);
2562	}
2563
2564	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2565	if (status != PSVC_SUCCESS)
2566		return (status);
2567
2568	fp = open(path, O_RDWR);
2569	if (fp == -1)
2570		return (PSVC_FAILURE);
2571
2572	ret = ioctl_retry(fp, I2C_GET_INPUT, (void *)&arg);
2573	if (ret == -1) {
2574		close(fp);
2575		errno = EIO;
2576		return (-1);
2577	}
2578
2579	close(fp);
2580
2581	return (status);
2582}
2583
2584/* SSC050 */
2585static int32_t
2586i_psvc_probe_11_7(EHdl_t *hdlp, EObj_t *objp)
2587{
2588	int32_t ret, status = PSVC_SUCCESS;
2589	char path[1024];
2590	i2c_port_t port;
2591	int32_t fp;
2592
2593	if (objp->present != PSVC_PRESENT) {
2594		errno = ENODEV;
2595		return (PSVC_FAILURE);
2596	}
2597
2598	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2599	if (status != PSVC_SUCCESS)
2600		return (status);
2601
2602	port.direction = DIR_NO_CHANGE;
2603
2604	fp = open(path, O_RDWR);
2605	if (fp == -1)
2606		return (PSVC_FAILURE);
2607
2608	ret = ioctl_retry(fp, I2C_GET_PORT, (void *)&port);
2609	if (ret == -1) {
2610		close(fp);
2611		errno = EIO;
2612		return (-1);
2613	}
2614
2615	close(fp);
2616
2617	return (status);
2618}
2619
2620/* TDA8444 */
2621static int32_t
2622i_psvc_probe_11_8(EHdl_t *hdlp, EObj_t *objp)
2623{
2624	int32_t ret, status = PSVC_SUCCESS;
2625	uint8_t value;
2626	char path[1024];
2627	int32_t fp;
2628
2629	if (objp->present != PSVC_PRESENT) {
2630		errno = ENODEV;
2631		return (PSVC_FAILURE);
2632	}
2633
2634	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2635	if (status != PSVC_SUCCESS)
2636		return (status);
2637
2638	fp = open(path, O_RDWR);
2639	if (fp == -1)
2640		return (PSVC_FAILURE);
2641
2642	ret = read(fp, &value, 1);
2643	if (ret == -1) {
2644		close(fp);
2645		errno = EIO;
2646		return (-1);
2647	}
2648
2649	close(fp);
2650
2651	return (status);
2652}
2653
2654
2655/* SSC100 */
2656static int32_t
2657i_psvc_probe_11_9(EHdl_t *hdlp, EObj_t *objp)
2658{
2659	int32_t ret, status = PSVC_SUCCESS;
2660	char path[1024];
2661	i2c_reg_t reg;
2662	int32_t fp;
2663
2664	if (objp->present != PSVC_PRESENT) {
2665		errno = ENODEV;
2666		return (PSVC_FAILURE);
2667	}
2668
2669	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
2670	if (status != PSVC_SUCCESS) {
2671		return (status);
2672	}
2673
2674	fp = open(path, O_RDWR);
2675	if (fp == -1) {
2676		return (PSVC_FAILURE);
2677	}
2678
2679	/*
2680	 * There are only a few register numbers that are valid numbers to
2681	 * read from. 0x10 is one of these registers. Any non-valid registers
2682	 * cause unknown behavior to the ssc100 device.
2683	 */
2684	reg.reg_num = 0x10;
2685	ret = ioctl_retry(fp, I2C_GET_REG, (void *)&reg);
2686	if (ret == -1) {
2687		close(fp);
2688		errno = EIO;
2689		return (-1);
2690	}
2691
2692	close(fp);
2693
2694	return (status);
2695}
2696
2697
2698/*
2699 * Find start of a section within the config file,
2700 * Returns number of records in the section.
2701 * FILE *fd is set to first data record within section.
2702 */
2703static int32_t
2704i_psvc_find_file_section(FILE *fd, char *start)
2705{
2706	char *ret;
2707	char buf[BUFSZ];
2708	char name[32];
2709	int found;
2710
2711	fseek(fd, 0, SEEK_SET);
2712	while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
2713		if (strncmp(start, buf, strlen(start)) == 0)
2714			break;
2715	}
2716
2717	if (ret == NULL) {
2718		errno = EINVAL;
2719		return (-1);
2720	}
2721
2722	found = sscanf(buf, "%s", name);
2723	if (found != 1) {
2724		errno = EINVAL;
2725		return (-1);
2726	} else {
2727		return (0);
2728	}
2729
2730}
2731
2732/* compare routine for qsort of str_tbl */
2733static int32_t
2734i_psvc_name_compare_qsort(EStringId_t *s1, EStringId_t *s2)
2735{
2736	return (strcmp(s1->name, s2->name));
2737}
2738
2739/* compare routine for bsearch of str_tbl */
2740static int32_t
2741i_psvc_name_compare_bsearch(char *s1, EStringId_t *s2)
2742{
2743	return (strcmp(s1, s2->name));
2744}
2745
2746/*
2747 * Determine the initial state of a device.
2748 */
2749static int32_t
2750i_psvc_init_state(EHdl_t *hp, EObj_t *objp)
2751{
2752	int32_t status = PSVC_SUCCESS;
2753
2754	if (objp->class == PSVC_ON_OFF_SWITCH_CLASS) {
2755		char state[32];
2756
2757		status = objp->get_attr(hp, objp, PSVC_SWITCH_STATE_ATTR,
2758			state);
2759		if (status != PSVC_SUCCESS)
2760			return (status);
2761
2762		if (strcmp(state, PSVC_SWITCH_ON) == 0)
2763			strcpy(objp->state, PSVC_ON);
2764		else
2765			strcpy(objp->state, PSVC_OFF);
2766	}
2767
2768	if (objp->class == PSVC_KEYSWITCH_CLASS) {
2769		char state[32];
2770
2771		status = objp->get_attr(hp, objp, PSVC_SWITCH_STATE_ATTR,
2772			state);
2773		if (status != PSVC_SUCCESS)
2774			return (status);
2775		strcpy(objp->state, state);
2776	}
2777
2778	return (status);
2779}
2780
2781/*
2782 * Return the object pointer for the object name passed in.
2783 * Creates the object if this is the first access,
2784 * Returns 0 if successful, -1 if not.
2785 */
2786static int32_t
2787i_psvc_get_obj(EHdl_t *hp, char *dev_name, EObj_t **objp)
2788{
2789	int32_t i, ret;
2790	int32_t found, key, array;
2791	int32_t class, subclass;
2792	boolean_t presence;
2793	char name[NAMELEN];
2794	char buf[BUFSZ];
2795	char *start;
2796	ETable_Array *tbl_arr;
2797
2798	key = psvc_get_str_key(dev_name);
2799	array = key % PSVC_MAX_TABLE_ARRAYS;
2800	tbl_arr = &(hp->tbl_arry[array]);
2801
2802	for (i = 0; i < tbl_arr->obj_count; ++i) {
2803		if (key ==  tbl_arr->obj_tbl[i].key) {
2804			if (strcmp(dev_name, tbl_arr->obj_tbl[i].name) == 0) {
2805				if (tbl_arr->obj_tbl[i].type != PSVC_OBJ)
2806					return (-1);
2807				*objp = tbl_arr->obj_tbl[i].objp;
2808				return (0);
2809			}
2810		}
2811	}
2812
2813	if (i_psvc_find_file_section(hp->fp, "OBJECT_INFO") == -1) {
2814		ENV_DEBUG("Couldn't find OBJECT_INFO section", dev_name);
2815		return (-1);
2816	}
2817
2818	fgets(buf, BUFSZ, hp->fp);
2819	while (strcmp(buf, "OBJECT_INFO_END")) {
2820		start = strrchr(buf, '/');
2821		if (start == NULL) {
2822			errno = EINVAL;
2823			return (PSVC_FAILURE);
2824		}
2825		found = sscanf(start + 1, "%s",  name);
2826		if (found != 1) {
2827			errno = EINVAL;
2828			return (PSVC_FAILURE);
2829		}
2830
2831		if (strcmp(name, dev_name) == 0) {
2832
2833			if (i_psvc_value(buf, PSVC_CLASS_ATTR, &class)
2834			    != PSVC_SUCCESS)
2835				return (PSVC_FAILURE);
2836			if (i_psvc_value(buf, PSVC_SUBCLASS_ATTR, &subclass)
2837			    != PSVC_SUCCESS)
2838				return (PSVC_FAILURE);
2839			ret = (*i_psvc_constructor[class][subclass])(hp,
2840				dev_name, objp);
2841			if (ret != PSVC_SUCCESS) {
2842				return (-1);
2843			}
2844			ret = (*objp)->get_attr(hp, *objp, PSVC_PRESENCE_ATTR,
2845				&presence);
2846			(*objp)->previous_presence = presence;
2847			if (ret != PSVC_SUCCESS || presence != PSVC_PRESENT)
2848				return (ret);
2849
2850			return (i_psvc_init_state(hp, *objp));
2851		}
2852		fgets(buf, BUFSZ, hp->fp);
2853	}
2854
2855	errno = EINVAL;
2856	return (-1);
2857}
2858
2859/*
2860 * Gets the device path associated with an object id.
2861 * Returns 0 if successful, -1 if not.
2862 */
2863static int32_t
2864i_psvc_get_devpath(EHdl_t *hp, uint64_t addr_spec, char *path)
2865{
2866	int i;
2867	EDevice_t *dp;
2868	uint32_t controller, bus, addr, port;
2869
2870	controller = PSVC_GET_ASPEC_CNTLR(addr_spec);
2871	bus = PSVC_GET_ASPEC_BUSNUM(addr_spec);
2872	addr = PSVC_GET_ASPEC_BUSADDR(addr_spec);
2873	port = PSVC_GET_ASPEC_PORT(addr_spec);
2874
2875	for (i = 0; i < hp->dev_count; ++i) {
2876		dp = &hp->dev_tbl[i];
2877		if (dp->controller == controller &&
2878		    dp->bus == bus &&
2879		    dp->addr == addr &&
2880		    dp->port == port) {
2881			strcpy(path, dp->path);
2882			return (PSVC_SUCCESS);
2883		}
2884	}
2885
2886	errno = EINVAL;
2887	return (PSVC_FAILURE);
2888}
2889
2890
2891/* Load the association table */
2892static int32_t
2893i_psvc_load_associations(EHdl_t *hp, FILE *fp)
2894{
2895	uint32_t count;
2896	int found;
2897	int i, j;
2898	char name1[32], name2[32];
2899	char buf[BUFSZ];
2900	EStringId_t *namep;
2901	EAssoc_t *ap;
2902	int32_t id;
2903	int32_t status;
2904
2905	/*
2906	 * ignore count in the file, correct count is highest
2907	 * association id + 1, now figured when loading ASSOC_STR
2908	 * section.
2909	 */
2910	if (i_psvc_find_file_section(fp, "ASSOCIATIONS") != PSVC_SUCCESS)
2911		return (-1);
2912	if ((hp->assoc_tbl = malloc(sizeof (EAssocList_t) * hp->assoc_count))
2913			== NULL) {
2914		return (-1);
2915	}
2916	memset(hp->assoc_tbl, 0, sizeof (EAssocList_t) * hp->assoc_count);
2917
2918	for (i = 0; i < hp->assoc_count; ++i) {
2919		fgets(buf, BUFSZ, fp);
2920		found = sscanf(buf, "%s %s", name1, name2);
2921		if (strcmp("ASSOCIATIONS_END", name1) == 0)
2922			break;
2923		if (found != 2) {
2924			errno = EINVAL;
2925			return (-1);
2926		}
2927		namep = (EStringId_t *)bsearch(name2, hp->othr_tbl,
2928			hp->othr_count, sizeof (EStringId_t),
2929			(int (*)(const void *, const void *))
2930			i_psvc_name_compare_bsearch);
2931		if (namep == NULL) {
2932			errno = EINVAL;
2933			return (-1);
2934		}
2935		id = namep->id;
2936
2937		status = i_psvc_count_records(fp, "ASSOCIATION_END", &count);
2938		if (status != PSVC_SUCCESS)
2939			return (status);
2940		hp->assoc_tbl[id].count = count;
2941		hp->assoc_tbl[id].table =
2942			(EAssoc_t *)malloc(sizeof (EAssoc_t) * count);
2943		if (hp->assoc_tbl[id].table == NULL)
2944			return (-1);
2945
2946		for (j = 0; j < count; ++j) {
2947			ap = &hp->assoc_tbl[id].table[j];
2948			fgets(buf, BUFSZ, fp);
2949			found = sscanf(buf, "%s %s", ap->antecedent_id,
2950				ap->dependent_id);
2951			ap->ant_key = psvc_get_str_key(ap->antecedent_id);
2952			if (found != 2) {
2953				errno = EINVAL;
2954				return (-1);
2955			}
2956		}
2957
2958
2959		fgets(buf, BUFSZ, fp);
2960		if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
2961			errno = EINVAL;
2962			return (-1);
2963		}
2964	}
2965
2966	return (0);
2967}
2968
2969/* Load the table of tables */
2970static int32_t
2971i_psvc_load_tables(EHdl_t *hp, FILE *fp)
2972{
2973	int i, j;
2974	int found;
2975	int ret;
2976	int32_t cell_type;
2977	int64_t *table;
2978	char buf[BUFSZ];
2979	int32_t status;
2980	uint32_t table_count;
2981	int32_t num, key, array;
2982	char name[NAMELEN];
2983	ETable_Array *tbl_arr;
2984
2985	if (i_psvc_find_file_section(fp, "TABLES") != PSVC_SUCCESS)
2986		return (PSVC_SUCCESS);	/* no tables */
2987	status = i_psvc_count_tables_associations(fp, &table_count,
2988			"TABLE_END");
2989	if (status != PSVC_SUCCESS || table_count == 0)
2990		return (status);
2991
2992	for (i = 0; i < table_count; ++i) {
2993		int slot;
2994		ETable_t *tblp;
2995
2996		fgets(buf, BUFSZ, fp);
2997		if (strncmp(buf, "TABLE", 5) != 0) {
2998			errno = EINVAL;
2999			return (-1);
3000		}
3001
3002		fgets(buf, BUFSZ, fp);
3003		found = sscanf(buf, "%s %d", name, &cell_type);
3004		key = psvc_get_str_key(name);
3005		array = key % PSVC_MAX_TABLE_ARRAYS;
3006		tbl_arr = &(hp->tbl_arry[array]);
3007
3008		if (tbl_arr->nextid == hp->total_obj_count) {
3009			errno = EINVAL;
3010			return (PSVC_FAILURE);
3011		} else {
3012			slot = tbl_arr->nextid++;
3013			tbl_arr->obj_count++;
3014		}
3015
3016		strcpy(tbl_arr->obj_tbl[slot].name, name);
3017
3018		tblp = (ETable_t *)malloc(sizeof (ETable_t));
3019		if (tblp == NULL)
3020			return (PSVC_FAILURE);
3021		tbl_arr->obj_tbl[slot].key = key;
3022		tbl_arr->obj_tbl[slot].objp = (EObj_t *)(void *)tblp;
3023		tbl_arr->obj_tbl[slot].type = PSVC_TBL;
3024
3025		status = i_psvc_count_table_records(fp, "TABLE_END",
3026			&tblp->size);
3027		if (status != PSVC_SUCCESS)
3028			return (status);
3029		tblp->cell_type = (uint8_t)cell_type;
3030		if (found != 2) {
3031			errno = EINVAL;
3032			return (-1);
3033		}
3034
3035		/* allocate and load table */
3036		tblp->table = (int64_t *)malloc(tblp->size *
3037			i_psvc_cell_size[tblp->cell_type]);
3038		if (tblp->table == NULL) {
3039			return (-1);
3040		}
3041
3042		table = tblp->table;
3043		for (j = 0; j < tblp->size; ++j) {
3044			switch (cell_type) {
3045				case 0:
3046					ret = fscanf(fp, "%d", &num);
3047					*((int8_t *)table + j) = num;
3048					break;
3049				case 1:
3050					ret = fscanf(fp, "%d", &num);
3051					*((uint8_t *)table + j) = (uint8_t)num;
3052					break;
3053				case 2:
3054					ret = fscanf(fp, "%hd",
3055						((int16_t *)table + j));
3056					break;
3057				case 3:
3058					ret = fscanf(fp, "%hd",
3059						((uint16_t *)table + j));
3060					break;
3061				case 4:
3062					ret = fscanf(fp, "%d",
3063						((int32_t *)table + j));
3064					break;
3065				case 5:
3066					ret = fscanf(fp, "%d",
3067						((uint32_t *)table + j));
3068					break;
3069				case 6:
3070					ret = fscanf(fp, "%lld",
3071						((int64_t *)table + j));
3072					break;
3073				case 7:
3074					ret = fscanf(fp, "%lld",
3075						((uint64_t *)table + j));
3076					break;
3077				default:
3078					errno = EINVAL;
3079					return (-1);
3080			}
3081			if (ret != 1) {
3082				errno = EINVAL;
3083				return (-1);
3084			}
3085		}
3086		fgets(buf, BUFSZ, fp);  /* reads newline on data line */
3087		fgets(buf, BUFSZ, fp);
3088		if (strncmp(buf, "TABLE_END", 9) != 0) {
3089			errno = EINVAL;
3090			return (-1);
3091		}
3092
3093	}
3094
3095	return (0);
3096}
3097
3098static int32_t
3099i_psvc_destructor(EHdl_t *hdlp, char *name, void *objp)
3100{
3101	int32_t i, key, array;
3102
3103	key = psvc_get_str_key(name);
3104	array = key % PSVC_MAX_TABLE_ARRAYS;
3105
3106	for (i = 0; i < hdlp->tbl_arry[array].obj_count; ++i) {
3107		if (key == hdlp->tbl_arry[array].obj_tbl[i].key) {
3108			if (strcmp(hdlp->tbl_arry[array].obj_tbl[i].name,
3109				name) == 0) {
3110				hdlp->tbl_arry[array].obj_tbl[i].name[0] = '\0';
3111				if (objp != NULL)
3112					free(objp);
3113				return (PSVC_SUCCESS);
3114			}
3115		}
3116	}
3117
3118	return (PSVC_SUCCESS);
3119}
3120
3121static int32_t
3122i_psvc_get_attr_generic(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id,
3123    void * attrp)
3124{
3125	int32_t status = PSVC_SUCCESS;
3126	char *parent_id;
3127
3128	switch (attr_id) {
3129	case PSVC_ADDR_SPEC_ATTR:
3130		*(uint64_t *)attrp = objp->addr_spec;
3131		break;
3132	case PSVC_CLASS_ATTR:
3133		*(int32_t *)attrp = objp->class;
3134		break;
3135	case PSVC_SUBCLASS_ATTR:
3136		*(int32_t *)attrp = objp->subclass;
3137		break;
3138	case PSVC_PRESENCE_ATTR:
3139		status = i_psvc_get_presence(hdlp, objp, (boolean_t *)attrp);
3140		break;
3141	case PSVC_PREV_PRESENCE_ATTR:
3142		*(boolean_t *)attrp = objp->previous_presence;
3143		break;
3144	case PSVC_STATE_ATTR:
3145		strcpy((char *)attrp, objp->state);
3146		break;
3147	case PSVC_PREV_STATE_ATTR:
3148		strcpy((char *)attrp, objp->previous_state);
3149		break;
3150	case PSVC_ENABLE_ATTR:
3151		*(boolean_t *)attrp = objp->enabled;
3152		break;
3153	case PSVC_FAULTID_ATTR:
3154		strcpy((char *)attrp, objp->fault_id);
3155		break;
3156	case PSVC_FEATURES_ATTR:
3157		*(uint64_t *)attrp = objp->features;
3158		break;
3159	case PSVC_LABEL_ATTR:
3160		strcpy((char *)attrp, objp->label);
3161		break;
3162	case PSVC_FRUID_ATTR:
3163		while ((objp->features & PSVC_DEV_FRU) == 0) {
3164			status = i_psvc_get_assoc_id(hdlp, objp->label,
3165				PSVC_PARENT, 0, &parent_id);
3166			if (status != PSVC_SUCCESS)
3167				return (status);
3168
3169			status = i_psvc_get_obj(hdlp, parent_id, &objp);
3170			if (status != PSVC_SUCCESS)
3171				return (status);
3172		}
3173
3174		strcpy((char *)attrp, objp->label);
3175		break;
3176	case PSVC_INSTANCE_ATTR:
3177		*(int32_t *)attrp = objp->instance;
3178		break;
3179	default:
3180		errno = EINVAL;
3181		return (PSVC_FAILURE);
3182	}
3183
3184	return (status);
3185}
3186
3187static int32_t
3188i_psvc_set_attr_generic(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id,
3189    void * attrp)
3190{
3191	int32_t status = PSVC_SUCCESS;
3192
3193	switch (attr_id) {
3194	case PSVC_PREV_PRESENCE_ATTR:
3195		objp->previous_presence = *(boolean_t *)attrp;
3196		break;
3197	case PSVC_STATE_ATTR:
3198		strcpy(objp->previous_state, objp->state);
3199		strcpy(objp->state, (char *)attrp);
3200		break;
3201	case PSVC_ENABLE_ATTR:
3202		objp->enabled = *(boolean_t *)attrp;
3203		break;
3204	case PSVC_FAULTID_ATTR:
3205		strcpy(objp->fault_id, (char *)attrp);
3206		break;
3207	default:
3208		errno = EINVAL;
3209		return (PSVC_FAILURE);
3210	}
3211	return (status);
3212}
3213
3214static int32_t
3215i_psvc_get_attr_0_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3216{
3217	int32_t status = PSVC_SUCCESS;
3218
3219	switch (attr_id) {
3220	case PSVC_SENSOR_VALUE_ATTR:
3221		return (i_psvc_get_device_value_0_0(hdlp, objp, attrp));
3222	case PSVC_LO_WARN_ATTR:
3223		*(int32_t *)attrp = ((ETempSensor_t *)objp)->lo_warn;
3224		return (status);
3225	case PSVC_LO_SHUT_ATTR:
3226		*(int32_t *)attrp = ((ETempSensor_t *)objp)->lo_shut;
3227		return (status);
3228	case PSVC_HI_WARN_ATTR:
3229		*(int32_t *)attrp = ((ETempSensor_t *)objp)->hi_warn;
3230		return (status);
3231	case PSVC_HI_SHUT_ATTR:
3232		*(int32_t *)attrp = ((ETempSensor_t *)objp)->hi_shut;
3233		return (status);
3234	}
3235
3236	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3237
3238	return (status);
3239}
3240
3241static int32_t
3242i_psvc_get_attr_0_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3243{
3244	int32_t status = PSVC_SUCCESS;
3245
3246	switch (attr_id) {
3247	case PSVC_SENSOR_VALUE_ATTR:
3248		return (i_psvc_get_device_value_0_1(hdlp, objp, attrp));
3249	case PSVC_LO_WARN_ATTR:
3250		*(int32_t *)attrp = ((ETempSensor_t *)objp)->lo_warn;
3251		return (status);
3252	case PSVC_LO_SHUT_ATTR:
3253		*(int32_t *)attrp = ((ETempSensor_t *)objp)->lo_shut;
3254		return (status);
3255	case PSVC_HI_WARN_ATTR:
3256		*(int32_t *)attrp = ((ETempSensor_t *)objp)->hi_warn;
3257		return (status);
3258	case PSVC_HI_SHUT_ATTR:
3259		*(int32_t *)attrp = ((ETempSensor_t *)objp)->hi_shut;
3260		return (status);
3261	case PSVC_OPTIMAL_TEMP_ATTR:
3262		*(int32_t *)attrp = ((ETempSensor_t *)objp)->opt_temp;
3263		return (status);
3264	case PSVC_HW_HI_SHUT_ATTR:
3265		*(int32_t *)attrp = ((ETempSensor_t *)objp)->hw_hi_shut;
3266		return (status);
3267	case PSVC_HW_LO_SHUT_ATTR:
3268		*(int32_t *)attrp = ((ETempSensor_t *)objp)->hw_lo_shut;
3269		return (status);
3270	}
3271
3272	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3273
3274	return (status);
3275}
3276
3277static int32_t
3278i_psvc_set_attr_0_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3279{
3280	int32_t status = PSVC_SUCCESS;
3281
3282	switch (attr_id) {
3283	case PSVC_LO_WARN_ATTR:
3284		((ETempSensor_t *)objp)->lo_warn = *(int32_t *)attrp;
3285		return (status);
3286	case PSVC_LO_SHUT_ATTR:
3287		((ETempSensor_t *)objp)->lo_shut = *(int32_t *)attrp;
3288		return (status);
3289	case PSVC_HI_WARN_ATTR:
3290		((ETempSensor_t *)objp)->hi_warn = *(int32_t *)attrp;
3291		return (status);
3292	case PSVC_HI_SHUT_ATTR:
3293		((ETempSensor_t *)objp)->hi_shut = *(int32_t *)attrp;
3294		return (status);
3295	case PSVC_OPTIMAL_TEMP_ATTR:
3296		((ETempSensor_t *)objp)->opt_temp = *(int32_t *)attrp;
3297		return (status);
3298	case PSVC_HW_HI_SHUT_ATTR:
3299		((ETempSensor_t *)objp)->hw_hi_shut = *(int32_t *)attrp;
3300		return (status);
3301	case PSVC_HW_LO_SHUT_ATTR:
3302		((ETempSensor_t *)objp)->hw_lo_shut = *(int32_t *)attrp;
3303		return (status);
3304	}
3305
3306	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3307
3308	return (status);
3309}
3310
3311static int32_t
3312i_psvc_get_attr_1_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3313{
3314	int32_t status = PSVC_SUCCESS;
3315
3316	switch (attr_id) {
3317	case PSVC_SENSOR_VALUE_ATTR:
3318		return (i_psvc_get_device_value_1_0(hdlp, objp, attrp));
3319	case PSVC_SETPOINT_ATTR:
3320		*(int16_t *)attrp = ((EFan_t *)objp)->setpoint;
3321		return (status);
3322	case PSVC_HYSTERESIS_ATTR:
3323		*(int16_t *)attrp = ((EFan_t *)objp)->hysteresis;
3324		return (status);
3325	case PSVC_LOOPGAIN_ATTR:
3326		*(int16_t *)attrp = ((EFan_t *)objp)->loopgain;
3327		return (status);
3328	case PSVC_LOOPBIAS_ATTR:
3329		*(int16_t *)attrp = ((EFan_t *)objp)->loopbias;
3330		return (status);
3331	case PSVC_TEMP_DIFFERENTIAL_ATTR:
3332		memcpy(attrp, ((EFan_t *)objp)->temp_differential,
3333			sizeof (((EFan_t *)objp)->temp_differential));
3334		return (status);
3335	case PSVC_TEMP_DIFFERENTIAL_INDEX_ATTR:
3336		*(int16_t *)attrp = ((EFan_t *)objp)->temp_differential_index;
3337		return (status);
3338	}
3339
3340	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3341
3342	return (status);
3343}
3344
3345static int32_t
3346i_psvc_set_attr_1_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3347{
3348	int32_t status = PSVC_SUCCESS;
3349
3350	switch (attr_id) {
3351	case PSVC_TEMP_DIFFERENTIAL_ATTR:
3352		memcpy(((EFan_t *)objp)->temp_differential, attrp,
3353			sizeof (((EFan_t *)objp)->temp_differential));
3354		return (status);
3355	case PSVC_TEMP_DIFFERENTIAL_INDEX_ATTR:
3356		((EFan_t *)objp)->temp_differential_index = *(int16_t *)attrp;
3357		return (status);
3358	case PSVC_SETPOINT_ATTR:
3359		((EFan_t *)objp)->setpoint = *(int16_t *)attrp;
3360		return (status);
3361	}
3362
3363	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3364
3365	return (PSVC_SUCCESS);
3366}
3367
3368static int32_t
3369i_psvc_get_attr_2_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3370{
3371	int32_t status = PSVC_SUCCESS;
3372
3373	switch (attr_id) {
3374	case PSVC_LED_STATE_ATTR:
3375	case PSVC_STATE_ATTR:
3376		return (i_psvc_get_device_state_2_0(hdlp, objp, attrp));
3377	case PSVC_LED_COLOR_ATTR:
3378		strcpy((char *)attrp, ((ELed_t *)objp)->color);
3379		return (status);
3380	case PSVC_LIT_COUNT_ATTR:
3381		*(int16_t *)attrp = ((ELed_t *)objp)->lit_count;
3382		return (status);
3383	}
3384
3385	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3386
3387	return (status);
3388}
3389
3390static int32_t
3391i_psvc_set_attr_2_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3392{
3393	int32_t status = PSVC_SUCCESS;
3394
3395	switch (attr_id) {
3396	case PSVC_LED_STATE_ATTR:
3397	case PSVC_STATE_ATTR:
3398		return (i_psvc_set_device_state_2_0(hdlp, objp, attrp));
3399	}
3400
3401	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3402
3403	return (status);
3404}
3405
3406static int32_t
3407i_psvc_get_attr_2_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3408{
3409	int32_t status = PSVC_SUCCESS;
3410
3411	switch (attr_id) {
3412	case PSVC_LED_STATE_ATTR:
3413	case PSVC_STATE_ATTR:
3414		return (i_psvc_get_device_state_2_1(hdlp, objp, attrp));
3415	case PSVC_LED_COLOR_ATTR:
3416		strcpy((char *)attrp, ((ELed_t *)objp)->color);
3417		return (status);
3418	case PSVC_LIT_COUNT_ATTR:
3419		*(int16_t *)attrp = ((ELed_t *)objp)->lit_count;
3420		return (status);
3421	}
3422
3423	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3424
3425	return (status);
3426}
3427
3428static int32_t
3429i_psvc_set_attr_2_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3430{
3431	int32_t status = PSVC_SUCCESS;
3432
3433	switch (attr_id) {
3434	case PSVC_LED_STATE_ATTR:
3435	case PSVC_STATE_ATTR:
3436		return (i_psvc_set_device_state_2_1(hdlp, objp, attrp));
3437	}
3438
3439	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3440
3441	return (status);
3442}
3443
3444static int32_t
3445i_psvc_get_attr_2_2(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3446{
3447	int32_t status = PSVC_SUCCESS;
3448
3449	switch (attr_id) {
3450	case PSVC_LED_STATE_ATTR:
3451	case PSVC_STATE_ATTR:
3452		return (i_psvc_get_device_state_2_0(hdlp, objp, attrp));
3453	case PSVC_LED_COLOR_ATTR:
3454		strcpy((char *)attrp, ((ELed_t *)objp)->color);
3455		return (status);
3456	case PSVC_LIT_COUNT_ATTR:
3457		*(int16_t *)attrp = ((ELed_t *)objp)->lit_count;
3458		return (status);
3459	case PSVC_LED_IS_LOCATOR_ATTR:
3460		strcpy((char *)attrp, ((ELed_t *)objp)->is_locator);
3461		return (status);
3462	case PSVC_LED_LOCATOR_NAME_ATTR:
3463		strcpy((char *)attrp, ((ELed_t *)objp)->locator_name);
3464		return (status);
3465	}
3466
3467	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3468
3469	return (status);
3470}
3471
3472static int32_t
3473i_psvc_get_attr_4_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3474{
3475	int32_t status = PSVC_SUCCESS;
3476
3477	switch (attr_id) {
3478	case PSVC_SENSOR_VALUE_ATTR:
3479		return (i_psvc_get_device_value_4_0(hdlp, objp, attrp));
3480	case PSVC_LO_WARN_ATTR:
3481		*(int32_t *)attrp = ((EDigiSensor_t *)objp)->lo_warn;
3482		return (status);
3483	case PSVC_LO_SHUT_ATTR:
3484		*(int32_t *)attrp = ((EDigiSensor_t *)objp)->lo_shut;
3485		return (status);
3486	case PSVC_HI_WARN_ATTR:
3487		*(int32_t *)attrp = ((EDigiSensor_t *)objp)->hi_warn;
3488		return (status);
3489	case PSVC_HI_SHUT_ATTR:
3490		*(int32_t *)attrp = ((EDigiSensor_t *)objp)->hi_shut;
3491		return (status);
3492	}
3493
3494	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3495
3496	return (PSVC_SUCCESS);
3497}
3498
3499static int32_t
3500i_psvc_get_attr_5_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3501{
3502	int32_t status = PSVC_SUCCESS;
3503
3504	if (attr_id == PSVC_CONTROL_VALUE_ATTR) {
3505		return (i_psvc_get_device_value_5_0(hdlp, objp, attrp));
3506	}
3507
3508	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3509
3510	return (status);
3511}
3512
3513static int32_t
3514i_psvc_set_attr_5_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3515{
3516	int32_t status = PSVC_SUCCESS;
3517
3518	if (attr_id == PSVC_CONTROL_VALUE_ATTR) {
3519		return (i_psvc_set_device_value_5_0(hdlp, objp, attrp));
3520	}
3521
3522	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3523
3524	return (status);
3525}
3526
3527static int32_t
3528i_psvc_get_attr_6_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3529{
3530	int32_t status = PSVC_SUCCESS;
3531
3532	switch (attr_id) {
3533	case PSVC_GPIO_VALUE_ATTR:
3534		return (i_psvc_get_device_value_6_0(hdlp, objp, attrp));
3535	case PSVC_GPIO_BITS:
3536		*(int32_t *)attrp = 1;
3537		return (status);
3538	}
3539
3540	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3541
3542	return (status);
3543}
3544
3545static int32_t
3546i_psvc_set_attr_6_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3547{
3548	int32_t status = PSVC_SUCCESS;
3549
3550	if (attr_id == PSVC_GPIO_VALUE_ATTR) {
3551		return (i_psvc_set_device_value_6_0(hdlp, objp, attrp));
3552	}
3553
3554	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3555
3556	return (status);
3557}
3558
3559static int32_t
3560i_psvc_get_attr_7_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3561{
3562	int32_t status = PSVC_SUCCESS;
3563
3564	switch (attr_id) {
3565	case PSVC_SENSOR_VALUE_ATTR:
3566		return (i_psvc_get_device_value_7_0(hdlp, objp, attrp));
3567	case PSVC_LO_WARN_ATTR:
3568		*(int32_t *)attrp = ((EFanTach_t *)objp)->lo_warn;
3569		return (status);
3570	case PSVC_LO_SHUT_ATTR:
3571		*(int32_t *)attrp = ((EFanTach_t *)objp)->lo_shut;
3572		return (status);
3573	case PSVC_HI_WARN_ATTR:
3574		*(int32_t *)attrp = ((EFanTach_t *)objp)->hi_warn;
3575		return (status);
3576	case PSVC_HI_SHUT_ATTR:
3577		*(int32_t *)attrp = ((EFanTach_t *)objp)->hi_shut;
3578		return (status);
3579	}
3580
3581	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3582
3583	return (PSVC_SUCCESS);
3584}
3585
3586static int32_t
3587i_psvc_get_attr_8_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3588{
3589	int32_t status = PSVC_SUCCESS;
3590
3591	switch (attr_id) {
3592	case PSVC_SWITCH_STATE_ATTR:
3593	case PSVC_STATE_ATTR:
3594		return (i_psvc_get_device_state_8_0(hdlp, objp, attrp));
3595	}
3596
3597	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3598
3599	return (status);
3600}
3601
3602static int32_t
3603i_psvc_set_attr_8_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3604{
3605	int32_t status = PSVC_SUCCESS;
3606
3607	switch (attr_id) {
3608	case PSVC_SWITCH_STATE_ATTR:
3609	case PSVC_STATE_ATTR:
3610		return (i_psvc_set_device_state_8_0(hdlp, objp, attrp));
3611	}
3612
3613	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3614
3615	return (status);
3616}
3617
3618static int32_t
3619i_psvc_get_attr_9_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3620{
3621	int32_t status = PSVC_SUCCESS;
3622
3623	switch (attr_id) {
3624	case PSVC_SWITCH_STATE_ATTR:
3625	case PSVC_STATE_ATTR:
3626		status = i_psvc_get_device_state_9_0(hdlp, objp, attrp);
3627		if ((status == PSVC_FAILURE) && (errno == EINVAL)) {
3628			strcpy((char *)attrp, PSVC_ERROR);
3629			return (PSVC_SUCCESS);
3630		} else {
3631			return (status);
3632		}
3633	}
3634
3635	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3636
3637	return (status);
3638}
3639
3640static int32_t
3641i_psvc_get_attr_10_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3642{
3643	int32_t status = PSVC_SUCCESS;
3644
3645	switch (attr_id) {
3646	case PSVC_GPIO_VALUE_ATTR:
3647		return (i_psvc_get_device_value_10_0(hdlp, objp, attrp));
3648	case PSVC_GPIO_BITS:
3649		*(int32_t *)attrp = 8;
3650		return (status);
3651	}
3652
3653	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3654
3655	return (status);
3656}
3657
3658static int32_t
3659i_psvc_set_attr_10_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3660{
3661	int32_t status = PSVC_SUCCESS;
3662
3663	if (attr_id == PSVC_GPIO_VALUE_ATTR) {
3664		return (i_psvc_set_device_value_10_0(hdlp, objp, attrp));
3665	}
3666
3667	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3668
3669	return (status);
3670}
3671
3672static int32_t
3673i_psvc_get_attr_10_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3674{
3675	int32_t status = PSVC_SUCCESS;
3676
3677	switch (attr_id) {
3678	case PSVC_GPIO_VALUE_ATTR:
3679		return (i_psvc_get_device_value_10_1(hdlp, objp, attrp));
3680	case PSVC_GPIO_BITS:
3681		*(int32_t *)attrp = 8;
3682		return (status);
3683	}
3684
3685	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3686
3687	return (status);
3688}
3689
3690static int32_t
3691i_psvc_set_attr_10_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3692{
3693	int32_t status = PSVC_SUCCESS;
3694
3695	if (attr_id == PSVC_GPIO_VALUE_ATTR) {
3696		return (i_psvc_set_device_value_10_1(hdlp, objp, attrp));
3697	}
3698
3699	status = i_psvc_set_attr_generic(hdlp, objp, attr_id, attrp);
3700
3701	return (status);
3702}
3703
3704/* AT24 */
3705static int32_t
3706i_psvc_get_attr_11_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3707{
3708	int32_t status = PSVC_SUCCESS;
3709	int32_t probe_status;
3710
3711	switch (attr_id) {
3712	case PSVC_PROBE_RESULT_ATTR:
3713		probe_status = i_psvc_probe_11_0(hdlp, objp);
3714		if (probe_status == PSVC_SUCCESS)
3715			strcpy((char *)attrp, PSVC_OK);
3716		else
3717			strcpy((char *)attrp, PSVC_ERROR);
3718		return (status);
3719	case PSVC_FRU_INFO_ATTR:
3720		status = i_psvc_get_reg_11_0(hdlp, objp, attr_id, attrp);
3721		return (status);
3722	}
3723
3724	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3725
3726	return (status);
3727}
3728
3729static int32_t
3730i_psvc_get_reg_11_0(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3731{
3732	int32_t status = PSVC_SUCCESS, ret;
3733	char path[1024], *data;
3734	int32_t fp, temp_errno;
3735	fru_info_t *fru_data;
3736
3737	fru_data = (fru_info_t *)attrp;
3738
3739	if (objp->present != PSVC_PRESENT) {
3740		errno = ENODEV;
3741		return (PSVC_FAILURE);
3742	}
3743
3744	status = i_psvc_get_devpath(hdlp, objp->addr_spec, path);
3745	if (status != PSVC_SUCCESS)
3746		return (status);
3747
3748	fp = open(path, O_RDWR);
3749	if (fp == -1) {
3750		return (PSVC_FAILURE);
3751	}
3752
3753	ret = lseek(fp, fru_data->buf_start, SEEK_SET);
3754	if (ret != fru_data->buf_start) {
3755		temp_errno = errno;
3756		close(fp);
3757		errno = temp_errno;
3758		return (PSVC_FAILURE);
3759	}
3760
3761	data = (char *)malloc(fru_data->read_size);
3762	ret = read(fp, data, fru_data->read_size);
3763	if (ret == -1) {
3764		free(data);
3765		close(fp);
3766		errno = EIO;
3767		return (-1);
3768	}
3769
3770	memcpy(fru_data->buf, data, fru_data->read_size);
3771	free(data);
3772	close(fp);
3773
3774	return (status);
3775}
3776
3777static int32_t
3778i_psvc_get_attr_11_1(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3779{
3780	int32_t status = PSVC_SUCCESS;
3781	int32_t probe_status;
3782
3783	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3784		probe_status = i_psvc_probe_11_1(hdlp, objp);
3785		if (probe_status == PSVC_SUCCESS)
3786			strcpy((char *)attrp, PSVC_OK);
3787		else
3788			strcpy((char *)attrp, PSVC_ERROR);
3789		return (status);
3790	}
3791
3792	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3793
3794	return (status);
3795}
3796
3797static int32_t
3798i_psvc_get_attr_11_2(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3799{
3800	int32_t status = PSVC_SUCCESS;
3801	int32_t probe_status;
3802
3803	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3804		probe_status = i_psvc_probe_11_2(hdlp, objp);
3805		if (probe_status == PSVC_SUCCESS)
3806			strcpy((char *)attrp, PSVC_OK);
3807		else
3808			strcpy((char *)attrp, PSVC_ERROR);
3809		return (status);
3810	}
3811
3812	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3813
3814	return (status);
3815}
3816
3817static int32_t
3818i_psvc_get_attr_11_3(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3819{
3820	int32_t status = PSVC_SUCCESS;
3821	int32_t probe_status;
3822
3823	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3824		probe_status = i_psvc_probe_11_3(hdlp, objp);
3825		if (probe_status == PSVC_SUCCESS)
3826			strcpy((char *)attrp, PSVC_OK);
3827		else
3828			strcpy((char *)attrp, PSVC_ERROR);
3829		return (status);
3830	}
3831
3832	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3833
3834	return (status);
3835}
3836
3837static int32_t
3838i_psvc_get_attr_11_4(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3839{
3840	int32_t status = PSVC_SUCCESS;
3841	int32_t probe_status;
3842
3843	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3844		probe_status = i_psvc_probe_11_4(hdlp, objp);
3845		if (probe_status == PSVC_SUCCESS)
3846			strcpy((char *)attrp, PSVC_OK);
3847		else
3848			strcpy((char *)attrp, PSVC_ERROR);
3849		return (status);
3850	}
3851
3852	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3853
3854	return (status);
3855}
3856
3857static int32_t
3858i_psvc_get_attr_11_5(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3859{
3860	int32_t status = PSVC_SUCCESS;
3861	int32_t probe_status;
3862
3863	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3864		probe_status = i_psvc_probe_11_5(hdlp, objp);
3865		if (probe_status == PSVC_SUCCESS)
3866			strcpy((char *)attrp, PSVC_OK);
3867		else
3868			strcpy((char *)attrp, PSVC_ERROR);
3869		return (status);
3870	}
3871
3872	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3873
3874	return (status);
3875}
3876
3877static int32_t
3878i_psvc_get_attr_11_6(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3879{
3880	int32_t status = PSVC_SUCCESS;
3881	int32_t probe_status;
3882
3883	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3884		probe_status = i_psvc_probe_11_6(hdlp, objp);
3885		if (probe_status == PSVC_SUCCESS)
3886			strcpy((char *)attrp, PSVC_OK);
3887		else
3888			strcpy((char *)attrp, PSVC_ERROR);
3889		return (status);
3890	}
3891
3892	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3893
3894	return (status);
3895}
3896
3897static int32_t
3898i_psvc_get_attr_11_7(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3899{
3900	int32_t status = PSVC_SUCCESS;
3901	int32_t probe_status;
3902
3903	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3904		probe_status = i_psvc_probe_11_7(hdlp, objp);
3905		if (probe_status == PSVC_SUCCESS)
3906			strcpy((char *)attrp, PSVC_OK);
3907		else
3908			strcpy((char *)attrp, PSVC_ERROR);
3909		return (status);
3910	}
3911
3912	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3913
3914	return (status);
3915}
3916
3917static int32_t
3918i_psvc_get_attr_11_8(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3919{
3920	int32_t status = PSVC_SUCCESS;
3921	int32_t probe_status;
3922
3923	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3924		probe_status = i_psvc_probe_11_8(hdlp, objp);
3925		if (probe_status == PSVC_SUCCESS)
3926			strcpy((char *)attrp, PSVC_OK);
3927		else
3928			strcpy((char *)attrp, PSVC_ERROR);
3929		return (status);
3930	}
3931
3932	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3933
3934	return (status);
3935}
3936
3937static int32_t
3938i_psvc_get_attr_11_9(EHdl_t *hdlp, EObj_t *objp, int32_t attr_id, void *attrp)
3939{
3940	int32_t status = PSVC_SUCCESS;
3941	int32_t probe_status;
3942
3943	if (attr_id == PSVC_PROBE_RESULT_ATTR) {
3944		probe_status = i_psvc_probe_11_9(hdlp, objp);
3945		if (probe_status == PSVC_SUCCESS)
3946			strcpy((char *)attrp, PSVC_OK);
3947		else
3948			strcpy((char *)attrp, PSVC_ERROR);
3949		return (status);
3950	}
3951
3952	status = i_psvc_get_attr_generic(hdlp, objp, attr_id, attrp);
3953
3954	return (status);
3955}
3956
3957static int32_t
3958i_psvc_load_generic(
3959	EHdl_t	*hdlp,
3960	char	*name,
3961	EObj_t    **objpp,
3962	char	  *buf,
3963	int32_t   obj_size)
3964{
3965	int32_t found, key, array;
3966	EObj_t *objp;
3967	char *start;
3968	char  cur_device[NAMELEN];
3969	int slot;
3970	ETable_Array *tbl_arr;
3971
3972	key = psvc_get_str_key(name);
3973	array = key % PSVC_MAX_TABLE_ARRAYS;
3974	tbl_arr = &(hdlp->tbl_arry[array]);
3975
3976	if (tbl_arr->nextid == hdlp->total_obj_count) {
3977		errno = EINVAL;
3978		return (PSVC_FAILURE);
3979	} else {
3980		slot = tbl_arr->nextid++;
3981		tbl_arr->obj_count++;
3982	}
3983
3984	if (i_psvc_find_file_section(hdlp->fp, "OBJECT_INFO") != PSVC_SUCCESS)
3985		return (PSVC_FAILURE);
3986
3987	fgets(buf, BUFSZ, hdlp->fp);
3988	while (strcmp(buf, "OBJECT_INFO_END")) {
3989		start = strrchr(buf, '/');
3990		if (start == NULL) {
3991			errno = EINVAL;
3992			return (PSVC_FAILURE);
3993		}
3994		found = sscanf(start + 1, "%s",  cur_device);
3995		if (found != 1) {
3996			errno = EINVAL;
3997			return (PSVC_FAILURE);
3998		}
3999		if (strcmp(name, cur_device) == 0)  /* found it */
4000			break;
4001		fgets(buf, BUFSZ, hdlp->fp);
4002	}
4003
4004	tbl_arr->obj_tbl[slot].objp = (EObj_t *)malloc(obj_size);
4005	if (tbl_arr->obj_tbl[slot].objp == 0)
4006		return (PSVC_FAILURE);
4007	objp = (EObj_t *)tbl_arr->obj_tbl[slot].objp;
4008	tbl_arr->obj_tbl[slot].type = PSVC_OBJ;
4009
4010	memset(objp, 0, obj_size);
4011	strcpy(objp->label, name);
4012	strcpy(tbl_arr->obj_tbl[slot].name, name);
4013
4014	tbl_arr->obj_tbl[slot].key = key;
4015
4016	if (i_psvc_value(buf, PSVC_CLASS_ATTR, &objp->class) != PSVC_SUCCESS) {
4017		i_psvc_destructor(hdlp, name, objp);
4018		return (PSVC_FAILURE);
4019	}
4020	if (i_psvc_value(buf, PSVC_SUBCLASS_ATTR, &objp->subclass) !=
4021		PSVC_SUCCESS) {
4022		i_psvc_destructor(hdlp, name, objp);
4023		return (PSVC_FAILURE);
4024	}
4025	if (i_psvc_value(buf, PSVC_INSTANCE_ATTR, &objp->instance) !=
4026		PSVC_SUCCESS) {
4027		i_psvc_destructor(hdlp, name, objp);
4028		return (PSVC_FAILURE);
4029	}
4030	if (i_psvc_value(buf, PSVC_FEATURES_ATTR, &objp->features) !=
4031		PSVC_SUCCESS) {
4032		i_psvc_destructor(hdlp, name, objp);
4033		return (PSVC_FAILURE);
4034	}
4035	if (i_psvc_value(buf, PSVC_ADDR_SPEC_ATTR, &objp->addr_spec) !=
4036		PSVC_SUCCESS) {
4037		i_psvc_destructor(hdlp, name, objp);
4038		return (PSVC_FAILURE);
4039	}
4040
4041	if (objp->features & PSVC_DEV_SECONDARY)
4042		objp->enabled = PSVC_DISABLED;
4043	else
4044		objp->enabled = PSVC_ENABLED;
4045
4046	if (PSVC_GET_VERSION(objp->addr_spec) > PSVC_VERSION) {
4047		errno = EINVAL;
4048		i_psvc_destructor(hdlp, name, objp);
4049		return (PSVC_FAILURE);
4050	}
4051
4052	*objpp = objp;
4053	return (PSVC_SUCCESS);
4054
4055}
4056
4057
4058static int32_t
4059i_psvc_not_supported()
4060{
4061	errno = ENOTSUP;
4062	return (PSVC_FAILURE);
4063}
4064
4065/* Temperature sensor */
4066/* Class 0 Subclass 0 are temperature sensors that cannot be updated */
4067static int32_t
4068i_psvc_constructor_0_0(
4069	EHdl_t	*hdlp,
4070	char	*id,
4071	EObj_t    **objpp)
4072{
4073	int32_t status;
4074	char buf[BUFSZ];
4075	ETempSensor_t *dp;
4076
4077	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4078		sizeof (ETempSensor_t));
4079	if (status != PSVC_SUCCESS)
4080		return (status);
4081
4082	/* Load class specific info */
4083	dp = (ETempSensor_t *)*objpp;
4084	if (i_psvc_value(buf, PSVC_LO_WARN_ATTR, &dp->lo_warn)
4085	    != PSVC_SUCCESS) {
4086		i_psvc_destructor(hdlp, id, dp);
4087		return (PSVC_FAILURE);
4088	}
4089	if (i_psvc_value(buf, PSVC_LO_SHUT_ATTR, &dp->lo_shut)
4090	    != PSVC_SUCCESS) {
4091		i_psvc_destructor(hdlp, id, dp);
4092		return (PSVC_FAILURE);
4093	}
4094	if (i_psvc_value(buf, PSVC_HI_WARN_ATTR, &dp->hi_warn)
4095	    != PSVC_SUCCESS) {
4096		i_psvc_destructor(hdlp, id, dp);
4097		return (PSVC_FAILURE);
4098	}
4099	if (i_psvc_value(buf, PSVC_HI_SHUT_ATTR, &dp->hi_shut)
4100	    != PSVC_SUCCESS) {
4101		i_psvc_destructor(hdlp, id, dp);
4102		return (PSVC_FAILURE);
4103	}
4104
4105	dp->ld.constructor = i_psvc_constructor_0_0;
4106	dp->ld.destructor = i_psvc_destructor;
4107	dp->ld.get_attr = i_psvc_get_attr_0_0;
4108	dp->ld.set_attr = i_psvc_set_attr_generic;
4109
4110	return (0);
4111}
4112
4113/* Class 0 Subclass 1 are temperature sensors that can be updated */
4114static int32_t
4115i_psvc_constructor_0_1(
4116	EHdl_t	*hdlp,
4117	char	*id,
4118	EObj_t    **objpp)
4119{
4120	int32_t status;
4121	char buf[BUFSZ];
4122	ETempSensor_t *dp;
4123
4124	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4125		sizeof (ETempSensor_t));
4126	if (status != PSVC_SUCCESS)
4127		return (status);
4128
4129	/* Load class specific info */
4130	dp = (ETempSensor_t *)*objpp;
4131	if (i_psvc_value(buf, PSVC_LO_WARN_ATTR, &dp->lo_warn)
4132	    != PSVC_SUCCESS) {
4133		i_psvc_destructor(hdlp, id, dp);
4134		return (PSVC_FAILURE);
4135	}
4136	if (i_psvc_value(buf, PSVC_LO_SHUT_ATTR, &dp->lo_shut)
4137	    != PSVC_SUCCESS) {
4138		i_psvc_destructor(hdlp, id, dp);
4139		return (PSVC_FAILURE);
4140	}
4141	if (i_psvc_value(buf, PSVC_HI_WARN_ATTR, &dp->hi_warn)
4142	    != PSVC_SUCCESS) {
4143		i_psvc_destructor(hdlp, id, dp);
4144		return (PSVC_FAILURE);
4145	}
4146	if (i_psvc_value(buf, PSVC_HI_SHUT_ATTR, &dp->hi_shut)
4147	    != PSVC_SUCCESS) {
4148		i_psvc_destructor(hdlp, id, dp);
4149		return (PSVC_FAILURE);
4150	}
4151
4152	if ((*objpp)->features & PSVC_OPT_TEMP) {
4153		if (i_psvc_value(buf, PSVC_OPTIMAL_TEMP_ATTR, &dp->opt_temp)
4154		    != PSVC_SUCCESS) {
4155			i_psvc_destructor(hdlp, id, dp);
4156			return (PSVC_FAILURE);
4157		}
4158	}
4159	if ((*objpp)->features & PSVC_HW_LOW_SHUT) {
4160		if (i_psvc_value(buf, PSVC_HW_LO_SHUT_ATTR, &dp->hw_lo_shut)
4161		    != PSVC_SUCCESS) {
4162			i_psvc_destructor(hdlp, id, dp);
4163			return (PSVC_FAILURE);
4164		}
4165	}
4166	if ((*objpp)->features & PSVC_HW_HIGH_SHUT) {
4167		if (i_psvc_value(buf, PSVC_HW_HI_SHUT_ATTR, &dp->hw_hi_shut)
4168		    != PSVC_SUCCESS) {
4169			i_psvc_destructor(hdlp, id, dp);
4170			return (PSVC_FAILURE);
4171		}
4172	}
4173
4174	dp->ld.constructor = i_psvc_constructor_0_1;
4175	dp->ld.destructor = i_psvc_destructor;
4176	dp->ld.get_attr = i_psvc_get_attr_0_1;
4177	dp->ld.set_attr = i_psvc_set_attr_0_1;
4178
4179	return (0);
4180}
4181
4182/* Fan */
4183static int32_t
4184i_psvc_constructor_1_0(
4185	EHdl_t	*hdlp,
4186	char	*id,
4187	EObj_t  **objpp)
4188{
4189	int32_t status;
4190	char buf[BUFSZ];
4191	EFan_t *dp;
4192
4193	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4194		sizeof (EFan_t));
4195	if (status != PSVC_SUCCESS)
4196		return (status);
4197
4198	/* Load class specific info */
4199	dp = (EFan_t *)*objpp;
4200	if (i_psvc_value(buf, PSVC_SETPOINT_ATTR, &dp->setpoint)
4201	    != PSVC_SUCCESS) {
4202		i_psvc_destructor(hdlp, id, dp);
4203		return (PSVC_FAILURE);
4204	}
4205	if (i_psvc_value(buf, PSVC_HYSTERESIS_ATTR, &dp->hysteresis)
4206	    != PSVC_SUCCESS) {
4207		i_psvc_destructor(hdlp, id, dp);
4208		return (PSVC_FAILURE);
4209	}
4210	if (i_psvc_value(buf, PSVC_LOOPGAIN_ATTR, &dp->loopgain)
4211	    != PSVC_SUCCESS) {
4212		i_psvc_destructor(hdlp, id, dp);
4213		return (PSVC_FAILURE);
4214	}
4215	if (i_psvc_value(buf, PSVC_LOOPBIAS_ATTR, &dp->loopbias)
4216	    != PSVC_SUCCESS) {
4217		i_psvc_destructor(hdlp, id, dp);
4218		return (PSVC_FAILURE);
4219	}
4220
4221	dp->ld.constructor = i_psvc_constructor_1_0;
4222	dp->ld.destructor = i_psvc_destructor;
4223	dp->ld.get_attr = i_psvc_get_attr_1_0;
4224	dp->ld.set_attr = i_psvc_set_attr_1_0;
4225
4226	return (PSVC_SUCCESS);
4227}
4228
4229
4230/* LED */
4231static int32_t
4232i_psvc_constructor_2_0(
4233	EHdl_t	*hdlp,
4234	char	*id,
4235	EObj_t  **objpp)
4236{
4237	int32_t status;
4238	char buf[BUFSZ];
4239	ELed_t *dp;
4240
4241	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4242		sizeof (ELed_t));
4243	if (status != PSVC_SUCCESS)
4244		return (status);
4245
4246	/* Load class specific info */
4247	dp = (ELed_t *)*objpp;
4248
4249	if (i_psvc_value(buf, PSVC_LED_COLOR_ATTR, dp->color)
4250	    != PSVC_SUCCESS) {
4251		i_psvc_destructor(hdlp, id, dp);
4252		return (PSVC_FAILURE);
4253	}
4254
4255	dp->ld.constructor = i_psvc_constructor_2_0;
4256	dp->ld.destructor = i_psvc_destructor;
4257	dp->ld.get_attr = i_psvc_get_attr_2_0;
4258	dp->ld.set_attr = i_psvc_set_attr_2_0;
4259
4260	return (PSVC_SUCCESS);
4261}
4262
4263static int32_t
4264i_psvc_constructor_2_1(
4265	EHdl_t	*hdlp,
4266	char	*id,
4267	EObj_t  **objpp)
4268{
4269	int32_t status;
4270	char buf[BUFSZ];
4271	ELed_t *dp;
4272
4273	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4274		sizeof (ELed_t));
4275	if (status != PSVC_SUCCESS)
4276		return (status);
4277
4278	/* Load class specific info */
4279	dp = (ELed_t *)*objpp;
4280
4281	if (i_psvc_value(buf, PSVC_LED_COLOR_ATTR, dp->color)
4282	    != PSVC_SUCCESS) {
4283		i_psvc_destructor(hdlp, id, dp);
4284		return (PSVC_FAILURE);
4285	}
4286
4287	dp->ld.constructor = i_psvc_constructor_2_1;
4288	dp->ld.destructor = i_psvc_destructor;
4289	dp->ld.get_attr = i_psvc_get_attr_2_1;
4290	dp->ld.set_attr = i_psvc_set_attr_2_1;
4291
4292	return (PSVC_SUCCESS);
4293}
4294
4295static int32_t
4296i_psvc_constructor_2_2(
4297	EHdl_t	*hdlp,
4298	char	*id,
4299	EObj_t  **objpp)
4300{
4301	int32_t status;
4302	char buf[BUFSZ];
4303	ELed_t *dp;
4304
4305	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4306		sizeof (ELed_t));
4307	if (status != PSVC_SUCCESS)
4308		return (status);
4309
4310	/* Load class specific info */
4311	dp = (ELed_t *)*objpp;
4312
4313	if (i_psvc_value(buf, PSVC_LED_COLOR_ATTR, dp->color)
4314	    != PSVC_SUCCESS) {
4315		i_psvc_destructor(hdlp, id, dp);
4316		return (PSVC_FAILURE);
4317	}
4318	if (i_psvc_value(buf, PSVC_LED_IS_LOCATOR_ATTR, dp->is_locator)
4319	    != PSVC_SUCCESS) {
4320		i_psvc_destructor(hdlp, id, dp);
4321		return (PSVC_FAILURE);
4322	}
4323	if (strcmp(dp->is_locator, PSVC_LOCATOR_TRUE) == 0) {
4324		if (i_psvc_value(buf, PSVC_LED_LOCATOR_NAME_ATTR,
4325		    dp->locator_name) != PSVC_SUCCESS) {
4326			i_psvc_destructor(hdlp, id, dp);
4327			return (PSVC_FAILURE);
4328		}
4329	} else {
4330		strcpy(dp->locator_name, "N/A");
4331	}
4332
4333	dp->ld.constructor = i_psvc_constructor_2_2;
4334	dp->ld.destructor = i_psvc_destructor;
4335	dp->ld.get_attr = i_psvc_get_attr_2_2;
4336	dp->ld.set_attr = i_psvc_set_attr_2_0;
4337
4338	return (PSVC_SUCCESS);
4339}
4340
4341/* System Device */
4342static int32_t
4343i_psvc_constructor_3_0(
4344	EHdl_t	*hdlp,
4345	char	*id,
4346	EObj_t  **objpp)
4347{
4348	int32_t status;
4349	char buf[BUFSZ];
4350	ESystem_t *dp;
4351
4352	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (ESystem_t));
4353	if (status != PSVC_SUCCESS)
4354		return (status);
4355
4356	/* Load class specific info */
4357	dp = (ESystem_t *)*objpp;
4358
4359	dp->ld.constructor = i_psvc_constructor_3_0;
4360	dp->ld.destructor = i_psvc_destructor;
4361	dp->ld.get_attr = i_psvc_get_attr_generic;
4362	dp->ld.set_attr = i_psvc_set_attr_generic;
4363
4364	return (PSVC_SUCCESS);
4365}
4366
4367/* Digital Sensor */
4368static int32_t
4369i_psvc_constructor_4_0(
4370	EHdl_t	*hdlp,
4371	char	*id,
4372	EObj_t  **objpp)
4373{
4374	int32_t status;
4375	char buf[BUFSZ];
4376	EDigiSensor_t *dp;
4377
4378	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4379		sizeof (EDigiSensor_t));
4380	if (status != PSVC_SUCCESS) {
4381		return (status);
4382	}
4383
4384	/* Load class specific info */
4385	dp = (EDigiSensor_t *)*objpp;
4386	if (i_psvc_value(buf, PSVC_LO_WARN_ATTR, &dp->lo_warn)
4387	    != PSVC_SUCCESS) {
4388		i_psvc_destructor(hdlp, id, dp);
4389		return (PSVC_FAILURE);
4390	}
4391	if (i_psvc_value(buf, PSVC_LO_SHUT_ATTR, &dp->lo_shut)
4392	    != PSVC_SUCCESS) {
4393		i_psvc_destructor(hdlp, id, dp);
4394		return (PSVC_FAILURE);
4395	}
4396	if (i_psvc_value(buf, PSVC_HI_WARN_ATTR, &dp->hi_warn)
4397	    != PSVC_SUCCESS) {
4398		i_psvc_destructor(hdlp, id, dp);
4399		return (PSVC_FAILURE);
4400	}
4401	if (i_psvc_value(buf, PSVC_HI_SHUT_ATTR, &dp->hi_shut)
4402	    != PSVC_SUCCESS) {
4403		i_psvc_destructor(hdlp, id, dp);
4404		return (PSVC_FAILURE);
4405	}
4406
4407	dp->ld.constructor = i_psvc_constructor_4_0;
4408	dp->ld.destructor = i_psvc_destructor;
4409	dp->ld.get_attr = i_psvc_get_attr_4_0;
4410	dp->ld.set_attr = i_psvc_set_attr_generic;
4411
4412	return (PSVC_SUCCESS);
4413}
4414
4415/* Digital Control */
4416static int32_t
4417i_psvc_constructor_5_0(
4418	EHdl_t	*hdlp,
4419	char	*id,
4420	EObj_t  **objpp)
4421{
4422	int32_t status;
4423	char buf[BUFSZ];
4424	EDigiControl_t *dp;
4425
4426	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4427		sizeof (EDigiControl_t));
4428	if (status != PSVC_SUCCESS)
4429		return (status);
4430
4431	/* Load class specific info */
4432	dp = (EDigiControl_t *)*objpp;
4433
4434	dp->ld.constructor = i_psvc_constructor_5_0;
4435	dp->ld.destructor = i_psvc_destructor;
4436	dp->ld.get_attr = i_psvc_get_attr_5_0;
4437	dp->ld.set_attr = i_psvc_set_attr_5_0;
4438	return (PSVC_SUCCESS);
4439}
4440
4441/* Boolean GPIO */
4442static int32_t
4443i_psvc_constructor_6_0(
4444	EHdl_t	*hdlp,
4445	char	*id,
4446	EObj_t  **objpp)
4447{
4448	int32_t status;
4449	char buf[BUFSZ];
4450	EBoolSensor_t *dp;
4451
4452	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4453		sizeof (EBoolSensor_t));
4454	if (status != PSVC_SUCCESS)
4455		return (status);
4456
4457	/* Load class specific info */
4458	dp = (EBoolSensor_t *)*objpp;
4459
4460	dp->ld.constructor = i_psvc_constructor_6_0;
4461	dp->ld.destructor = i_psvc_destructor;
4462	dp->ld.get_attr = i_psvc_get_attr_6_0;
4463	dp->ld.set_attr = i_psvc_set_attr_6_0;
4464
4465	return (PSVC_SUCCESS);
4466}
4467
4468/* Fan Tachometer */
4469static int32_t
4470i_psvc_constructor_7_0(
4471	EHdl_t	*hdlp,
4472	char	*id,
4473	EObj_t  **objpp)
4474{
4475	int32_t status;
4476	char buf[BUFSZ];
4477	EFanTach_t *dp;
4478
4479	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4480		sizeof (EFanTach_t));
4481	if (status != PSVC_SUCCESS)
4482		return (status);
4483
4484	/* Load class specific info */
4485	dp = (EFanTach_t *)*objpp;
4486	if (i_psvc_value(buf, PSVC_LO_WARN_ATTR, &dp->lo_warn)
4487	    != PSVC_SUCCESS) {
4488		i_psvc_destructor(hdlp, id, dp);
4489		return (PSVC_FAILURE);
4490	}
4491	if (i_psvc_value(buf, PSVC_LO_SHUT_ATTR, &dp->lo_shut)
4492	    != PSVC_SUCCESS) {
4493		i_psvc_destructor(hdlp, id, dp);
4494		return (PSVC_FAILURE);
4495	}
4496	if (i_psvc_value(buf, PSVC_HI_WARN_ATTR, &dp->hi_warn)
4497	    != PSVC_SUCCESS) {
4498		i_psvc_destructor(hdlp, id, dp);
4499		return (PSVC_FAILURE);
4500	}
4501	if (i_psvc_value(buf, PSVC_HI_SHUT_ATTR, &dp->hi_shut)
4502	    != PSVC_SUCCESS) {
4503		i_psvc_destructor(hdlp, id, dp);
4504		return (PSVC_FAILURE);
4505	}
4506
4507	dp->ld.constructor = i_psvc_constructor_7_0;
4508	dp->ld.destructor = i_psvc_destructor;
4509	dp->ld.get_attr = i_psvc_get_attr_7_0;
4510	dp->ld.set_attr = i_psvc_set_attr_generic;
4511
4512	return (PSVC_SUCCESS);
4513}
4514
4515/* On Off Switch */
4516static int32_t
4517i_psvc_constructor_8_0(
4518	EHdl_t	*hdlp,
4519	char	*id,
4520	EObj_t  **objpp)
4521{
4522	int32_t status;
4523	char buf[BUFSZ];
4524	ESwitch_t *dp;
4525
4526	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4527		sizeof (ESwitch_t));
4528	if (status != PSVC_SUCCESS)
4529		return (status);
4530
4531	/* Load class specific info */
4532	dp = (ESwitch_t *)*objpp;
4533
4534	dp->ld.constructor = i_psvc_constructor_8_0;
4535	dp->ld.destructor = i_psvc_destructor;
4536	dp->ld.get_attr = i_psvc_get_attr_8_0;
4537	dp->ld.set_attr = i_psvc_set_attr_8_0;
4538
4539	return (PSVC_SUCCESS);
4540}
4541
4542/* Key Switch */
4543static int32_t
4544i_psvc_constructor_9_0(
4545	EHdl_t	*hdlp,
4546	char	*id,
4547	EObj_t  **objpp)
4548{
4549	int32_t status;
4550	char buf[BUFSZ];
4551	EKeySwitch_t *dp;
4552
4553	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4554		sizeof (EKeySwitch_t));
4555	if (status != PSVC_SUCCESS)
4556		return (status);
4557
4558	/* Load class specific info */
4559	dp = (EKeySwitch_t *)*objpp;
4560
4561	dp->ld.constructor = i_psvc_constructor_9_0;
4562	dp->ld.destructor = i_psvc_destructor;
4563	dp->ld.get_attr = i_psvc_get_attr_9_0;
4564	dp->ld.set_attr = i_psvc_set_attr_generic;
4565
4566	return (PSVC_SUCCESS);
4567}
4568
4569/* 8 Bit GPIO , devices with registers, calls get_reg()/set_reg() */
4570static int32_t
4571i_psvc_constructor_10_0(
4572	EHdl_t	*hdlp,
4573	char	*id,
4574	EObj_t  **objpp)
4575{
4576	int32_t status;
4577	char buf[BUFSZ];
4578	EGPIO8_t *dp;
4579
4580	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EGPIO8_t));
4581	if (status != PSVC_SUCCESS)
4582		return (status);
4583
4584	/* Load class specific info */
4585	dp = (EGPIO8_t *)*objpp;
4586
4587	dp->ld.constructor = i_psvc_constructor_10_0;
4588	dp->ld.destructor = i_psvc_destructor;
4589	dp->ld.get_attr = i_psvc_get_attr_10_0;
4590	dp->ld.set_attr = i_psvc_set_attr_10_0;
4591
4592	return (PSVC_SUCCESS);
4593}
4594
4595/* 8 Bit GPIO , devices with ports, calls get_port()/set_port() */
4596static int32_t
4597i_psvc_constructor_10_1(
4598	EHdl_t	*hdlp,
4599	char	*id,
4600	EObj_t  **objpp)
4601{
4602	int32_t status;
4603	char buf[BUFSZ];
4604	EGPIO8_t *dp;
4605
4606	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EGPIO8_t));
4607	if (status != PSVC_SUCCESS)
4608		return (status);
4609
4610	/* Load class specific info */
4611	dp = (EGPIO8_t *)*objpp;
4612
4613	dp->ld.constructor = i_psvc_constructor_10_1;
4614	dp->ld.destructor = i_psvc_destructor;
4615	dp->ld.get_attr = i_psvc_get_attr_10_1;
4616	dp->ld.set_attr = i_psvc_set_attr_10_1;
4617
4618	return (PSVC_SUCCESS);
4619}
4620
4621/* AT24 */
4622static int32_t
4623i_psvc_constructor_11_0(
4624	EHdl_t	*hdlp,
4625	char	*id,
4626	EObj_t  **objpp)
4627{
4628	int32_t status;
4629	char buf[BUFSZ];
4630	EPhysDev_t *dp;
4631
4632	status = i_psvc_load_generic(hdlp, id, objpp, buf,
4633		sizeof (EPhysDev_t));
4634	if (status != PSVC_SUCCESS)
4635		return (status);
4636
4637	/* Load class specific info */
4638	dp = (EPhysDev_t *)*objpp;
4639
4640	dp->ld.constructor = i_psvc_constructor_11_0;
4641	dp->ld.destructor = i_psvc_destructor;
4642	dp->ld.get_attr = i_psvc_get_attr_11_0;
4643	dp->ld.set_attr = i_psvc_set_attr_generic;
4644	dp->get_temperature = i_psvc_not_supported;
4645	dp->get_fanspeed = i_psvc_not_supported;
4646	dp->get_input = i_psvc_not_supported;
4647	dp->get_bit = i_psvc_not_supported;
4648	dp->set_bit = i_psvc_not_supported;
4649	dp->get_port = i_psvc_not_supported;
4650	dp->set_port = i_psvc_not_supported;
4651	dp->get_output = i_psvc_not_supported;
4652	dp->set_output = i_psvc_not_supported;
4653	dp->get_reg = i_psvc_get_reg_11_0;
4654	dp->set_reg = i_psvc_not_supported;
4655
4656	return (PSVC_SUCCESS);
4657}
4658
4659/* HPC3130 */
4660static int32_t
4661i_psvc_constructor_11_1(
4662	EHdl_t	*hdlp,
4663	char	*id,
4664	EObj_t  **objpp)
4665{
4666	int32_t status;
4667	char buf[BUFSZ];
4668	EPhysDev_t *dp;
4669
4670	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4671	if (status != PSVC_SUCCESS)
4672		return (status);
4673
4674	/* Load class specific info */
4675	dp = (EPhysDev_t *)*objpp;
4676
4677	dp->ld.constructor = i_psvc_constructor_11_1;
4678	dp->ld.destructor = i_psvc_destructor;
4679	dp->ld.get_attr = i_psvc_get_attr_11_1;
4680	dp->ld.set_attr = i_psvc_set_attr_generic;
4681	dp->get_temperature = i_psvc_not_supported;
4682	dp->get_fanspeed = i_psvc_not_supported;
4683	dp->get_input = i_psvc_not_supported;
4684	dp->get_bit = i_psvc_not_supported;
4685	dp->set_bit = i_psvc_not_supported;
4686	dp->get_port = i_psvc_not_supported;
4687	dp->set_port = i_psvc_not_supported;
4688	dp->get_output = i_psvc_not_supported;
4689	dp->set_output = i_psvc_not_supported;
4690	dp->get_reg = i_psvc_get_reg_11_1;
4691	dp->set_reg = i_psvc_set_reg_11_1;
4692
4693	return (PSVC_SUCCESS);
4694}
4695
4696/* LM75 */
4697static int32_t
4698i_psvc_constructor_11_2(
4699	EHdl_t	*hdlp,
4700	char	*id,
4701	EObj_t  **objpp)
4702{
4703	int32_t status;
4704	char buf[BUFSZ];
4705	EPhysDev_t *dp;
4706
4707	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4708	if (status != PSVC_SUCCESS)
4709		return (status);
4710
4711	/* Load class specific info */
4712	dp = (EPhysDev_t *)*objpp;
4713
4714	dp->ld.constructor = i_psvc_constructor_11_2;
4715	dp->ld.destructor = i_psvc_destructor;
4716	dp->ld.get_attr = i_psvc_get_attr_11_2;
4717	dp->ld.set_attr = i_psvc_set_attr_generic;
4718	dp->get_temperature = i_psvc_get_temperature_11_2;
4719	dp->get_fanspeed = i_psvc_not_supported;
4720	dp->get_input = i_psvc_not_supported;
4721	dp->get_bit = i_psvc_not_supported;
4722	dp->set_bit = i_psvc_not_supported;
4723	dp->get_port = i_psvc_not_supported;
4724	dp->set_port = i_psvc_not_supported;
4725	dp->get_output = i_psvc_not_supported;
4726	dp->set_output = i_psvc_not_supported;
4727	dp->get_reg = i_psvc_not_supported;
4728	dp->set_reg = i_psvc_not_supported;
4729
4730	return (PSVC_SUCCESS);
4731}
4732
4733/* LTC1427 */
4734static int32_t
4735i_psvc_constructor_11_3(
4736	EHdl_t	*hdlp,
4737	char	*id,
4738	EObj_t  **objpp)
4739{
4740	int32_t status;
4741	char buf[BUFSZ];
4742	EPhysDev_t *dp;
4743	char path[1024];
4744
4745	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4746	if (status != PSVC_SUCCESS)
4747		return (status);
4748
4749	/*
4750	 * The following code upto and including the open() call is so the
4751	 * device driver for the ltc1427 does not get unloaded by the OS at
4752	 * any time. This is important as the device driver is a write only
4753	 * physical device but DOES keep readable states in the device unitp
4754	 * structure (I2C_GET_OUTPUT) as a result this device should not
4755	 * be unload while PSVC is up and running
4756	 */
4757	status = i_psvc_get_devpath(hdlp, (*objpp)->addr_spec, path);
4758	if (status != PSVC_SUCCESS) {
4759		return (status);
4760	}
4761
4762	/*
4763	 * We deliberately do not close our file handle, to prevent
4764	 * any device instances from being detached.  If an instance
4765	 * is detached, the "readable states in the device unitp"
4766	 * will be unloaded, causing loss of control of the device
4767	 * and incorrect error(s) to be displayed.
4768	 */
4769	if (open(path, O_RDWR) == -1) {
4770		return (PSVC_FAILURE);
4771	}
4772	/* Load class specific info */
4773	dp = (EPhysDev_t *)*objpp;
4774
4775	dp->ld.constructor = i_psvc_constructor_11_3;
4776	dp->ld.destructor = i_psvc_destructor;
4777	dp->ld.get_attr = i_psvc_get_attr_11_3;
4778	dp->ld.set_attr = i_psvc_set_attr_generic;
4779	dp->get_temperature = i_psvc_not_supported;
4780	dp->get_fanspeed = i_psvc_not_supported;
4781	dp->get_input = i_psvc_not_supported;
4782	dp->get_bit = i_psvc_not_supported;
4783	dp->set_bit = i_psvc_not_supported;
4784	dp->get_port = i_psvc_not_supported;
4785	dp->set_port = i_psvc_not_supported;
4786	dp->get_output = i_psvc_get_output_11_3;
4787	dp->set_output = i_psvc_set_output_11_3;
4788	dp->get_reg = i_psvc_not_supported;
4789	dp->set_reg = i_psvc_not_supported;
4790
4791	return (PSVC_SUCCESS);
4792}
4793
4794/* MAX1617 */
4795static int32_t
4796i_psvc_constructor_11_4(
4797	EHdl_t	*hdlp,
4798	char	*id,
4799	EObj_t  **objpp)
4800{
4801	int32_t status;
4802	char buf[BUFSZ];
4803	EPhysDev_t *dp;
4804
4805	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4806	if (status != PSVC_SUCCESS)
4807		return (status);
4808
4809	/* Load class specific info */
4810	dp = (EPhysDev_t *)*objpp;
4811
4812	dp->ld.constructor = i_psvc_constructor_11_4;
4813	dp->ld.destructor = i_psvc_destructor;
4814	dp->ld.get_attr = i_psvc_get_attr_11_4;
4815	dp->ld.set_attr = i_psvc_set_attr_generic;
4816	dp->get_temperature = i_psvc_get_temperature_11_4;
4817	dp->get_fanspeed = i_psvc_not_supported;
4818	dp->get_input = i_psvc_not_supported;
4819	dp->get_bit = i_psvc_not_supported;
4820	dp->set_bit = i_psvc_not_supported;
4821	dp->get_port = i_psvc_not_supported;
4822	dp->set_port = i_psvc_not_supported;
4823	dp->get_output = i_psvc_not_supported;
4824	dp->set_output = i_psvc_not_supported;
4825	dp->get_reg = i_psvc_not_supported;
4826	dp->set_reg = i_psvc_not_supported;
4827
4828	return (PSVC_SUCCESS);
4829}
4830
4831/* PCF8574 */
4832static int32_t
4833i_psvc_constructor_11_5(
4834	EHdl_t	*hdlp,
4835	char	*id,
4836	EObj_t  **objpp)
4837{
4838	int32_t status;
4839	char buf[BUFSZ];
4840	EPhysDev_t *dp;
4841
4842	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4843	if (status != PSVC_SUCCESS)
4844		return (status);
4845
4846	/* Load class specific info */
4847	dp = (EPhysDev_t *)*objpp;
4848
4849	dp->ld.constructor = i_psvc_constructor_11_5;
4850	dp->ld.destructor = i_psvc_destructor;
4851	dp->ld.get_attr = i_psvc_get_attr_11_5;
4852	dp->ld.set_attr = i_psvc_set_attr_generic;
4853	dp->get_temperature = i_psvc_not_supported;
4854	dp->get_fanspeed = i_psvc_not_supported;
4855	dp->get_input = i_psvc_not_supported;
4856	dp->get_bit = i_psvc_get_bit_11_5;
4857	dp->set_bit = i_psvc_set_bit_11_5;
4858	dp->get_port = i_psvc_get_port_11_5;
4859	dp->set_port = i_psvc_set_port_11_5;
4860	dp->get_output = i_psvc_not_supported;
4861	dp->set_output = i_psvc_not_supported;
4862	dp->get_reg = i_psvc_not_supported;
4863	dp->set_reg = i_psvc_not_supported;
4864
4865	return (PSVC_SUCCESS);
4866}
4867
4868/* PCF8591 */
4869static int32_t
4870i_psvc_constructor_11_6(
4871	EHdl_t	*hdlp,
4872	char	*id,
4873	EObj_t  **objpp)
4874{
4875	int32_t status;
4876	char buf[BUFSZ];
4877	EPhysDev_t *dp;
4878
4879	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4880	if (status != PSVC_SUCCESS)
4881		return (status);
4882
4883	/* Load class specific info */
4884	dp = (EPhysDev_t *)*objpp;
4885
4886	dp->ld.constructor = i_psvc_constructor_11_6;
4887	dp->ld.destructor = i_psvc_destructor;
4888	dp->ld.get_attr = i_psvc_get_attr_11_6;
4889	dp->ld.set_attr = i_psvc_set_attr_generic;
4890	dp->get_temperature = i_psvc_get_temperature_11_6;
4891	dp->get_fanspeed = i_psvc_not_supported;
4892	dp->get_input = i_psvc_get_input_11_6;
4893	dp->get_bit = i_psvc_not_supported;
4894	dp->set_bit = i_psvc_not_supported;
4895	dp->get_port = i_psvc_not_supported;
4896	dp->set_port = i_psvc_not_supported;
4897	dp->get_output = i_psvc_get_output_11_6;
4898	dp->set_output = i_psvc_set_output_11_6;
4899	dp->get_reg = i_psvc_not_supported;
4900	dp->set_reg = i_psvc_not_supported;
4901
4902	return (PSVC_SUCCESS);
4903}
4904
4905/* SSC050 */
4906static int32_t
4907i_psvc_constructor_11_7(
4908	EHdl_t	*hdlp,
4909	char	*id,
4910	EObj_t  **objpp)
4911{
4912	int32_t status;
4913	char buf[BUFSZ];
4914	EPhysDev_t *dp;
4915
4916	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4917	if (status != PSVC_SUCCESS)
4918		return (status);
4919
4920	/* Load class specific info */
4921	dp = (EPhysDev_t *)*objpp;
4922
4923	dp->ld.constructor = i_psvc_constructor_11_7;
4924	dp->ld.destructor = i_psvc_destructor;
4925	dp->ld.get_attr = i_psvc_get_attr_11_7;
4926	dp->ld.set_attr = i_psvc_set_attr_generic;
4927	dp->get_temperature = i_psvc_not_supported;
4928	dp->get_fanspeed = i_psvc_get_fanspeed_11_7;
4929	dp->get_input = i_psvc_not_supported;
4930	dp->get_bit = i_psvc_get_bit_11_7;
4931	dp->set_bit = i_psvc_set_bit_11_7;
4932	dp->get_port = i_psvc_get_port_11_5;	/* same as for class = 11, 5 */
4933	dp->set_port = i_psvc_set_port_11_5;
4934	dp->get_output = i_psvc_not_supported;
4935	dp->set_output = i_psvc_not_supported;
4936	dp->get_reg = i_psvc_get_reg_11_7;
4937	dp->set_reg = i_psvc_set_reg_11_7;
4938
4939	return (PSVC_SUCCESS);
4940}
4941
4942/* TDA8444 */
4943static int32_t
4944i_psvc_constructor_11_8(
4945	EHdl_t	*hdlp,
4946	char	*id,
4947	EObj_t  **objpp)
4948{
4949	int32_t status;
4950	char buf[BUFSZ];
4951	EPhysDev_t *dp;
4952
4953	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4954	if (status != PSVC_SUCCESS)
4955		return (status);
4956
4957	/* Load class specific info */
4958	dp = (EPhysDev_t *)*objpp;
4959
4960	dp->ld.constructor = i_psvc_constructor_11_8;
4961	dp->ld.destructor = i_psvc_destructor;
4962	dp->ld.get_attr = i_psvc_get_attr_11_8;
4963	dp->ld.set_attr = i_psvc_set_attr_generic;
4964	dp->get_temperature = i_psvc_not_supported;
4965	dp->get_fanspeed = i_psvc_not_supported;
4966	dp->get_input = i_psvc_not_supported;
4967	dp->get_bit = i_psvc_not_supported;
4968	dp->set_bit = i_psvc_not_supported;
4969	dp->get_port = i_psvc_not_supported;
4970	dp->set_port = i_psvc_not_supported;
4971	dp->get_output = i_psvc_get_output_11_8;
4972	dp->set_output = i_psvc_set_output_11_8;
4973	dp->get_reg = i_psvc_not_supported;
4974	dp->set_reg = i_psvc_not_supported;
4975
4976	return (PSVC_SUCCESS);
4977}
4978
4979/* SSC100 */
4980static int32_t
4981i_psvc_constructor_11_9(
4982	EHdl_t	*hdlp,
4983	char	*id,
4984	EObj_t  **objpp)
4985{
4986	int32_t status;
4987	char buf[BUFSZ];
4988	EPhysDev_t *dp;
4989
4990	status = i_psvc_load_generic(hdlp, id, objpp, buf, sizeof (EPhysDev_t));
4991	if (status != PSVC_SUCCESS)
4992		return (status);
4993
4994	/* Load class specific info */
4995	dp = (EPhysDev_t *)*objpp;
4996
4997	dp->ld.constructor = i_psvc_constructor_11_9;
4998	dp->ld.destructor = i_psvc_destructor;
4999	dp->ld.get_attr = i_psvc_get_attr_11_9;
5000	dp->ld.set_attr = i_psvc_set_attr_generic;
5001	dp->get_temperature = i_psvc_not_supported;
5002	dp->get_fanspeed = i_psvc_not_supported;
5003	dp->get_input = i_psvc_not_supported;
5004	dp->get_bit = i_psvc_not_supported;
5005	dp->set_bit = i_psvc_not_supported;
5006	dp->get_port = i_psvc_get_port_11_5;	/* Same as for class = 11, 5 */
5007	dp->set_port = i_psvc_set_port_11_5;
5008	dp->get_output = i_psvc_not_supported;
5009	dp->set_output = i_psvc_not_supported;
5010	dp->get_reg = i_psvc_not_supported;
5011	dp->set_reg = i_psvc_not_supported;
5012
5013	return (PSVC_SUCCESS);
5014}
5015
5016int32_t
5017psvc_init(EHdl_t **hdlpp)
5018{
5019	EHdl_t *hdlp;
5020	int    i;
5021	char   buf[BUFSZ];
5022	char   platform[32];
5023	char   filename[256];
5024	int    found;
5025	int32_t status;
5026	pthread_mutexattr_t mutex_attr;
5027	uint32_t table_count;
5028	int	forward_slash = 47;
5029	int	new_line = 10;
5030	char	*nl_char;
5031
5032	hdlp = (EHdl_t *)malloc(sizeof (EHdl_t));
5033	if (hdlp == NULL)
5034		return (-1);
5035	memset(hdlp, 0, sizeof (EHdl_t));
5036
5037	/* Initialize the lock */
5038	status = pthread_mutexattr_init(&mutex_attr);
5039	if (status != 0) {
5040		errno = status;
5041		return (-1);
5042	}
5043	status = pthread_mutex_init(&hdlp->mutex, &mutex_attr);
5044	if (status != 0) {
5045		errno = status;
5046		return (-1);
5047	}
5048	pthread_mutexattr_destroy(&mutex_attr);
5049
5050	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
5051		return (-1);
5052	}
5053
5054	snprintf(filename, sizeof (filename),
5055	    "/usr/platform/%s/lib/psvcobj.conf", platform);
5056	if ((hdlp->fp = fopen(filename, "r")) == NULL) {
5057		return (-1);
5058	}
5059
5060
5061	/* Build the association ID lookup table */
5062
5063	hdlp->othr_count = hdlp->assoc_count = ASSOC_STR_TAB_SIZE;
5064	if ((hdlp->othr_tbl = (EStringId_t *)malloc(sizeof (EStringId_t) *
5065		hdlp->othr_count)) == NULL) {
5066		return (-1);
5067	}
5068
5069	for (i = 0; i < hdlp->othr_count; ++i) {
5070		hdlp->othr_tbl[i].id = i;
5071		strcpy(hdlp->othr_tbl[i].name, assoc_str_tab[i]);
5072	}
5073	qsort(hdlp->othr_tbl, hdlp->othr_count, sizeof (EStringId_t),
5074		(int (*)(const void *, const void *))i_psvc_name_compare_qsort);
5075
5076	/* determine total number of objects + tables */
5077	if (i_psvc_find_file_section(hdlp->fp, "OBJECT_INFO") == -1) {
5078		return (-1);
5079	}
5080	if (i_psvc_count_records(hdlp->fp, "OBJECT_INFO_END",
5081		&hdlp->total_obj_count) == -1) {
5082		return (-1);
5083	}
5084	if (i_psvc_find_file_section(hdlp->fp, "TABLES") == PSVC_SUCCESS) {
5085		status = i_psvc_count_tables_associations(hdlp->fp,
5086			&table_count, "TABLE_END");
5087		if (status == PSVC_FAILURE) {
5088			return (status);
5089		}
5090		hdlp->total_obj_count += table_count;
5091	}
5092
5093	/* Allocate object name to object pointer translation table */
5094	for (i = 0; i < PSVC_MAX_TABLE_ARRAYS; i++) {
5095		if ((hdlp->tbl_arry[i].obj_tbl =
5096			(ENamePtr_t *)malloc(
5097		sizeof (ENamePtr_t) *hdlp->total_obj_count)) == NULL) {
5098			return (-1);
5099		}
5100		memset(hdlp->tbl_arry[i].obj_tbl, 0,
5101		    sizeof (ENamePtr_t) * hdlp->total_obj_count);
5102		hdlp->tbl_arry[i].obj_count = 0;
5103	}
5104
5105	/* Build the association table */
5106	if (i_psvc_load_associations(hdlp, hdlp->fp) == -1)
5107		return (-1);
5108
5109	/* Build the table of device paths */
5110	if (i_psvc_find_file_section(hdlp->fp, "DEVPATHS") == -1)
5111		return (-1);
5112	if (i_psvc_count_records(hdlp->fp, "DEVPATHS_END",
5113		&hdlp->dev_count) == -1)
5114		return (-1);
5115	if ((hdlp->dev_tbl = (EDevice_t *)malloc(sizeof (EDevice_t) *
5116		hdlp->dev_count)) == NULL) {
5117		return (-1);
5118	}
5119	for (i = 0; i < hdlp->dev_count; ++i) {
5120		fgets(buf, BUFSZ, hdlp->fp);
5121		found = sscanf(buf, "%d %d %x %d",
5122			&hdlp->dev_tbl[i].controller,
5123			&hdlp->dev_tbl[i].bus, &hdlp->dev_tbl[i].addr,
5124			&hdlp->dev_tbl[i].port);
5125		if (found != 4) {
5126			errno = EINVAL;
5127			return (-1);
5128		}
5129		strcpy(hdlp->dev_tbl[i].path, strchr(buf, forward_slash));
5130		/*
5131		 * Replace new line character with NUL character
5132		 */
5133		nl_char = strchr(hdlp->dev_tbl[i].path, new_line);
5134		*nl_char = 0;
5135	}
5136
5137	/* Build the table of tables */
5138	if (i_psvc_load_tables(hdlp, hdlp->fp) == -1)
5139		return (-1);
5140	*hdlpp = hdlp;
5141	return (0);
5142}
5143
5144int32_t
5145psvc_fini(EHdl_t *hdlp)
5146{
5147	int32_t i, j;
5148	ETable_Array *array;
5149
5150	if (hdlp == 0)
5151		return (PSVC_SUCCESS);
5152
5153	for (j = 0; j < PSVC_MAX_TABLE_ARRAYS; j++) {
5154		if (hdlp->tbl_arry[j].obj_tbl != 0) {
5155			array = &(hdlp->tbl_arry[j]);
5156			for (i = 0; i < array->obj_count; ++i) {
5157				if (array->obj_tbl[i].type == PSVC_OBJ) {
5158					if (!array->obj_tbl[i].objp) {
5159						/* Skip non-existent object */
5160						continue;
5161					}
5162					array->obj_tbl[i].objp->destructor(hdlp,
5163					    array->obj_tbl[i].objp->label,
5164					    array->obj_tbl[i].objp);
5165				}
5166
5167				if (array->obj_tbl[i].type == PSVC_TBL) {
5168					ETable_t *tblp =
5169					    (ETable_t *)array->obj_tbl[i].objp;
5170					if (tblp->table != 0)
5171						free(tblp->table);
5172				}
5173			}
5174
5175			free(array->obj_tbl);
5176		}
5177	}
5178
5179	if (hdlp->othr_tbl != 0)
5180		free(hdlp->othr_tbl);
5181
5182	if (hdlp->assoc_tbl != 0) {
5183		for (i = 0; i < hdlp->assoc_count; ++i) {
5184			if (hdlp->assoc_tbl[i].table != 0)
5185				free(hdlp->assoc_tbl[i].table);
5186		}
5187		free(hdlp->assoc_tbl);
5188	}
5189
5190	if (hdlp->dev_tbl != 0)
5191		free(hdlp->dev_tbl);
5192	if (hdlp->fp != 0)
5193		fclose(hdlp->fp);
5194	pthread_mutex_destroy(&hdlp->mutex);
5195	free(hdlp);
5196	return (PSVC_SUCCESS);
5197}
5198
5199int32_t
5200ioctl_retry(int fp, int request, void * arg_pointer)
5201{
5202	int32_t ret = PSVC_SUCCESS;
5203	int32_t tries = 0;
5204
5205	/*
5206	 * Becuase the i2c bus is a multimaster bus we need to protect
5207	 * ourselves from bus masters that are not being good bus citizens.
5208	 * A retry number of 10 should be sufficient to handle any bad bus
5209	 * citizens.  After that we will simply say that there is something
5210	 * wrong with the ioctl transaction and let it bubble back up.
5211	 */
5212	do {
5213		ret = ioctl(fp, request, arg_pointer);
5214		tries ++;
5215	} while ((ret == -1) && (tries < 10));
5216
5217	return (ret);
5218}
5219
5220static int32_t
5221psvc_get_str_key(char *object)
5222{
5223	int32_t key = 0;
5224	int i, length;
5225
5226	length = strlen(object);
5227	for (i = 0; i < length; i++) {
5228		if ((object[i] > 47) && (object[i] < 58)) {
5229			key = key + ((object[i] - 50) + 2);
5230		} else {
5231			key = key + object[i];
5232		}
5233	}
5234
5235
5236	return (key);
5237}
5238