1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
27*7c478bd9Sstevel@tonic-gate
28*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
29*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
34*7c478bd9Sstevel@tonic-gate #include "devid_impl.h"
35*7c478bd9Sstevel@tonic-gate
36*7c478bd9Sstevel@tonic-gate static int devid_str_decode_id(char *devidstr, ddi_devid_t *devidp,
37*7c478bd9Sstevel@tonic-gate char **minor_namep, impl_devid_t *id);
38*7c478bd9Sstevel@tonic-gate
39*7c478bd9Sstevel@tonic-gate
40*7c478bd9Sstevel@tonic-gate /*
41*7c478bd9Sstevel@tonic-gate * Validate device id.
42*7c478bd9Sstevel@tonic-gate */
43*7c478bd9Sstevel@tonic-gate int
44*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_valid(ddi_devid_t devid)45*7c478bd9Sstevel@tonic-gate ddi_devid_valid(ddi_devid_t devid)
46*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
47*7c478bd9Sstevel@tonic-gate devid_valid(ddi_devid_t devid)
48*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
49*7c478bd9Sstevel@tonic-gate {
50*7c478bd9Sstevel@tonic-gate impl_devid_t *id = (impl_devid_t *)devid;
51*7c478bd9Sstevel@tonic-gate ushort_t type;
52*7c478bd9Sstevel@tonic-gate
53*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(devid != NULL);
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate if (id->did_magic_hi != DEVID_MAGIC_MSB)
56*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
57*7c478bd9Sstevel@tonic-gate
58*7c478bd9Sstevel@tonic-gate if (id->did_magic_lo != DEVID_MAGIC_LSB)
59*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
60*7c478bd9Sstevel@tonic-gate
61*7c478bd9Sstevel@tonic-gate if (id->did_rev_hi != DEVID_REV_MSB)
62*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gate if (id->did_rev_lo != DEVID_REV_LSB)
65*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
66*7c478bd9Sstevel@tonic-gate
67*7c478bd9Sstevel@tonic-gate type = DEVID_GETTYPE(id);
68*7c478bd9Sstevel@tonic-gate if ((type == DEVID_NONE) || (type > DEVID_MAXTYPE))
69*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
70*7c478bd9Sstevel@tonic-gate
71*7c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID);
72*7c478bd9Sstevel@tonic-gate }
73*7c478bd9Sstevel@tonic-gate
74*7c478bd9Sstevel@tonic-gate /*
75*7c478bd9Sstevel@tonic-gate * Return the sizeof a device id. If called with NULL devid it returns
76*7c478bd9Sstevel@tonic-gate * the amount of space needed to determine the size.
77*7c478bd9Sstevel@tonic-gate */
78*7c478bd9Sstevel@tonic-gate size_t
79*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_sizeof(ddi_devid_t devid)80*7c478bd9Sstevel@tonic-gate ddi_devid_sizeof(ddi_devid_t devid)
81*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
82*7c478bd9Sstevel@tonic-gate devid_sizeof(ddi_devid_t devid)
83*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
84*7c478bd9Sstevel@tonic-gate {
85*7c478bd9Sstevel@tonic-gate impl_devid_t *id = (impl_devid_t *)devid;
86*7c478bd9Sstevel@tonic-gate
87*7c478bd9Sstevel@tonic-gate if (id == NULL)
88*7c478bd9Sstevel@tonic-gate return (sizeof (*id) - sizeof (id->did_id));
89*7c478bd9Sstevel@tonic-gate
90*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(DEVID_FUNC(devid_valid)(devid) == DEVID_RET_VALID);
91*7c478bd9Sstevel@tonic-gate
92*7c478bd9Sstevel@tonic-gate return (sizeof (*id) + DEVID_GETLEN(id) - sizeof (id->did_id));
93*7c478bd9Sstevel@tonic-gate }
94*7c478bd9Sstevel@tonic-gate
95*7c478bd9Sstevel@tonic-gate /*
96*7c478bd9Sstevel@tonic-gate * Compare two device id's.
97*7c478bd9Sstevel@tonic-gate * -1 - less than
98*7c478bd9Sstevel@tonic-gate * 0 - equal
99*7c478bd9Sstevel@tonic-gate * 1 - greater than
100*7c478bd9Sstevel@tonic-gate */
101*7c478bd9Sstevel@tonic-gate int
102*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_compare(ddi_devid_t id1,ddi_devid_t id2)103*7c478bd9Sstevel@tonic-gate ddi_devid_compare(ddi_devid_t id1, ddi_devid_t id2)
104*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
105*7c478bd9Sstevel@tonic-gate devid_compare(ddi_devid_t id1, ddi_devid_t id2)
106*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
107*7c478bd9Sstevel@tonic-gate {
108*7c478bd9Sstevel@tonic-gate int rval;
109*7c478bd9Sstevel@tonic-gate impl_devid_t *i_id1 = (impl_devid_t *)id1;
110*7c478bd9Sstevel@tonic-gate impl_devid_t *i_id2 = (impl_devid_t *)id2;
111*7c478bd9Sstevel@tonic-gate ushort_t i_id1_type;
112*7c478bd9Sstevel@tonic-gate ushort_t i_id2_type;
113*7c478bd9Sstevel@tonic-gate
114*7c478bd9Sstevel@tonic-gate DEVID_ASSERT((id1 != NULL) && (id2 != NULL));
115*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(DEVID_FUNC(devid_valid)(id1) == DEVID_RET_VALID);
116*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(DEVID_FUNC(devid_valid)(id2) == DEVID_RET_VALID);
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gate /* magic and revision comparison */
119*7c478bd9Sstevel@tonic-gate if ((rval = bcmp(id1, id2, 4)) != 0) {
120*7c478bd9Sstevel@tonic-gate return (rval);
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate
123*7c478bd9Sstevel@tonic-gate /* get current devid types */
124*7c478bd9Sstevel@tonic-gate i_id1_type = DEVID_GETTYPE(i_id1);
125*7c478bd9Sstevel@tonic-gate i_id2_type = DEVID_GETTYPE(i_id2);
126*7c478bd9Sstevel@tonic-gate
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate * Originaly all page83 devids used DEVID_SCSI3_WWN.
129*7c478bd9Sstevel@tonic-gate * To avoid a possible uniqueness issue each type of page83
130*7c478bd9Sstevel@tonic-gate * encoding supported is represented as a separate
131*7c478bd9Sstevel@tonic-gate * devid type. If comparing DEVID_SCSI3_WWN against
132*7c478bd9Sstevel@tonic-gate * one of the new page83 encodings we assume that no
133*7c478bd9Sstevel@tonic-gate * uniqueness issue exists (since we had apparently been
134*7c478bd9Sstevel@tonic-gate * running with the old DEVID_SCSI3_WWN encoding without
135*7c478bd9Sstevel@tonic-gate * a problem).
136*7c478bd9Sstevel@tonic-gate */
137*7c478bd9Sstevel@tonic-gate if ((i_id1_type == DEVID_SCSI3_WWN) ||
138*7c478bd9Sstevel@tonic-gate (i_id2_type == DEVID_SCSI3_WWN)) {
139*7c478bd9Sstevel@tonic-gate /*
140*7c478bd9Sstevel@tonic-gate * Atleast one devid is using old scsi
141*7c478bd9Sstevel@tonic-gate * encode algorithm. Force devid types
142*7c478bd9Sstevel@tonic-gate * to same scheme for comparison.
143*7c478bd9Sstevel@tonic-gate */
144*7c478bd9Sstevel@tonic-gate if (IS_DEVID_SCSI3_VPD_TYPE(i_id1_type)) {
145*7c478bd9Sstevel@tonic-gate i_id1_type = DEVID_SCSI3_WWN;
146*7c478bd9Sstevel@tonic-gate }
147*7c478bd9Sstevel@tonic-gate if (IS_DEVID_SCSI3_VPD_TYPE(i_id2_type)) {
148*7c478bd9Sstevel@tonic-gate i_id2_type = DEVID_SCSI3_WWN;
149*7c478bd9Sstevel@tonic-gate }
150*7c478bd9Sstevel@tonic-gate }
151*7c478bd9Sstevel@tonic-gate
152*7c478bd9Sstevel@tonic-gate /* type comparison */
153*7c478bd9Sstevel@tonic-gate if (i_id1_type != i_id2_type) {
154*7c478bd9Sstevel@tonic-gate return ((i_id1_type < i_id2_type) ? -1 : 1);
155*7c478bd9Sstevel@tonic-gate }
156*7c478bd9Sstevel@tonic-gate
157*7c478bd9Sstevel@tonic-gate /* length comparison */
158*7c478bd9Sstevel@tonic-gate if (DEVID_GETLEN(i_id1) != DEVID_GETLEN(i_id2)) {
159*7c478bd9Sstevel@tonic-gate return (DEVID_GETLEN(i_id1) < DEVID_GETLEN(i_id2) ? -1 : 1);
160*7c478bd9Sstevel@tonic-gate }
161*7c478bd9Sstevel@tonic-gate
162*7c478bd9Sstevel@tonic-gate /* id comparison */
163*7c478bd9Sstevel@tonic-gate rval = bcmp(i_id1->did_id, i_id2->did_id, DEVID_GETLEN(i_id1));
164*7c478bd9Sstevel@tonic-gate
165*7c478bd9Sstevel@tonic-gate return (rval);
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate
168*7c478bd9Sstevel@tonic-gate /*
169*7c478bd9Sstevel@tonic-gate * Free a Device Id
170*7c478bd9Sstevel@tonic-gate */
171*7c478bd9Sstevel@tonic-gate void
172*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_free(ddi_devid_t devid)173*7c478bd9Sstevel@tonic-gate ddi_devid_free(ddi_devid_t devid)
174*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
175*7c478bd9Sstevel@tonic-gate devid_free(ddi_devid_t devid)
176*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
177*7c478bd9Sstevel@tonic-gate {
178*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(devid != NULL);
179*7c478bd9Sstevel@tonic-gate DEVID_FREE(devid, DEVID_FUNC(devid_sizeof)(devid));
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate * Encode a device id into a string. See ddi_impldefs.h for details.
184*7c478bd9Sstevel@tonic-gate */
185*7c478bd9Sstevel@tonic-gate char *
186*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_str_encode(ddi_devid_t devid,char * minor_name)187*7c478bd9Sstevel@tonic-gate ddi_devid_str_encode(ddi_devid_t devid, char *minor_name)
188*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
189*7c478bd9Sstevel@tonic-gate devid_str_encode(ddi_devid_t devid, char *minor_name)
190*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate impl_devid_t *id = (impl_devid_t *)devid;
193*7c478bd9Sstevel@tonic-gate size_t driver_len, devid_len, slen;
194*7c478bd9Sstevel@tonic-gate char *sbuf, *dsp, *dp, ta;
195*7c478bd9Sstevel@tonic-gate int i, n, ascii;
196*7c478bd9Sstevel@tonic-gate
197*7c478bd9Sstevel@tonic-gate /* "id0" is the encoded representation of a NULL device id */
198*7c478bd9Sstevel@tonic-gate if (devid == NULL) {
199*7c478bd9Sstevel@tonic-gate if ((sbuf = DEVID_MALLOC(4)) == NULL)
200*7c478bd9Sstevel@tonic-gate return (NULL);
201*7c478bd9Sstevel@tonic-gate *(sbuf+0) = DEVID_MAGIC_MSB;
202*7c478bd9Sstevel@tonic-gate *(sbuf+1) = DEVID_MAGIC_LSB;
203*7c478bd9Sstevel@tonic-gate *(sbuf+2) = '0';
204*7c478bd9Sstevel@tonic-gate *(sbuf+3) = 0;
205*7c478bd9Sstevel@tonic-gate return (sbuf);
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate
208*7c478bd9Sstevel@tonic-gate /* verify input */
209*7c478bd9Sstevel@tonic-gate if (DEVID_FUNC(devid_valid)(devid) != DEVID_RET_VALID)
210*7c478bd9Sstevel@tonic-gate return (NULL);
211*7c478bd9Sstevel@tonic-gate
212*7c478bd9Sstevel@tonic-gate /* scan the driver hint to see how long the hint is */
213*7c478bd9Sstevel@tonic-gate for (driver_len = 0; driver_len < DEVID_HINT_SIZE; driver_len++)
214*7c478bd9Sstevel@tonic-gate if (id->did_driver[driver_len] == '\0')
215*7c478bd9Sstevel@tonic-gate break;
216*7c478bd9Sstevel@tonic-gate
217*7c478bd9Sstevel@tonic-gate /* scan the contained did_id to see if it meets ascii requirements */
218*7c478bd9Sstevel@tonic-gate devid_len = DEVID_GETLEN(id);
219*7c478bd9Sstevel@tonic-gate for (ascii = 1, i = 0; i < devid_len; i++)
220*7c478bd9Sstevel@tonic-gate if (!DEVID_IDBYTE_ISASCII(id->did_id[i])) {
221*7c478bd9Sstevel@tonic-gate ascii = 0;
222*7c478bd9Sstevel@tonic-gate break;
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate
225*7c478bd9Sstevel@tonic-gate /* some types should always go hex even if they look ascii */
226*7c478bd9Sstevel@tonic-gate if (DEVID_TYPE_BIN_FORCEHEX(id->did_type_lo))
227*7c478bd9Sstevel@tonic-gate ascii = 0;
228*7c478bd9Sstevel@tonic-gate
229*7c478bd9Sstevel@tonic-gate /* set the length of the resulting string */
230*7c478bd9Sstevel@tonic-gate slen = 2 + 1; /* <magic><rev> "id1" */
231*7c478bd9Sstevel@tonic-gate slen += 1 + driver_len + 1 + 1; /* ",<driver>@<type>" */
232*7c478bd9Sstevel@tonic-gate slen += ascii ? devid_len : (devid_len * 2); /* did_id field */
233*7c478bd9Sstevel@tonic-gate if (minor_name) {
234*7c478bd9Sstevel@tonic-gate slen += 1; /* '/' */
235*7c478bd9Sstevel@tonic-gate slen += strlen(minor_name); /* len of minor_name */
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate slen += 1; /* NULL */
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate /* allocate string */
240*7c478bd9Sstevel@tonic-gate if ((sbuf = DEVID_MALLOC(slen)) == NULL)
241*7c478bd9Sstevel@tonic-gate return (NULL);
242*7c478bd9Sstevel@tonic-gate
243*7c478bd9Sstevel@tonic-gate /* perform encode of id to hex string */
244*7c478bd9Sstevel@tonic-gate dsp = sbuf;
245*7c478bd9Sstevel@tonic-gate *dsp++ = id->did_magic_hi;
246*7c478bd9Sstevel@tonic-gate *dsp++ = id->did_magic_lo;
247*7c478bd9Sstevel@tonic-gate *dsp++ = DEVID_REV_BINTOASCII(id->did_rev_lo);
248*7c478bd9Sstevel@tonic-gate *dsp++ = ',';
249*7c478bd9Sstevel@tonic-gate for (i = 0; i < driver_len; i++)
250*7c478bd9Sstevel@tonic-gate *dsp++ = id->did_driver[i];
251*7c478bd9Sstevel@tonic-gate *dsp++ = '@';
252*7c478bd9Sstevel@tonic-gate ta = DEVID_TYPE_BINTOASCII(id->did_type_lo);
253*7c478bd9Sstevel@tonic-gate if (ascii)
254*7c478bd9Sstevel@tonic-gate ta = DEVID_TYPE_SETASCII(ta);
255*7c478bd9Sstevel@tonic-gate *dsp++ = ta;
256*7c478bd9Sstevel@tonic-gate for (i = 0, dp = &id->did_id[0]; i < devid_len; i++, dp++) {
257*7c478bd9Sstevel@tonic-gate if (ascii) {
258*7c478bd9Sstevel@tonic-gate if (*dp == ' ')
259*7c478bd9Sstevel@tonic-gate *dsp++ = '_';
260*7c478bd9Sstevel@tonic-gate else if (*dp == 0x00)
261*7c478bd9Sstevel@tonic-gate *dsp++ = '~';
262*7c478bd9Sstevel@tonic-gate else
263*7c478bd9Sstevel@tonic-gate *dsp++ = *dp;
264*7c478bd9Sstevel@tonic-gate } else {
265*7c478bd9Sstevel@tonic-gate n = ((*dp) >> 4) & 0xF;
266*7c478bd9Sstevel@tonic-gate *dsp++ = (n < 10) ? (n + '0') : (n + ('a' - 10));
267*7c478bd9Sstevel@tonic-gate n = (*dp) & 0xF;
268*7c478bd9Sstevel@tonic-gate *dsp++ = (n < 10) ? (n + '0') : (n + ('a' - 10));
269*7c478bd9Sstevel@tonic-gate }
270*7c478bd9Sstevel@tonic-gate }
271*7c478bd9Sstevel@tonic-gate
272*7c478bd9Sstevel@tonic-gate if (minor_name) {
273*7c478bd9Sstevel@tonic-gate *dsp++ = '/';
274*7c478bd9Sstevel@tonic-gate (void) strcpy(dsp, minor_name);
275*7c478bd9Sstevel@tonic-gate } else
276*7c478bd9Sstevel@tonic-gate *dsp++ = 0;
277*7c478bd9Sstevel@tonic-gate
278*7c478bd9Sstevel@tonic-gate /* ensure that (strlen + 1) is correct length for free */
279*7c478bd9Sstevel@tonic-gate DEVID_ASSERT((strlen(sbuf) + 1) == slen);
280*7c478bd9Sstevel@tonic-gate return (sbuf);
281*7c478bd9Sstevel@tonic-gate }
282*7c478bd9Sstevel@tonic-gate
283*7c478bd9Sstevel@tonic-gate /* free the string returned by devid_str_encode */
284*7c478bd9Sstevel@tonic-gate void
285*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_str_free(char * devidstr)286*7c478bd9Sstevel@tonic-gate ddi_devid_str_free(char *devidstr)
287*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
288*7c478bd9Sstevel@tonic-gate devid_str_free(char *devidstr)
289*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
290*7c478bd9Sstevel@tonic-gate {
291*7c478bd9Sstevel@tonic-gate DEVID_FREE(devidstr, strlen(devidstr) + 1);
292*7c478bd9Sstevel@tonic-gate }
293*7c478bd9Sstevel@tonic-gate
294*7c478bd9Sstevel@tonic-gate /*
295*7c478bd9Sstevel@tonic-gate * given the string representation of a device id returned by calling
296*7c478bd9Sstevel@tonic-gate * devid_str_encode (passed in as devidstr), return pointers to the
297*7c478bd9Sstevel@tonic-gate * broken out devid and minor_name as requested. Devidstr remains
298*7c478bd9Sstevel@tonic-gate * allocated and unmodified. The devid returned in *devidp should be freed by
299*7c478bd9Sstevel@tonic-gate * calling devid_free. The minor_name returned in minor_namep should
300*7c478bd9Sstevel@tonic-gate * be freed by calling devid_str_free(minor_namep).
301*7c478bd9Sstevel@tonic-gate *
302*7c478bd9Sstevel@tonic-gate * See ddi_impldefs.h for format details.
303*7c478bd9Sstevel@tonic-gate */
304*7c478bd9Sstevel@tonic-gate int
305*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_str_decode(char * devidstr,ddi_devid_t * devidp,char ** minor_namep)306*7c478bd9Sstevel@tonic-gate ddi_devid_str_decode(
307*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
308*7c478bd9Sstevel@tonic-gate devid_str_decode(
309*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
310*7c478bd9Sstevel@tonic-gate char *devidstr, ddi_devid_t *devidp, char **minor_namep)
311*7c478bd9Sstevel@tonic-gate {
312*7c478bd9Sstevel@tonic-gate return (devid_str_decode_id(devidstr, devidp, minor_namep, NULL));
313*7c478bd9Sstevel@tonic-gate }
314*7c478bd9Sstevel@tonic-gate
315*7c478bd9Sstevel@tonic-gate /* implementation for (ddi_)devid_str_decode */
316*7c478bd9Sstevel@tonic-gate static int
devid_str_decode_id(char * devidstr,ddi_devid_t * devidp,char ** minor_namep,impl_devid_t * id)317*7c478bd9Sstevel@tonic-gate devid_str_decode_id(char *devidstr, ddi_devid_t *devidp,
318*7c478bd9Sstevel@tonic-gate char **minor_namep, impl_devid_t *id)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate char *str, *msp, *dsp, *dp, ta;
321*7c478bd9Sstevel@tonic-gate int slen, devid_len, ascii, i, n, c, pre_alloc = FALSE;
322*7c478bd9Sstevel@tonic-gate unsigned short id_len, type; /* for hibyte/lobyte */
323*7c478bd9Sstevel@tonic-gate
324*7c478bd9Sstevel@tonic-gate if (devidp != NULL)
325*7c478bd9Sstevel@tonic-gate *devidp = NULL;
326*7c478bd9Sstevel@tonic-gate if (minor_namep != NULL)
327*7c478bd9Sstevel@tonic-gate *minor_namep = NULL;
328*7c478bd9Sstevel@tonic-gate if (id != NULL)
329*7c478bd9Sstevel@tonic-gate pre_alloc = TRUE;
330*7c478bd9Sstevel@tonic-gate
331*7c478bd9Sstevel@tonic-gate if (devidstr == NULL)
332*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
333*7c478bd9Sstevel@tonic-gate
334*7c478bd9Sstevel@tonic-gate /* the string must atleast contain the ascii two byte header */
335*7c478bd9Sstevel@tonic-gate slen = strlen(devidstr);
336*7c478bd9Sstevel@tonic-gate if ((slen < 3) || (devidstr[0] != DEVID_MAGIC_MSB) ||
337*7c478bd9Sstevel@tonic-gate (devidstr[1] != DEVID_MAGIC_LSB))
338*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
339*7c478bd9Sstevel@tonic-gate
340*7c478bd9Sstevel@tonic-gate /* "id0" is the encoded representation of a NULL device id */
341*7c478bd9Sstevel@tonic-gate if ((devidstr[2] == '0') && (slen == 3))
342*7c478bd9Sstevel@tonic-gate return (DEVID_SUCCESS);
343*7c478bd9Sstevel@tonic-gate
344*7c478bd9Sstevel@tonic-gate /* "id1,@S0" is the shortest possible, reject if shorter */
345*7c478bd9Sstevel@tonic-gate if (slen < 7)
346*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
347*7c478bd9Sstevel@tonic-gate
348*7c478bd9Sstevel@tonic-gate /* find the optional minor name, start after ',' */
349*7c478bd9Sstevel@tonic-gate if ((msp = strchr(&devidstr[4], '/')) != NULL)
350*7c478bd9Sstevel@tonic-gate msp++;
351*7c478bd9Sstevel@tonic-gate
352*7c478bd9Sstevel@tonic-gate /* skip devid processing if we are not asked to return it */
353*7c478bd9Sstevel@tonic-gate if (devidp) {
354*7c478bd9Sstevel@tonic-gate /* find the required '@' separator */
355*7c478bd9Sstevel@tonic-gate if ((str = strchr(devidstr, '@')) == NULL)
356*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
357*7c478bd9Sstevel@tonic-gate str++; /* skip '@' */
358*7c478bd9Sstevel@tonic-gate
359*7c478bd9Sstevel@tonic-gate /* pick up <type> after the '@' and verify */
360*7c478bd9Sstevel@tonic-gate ta = *str++;
361*7c478bd9Sstevel@tonic-gate ascii = DEVID_TYPE_ISASCII(ta);
362*7c478bd9Sstevel@tonic-gate type = DEVID_TYPE_ASCIITOBIN(ta);
363*7c478bd9Sstevel@tonic-gate if (type > DEVID_MAXTYPE)
364*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
365*7c478bd9Sstevel@tonic-gate
366*7c478bd9Sstevel@tonic-gate /* determine length of id->did_id field */
367*7c478bd9Sstevel@tonic-gate if (msp == NULL)
368*7c478bd9Sstevel@tonic-gate id_len = strlen(str);
369*7c478bd9Sstevel@tonic-gate else
370*7c478bd9Sstevel@tonic-gate id_len = msp - str - 1;
371*7c478bd9Sstevel@tonic-gate
372*7c478bd9Sstevel@tonic-gate /* account for encoding: with hex, binary is half the size */
373*7c478bd9Sstevel@tonic-gate if (!ascii) {
374*7c478bd9Sstevel@tonic-gate /* hex id field must be even length */
375*7c478bd9Sstevel@tonic-gate if (id_len & 1)
376*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
377*7c478bd9Sstevel@tonic-gate id_len /= 2;
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate
380*7c478bd9Sstevel@tonic-gate /* add in size of the binary devid header */
381*7c478bd9Sstevel@tonic-gate devid_len = id_len + sizeof (*id) - sizeof (id->did_id);
382*7c478bd9Sstevel@tonic-gate
383*7c478bd9Sstevel@tonic-gate /*
384*7c478bd9Sstevel@tonic-gate * Allocate space for devid if we are asked to decode it
385*7c478bd9Sstevel@tonic-gate * decode it and space wasn't pre-allocated.
386*7c478bd9Sstevel@tonic-gate */
387*7c478bd9Sstevel@tonic-gate if (pre_alloc == FALSE) {
388*7c478bd9Sstevel@tonic-gate if ((id = (impl_devid_t *)DEVID_MALLOC(
389*7c478bd9Sstevel@tonic-gate devid_len)) == NULL)
390*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate
393*7c478bd9Sstevel@tonic-gate /* decode header portion of the string into the binary devid */
394*7c478bd9Sstevel@tonic-gate dsp = devidstr;
395*7c478bd9Sstevel@tonic-gate id->did_magic_hi = *dsp++; /* <magic> "id" */
396*7c478bd9Sstevel@tonic-gate id->did_magic_lo = *dsp++;
397*7c478bd9Sstevel@tonic-gate id->did_rev_hi = 0;
398*7c478bd9Sstevel@tonic-gate id->did_rev_lo =
399*7c478bd9Sstevel@tonic-gate DEVID_REV_ASCIITOBIN(*dsp); /* <rev> "1" */
400*7c478bd9Sstevel@tonic-gate dsp++; /* skip "1" */
401*7c478bd9Sstevel@tonic-gate dsp++; /* skip "," */
402*7c478bd9Sstevel@tonic-gate for (i = 0; i < DEVID_HINT_SIZE; i++) { /* <driver>@ */
403*7c478bd9Sstevel@tonic-gate if (*dsp == '@')
404*7c478bd9Sstevel@tonic-gate break;
405*7c478bd9Sstevel@tonic-gate id->did_driver[i] = *dsp++;
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate for (; i < DEVID_HINT_SIZE; i++)
408*7c478bd9Sstevel@tonic-gate id->did_driver[i] = 0;
409*7c478bd9Sstevel@tonic-gate
410*7c478bd9Sstevel@tonic-gate /* we must now be at the '@' */
411*7c478bd9Sstevel@tonic-gate if (*dsp != '@')
412*7c478bd9Sstevel@tonic-gate goto efree;
413*7c478bd9Sstevel@tonic-gate
414*7c478bd9Sstevel@tonic-gate /* set the type and length */
415*7c478bd9Sstevel@tonic-gate DEVID_FORMTYPE(id, type);
416*7c478bd9Sstevel@tonic-gate DEVID_FORMLEN(id, id_len);
417*7c478bd9Sstevel@tonic-gate
418*7c478bd9Sstevel@tonic-gate /* decode devid portion of string into the binary */
419*7c478bd9Sstevel@tonic-gate for (i = 0, dsp = str, dp = &id->did_id[0];
420*7c478bd9Sstevel@tonic-gate i < id_len; i++, dp++) {
421*7c478bd9Sstevel@tonic-gate if (ascii) {
422*7c478bd9Sstevel@tonic-gate if (*dsp == '_')
423*7c478bd9Sstevel@tonic-gate *dp = ' ';
424*7c478bd9Sstevel@tonic-gate else if (*dsp == '~')
425*7c478bd9Sstevel@tonic-gate *dp = 0x00;
426*7c478bd9Sstevel@tonic-gate else
427*7c478bd9Sstevel@tonic-gate *dp = *dsp;
428*7c478bd9Sstevel@tonic-gate dsp++;
429*7c478bd9Sstevel@tonic-gate } else {
430*7c478bd9Sstevel@tonic-gate c = *dsp++;
431*7c478bd9Sstevel@tonic-gate if (c >= '0' && c <= '9')
432*7c478bd9Sstevel@tonic-gate n = (c - '0') & 0xFF;
433*7c478bd9Sstevel@tonic-gate else if (c >= 'a' && c <= 'f')
434*7c478bd9Sstevel@tonic-gate n = (c - ('a' - 10)) & 0xFF;
435*7c478bd9Sstevel@tonic-gate else
436*7c478bd9Sstevel@tonic-gate goto efree;
437*7c478bd9Sstevel@tonic-gate n <<= 4;
438*7c478bd9Sstevel@tonic-gate c = *dsp++;
439*7c478bd9Sstevel@tonic-gate if (c >= '0' && c <= '9')
440*7c478bd9Sstevel@tonic-gate n |= (c - '0') & 0xFF;
441*7c478bd9Sstevel@tonic-gate else if (c >= 'a' && c <= 'f')
442*7c478bd9Sstevel@tonic-gate n |= (c - ('a' - 10)) & 0xFF;
443*7c478bd9Sstevel@tonic-gate else
444*7c478bd9Sstevel@tonic-gate goto efree;
445*7c478bd9Sstevel@tonic-gate *dp = n;
446*7c478bd9Sstevel@tonic-gate }
447*7c478bd9Sstevel@tonic-gate }
448*7c478bd9Sstevel@tonic-gate
449*7c478bd9Sstevel@tonic-gate /* verify result */
450*7c478bd9Sstevel@tonic-gate if (DEVID_FUNC(devid_valid)((ddi_devid_t)id) != DEVID_RET_VALID)
451*7c478bd9Sstevel@tonic-gate goto efree;
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate
454*7c478bd9Sstevel@tonic-gate /* duplicate minor_name if we are asked to decode it */
455*7c478bd9Sstevel@tonic-gate if (minor_namep && msp) {
456*7c478bd9Sstevel@tonic-gate if ((*minor_namep = DEVID_MALLOC(strlen(msp) + 1)) == NULL)
457*7c478bd9Sstevel@tonic-gate goto efree;
458*7c478bd9Sstevel@tonic-gate (void) strcpy(*minor_namep, msp);
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate
461*7c478bd9Sstevel@tonic-gate /* return pointer to binary */
462*7c478bd9Sstevel@tonic-gate if (devidp)
463*7c478bd9Sstevel@tonic-gate *devidp = (ddi_devid_t)id;
464*7c478bd9Sstevel@tonic-gate return (DEVID_SUCCESS);
465*7c478bd9Sstevel@tonic-gate
466*7c478bd9Sstevel@tonic-gate efree:
467*7c478bd9Sstevel@tonic-gate if ((pre_alloc == FALSE) && (id))
468*7c478bd9Sstevel@tonic-gate DEVID_FREE(id, devid_len);
469*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate
472*7c478bd9Sstevel@tonic-gate
473*7c478bd9Sstevel@tonic-gate /*
474*7c478bd9Sstevel@tonic-gate * Compare two device id's in string form
475*7c478bd9Sstevel@tonic-gate * -1 - id1 less than id2
476*7c478bd9Sstevel@tonic-gate * 0 - equal
477*7c478bd9Sstevel@tonic-gate * 1 - id1 greater than id2
478*7c478bd9Sstevel@tonic-gate */
479*7c478bd9Sstevel@tonic-gate int
480*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_str_compare(char * id1_str,char * id2_str)481*7c478bd9Sstevel@tonic-gate ddi_devid_str_compare(char *id1_str, char *id2_str)
482*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
483*7c478bd9Sstevel@tonic-gate devid_str_compare(char *id1_str, char *id2_str)
484*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate int rval = DEVID_FAILURE;
487*7c478bd9Sstevel@tonic-gate ddi_devid_t devid1;
488*7c478bd9Sstevel@tonic-gate ddi_devid_t devid2;
489*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
490*7c478bd9Sstevel@tonic-gate /* kernel use static protected by lock. */
491*7c478bd9Sstevel@tonic-gate static kmutex_t id_lock;
492*7c478bd9Sstevel@tonic-gate static uchar_t id1[sizeof (impl_devid_t) + MAXPATHLEN];
493*7c478bd9Sstevel@tonic-gate static uchar_t id2[sizeof (impl_devid_t) + MAXPATHLEN];
494*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
495*7c478bd9Sstevel@tonic-gate /* userland place on stack, since malloc might fail */
496*7c478bd9Sstevel@tonic-gate uchar_t id1[sizeof (impl_devid_t) + MAXPATHLEN];
497*7c478bd9Sstevel@tonic-gate uchar_t id2[sizeof (impl_devid_t) + MAXPATHLEN];
498*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
499*7c478bd9Sstevel@tonic-gate
500*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
501*7c478bd9Sstevel@tonic-gate mutex_enter(&id_lock);
502*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
503*7c478bd9Sstevel@tonic-gate
504*7c478bd9Sstevel@tonic-gate /*
505*7c478bd9Sstevel@tonic-gate * encode string form of devid
506*7c478bd9Sstevel@tonic-gate */
507*7c478bd9Sstevel@tonic-gate if ((devid_str_decode_id(id1_str, &devid1, NULL, (impl_devid_t *)id1) ==
508*7c478bd9Sstevel@tonic-gate DEVID_SUCCESS) &&
509*7c478bd9Sstevel@tonic-gate (devid_str_decode_id(id2_str, &devid2, NULL, (impl_devid_t *)id2) ==
510*7c478bd9Sstevel@tonic-gate DEVID_SUCCESS)) {
511*7c478bd9Sstevel@tonic-gate rval = DEVID_FUNC(devid_compare)(devid1, devid2);
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate
514*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
515*7c478bd9Sstevel@tonic-gate mutex_exit(&id_lock);
516*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
517*7c478bd9Sstevel@tonic-gate
518*7c478bd9Sstevel@tonic-gate return (rval);
519*7c478bd9Sstevel@tonic-gate }
520