/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "cfga_usb.h"
#define MAX(a, b) ((a) < (b) ? (b) : (a))
typedef struct usb_configrec {
char *selection;
char *serialno;
char *pathname;
char *driver;
typedef enum {
typedef struct usbcfg_var {
const char *name;
} usbcfg_var_t;
{ "selection", USB_SELECTION },
{ "idVendor", USB_VENDOR },
{ "idProduct", USB_PRODUCT },
{ "cfgndx", USB_CFGNDX },
{ "srno", USB_SRNO },
{ "pathname", USB_PATH },
{ "driver", USB_DRIVER },
};
typedef enum {
STAR,
} token_t;
static int cntr = 0;
static int frec = 0;
static int brec = 0;
static int btoken = 0;
/*
* prototypes
*/
/*
* The next item on the line is a string value. Allocate memory for
* it and copy the string. Return 1, and set arg ptr to newly allocated
* and initialized buffer, or NULL if an error occurs.
*/
static int
{
register char *cp;
register char *start = (char *)0;
register int len = 0;
/* copy string */
return (0);
}
/* convert some common escape sequences */
if (*start == '\\') {
switch (*(start + 1)) {
case 't':
/* tab */
*cp++ = '\t';
len--;
start += 2;
break;
case 'n':
/* new line */
*cp++ = '\n';
len--;
start += 2;
break;
case 'b':
/* back space */
*cp++ = '\b';
len--;
start += 2;
break;
default:
/* simply copy it */
break;
}
} else {
}
}
*cp = '\0';
return (1);
}
/*
* get a decimal octal or hex number. Handle '~' for one's complement.
*/
static int
{
register int radix;
register int onescompl = 0;
register int negate = 0;
register char c;
if (*token == '~') {
onescompl++; /* perform one's complement on result */
token++;
} else if (*token == '-') {
negate++;
token++;
}
if (*token == '0') {
token++;
c = *token;
if (c == '\0') {
*valuep = 0; /* value is 0 */
return (0);
}
if (c == 'x' || c == 'X') {
radix = 16;
token++;
} else {
radix = 8;
}
} else {
radix = 10;
}
while ((c = *token++)) {
switch (radix) {
case 8:
if (c >= '0' && c <= '7') {
c -= '0';
} else {
return (-1); /* invalid number */
}
break;
case 10:
if (c >= '0' && c <= '9') {
c -= '0';
} else {
return (-1); /* invalid number */
}
break;
case 16:
if (c >= 'a' && c <= 'f') {
c = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
c = c - 'A' + 10;
} else if (c >= '0' && c <= '9') {
c -= '0';
} else {
return (-1); /* invalid number */
}
break;
}
}
if (onescompl)
if (negate)
return (0);
}
/*
* returns the field from the token
*/
static config_field_t
{
cfgvar = &usbcfg_varlist[0];
break;
} else {
cfgvar++;
}
}
}
/* ARGSUSED */
static token_t
{
char *cp;
/*
* Note the beginning of a token
*/
switch (ch) {
case '=':
break;
case '&':
break;
case '|':
break;
case '*':
break;
case '#':
break;
case ':':
break;
case ';':
break;
case ',':
break;
case '/':
break;
case ' ':
case '\t':
case '\f':
token = WHITE_SPACE;
break;
case '\n':
case '\r':
break;
case '"':
cp--;
badquote = 0;
switch (ch) {
case '\n':
case -1:
"Missing \"");
*cp++ = '\n';
badquote = 1;
break;
case '\\':
/* escape the character */
break;
}
oval = 0;
ch -= '0';
}
/* check for character overflow? */
if (oval > 127) {
"Character overflow detected.\n");
}
break;
default:
break;
}
}
break;
default:
if (ch == -1) {
break;
}
/*
* detect a lone '-' (including at the end of a line), and
* identify it as a 'name'
*/
if (ch == '-') {
cp--;
break;
}
}
if (ch == '0') {
}
} else {
goto digit;
}
} else {
}
}
if (ch != '\\') {
} else {
/*
* if the character was a backslash,
* back up so we can overwrite it with
* the next (i.e. escaped) character.
*/
cp--;
}
if (ch == '\\')
}
} else {
return (-1);
}
break;
}
*cp = '\0';
return (token);
}
/*
* Leave NEWLINE as the next character.
*/
static void
{
register int ch;
break;
}
}
}
/*
* Fetch one record from the USBCONF_FILE
*/
static token_t
{
enum {
DPRINTF("usb_get_conf_rec:\n");
return (0);
}
switch (token) {
case STAR:
case POUND:
/* skip comments */
break;
case NEWLINE:
linenum++;
break;
case NAME:
case STRING:
switch (parse_state) {
case USB_NEWVAR:
"Syntax Error: Invalid field %s",
tokval);
} else {
/*
* Note the beginning of a record
*/
if (sor) {
}
}
break;
case USB_VAR_VALUE:
if ((cfgvar == USB_VENDOR) ||
(cfgvar == USB_PRODUCT) ||
(cfgvar == USB_CFGNDX)) {
"Syntax Error: Invalid value %s "
"for field: %s\n", tokval,
switch (cfgvar) {
case USB_SELECTION:
break;
case USB_SRNO:
break;
case USB_PATH:
break;
case USB_DRIVER:
break;
default:
}
} else {
"Syntax Error: Invalid value %s "
"for field: %s\n", tokval,
}
break;
case USB_ERROR:
/* just skip */
break;
default:
"Syntax Error: at %s", tokval);
break;
}
break;
case EQUALS:
if (parse_state == USB_CONFIG_VAR) {
"Syntax Error: unexpected '='");
} else {
}
} else if (parse_state != USB_ERROR) {
"Syntax Error: unexpected '='");
}
break;
case HEXVAL:
case DECVAL:
USB_NONE)) {
switch (cfgvar) {
case USB_VENDOR:
break;
case USB_PRODUCT:
break;
case USB_CFGNDX:
break;
default:
"Syntax Error: Invalid value for "
}
} else if (parse_state != USB_ERROR) {
tokval);
}
break;
default:
"Syntax Error: at: %s", tokval);
break;
}
}
return (token);
}
/*
* Here we compare the two records and determine if they are the same
*/
static boolean_t
{
DPRINTF("usb_cmp_rec:\n");
} else {
return (B_FALSE);
}
/*
* Comparing on this is tricky. At this point
* First compare till .../hubd@P
* Second compare is just P in "device@P"
*
* XXX: note that we assume P as one character
* as there are no 2 digit hubs in the market.
*/
} else {
return (B_FALSE);
}
return (B_FALSE);
} else {
return (B_TRUE);
}
} else {
return (B_FALSE);
}
}
/*
* free the record allocated in usb_get_conf_rec
*/
static void
{
return;
}
}
int
{
int file;
DPRINTF("add_entry: driver=%s, path=%s\n",
return (CFGA_USB_CONFIG_FILE);
}
}
(void) mutex_lock(&file_lock);
/* Initialize the cfgrec */
/* open config_map.conf file */
if (file == -1) {
"failed to open config file\n");
(void) mutex_unlock(&file_lock);
return (CFGA_USB_CONFIG_FILE);
}
"failed to lock config file\n");
(void) mutex_unlock(&file_lock);
return (CFGA_USB_LOCK_FILE);
}
/*
* These variables need to be reinitialized here as they may
* have been modified by a previous thread that called this
* function
*/
linenum = 1;
cntr = 0;
frec = 0;
brec = 0;
btoken = 0;
DPRINTF("add_entry: failed to fstat config file\n");
goto exit;
}
DPRINTF("add_entry: failed to fstat config file\n");
goto exit;
}
DPRINTF("add_entry: failed to read config file\n");
goto exit;
}
/* set up for reading the file */
if (user_rec) {
}
}
if (found) {
DPRINTF("FOUND\n");
"idProduct=0x%x ",
}
}
}
}
}
/*
* Seek to the beginning of the record
*/
DPRINTF("add_entry: failed to lseek config file\n");
goto exit;
}
/*
* Write the modified record
*/
DPRINTF("add_entry: failed to write config file\n");
goto exit;
}
/*
* Write the rest of the file as it was
*/
DPRINTF("add_entry: failed to write config file\n");
goto exit;
}
} else {
DPRINTF("!FOUND\n");
"selection=%s idVendor=0x%x idProduct=0x%x ",
}
}
}
}
}
/*
* Incase this is the first entry, add it after the comments
*/
if (frec == 0) {
}
/*
* Go to the beginning of the records
*/
DPRINTF("add_entry: failed to lseek config file\n");
goto exit;
}
/*
* Add the entry
*/
DPRINTF("add_entry: failed to write config file\n");
goto exit;
}
/*
* write the remaining file as it was
*/
DPRINTF("add_entry: failed to write config file\n");
goto exit;
}
}
/* no error encountered */
if (rval == CFGA_USB_OK) {
}
exit:
}
DPRINTF("add_entry: failed to unlock config file\n");
}
(void) mutex_unlock(&file_lock);
return (rval);
}