hidparser.c revision 41d01d3135be8275a23b98140fdcac704a7ae8d3
/*
* 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"
/*
* hidparser: Parser to generate parse tree for Report Descriptors
* in HID devices.
*/
static usb_log_handle_t hparser_log_handle;
/*
* Array used to store corresponding strings for the
* different item types for debugging.
*/
/*
* modload support
*/
extern struct mod_ops mod_miscops;
&mod_miscops, /* Type of module */
"HID PARSER %I%"
};
static struct modlinkage modlinkage = {
};
int
_init(void)
{
if (rval == 0) {
}
return (rval);
}
int
_fini()
{
if (rval == 0) {
}
return (rval);
}
int
{
}
/*
* These functions are used internally in the parser.
* local declarations
*/
static void hidparser_scan(hidparser_tok_t *);
static int hidparser_Items(hidparser_tok_t *);
static int hidparser_LocalItem(hidparser_tok_t *);
static int hidparser_GlobalItem(hidparser_tok_t *);
static int hidparser_ItemList(entity_item_t **,
hidparser_tok_t *);
static int hidparser_ReportDescriptor(entity_item_t **,
hidparser_tok_t *);
static int hidparser_ReportDescriptorDash(entity_item_t **,
hidparser_tok_t *);
static int hidparser_MainItem(entity_item_t **,
hidparser_tok_t *);
static void hidparser_free_attribute_list(
static void hidparser_add_attribute(hidparser_tok_t *);
static entity_attribute_t *hidparser_alloc_attrib_list(int);
static void hidparser_report_err(int, int,
int, int, char *);
static int hidparser_isvalid_item(int);
int);
static void hidparser_global_err_check(entity_item_t *);
static void hidparser_local_err_check(entity_item_t *);
static void hidparser_mainitem_err_check(entity_item_t *);
static unsigned int hidparser_find_unsigned_val(
static int hidparser_find_signed_val(
static void hidparser_check_correspondence(
entity_item_t *, int, int, int,
int, char *, char *);
static void hidparser_check_minmax_val(entity_item_t *,
int, int, int, int);
static void hidparser_check_minmax_val_signed(
int, int, int, int);
static void hidparser_error_delim(entity_item_t *, int);
static int hidparser_get_usage_attribute_report_des(
static int hidparser_get_packet_size_report_des(
uint32_t *);
static int hidparser_get_main_item_data_descr_main(
uint32_t *);
static void hidparser_print_entity(
int indent_level);
static void hidparser_print_this_attribute(
char *ident_space);
static int hidparser_main(unsigned char *, size_t,
entity_item_t **);
static void hidparser_initialize_items();
static void hidparser_free_report_descr_handle(
entity_item_t *);
static int hidparser_print_report_descr_handle(
int indent_level);
static int hidparser_get_usage_list_in_order_internal(
static void hidparser_fill_usage_info(
static int hidparser_get_report_id_list_internal(
/*
* The hidparser_lookup_first(N) of a non-terminal N is stored as an array of
* integer tokens, terminated by 0. Right now there is only one element.
*/
static hidparser_terminal_t first_Items[] = {
0
};
/*
* Each non-terminal is represented by a function. In a top-down parser,
* whenever a non-terminal is encountered on the state diagram, the
* corresponding function is called. Because of the grammar, there is NO
* backtracking. If there is an error in the middle, the parser returns
* HIDPARSER_FAILURE
*/
static hidparser_terminal_t *hid_first_list[] = {
};
/*
* hidparser_parse_report_descriptor:
* Calls the main parser routine
*/
int
unsigned char *descriptor,
{
int error = 0;
if (error != HIDPARSER_SUCCESS) {
return (HIDPARSER_FAILURE);
} else {
sizeof (hidparser_handle), KM_SLEEP);
return (HIDPARSER_SUCCESS);
}
}
/*
* hidparser_free_report_descriptor_handle:
* Frees the parse_handle which consists of a pointer to the parse
* tree and a pointer to the Hid descriptor structure
*/
int
{
if (parse_handle != NULL) {
if (parse_handle != NULL) {
}
}
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_get_country_code:
* Return the bCountryCode from the Hid Descriptor
* to the hid module.
*/
int
{
if ((parser_handle == NULL) ||
return (HIDPARSER_FAILURE);
}
*country_code =
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_get_packet_size:
* Get the packet size(sum of REPORT_SIZE * REPORT_COUNT)
* corresponding to a report id and an item type
*/
int
{
hidparser_handle_parse_tree == NULL)) {
return (HIDPARSER_FAILURE);
}
*size = 0;
return (hidparser_get_packet_size_report_des(
}
/*
* hidparser_get_packet_size_report_des:
* Get the packet size(sum of REPORT_SIZE * REPORT_COUNT)
* corresponding to a report id and an item type
*/
int
{
foundsize = 0;
foundcount = 0;
right_report_id = 0;
while (current) {
size);
temp = 1;
foundsize = 0;
foundcount = 0;
foundreportid = 0;
if (attribute->entity_attribute_tag ==
foundreportid = 1;
if ((attribute->
entity_attribute_value[0]) ==
report_id) {
right_report_id = 1;
}
} else if (attribute->entity_attribute_tag ==
foundsize = 1;
if (foundcount == 1) {
if (report_id &&
break;
}
}
} else if (attribute->entity_attribute_tag ==
foundcount = 1;
if (foundsize == 1) {
if (report_id &&
break;
}
}
}
} /* end while */
if (foundreportid) {
if (right_report_id) {
}
} else if (report_id == HID_REPORT_ID_UNDEFINED) {
/* Just sanity checking */
}
right_report_id = 0;
} /* end else if */
} /* end while current */
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_get_usage_attribute:
* Get the attribute value corresponding to a particular
* report id, main item and usage
*/
int
int *usage_attribute_value)
{
}
/*
* hidparser_get_usage_attribute_report_des:
* Called by the wrapper function hidparser_get_usage_attribute()
*/
static int
int *usage_attribute_value)
{
short attvalue;
found_page = 0;
found_ret_value = 0;
found_usage_id = 0;
foundreportid = 0;
right_report_id = 0;
while (current) {
if (usage_id == HID_USAGE_UNDEFINED) {
found_usage_id = 1;
}
return (HIDPARSER_SUCCESS);
}
/* Match Item Type */
if (attribute->entity_attribute_tag ==
R_ITEM_USAGE) {
found_usage_id = 1;
} else {
/*
* If we are trying to find out
* say, report size of usage =
* 0, a m.i with a valid usage
* will not contain that
*/
if (usage_id ==
found_usage_id = 0;
}
}
if (found_usage_id && attribute->
entity_attribute_length == 3) {
/*
* This is an extended usage ie.
* usage page in upper 16 bits
* or-ed with usage in the lower
* 16 bits.
*/
if (HID_USAGE_PAGE(usage) &&
HID_USAGE_PAGE(usage) ==
usage_page) {
found_page = 1;
} else {
found_usage_id = 0;
}
}
} else if (attribute->entity_attribute_tag ==
if (attribute->
entity_attribute_value[0] ==
usage_page) {
/* Match Usage Page */
found_page = 1;
}
} else if (attribute->entity_attribute_tag ==
foundreportid = 1;
if (attribute->
entity_attribute_value[0] ==
report_id) {
right_report_id = 1;
}
}
if (attribute->entity_attribute_tag ==
/* Match attribute */
found_ret_value = 1;
if (attribute->
entity_attribute_length == 2) {
attvalue =
(attribute->
0xff) |
(attribute->
entity_attribute_value[1] <<
8);
}
}
}
if (foundreportid) {
if (right_report_id) {
return (HIDPARSER_SUCCESS);
} else if (report_id ==
return (HIDPARSER_SUCCESS);
}
} else {
return (HIDPARSER_SUCCESS);
}
}
}
/*
* search the next main item, right sibling of this one
*/
/* Don't change foundreportid */
right_report_id = 0;
} else {
break;
}
}
/* Don't give junk result */
*usage_attribute_value = 0;
return (HIDPARSER_NOT_FOUND);
}
/*
* hidparser_get_main_item_data_descr:
* Get the data value corresponding to a particular
* Main Item (Input, Output, Feature)
*/
int
{
}
/*
* hidparser_get_main_item_data_descr_main:
* Called by the wrapper function hidparser_get_main_item_data_descr()
*/
static int
{
found_page = 0;
found_usage_id = 0;
foundreportid = 0;
right_report_id = 0;
while (current) {
if (usage_id == HID_USAGE_UNDEFINED) {
found_usage_id = 1;
}
return (HIDPARSER_SUCCESS);
}
/* Match Item Type */
if (report_id == HID_REPORT_ID_UNDEFINED) {
}
if (attribute->entity_attribute_tag ==
R_ITEM_USAGE) {
found_usage_id = 1;
if (attribute->
3) {
if (HID_USAGE_PAGE(
usage) &&
usage) ==
usage_page) {
found_page = 1;
} else {
found_usage_id = 0;
}
}
if (found_usage_id &&
found_page &&
current->
break;
}
}
} else if ((attribute->entity_attribute_tag ==
(attribute->entity_attribute_value[0] ==
usage_page)) {
/* Match Usage Page */
found_page = 1;
if (found_usage_id && foundreportid &&
current->
break;
}
} else if (attribute->entity_attribute_tag ==
foundreportid = 1;
if (attribute->
entity_attribute_value[0] ==
report_id) {
right_report_id = 1;
} else {
break;
}
}
}
if (foundreportid) {
if (right_report_id) {
if (found_usage_id && found_page) {
return (HIDPARSER_SUCCESS);
}
}
}
}
/*
* search the next main item, right sibling of this one
*/
} else {
break;
}
}
return (HIDPARSER_NOT_FOUND);
}
/*
* hidparser_get_top_level_collection_usage:
* Get the usage page and usage for the top level collection item
*/
int
{
int found_usage_id = 0;
int found_page = 0;
if ((parse_handle == NULL) ||
return (HIDPARSER_FAILURE);
return (HIDPARSER_FAILURE);
}
found_usage_id = 1;
if (HID_USAGE_PAGE(usage)) {
found_page = 1;
}
}
if (found_usage_id && found_page) {
return (HIDPARSER_SUCCESS);
}
} else if (attribute->entity_attribute_tag ==
found_page = 1;
if (found_usage_id && found_page) {
return (HIDPARSER_SUCCESS);
}
}
}
return (HIDPARSER_FAILURE);
}
/*
* hidparser_get_usage_list_in_order:
* Find all the usages corresponding to a main item and report id.
* Note that only short items are supported.
*
* Arguments:
* parser_handle:
* hid parser handle
* report id:
* report id of the particular report where the usages belong to
* main_item_type:
* type of report, either Input, Output, or Feature
* usage_list:
* Filled in with the pointer to the first element of the
* usage list
*
* Return values:
* HIDPARSER_SUCCESS - returned success
* HIDPARSER_NOT_FOUND - usage specified by the parameters was not found
* HIDPARSER_FAILURE - unspecified failure
*/
int
{
if ((parser_handle == NULL) ||
return (HIDPARSER_FAILURE);
}
rpt->no_of_usages = 0;
}
static int
{
/* setup wrapper function */
int i = 0;
int rval;
found_usage_min = 0;
found_usage_max = 0;
foundreportid = 0;
right_report_id = 0;
while (current) {
/*
* find collection usage information for this
* collection
*/
valid_usage = 0;
if (attribute->entity_attribute_tag ==
R_ITEM_USAGE) {
valid_usage = 1;
}
}
if (!valid_usage) {
}
if (rval != HIDPARSER_SUCCESS) {
return (rval);
}
/* Match Item Type */
foundreportid = 0;
right_report_id = 0;
found_usage_min = 0;
found_usage_max = 0;
valid_usage = 0;
switch (attribute->entity_attribute_tag) {
case R_ITEM_REPORT_ID:
foundreportid = 1;
if (attribute->
entity_attribute_value[0] ==
report_id) {
right_report_id = 1;
} else {
/* different report id */
valid_usage = 1;
}
break;
case R_ITEM_USAGE_MIN:
found_usage_min = 1;
break;
case R_ITEM_USAGE_MAX:
found_usage_max = 1;
if (attribute->
entity_attribute_length == 3) {
}
break;
case R_ITEM_SET_DELIMITER:
break;
}
/*
* If we have a usage item, and we had
* a report id match (or report ids
* are not present), put the usage
* item into the list.
* Don't put undefined usage items
* (HID_USAGE_UNDEFINED, 0) into
* the list; a 0 usage item is
* used to match padding fields
* that don't have an attached
* usage.
*/
if ((!foundreportid ||
(foundreportid && right_report_id)) &&
R_ITEM_USAGE) &&
/* Put in usage list */
return (HIDPARSER_FAILURE);
}
if (attribute->
entity_attribute_length == 3) {
if (HID_USAGE_PAGE(usage))
ui.usage_page =
usage);
}
i = rpt->no_of_usages++;
valid_usage = 1;
/* skip over alternate usages */
while (attribute->
}
}
}
/*
* If we have a usage min & max, and
* we had a report id match(or report
* ids are not present) put the usage
* range into the list.
*/
if ((!foundreportid || (foundreportid &&
right_report_id)) &&
/* Put in usage list */
return (HIDPARSER_FAILURE);
}
i = rpt->no_of_usages++;
valid_usage = 1;
/* skip over alternate usages */
while (attribute->
}
}
found_usage_min = found_usage_max = 0;
}
}
/*
* This main item contains no usage
* Fill in with usage "UNDEFINED".
* If report id is valid, only the
* main item with matched report id
* can be filled in.
*/
if (!valid_usage) {
return (HIDPARSER_FAILURE);
}
i = rpt->no_of_usages++;
}
}
} /* end while current */
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_fill_usage_info():
* Fill in the mandatory item information for a main item.
* See HID 6.2.2.
*/
static void
{
while (attribute) {
switch (attribute->entity_attribute_tag) {
case R_ITEM_LOGICAL_MINIMUM:
break;
case R_ITEM_LOGICAL_MAXIMUM:
break;
case R_ITEM_REPORT_COUNT:
break;
case R_ITEM_REPORT_SIZE:
break;
case R_ITEM_USAGE_PAGE:
& 0xffff;
break;
}
}
}
/*
* hidparser_get_report_id_list:
* Return a list of all report ids used for descriptor items
* corresponding to a main item.
*
* Arguments:
* parser_handle:
* hid parser handle
* main_item_type:
* type of report, either Input, Output, or Feature
* report_id_list:
* Filled in with a list of report ids found in the descriptor
*
* Return values:
* HIDPARSER_SUCCESS - returned success
* HIDPARSER_FAILURE - unspecified failure
*/
int
{
if ((parser_handle == NULL) ||
return (HIDPARSER_FAILURE);
}
}
/*
* hidparser_get_report_id_list_internal:
* internal function that generates list of all report ids
*/
int
{
/* setup wrapper function */
int i = 0;
int rval;
while (current) {
if (rval != HIDPARSER_SUCCESS) {
return (rval);
}
/* Match Item Type */
if (attribute->entity_attribute_tag ==
/* Found a Report ID */
/* Report ID already in list? */
for (i = 0;
i < id_lst->no_of_report_ids;
i++) {
report_id[i]) {
break;
}
}
if (i >= id_lst->no_of_report_ids) {
/*
* New Report ID found, put
* in list
*/
if (i >= REPORT_ID_MAX) {
return
}
}
}
}
}
} /* end while current */
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_print_report_descr_handle:
* Functions to print the parse tree. Currently not
* being called.
*/
static int
int indent_level)
{
while (current) {
/* do children */
} else /* just a regular entity */ {
}
}
return (HIDPARSER_SUCCESS);
}
#define SPACE_PER_LEVEL 5
/*
* hidparser_print_entity ;
* Prints the entity items recursively
*/
static void
{
char indent_space[256];
int count;
indent_space[count] = 0;
while (attr) {
}
}
/*
* hidparser_print_this_attribute:
* Prints the attribute passed in the argument
*/
static void
char *ident_space)
{
if (ident_space == NULL) {
"%s(0x%X)",
} else {
"%s%s(0x%X)", ident_space,
}
}
/*
* The next few functions will be used for parsing using the
* grammar:
*
* Start -> ReportDescriptor <EOF>
*
* ReportDescriptor -> ItemList
*
* ItemList -> Items MainItem ItemList
* | epsilon
*
* MainItem -> BeginCollection ItemList EndCollection
* | Input
* | Output
* | Feature
*
* Items -> GlobalItem Items
* | LocalItem Items
* | SetDelimiterOpen LocalItemList
* SetDelimiterClose Items
* | epsilon
*
* LocalItemList -> LocalItem Temp2
*
* Temp2 -> LocalItem Temp2
* | epsilon
*
* GlobalItem -> UsagePage
* | LogicalMinimum
* | LogicalMaximum
* | PhysicalMinimum
* | PhysicalMaximum
* | Unit
* | Exponent
* | ReportSize
* | ReportCount
* | ReportID
*
* LocalItem -> Usage
* | UsageMinimum
* | UsageMaximum
* | DesignatorIndex
* | DesignatorMinimum
* | StringIndex
* | StringMinimum
* | StringMaximum
*
*/
/*
* hidparser_lookup_first:
* Looks up if token belongs to the FIRST of the function tag
* that is passed through the first argument
*/
static int
int token)
{
int *itemp;
while (*itemp != 0) {
/* get the next terminal on the list */
return (HIDPARSER_SUCCESS);
}
itemp++;
}
/* token is not on the FIRST list */
return (HIDPARSER_FAILURE);
}
/*
* hidparser_main:
* Function called from hidparser_parse_report_descriptor()
* to parse the Report Descriptor
*/
static int
hidparser_main(unsigned char *descriptor,
{
int retval;
/*
* Free the Local & Global item list
* It maybe the case that no tree has been built
* up but there have been allocation in the attribute
* & control lists
*/
if (scan_ifp->hidparser_tok_gitem_head) {
}
if (scan_ifp->hidparser_tok_litem_head) {
}
return (retval);
}
/*
* hidparser_ReportDescriptorDash:
* Synthetic start symbol, implements
* hidparser_ReportDescriptor <EOF>
*/
static int
{
return (HIDPARSER_SUCCESS);
}
/*
* In case of failure, free the kernel memory
* allocated for partial building of the tree,
* if any
*/
(void) hidparser_free_report_descr_handle(*item_ptr);
}
return (HIDPARSER_FAILURE);
}
/*
* hidparser_ReportDescriptor:
* Implements the Rule:
* ReportDescriptor -> ItemList
*/
static int
{
/*
* We do not search for the token in FIRST(ReportDescriptor)
* since -
*
* FIRST(ReportDescriptor) == FIRST(ItemList)
* ReportDescriptor ----> ItemList
*/
return (HIDPARSER_SUCCESS);
}
return (HIDPARSER_FAILURE);
}
/*
* hidparser_ItemList:
* Implements the Rule:
* ItemList -> Items MainItem ItemList | epsilon
*
* This function constructs the tree on which depends the "hidparser"
* consumer functions. Basically the structure of the tree is
*
* C--[RS]->EC--[RS]->C--[RS]->EC..(and so on)
* |
* [CH] <== This relationship is true for other "C's"
* | also.
* v
* C/-------------/I/O/F <== [ Any of these ]
* | ------
* | |
* v v
* [CH | RS] [ RS ]
* C/I/O/F | EC I/O/F
* |
* |
* and so on...
*
* where C = Collection
* EC = EndCollection
* I = Input
* O = Output
* F = Feature "Main" Items.
*
* and the relationships are [RS] for right sibling and [CH] for
* child. [CH | RS ] stands for "child or right sibling" with the
* possible values below it.
*/
static int
{
while (scan_ifp->hidparser_tok_token != 0) {
return (HIDPARSER_FAILURE);
}
"Invalid MAIN item 0x%x in input stream",
return (HIDPARSER_FAILURE);
}
}
"Start Collection:cache_ei = 0x%lx,"
" curr_ei = 0x%lx",
continue;
}
if (prev_ei->entity_item_type ==
} else {
}
} else if (curr_ei->entity_item_type ==
"End Collection: cache_ei = 0x%lx, "
"curr_ei = 0x%lx",
/*
* As will be the case for final end
* collection.
*/
}
} else {
if (prev_ei->entity_item_type ==
"Main Item: token = 0x%x, "
"curr_ei = 0x%lx "
"will be the child of prev_ei "
"= 0x%lx, "
"cache_ei being 0x%lx",
} else {
"Main Item: token = 0x%x, "
"curr_ei = 0x%lx "
"will be the right sibling of "
"prev_ei = 0x%lx, "
"cache_ei being 0x%lx",
}
}
}
/* Something wrong happened */
"Failed to parse report descriptor");
return (HIDPARSER_FAILURE);
}
(void) hidparser_print_report_descr_handle(cache_ei, 0);
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_MainItem:
* Implements the Rule:
* MainItem -> BeginCollection ItemList EndCollection
* | Input
* | Output
* | Feature
*/
static int
{
switch (scan_ifp->hidparser_tok_token) {
case R_ITEM_INPUT:
/* FALLTHRU */
case R_ITEM_OUTPUT:
/* FALLTHRU */
case R_ITEM_FEATURE:
case R_ITEM_COLLECTION:
case R_ITEM_END_COLLECTION:
"hidparser_MainItem:index = 0x%x token = 0x%x",
return (HIDPARSER_SUCCESS);
default:
break;
}
return (HIDPARSER_FAILURE);
}
/*
* hidparser_Items:
* Implements the Rule:
* Items -> GlobalItem Items
* | LocalItem Items
* | SetDelimiterOpen LocalItemList
* SetDelimiterClose Items
* | epsilon
*/
static int
{
if (token == R_ITEM_SET_DELIMITER) {
} else {
}
} else {
if (scan_ifp->hidparser_tok_text[0] !=
0) {
} else {
}
}
(void) hidparser_LocalItem(scan_ifp);
} else if (hidparser_GlobalItem(scan_ifp) ==
}
}
return (HIDPARSER_SUCCESS); /* epsilon */
}
/*
* hidparser_GlobalItem:
* Implements the Rule:
* GlobalItem -> UsagePage
* | LogicalMinimum
* | LocgicalMaximum
* | PhysicalMinimum
* | PhysicalMaximum
* | Unit
* | Exponent
* | ReportSize
* | ReportCount
* | ReportID
*/
static int
{
int i;
switch (scan_ifp->hidparser_tok_token) {
case R_ITEM_USAGE_PAGE:
/* Error check */
for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) {
/* Undefined data value: 0 */
if (scan_ifp->hidparser_tok_text[i] == 0) {
0,
"Data field should be non-Zero");
}
/* Reserved values 0x0A-0xFE */
else if ((scan_ifp->hidparser_tok_text[i] >=
0x0a) &&
(scan_ifp->hidparser_tok_text[i] <=
0xFE)) {
1,
"Data field should not use "
"reserved values");
}
}
break;
case R_ITEM_UNIT:
/* FALLTHRU */
case R_ITEM_EXPONENT:
/*
* Error check:
* Nibble 7 should be zero
*/
0xf0) != 0) {
0,
"Data field reserved bits should "
"be Zero");
}
}
break;
case R_ITEM_REPORT_COUNT:
/*
* Error Check:
* Report Count should be nonzero
*/
for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) {
if (scan_ifp->hidparser_tok_text[i])
break;
}
if (i == scan_ifp->hidparser_tok_leng) {
0,
"Report Count = 0");
}
break;
case R_ITEM_REPORT_ID:
/*
* Error check:
* Report Id should be nonzero & <= 255
*/
1,
"Must be contained in a byte");
}
if (!scan_ifp->hidparser_tok_text[0]) {
0,
"Report Id must be non-zero");
}
break;
case R_ITEM_LOGICAL_MINIMUM:
break;
case R_ITEM_LOGICAL_MAXIMUM:
break;
case R_ITEM_PHYSICAL_MINIMUM:
break;
case R_ITEM_PHYSICAL_MAXIMUM:
break;
case R_ITEM_REPORT_SIZE:
break;
case R_ITEM_PUSH:
if (scan_ifp->hidparser_tok_leng != 0) {
0,
"Data Field size should be zero");
} else {
sizeof (entity_attribute_stack_t),
KM_SLEEP);
if (scan_ifp->hidparser_head) {
}
}
break;
case R_ITEM_POP:
if (scan_ifp->hidparser_tok_leng != 0) {
0,
"Data Field size should be zero");
} else {
/* Free the current global list */
sizeof (entity_attribute_stack_t));
}
break;
default:
return (HIDPARSER_FAILURE);
/*NOTREACHED*/
}
"hidparser_GlobalItem:index = 0x%x token = 0x%x",
return (HIDPARSER_SUCCESS);
}
/*
* hidparser_LocalItem:
* Implements the Rule:
* LocalItem -> Usage
* | UsageMinimum
* | UsageMaximum
* | DesignatorIndex
* | DesignatorMinimum
* | StringIndex
* | StringMinimum
* | StringMaximum
*/
static int
{
int i;
switch (scan_ifp->hidparser_tok_token) {
case R_ITEM_USAGE:
/*
* Error Check:
* Data Field should be nonzero
*/
for (i = 0; i < scan_ifp->hidparser_tok_leng; i++) {
if (scan_ifp->hidparser_tok_text[i])
break;
}
if (i == scan_ifp->hidparser_tok_leng) {
0,
"Data Field should be non-zero");
}
/* FALLTHRU */
case R_ITEM_USAGE_MIN:
/* FALLTHRU */
case R_ITEM_USAGE_MAX:
/* FALLTHRU */
case R_ITEM_DESIGNATOR_INDEX:
/* FALLTHRU */
case R_ITEM_DESIGNATOR_MIN:
/* FALLTHRU */
case R_ITEM_STRING_INDEX:
/* FALLTHRU */
case R_ITEM_STRING_MIN:
/* FALLTHRU */
case R_ITEM_STRING_MAX:
/* FALLTHRU */
case R_ITEM_SET_DELIMITER:
"hidparser_LocalItem:index = 0x%x token = 0x%x",
return (HIDPARSER_SUCCESS);
/*NOTREACHED*/
default:
break;
}
return (HIDPARSER_FAILURE);
}
/*
* hidparser_allocate_entity:
* Allocate Item of type 'type', length 'leng' and
* params 'text'. Fill in the attributes allocated
* so far from both the local and global item lists.
* Make the child and sibling of the item NULL.
*/
static entity_item_t *
{
if (len != 0) {
}
/*
* Copy attributes from entity attribute state table if not
* end collection.
*/
if (entity_type != R_ITEM_END_COLLECTION) {
/*
* append the control attributes, then clear out the control
* attribute state table list
*/
if (entity->entity_item_attributes) {
} else {
}
}
return (entity);
}
/*
* hidparser_add_attribute:
* Add an attribute to the global or local item list
* If the last 4th bit from right is 1, add to the local item list
* Else add to the global item list
*/
static void
{
if (len == 0) {
"hidparser_add_attribute: len = 0 for item = 0x%x",
entity);
return;
}
if (entity & HIDPARSER_ISLOCAL_MASK) {
} else {
}
/*
* remove attribute if it is already on list, except
* for control attributes(local items), as we could have
* multiple usages...
* unless we want to hassle with checking for unique parameters.
*/
while (elem) {
!(entity & HIDPARSER_ISLOCAL_MASK)) {
} else {
}
}
/* create new attribute for this entry */
/* attach to end of list */
}
/*
* hidparser_alloc_attrib_list:
* Allocate space for n attributes , create a linked list and
* return the head
*/
static entity_attribute_t *
{
if (count <= 0) {
return (NULL);
}
count--;
while (count--) {
sizeof (entity_attribute_t), KM_SLEEP);
}
return (head);
}
/*
* hidparser_cp_attribute_list:
* Copies the Global item list pointed to by head
* We create a clone of the global item list here
* because we want to retain the Global items to
* the next Main Item.
*/
static entity_attribute_t *
{
if (!head) {
return (NULL);
}
current_src = head;
while (current_src) {
if (current_src->entity_attribute_next) {
} else {
}
}
return (return_value);
}
/*
* hidparser_find_attribute_end:
* Find the last item in the attribute list pointed to by head
*/
static entity_attribute_t *
{
return (NULL);
}
}
return (head);
}
/*
* hidparser_find_item_end:
* Search the siblings of items and find the last item in the list
*/
static entity_item_t *
{
if (!head) {
return (NULL);
}
while (head->entity_item_right_sibling) {
}
return (head);
}
/*
* hidparser_free_report_descr_handle:
* Free the parse tree pointed to by handle
*/
static void
{
while (current) {
"FREE 1: %s",
(void) hidparser_free_report_descr_handle(child);
} else {
}
}
hparser_log_handle, "FREE 2: %s",
}
}
}
/*
* hidparser_free_attribute_list:
* Free the attribute list pointed to by head
*/
static void
{
while (current) {
hparser_log_handle, "FREE: %s value_length = %d",
"\tvalue = 0x%x",
}
}
}
/*
* hidparser_initialize_items:
* Initialize items array before start scanning and parsing.
* This array of strings are used for printing purpose.
*/
static void
{
}
/*
* hidparser_scan:
* This function scans the input entity descriptor, sees the data
* length, returns the next token, data bytes and length in the
* scan_ifp structure.
*/
static void
{
int count;
int ch;
int parsed_length;
unsigned char *parsed_text;
unsigned char *entity_descriptor;
char err_str[32];
parsed_length = 0;
hparser_log_handle, "scanner: index = 0x%lx ch = 0x%x",
index++;
/*
* Error checking:
* Unrecognized items should be passed over
* by the parser.
* Section 5.4
*/
if (!(hidparser_isvalid_item(ch))) {
"Unknown or reserved item", ch);
goto next_item;
}
if (ch == EXTENDED_ITEM) {
0,
0x3E,
"Long item defined");
} else {
"scanner: parsed_length = %x", parsed_length);
/* 3 really means 4.. see p.21 HID */
if (parsed_length == 3)
}
"scanner: parsed_text[%d] = 0x%x,"
"index = 0x%lx",
index++;
}
hparser_log_handle, "scanner: lexical analyzer found 0x%x "
"before translation", ch);
} else {
scan_ifp->hidparser_tok_leng = 0;
}
}
/*
* hidparser_report_err:
* Construct and print the error code
* Ref: Hidview error check list
*/
static void
int err_type,
int tag,
int subcode,
char *msg)
{
unsigned int BmParserErrorCode = 0;
if (err_level) {
}
if (err_type) {
}
if (err_level) {
"err code = 0x%4x, err str = %s",
} else {
"wrn code = 0x%4x, wrn str = %s",
}
}
/*
* hidparser_isvalid_item:
* Find if the item tag is a valid one
*/
static int
{
if (tag == EXTENDED_ITEM) {
return (1);
}
tag &= 0xFC;
if ((tag == R_ITEM_INPUT) ||
(tag == R_ITEM_OUTPUT) ||
(tag == R_ITEM_COLLECTION) ||
(tag == R_ITEM_FEATURE) ||
(tag == R_ITEM_END_COLLECTION) ||
(tag == R_ITEM_USAGE_PAGE) ||
(tag == R_ITEM_LOGICAL_MINIMUM) ||
(tag == R_ITEM_LOGICAL_MAXIMUM) ||
(tag == R_ITEM_PHYSICAL_MINIMUM) ||
(tag == R_ITEM_PHYSICAL_MAXIMUM) ||
(tag == R_ITEM_EXPONENT) ||
(tag == R_ITEM_UNIT) ||
(tag == R_ITEM_REPORT_SIZE) ||
(tag == R_ITEM_REPORT_ID) ||
(tag == R_ITEM_REPORT_COUNT) ||
(tag == R_ITEM_PUSH) ||
(tag == R_ITEM_POP) ||
(tag == R_ITEM_USAGE) ||
(tag == R_ITEM_USAGE_MIN) ||
(tag == R_ITEM_USAGE_MAX) ||
(tag == R_ITEM_DESIGNATOR_INDEX) ||
(tag == R_ITEM_DESIGNATOR_MIN) ||
(tag == R_ITEM_DESIGNATOR_MAX) ||
(tag == R_ITEM_STRING_INDEX) ||
(tag == R_ITEM_STRING_MIN) ||
(tag == R_ITEM_STRING_MAX) ||
(tag == R_ITEM_SET_DELIMITER)) {
return (1);
} else {
return (0);
}
}
/*
* hidparser_lookup_attribute:
* Takes an item pointer(report structure) and a tag(e.g Logical
* Min) as input. Returns the corresponding attribute structure.
* Presently used for error checking only.
*/
static entity_attribute_t *
{
return (NULL);
}
return (temp);
}
}
return (NULL);
}
/*
* hidparser_global_err_check:
* Error checking for Global Items that need to be
* performed in MainItem
*/
static void
{
R_ITEM_LOGICAL_MAXIMUM, 0, 0);
R_ITEM_PHYSICAL_MAXIMUM, 0, 0);
R_ITEM_PHYSICAL_MAXIMUM, 0, 0,
"Must have a corresponding Physical min",
"Must have a corresponding Physical max");
1, 0, "Should have a corresponding Pop",
"Must have a corresponding Push");
}
/*
* hidparser_mainitem_err_check:
* Error checking for Main Items
*/
static void
{
int itemmask = 0;
while (attr) {
switch (attr->entity_attribute_tag) {
case R_ITEM_LOGICAL_MINIMUM:
itemmask |= 0x01;
break;
case R_ITEM_LOGICAL_MAXIMUM:
itemmask |= 0x02;
break;
case R_ITEM_REPORT_SIZE:
itemmask |= 0x04;
break;
case R_ITEM_REPORT_COUNT:
itemmask |= 0x08;
break;
case R_ITEM_USAGE_PAGE:
itemmask |= 0x10;
break;
default:
break;
} /* switch */
} /* while */
} /* if */
return;
}
if (itemmask != 0x1f) {
0,
}
}
/*
* hidparser_local_err_check:
* Error checking for Local items that is done when a MainItem
* is encountered
*/
static void
{
R_ITEM_USAGE_MAX, 0, 0,
"Must have a corresponding Usage Min",
"Must have a corresponding Usage Max");
R_ITEM_DESIGNATOR_MAX, 0, 0,
"Must have a corresponding Designator min",
"Must have a corresponding Designator Max");
R_ITEM_STRING_MAX, 0, 0,
"Must have a corresponding String min",
"Must have a corresponding String Max");
}
/*
* hidparser_find_unsigned_val:
* Find the value for multibyte data
* Ref: Section 5.8 of HID Spec 1.0
*/
static unsigned int
{
char *text;
int len, i;
unsigned int ret = 0;
for (i = 0; i < len; i++) {
}
return (ret);
}
/*
* hidparser_find_signed_val:
* Find the value for signed multibyte data
* Ref: Section 5.8 of HID Spec 1.0
*/
static signed int
{
char *text;
int len, i;
int ret = 0;
for (i = 0; i < len - 1; i++) {
}
if (len > 0) {
}
return (ret);
}
/*
* hidparser_check_correspondence:
* Check if the item item2 corresponding to item1 exists and vice versa
* If not report the appropriate error
*/
static void
int item_tag1,
int item_tag2,
int val1,
int val2,
char *str1,
char *str2)
{
val1,
str1);
}
val2,
str2);
}
}
/*
* hidparser_check_minmax_val:
* Check if the Min value <= Max and vice versa
* Print for warnings and errors have been taken care separately.
*/
static void
int item_tag1,
int item_tag2,
int val1,
int val2)
{
if (hidparser_find_unsigned_val(temp1) >
if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) ||
(item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) {
val1,
"unsigned: Min should be <= to Max");
} else {
val1,
"Min must be <= to Max");
}
}
if (hidparser_find_unsigned_val(temp2) <
if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) ||
(item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) {
val2,
"unsigned: Max should be >= to Min");
} else {
val2,
"Max must be >= to Min");
}
}
} /* if (temp1 != NULL) && (temp2 != NULL) */
}
/*
* hidparser_check_minmax_val_signed:
* Check if the Min value <= Max and vice versa
* Print for warnings and errors have been taken care separately.
*/
static void
int item_tag1,
int item_tag2,
int val1,
int val2)
{
if (hidparser_find_signed_val(temp1) >
if ((item_tag1 == R_ITEM_LOGICAL_MINIMUM) ||
(item_tag1 == R_ITEM_PHYSICAL_MINIMUM)) {
val1,
"signed: Min should be <= to Max");
} else {
val1,
"Min must be <= to Max");
}
}
if (hidparser_find_signed_val(temp2) <
if ((item_tag2 == R_ITEM_LOGICAL_MAXIMUM) ||
(item_tag2 == R_ITEM_PHYSICAL_MAXIMUM)) {
val2,
"signed: Max should be >= to Min");
} else {
val2,
"Max must be >= to Min");
}
}
} /* if (temp1 != NULL) && (temp2 != NULL) */
}
/*
* hidparser_error_delim:
* Error check for Delimiter Sets
*/
static void
{
switch (err) {
case HIDPARSER_DELIM_ERR1:
0,
"Must be Delimiter Open");
break;
case HIDPARSER_DELIM_ERR2:
0,
"Must be Delimiter Close");
break;
case HIDPARSER_DELIM_ERR3:
if ((attr->entity_attribute_tag !=
R_ITEM_USAGE) &&
(attr->entity_attribute_tag !=
R_ITEM_USAGE_MIN) &&
(attr->entity_attribute_tag !=
R_ITEM_USAGE_MAX)) {
3,
"May only contain Usage, "
"Usage Min and Usage Max");
}
}
break;
default:
break;
}
}
/*
* hidparser_find_max_packet_size_from_report_descriptor:
* find packet size of the largest report in the report descriptor
*/
void
{
int rval, i;
"hidparser_find_max_packet_size_from_report_descriptor");
/* get a list of input reports */
if (rval != HIDPARSER_SUCCESS) {
"No report id used");
} else {
"%d unique report IDs found in hid report descriptor",
for (i = 0; i < (report_id_list.no_of_report_ids); i++) {
}
}
if ((rval != HIDPARSER_SUCCESS) ||
(report_id_list.no_of_report_ids == 0)) {
/*
* since no report id is used, get the packet size
* for the only report available
*/
0, R_ITEM_INPUT, &packet_size);
"Not using report id prefix. HID packet size = %d",
} else {
/*
* hid device uses multiple reports with report id prefix byte.
* Find the longest input report.
* See HID 8.4.
*/
max_packet_size = 0;
max_report_id = 0;
for (i = 0; i < (report_id_list.no_of_report_ids); i++) {
&packet_size);
if (packet_size > max_packet_size) {
}
"Report ID %d has a packet size of %d",
}
"Report ID %d has the maximum packet size of %d",
}
}