1ae115bc7Smrj /* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 5ae8fa80cSmyers * Common Development and Distribution License (the "License"). 6ae8fa80cSmyers * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 21ae115bc7Smrj /* 22*c61d8baaSDana Myers * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23ae115bc7Smrj */ 24ae115bc7Smrj 25ae115bc7Smrj #include <sys/kobj.h> 26ae115bc7Smrj #include <sys/kobj_lex.h> 27ae115bc7Smrj #include <sys/ddi.h> 28ae115bc7Smrj #include <sys/sunddi.h> 29ae115bc7Smrj #include <sys/sunndi.h> 30aa2aa9a6SDana Myers #include <sys/acpi/acpi.h> 31aa2aa9a6SDana Myers #include <sys/acpica.h> 32ae115bc7Smrj 33ae115bc7Smrj #define masterfile "/boot/solaris/devicedb/master" 34ae115bc7Smrj 35aa2aa9a6SDana Myers /* 36aa2aa9a6SDana Myers * Internal definitions 37aa2aa9a6SDana Myers */ 38ae115bc7Smrj 39aa2aa9a6SDana Myers typedef enum { 40aa2aa9a6SDana Myers MF_UNEXPECTED = -1, 41aa2aa9a6SDana Myers MF_IDENT, 42aa2aa9a6SDana Myers MF_STRING, 43aa2aa9a6SDana Myers MF_EOF, 44aa2aa9a6SDana Myers MF_NEWLINE, 45aa2aa9a6SDana Myers MF_EQUALS, 46aa2aa9a6SDana Myers MF_BIT_OR 47aa2aa9a6SDana Myers } mftoken_t; 48aa2aa9a6SDana Myers 49aa2aa9a6SDana Myers typedef enum { 50aa2aa9a6SDana Myers MF_INIT, 51aa2aa9a6SDana Myers MF_DEVID, 52aa2aa9a6SDana Myers MF_NAME, 53aa2aa9a6SDana Myers MF_DEVTYPE, 54aa2aa9a6SDana Myers MF_BUSTYPE, 55aa2aa9a6SDana Myers MF_BEFNAME, 56aa2aa9a6SDana Myers MF_DESCRIPTION, 57aa2aa9a6SDana Myers MF_PROPNAME, 58aa2aa9a6SDana Myers MF_PROPASSIGN, 59aa2aa9a6SDana Myers MF_PROPVAL, 60aa2aa9a6SDana Myers MF_VERSION_DONE, 61aa2aa9a6SDana Myers MF_VALID_DONE, 62aa2aa9a6SDana Myers MF_ERROR_DONE 63aa2aa9a6SDana Myers } mfparse_t; 64aa2aa9a6SDana Myers 65aa2aa9a6SDana Myers 66aa2aa9a6SDana Myers static master_rec_t *master_list = NULL; 67aa2aa9a6SDana Myers 68aa2aa9a6SDana Myers device_id_t * 69aa2aa9a6SDana Myers mf_alloc_device_id() 70aa2aa9a6SDana Myers { 71aa2aa9a6SDana Myers return ((device_id_t *)kmem_zalloc(sizeof (device_id_t), KM_SLEEP)); 72aa2aa9a6SDana Myers } 73aa2aa9a6SDana Myers 74aa2aa9a6SDana Myers void 75aa2aa9a6SDana Myers mf_free_device_id(device_id_t *d) 76aa2aa9a6SDana Myers { 77aa2aa9a6SDana Myers if (d->id != NULL) 78aa2aa9a6SDana Myers strfree(d->id); 79aa2aa9a6SDana Myers 80aa2aa9a6SDana Myers kmem_free(d, sizeof (device_id_t)); 81aa2aa9a6SDana Myers } 82aa2aa9a6SDana Myers 83aa2aa9a6SDana Myers static property_t * 84aa2aa9a6SDana Myers mf_alloc_property() 85aa2aa9a6SDana Myers { 86aa2aa9a6SDana Myers return ((property_t *)kmem_zalloc(sizeof (property_t), KM_SLEEP)); 87aa2aa9a6SDana Myers } 88ae115bc7Smrj 89ae115bc7Smrj static void 90aa2aa9a6SDana Myers mf_free_property(property_t *p) 91aa2aa9a6SDana Myers { 92aa2aa9a6SDana Myers if (p->name != NULL) 93aa2aa9a6SDana Myers strfree(p->name); 94ae115bc7Smrj 95aa2aa9a6SDana Myers if (p->value != NULL) 96aa2aa9a6SDana Myers strfree(p->value); 97aa2aa9a6SDana Myers 98aa2aa9a6SDana Myers kmem_free(p, sizeof (property_t)); 99ae115bc7Smrj } 100aa2aa9a6SDana Myers 101aa2aa9a6SDana Myers static master_rec_t * 102aa2aa9a6SDana Myers mf_alloc_master_rec() 103aa2aa9a6SDana Myers { 104aa2aa9a6SDana Myers return ((master_rec_t *)kmem_zalloc(sizeof (master_rec_t), KM_SLEEP)); 105ae115bc7Smrj } 106aa2aa9a6SDana Myers 107aa2aa9a6SDana Myers static void 108aa2aa9a6SDana Myers mf_free_master_rec(master_rec_t *m) 109aa2aa9a6SDana Myers { 110aa2aa9a6SDana Myers device_id_t *d; 111aa2aa9a6SDana Myers property_t *p; 112aa2aa9a6SDana Myers 113aa2aa9a6SDana Myers if (m->name != NULL) 114aa2aa9a6SDana Myers strfree(m->name); 115aa2aa9a6SDana Myers 116aa2aa9a6SDana Myers if (m->description != NULL) 117aa2aa9a6SDana Myers strfree(m->description); 118aa2aa9a6SDana Myers 119aa2aa9a6SDana Myers d = m->device_ids; 120aa2aa9a6SDana Myers while (d != NULL) { 121aa2aa9a6SDana Myers device_id_t *next; 122aa2aa9a6SDana Myers 123aa2aa9a6SDana Myers next = d->next; 124aa2aa9a6SDana Myers mf_free_device_id(d); 125aa2aa9a6SDana Myers d = next; 126ae115bc7Smrj } 127aa2aa9a6SDana Myers 128aa2aa9a6SDana Myers p = m->properties; 129aa2aa9a6SDana Myers while (p != NULL) { 130aa2aa9a6SDana Myers property_t *next; 131aa2aa9a6SDana Myers 132aa2aa9a6SDana Myers next = p->next; 133aa2aa9a6SDana Myers mf_free_property(p); 134aa2aa9a6SDana Myers p = next; 135ae115bc7Smrj } 136aa2aa9a6SDana Myers 137aa2aa9a6SDana Myers kmem_free(m, sizeof (master_rec_t)); 138ae115bc7Smrj } 139aa2aa9a6SDana Myers 140aa2aa9a6SDana Myers void 141aa2aa9a6SDana Myers free_master_data() 142aa2aa9a6SDana Myers { 143aa2aa9a6SDana Myers master_rec_t *m; 144aa2aa9a6SDana Myers 145aa2aa9a6SDana Myers m = master_list; 146aa2aa9a6SDana Myers while (m != NULL) { 147aa2aa9a6SDana Myers master_rec_t *next; 148aa2aa9a6SDana Myers 149aa2aa9a6SDana Myers next = m->next; 150aa2aa9a6SDana Myers mf_free_master_rec(m); 151aa2aa9a6SDana Myers m = next; 152aa2aa9a6SDana Myers } 153aa2aa9a6SDana Myers master_list = NULL; 154ae115bc7Smrj } 155ae115bc7Smrj 156ae115bc7Smrj /* 157aa2aa9a6SDana Myers * Unfortunately, kobj_lex() is too sophisticated for our needs 158ae115bc7Smrj */ 159aa2aa9a6SDana Myers static mftoken_t 160aa2aa9a6SDana Myers mf_lex(struct _buf *file, char *val, size_t size) 161aa2aa9a6SDana Myers { 162ae115bc7Smrj char *cp; 163aa2aa9a6SDana Myers int ch, badquote; 164aa2aa9a6SDana Myers size_t remain; 165aa2aa9a6SDana Myers mftoken_t token = MF_UNEXPECTED; 166aa2aa9a6SDana Myers 167aa2aa9a6SDana Myers if (size < 2) 168aa2aa9a6SDana Myers return (token); /* MF_UNEXPECTED */ 169ae115bc7Smrj 170ae115bc7Smrj cp = val; 171aa2aa9a6SDana Myers 172aa2aa9a6SDana Myers /* skip leading whitespace */ 173aa2aa9a6SDana Myers while ((ch = kobj_getc(file)) == ' ' || ch == '\t') 174ae115bc7Smrj ; 175aa2aa9a6SDana Myers 176aa2aa9a6SDana Myers /* strip comments */ 177aa2aa9a6SDana Myers if (ch == '#') { 178aa2aa9a6SDana Myers while ((ch = kobj_getc(file)) != '\n' && ch != '\r' && 179aa2aa9a6SDana Myers ch != -1) 180aa2aa9a6SDana Myers ; 181ae115bc7Smrj } 182aa2aa9a6SDana Myers 183aa2aa9a6SDana Myers remain = size - 1; 184ae115bc7Smrj *cp++ = (char)ch; 185ae115bc7Smrj switch (ch) { 186aa2aa9a6SDana Myers case -1: 187aa2aa9a6SDana Myers token = MF_EOF; 188ae115bc7Smrj break; 189ae115bc7Smrj case '\n': 190ae115bc7Smrj case '\r': 191aa2aa9a6SDana Myers token = MF_NEWLINE; 192aa2aa9a6SDana Myers break; 193aa2aa9a6SDana Myers case '=': 194aa2aa9a6SDana Myers token = MF_EQUALS; 195aa2aa9a6SDana Myers break; 196aa2aa9a6SDana Myers case '|': 197aa2aa9a6SDana Myers token = MF_BIT_OR; 198ae115bc7Smrj break; 199ae115bc7Smrj case '"': 200aa2aa9a6SDana Myers remain++; 201ae115bc7Smrj cp--; 202aa2aa9a6SDana Myers badquote = 0; 203aa2aa9a6SDana Myers while (!badquote && (ch = kobj_getc(file)) != '"') { 204aa2aa9a6SDana Myers switch (ch) { 205aa2aa9a6SDana Myers case '\n': 206aa2aa9a6SDana Myers case -1: 207aa2aa9a6SDana Myers remain = size - 1; 208aa2aa9a6SDana Myers cp = val; 209aa2aa9a6SDana Myers *cp++ = '\n'; 210aa2aa9a6SDana Myers badquote = 1; 211aa2aa9a6SDana Myers /* since we consumed the newline/EOF */ 212aa2aa9a6SDana Myers (void) kobj_ungetc(file); 213ae115bc7Smrj break; 214ae115bc7Smrj default: 215aa2aa9a6SDana Myers if (--remain == 0) { 216aa2aa9a6SDana Myers token = MF_UNEXPECTED; 217aa2aa9a6SDana Myers goto out; 218ae115bc7Smrj } 219aa2aa9a6SDana Myers *cp++ = (char)ch; 220ae115bc7Smrj break; 221ae115bc7Smrj } 222aa2aa9a6SDana Myers } 223aa2aa9a6SDana Myers token = MF_STRING; 224aa2aa9a6SDana Myers break; 225aa2aa9a6SDana Myers default: 226aa2aa9a6SDana Myers do { 227aa2aa9a6SDana Myers if (--remain == 0) { 228aa2aa9a6SDana Myers token = MF_UNEXPECTED; 229aa2aa9a6SDana Myers break; 230aa2aa9a6SDana Myers } 231aa2aa9a6SDana Myers 232aa2aa9a6SDana Myers token = MF_IDENT; 233aa2aa9a6SDana Myers *cp++ = (char)(ch = kobj_getc(file)); 234aa2aa9a6SDana Myers 235aa2aa9a6SDana Myers /* if terminating character, break out */ 236aa2aa9a6SDana Myers if ((ch == -1) || (ch == ' ') || (ch == '\t') || 237aa2aa9a6SDana Myers (ch == '\n') || (ch == '\r') || (ch == '=') || 238aa2aa9a6SDana Myers (ch == '|')) { 239aa2aa9a6SDana Myers (void) kobj_ungetc(file); 240aa2aa9a6SDana Myers remain++; 241aa2aa9a6SDana Myers cp--; 242aa2aa9a6SDana Myers break; 243aa2aa9a6SDana Myers } 244aa2aa9a6SDana Myers 245aa2aa9a6SDana Myers if ((ch == '#') || (ch == '"')) 246aa2aa9a6SDana Myers token = MF_UNEXPECTED; 247aa2aa9a6SDana Myers } while (token != MF_UNEXPECTED); 248aa2aa9a6SDana Myers break; 249aa2aa9a6SDana Myers } 250aa2aa9a6SDana Myers out: 251ae115bc7Smrj *cp = '\0'; 252aa2aa9a6SDana Myers 253ae115bc7Smrj return (token); 254ae115bc7Smrj } 255ae115bc7Smrj 256aa2aa9a6SDana Myers static master_rec_t * 257aa2aa9a6SDana Myers get_line(struct _buf *file) 258ae115bc7Smrj { 259aa2aa9a6SDana Myers master_rec_t *m = NULL; 260aa2aa9a6SDana Myers device_id_t *d = NULL; 261aa2aa9a6SDana Myers property_t *p = NULL; 262aa2aa9a6SDana Myers mftoken_t token; 263aa2aa9a6SDana Myers char tokval[MAXPATHLEN]; 264aa2aa9a6SDana Myers mfparse_t parse_state; 265ae115bc7Smrj 266aa2aa9a6SDana Myers parse_state = MF_INIT; 267aa2aa9a6SDana Myers token = mf_lex(file, tokval, sizeof (tokval)); 268aa2aa9a6SDana Myers while (token != MF_EOF) { 269aa2aa9a6SDana Myers switch (parse_state) { 270aa2aa9a6SDana Myers case MF_INIT: 271aa2aa9a6SDana Myers m = mf_alloc_master_rec(); 272aa2aa9a6SDana Myers parse_state = MF_DEVID; 273aa2aa9a6SDana Myers /*FALLTHROUGH*/ 274aa2aa9a6SDana Myers case MF_DEVID: 275aa2aa9a6SDana Myers if (token == MF_IDENT) { 276aa2aa9a6SDana Myers d = mf_alloc_device_id(); 277aa2aa9a6SDana Myers d->id = strdup(tokval); 278aa2aa9a6SDana Myers d->next = m->device_ids; 279aa2aa9a6SDana Myers m->device_ids = d; 280aa2aa9a6SDana Myers parse_state = MF_NAME; 281aa2aa9a6SDana Myers } else if (token != MF_NEWLINE) 282aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 283aa2aa9a6SDana Myers break; 284aa2aa9a6SDana Myers case MF_NAME: 285aa2aa9a6SDana Myers if (token == MF_IDENT) { 286aa2aa9a6SDana Myers m->name = strdup(tokval); 287aa2aa9a6SDana Myers parse_state = MF_DEVTYPE; 288aa2aa9a6SDana Myers } else if (token == MF_BIT_OR) { 289aa2aa9a6SDana Myers parse_state = MF_DEVID; 290aa2aa9a6SDana Myers } else 291aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 292aa2aa9a6SDana Myers break; 293aa2aa9a6SDana Myers case MF_DEVTYPE: 294aa2aa9a6SDana Myers if (token == MF_IDENT) { 295aa2aa9a6SDana Myers /* device_type not used */ 296aa2aa9a6SDana Myers parse_state = MF_BUSTYPE; 297aa2aa9a6SDana Myers } else if (token == MF_NEWLINE) { 298aa2aa9a6SDana Myers /* version line ignored */ 299aa2aa9a6SDana Myers parse_state = MF_VERSION_DONE; 300aa2aa9a6SDana Myers } else 301aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 302aa2aa9a6SDana Myers break; 303aa2aa9a6SDana Myers case MF_BUSTYPE: 304aa2aa9a6SDana Myers if (token == MF_IDENT) { 305aa2aa9a6SDana Myers /* bus_type ignored */ 306aa2aa9a6SDana Myers parse_state = MF_BEFNAME; 307aa2aa9a6SDana Myers } else 308aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 309aa2aa9a6SDana Myers break; 310aa2aa9a6SDana Myers case MF_BEFNAME: 311aa2aa9a6SDana Myers if (token == MF_IDENT) { 312aa2aa9a6SDana Myers /* realmode driver name ignored */ 313aa2aa9a6SDana Myers parse_state = MF_DESCRIPTION; 314aa2aa9a6SDana Myers } else 315aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 316aa2aa9a6SDana Myers break; 317aa2aa9a6SDana Myers case MF_DESCRIPTION: 318aa2aa9a6SDana Myers if (token == MF_STRING) { 319aa2aa9a6SDana Myers m->description = strdup(tokval); 320aa2aa9a6SDana Myers parse_state = MF_PROPNAME; 321aa2aa9a6SDana Myers } else 322aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 323aa2aa9a6SDana Myers break; 324aa2aa9a6SDana Myers case MF_PROPNAME: 325aa2aa9a6SDana Myers if (token == MF_IDENT) { 326aa2aa9a6SDana Myers p = mf_alloc_property(); 327aa2aa9a6SDana Myers p->name = strdup(tokval); 328aa2aa9a6SDana Myers parse_state = MF_PROPASSIGN; 329aa2aa9a6SDana Myers } else if (token == MF_NEWLINE) { 330aa2aa9a6SDana Myers parse_state = MF_VALID_DONE; 331aa2aa9a6SDana Myers } else 332aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 333aa2aa9a6SDana Myers break; 334aa2aa9a6SDana Myers case MF_PROPASSIGN: 335aa2aa9a6SDana Myers if (token == MF_EQUALS) { 336aa2aa9a6SDana Myers parse_state = MF_PROPVAL; 337aa2aa9a6SDana Myers } else 338aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 339aa2aa9a6SDana Myers break; 340aa2aa9a6SDana Myers case MF_PROPVAL: 341aa2aa9a6SDana Myers if (token == MF_STRING || token == MF_IDENT) { 342aa2aa9a6SDana Myers p->value = strdup(tokval); 343aa2aa9a6SDana Myers p->next = m->properties; 344aa2aa9a6SDana Myers /* delete properties which begin with '$' */ 345aa2aa9a6SDana Myers if (*p->name == '$') { 346aa2aa9a6SDana Myers mf_free_property(p); 347aa2aa9a6SDana Myers } else 348aa2aa9a6SDana Myers m->properties = p; 349aa2aa9a6SDana Myers p = NULL; 350aa2aa9a6SDana Myers parse_state = MF_PROPNAME; 351aa2aa9a6SDana Myers } else 352aa2aa9a6SDana Myers parse_state = MF_ERROR_DONE; 353aa2aa9a6SDana Myers break; 354aa2aa9a6SDana Myers case MF_VERSION_DONE: 355aa2aa9a6SDana Myers case MF_VALID_DONE: 356aa2aa9a6SDana Myers case MF_ERROR_DONE: 357aa2aa9a6SDana Myers /* terminating states handled outside switch() */ 358aa2aa9a6SDana Myers break; 359ae115bc7Smrj } 360ae115bc7Smrj 361aa2aa9a6SDana Myers if (parse_state == MF_VERSION_DONE) { 362aa2aa9a6SDana Myers /* ignore version line */ 363aa2aa9a6SDana Myers mf_free_master_rec(m); 364aa2aa9a6SDana Myers parse_state = MF_INIT; 365aa2aa9a6SDana Myers } else if (parse_state == MF_VALID_DONE) { 366aa2aa9a6SDana Myers /* valid line */ 367aa2aa9a6SDana Myers break; 368aa2aa9a6SDana Myers } else if (parse_state == MF_ERROR_DONE) { 369aa2aa9a6SDana Myers mf_free_master_rec(m); 370aa2aa9a6SDana Myers if (p != NULL) 371aa2aa9a6SDana Myers mf_free_property(p); 372ae115bc7Smrj /* 373aa2aa9a6SDana Myers * Error in master file. Should never happen 374aa2aa9a6SDana Myers * since master file is not user-edited. Eat rest 375aa2aa9a6SDana Myers * of line to attempt error recovery 376ae115bc7Smrj */ 377aa2aa9a6SDana Myers cmn_err(CE_NOTE, "!error in %s", masterfile); 378aa2aa9a6SDana Myers while (token != MF_NEWLINE && token != MF_EOF) 379aa2aa9a6SDana Myers token = mf_lex(file, tokval, sizeof (tokval)); 380aa2aa9a6SDana Myers parse_state = MF_INIT; 381aa2aa9a6SDana Myers continue; 382aa2aa9a6SDana Myers } 383aa2aa9a6SDana Myers 384aa2aa9a6SDana Myers token = mf_lex(file, tokval, sizeof (tokval)); 385aa2aa9a6SDana Myers } 386aa2aa9a6SDana Myers 387aa2aa9a6SDana Myers return (m); 388aa2aa9a6SDana Myers } 389aa2aa9a6SDana Myers 390ae115bc7Smrj void 391aa2aa9a6SDana Myers process_master_file() 392aa2aa9a6SDana Myers { 393aa2aa9a6SDana Myers struct _buf *file; 394aa2aa9a6SDana Myers master_rec_t *m; 395ae115bc7Smrj 396*c61d8baaSDana Myers if ((file = kobj_open_file(masterfile)) == (struct _buf *)-1) { 397ae115bc7Smrj cmn_err(CE_WARN, "!cannot open master file: %s", masterfile); 398ae115bc7Smrj return; 399ae115bc7Smrj } 400aa2aa9a6SDana Myers 401aa2aa9a6SDana Myers while ((m = get_line(file)) != NULL) { 402aa2aa9a6SDana Myers m->next = master_list; 403aa2aa9a6SDana Myers master_list = m; 404ae115bc7Smrj } 405aa2aa9a6SDana Myers 406ae115bc7Smrj kobj_close_file(file); 407ae115bc7Smrj } 408ae115bc7Smrj 409ae115bc7Smrj /* 410aa2aa9a6SDana Myers * Return the first master file record found matching pnpid list 411ae115bc7Smrj */ 412aa2aa9a6SDana Myers const master_rec_t * 413aa2aa9a6SDana Myers master_file_lookup(device_id_t *pnpid) 414ae115bc7Smrj { 415aa2aa9a6SDana Myers master_rec_t *m; 416aa2aa9a6SDana Myers device_id_t *d; 417ae115bc7Smrj 418aa2aa9a6SDana Myers while (pnpid != NULL) { 419aa2aa9a6SDana Myers m = master_list; 420aa2aa9a6SDana Myers while (m != NULL) { 421aa2aa9a6SDana Myers d = m->device_ids; 422aa2aa9a6SDana Myers while (d != NULL) { 423aa2aa9a6SDana Myers if (strcmp(pnpid->id, d->id) == 0) 424aa2aa9a6SDana Myers return (m); 425aa2aa9a6SDana Myers d = d->next; 426ae115bc7Smrj } 427aa2aa9a6SDana Myers m = m->next; 428ae115bc7Smrj } 429aa2aa9a6SDana Myers pnpid = pnpid->next; 430ae115bc7Smrj } 431ae115bc7Smrj 432aa2aa9a6SDana Myers return (NULL); 433ae115bc7Smrj } 434