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