#pragma module ug_barcode_support "X-1" /* ******************************************************************************** ** ** ** © Copyright 1976, 2006 Hewlett-Packard Development Company, L.P. ** ** ** ** Confidential computer software. Valid license from HP and/or ** ** its subsidiaries required for possession, use, or copying. ** ** ** ** Consistent with FAR 12.211 and 12.212, Commercial Computer Software, ** ** Computer Software Documentation, and Technical Data for Commercial ** ** Items are licensed to the U.S. Government under vendor's standard ** ** commercial license. ** ** ** ** Neither HP nor any of its subsidiaries shall be liable for technical ** ** or editorial errors or omissions contained herein. The information ** ** in this document is provided "as is" without warranty of any kind and ** ** is subject to change without notice. The warranties for HP products ** ** are set forth in the express limited warranty statements accompanying ** ** such products. Nothing herein should be construed as constituting an ** ** additional warranty. ** ** ** ******************************************************************************** ** ** ** FACILITY: ** ** Example ** ** ABSTRACT: ** ** This module has minimal code to support a USB barcode reader. It ** requires that the user has alread determined the vendor id and product ** id of the readers. The reader will have to be associated to UGDRVIER ** with an entry that look something like this: ** ** ** device = "Intermec barcode scanner" ** name = UG ** driver = sys$ugdriver ** begin_private ** usb_config_type = interface ** vendor_id = 1662 ** product_id = 256 ** release_number = 1 ** begin_interface ** interface_class = 3 ! Hid ** interface_sub_class = 1 ** interface_protocol = 1 ** end_interface ** end_private ** end_device ** ** The vendor and product ID'S also need to be supplied to the open ** barcode routine. They are used as part of a simple sanity check to ** make sure that we have the correct device. ** ** The user will also need to dump the HID data once to get the length ** of the input data from the scanner. A sample report is attached below: ** ** Item Hex Value ** -------------------------------------------------------------------------------- ** Usage Page Generic Desktop 05 01 ** Usage (reserved) 09 06 ** Collection Application a1 01 ** Usage Page Keyboard Keypad 05 07 ** Usage Minimum (e0) 19 e0 ** Usage Maximum (e7) 29 e7 ** Logical Minimum (00) 15 00 ** Logical Maximum (01) 25 01 ** Report Size (01) 75 01 ** Report Count (08) 95 08 ** Input (Data, Variable) 81 02 ** Report Count (01) 95 01 ** Report Size (08) 75 08 ** Input (Constant) 81 01 ** Report Count (05) 95 05 ** Report Size (01) 75 01 ** Usage Page LEDs 05 08 ** Usage Minimum (01) 19 01 ** Usage Maximum (05) 29 05 ** Output (Data, Variable) 91 02 ** Report Count (01) 95 01 ** Report Size (03) 75 03 ** Output (Constant) 91 01 ** Report Count (06) 95 06 ** Report Size (08) 75 08 ** Logical Minimum (00) 15 00 ** Logical Maximum (65) 25 65 ** Usage Page Keyboard Keypad 05 07 ** Usage Minimum (00) 19 00 ** Usage Maximum (65) 29 65 ** Input (Data, Array) 81 00 ** End Collection ** ** ** The determine the size of the input data you need to look for report ** count and report size fields that are followed by "Input" items. You will ** see 5 report size and count tags. The first, second and fith instances are ** the ones of interest. The total up to 8 bytes. Big warning this code ** assumes all items fall on byte boundaries. That may not always be the ** case. If so the decode_keys code will need to be rewritten. ** ** To get the report generated you need to compile this module with the ** symbol HID_DISPLAY defined. Then compule and link your code with ** barcode_support, and ug_hid_decode and run it. You can then recompile ** barcode_support and relink with out enabling the disply. ** ** ** AUTHOR: Forrest A. Kenney 08-September-2006 ** ** REVISION HISTORY: ** ** X-1 FAK001 Forrest A. Kenney 29_dECEMBER-2006 ** Initial check in. **/ /* ** Include files */ #include #include /* String descriptors */ #include /* VMS I/O function codes */ #include #include /* LIB RTL routines */ #include /* C signals */ #include /* System error codes */ #include /* System routines */ #include /* Stand I/O routines */ #include /* String functions */ #include #include #include "ugdef.h" /* UG definitions */ #include "ug_barcode.h" #include "ug_hid_decode.h" /* Globals */ int caps_lock = 0; int num_lock = 0; int scroll_lock = 0; #define REPORT_MAX 512 unsigned char report_desc[REPORT_MAX]; int report_size; #define CONTROL_S 19 #define CONTROL_Q 17 #define EDIT_TABLE_START 0x49 #define EDIT_TABLE_END 0x4e #define EDIT_SEQUENCE_LENGTH 4 unsigned char *usb_kbd_edit_table[] = { ((unsigned char *)"\33\133\065\176"), /* Find */ ((unsigned char *)"\33\133\066\176"), /* Insert Here */ ((unsigned char *)"\33\133\067\176"), /* Remove */ ((unsigned char *)"\33\133\070\176"), /* Select */ ((unsigned char *)"\33\133\071\176"), /* Prev Screen */ ((unsigned char *)"\33\133\072\176") /* Next Screen */ }; #define ARROW_TABLE_START 0x4F #define ARROW_TABLE_END 0x52 #define ARROW_SEQUENCE_LENGTH 3 unsigned char *usb_kbd_arrow_table[] = { ((unsigned char *)"\33\133\103"), /* Right arrow */ ((unsigned char *)"\33\133\104"), /* Left arrow */ ((unsigned char *)"\33\133\102"), /* Down arrow */ ((unsigned char *)"\33\133\101") /* Up arrow */ }; #define KEYPAD_TABLE_START 0x54 #define KEYPAD_TABLE_END 0x63 char usb_kbd_keypad_table[] = { '/', '*', '-', '+', 0x0d, '1', '2', '3', '4','5', '6', '7', '8', '9', '0', '.'}; #define LK_KEYPAD_COMMA 0x85 #define KEYBOARD_START 1 #define KEYBOARD_END 0X38 unsigned char usb_kbd_trans_table[][3] = { /* 0x00 reserved (no event indicated) */ { 0x00, 0x00, 0x00 }, /* 0x01 keyboard ErrorRollOver */ { 0xff, 0xff, 0xff }, /* 0x02 keyboard POSTFail */ { 0xff, 0xff, 0xff }, /* 0x03 keyboard ErrorUndefined */ { 0xff, 0xff, 0xff }, /* 0x04 keyboard a and A */ { 0x61, 0x41, 0x01 }, /* 0x05 keyboard b and B */ { 0x62, 0x42, 0x02 }, /* 0x06 keyboard c and C */ { 0x63, 0x43, 0x03 }, /* 0x07 keyboard d and D */ { 0x64, 0x44, 0x04 }, /* 0x08 keyboard e and E */ { 0x65, 0x45, 0x05 }, /* 0x09 keyboard f and F */ { 0x66, 0x46, 0x06 }, /* 0x0a keyboard g and G */ { 0x67, 0x47, 0x07 }, /* 0x0b keyboard h and H */ { 0x68, 0x48, 0x08 }, /* 0x0c keyboard i and I */ { 0x69, 0x49, 0x09 }, /* 0x0d keyboard j and J */ { 0x6a, 0x4a, 0x0a }, /* 0x0e keyboard k and K */ { 0x6b, 0x4b, 0x0b }, /* 0x0f keyboard l and L */ { 0x6c, 0x4c, 0x0c }, /* 0x10 keyboard m and M */ { 0x6d, 0x4d, 0x0d }, /* 0x11 keyboard n and N */ { 0x6e, 0x4e, 0x0e }, /* 0x12 keyboard o and O */ { 0x6f, 0x4f, 0x0f }, /* 0x13 keyboard p and P */ { 0x70, 0x50, 0x10 }, /* 0x14 keyboard q and Q */ { 0x71, 0x51, 0x11 }, /* 0x15 keyboard r and R */ { 0x72, 0x52, 0x12 }, /* 0x16 keyboard s and S */ { 0x73, 0x53, 0x13 }, /* 0x17 keyboard t and T */ { 0x74, 0x54, 0x14,}, /* 0x18 keyboard u and U */ { 0x75, 0x55, 0x15 }, /* 0x19 keyboard v and V */ { 0x76, 0x56, 0x16 }, /* 0x1a keyboard w and W */ { 0x77, 0x57, 0x17 }, /* 0x1b keyboard x and X */ { 0x78, 0x58, 0x18 }, /* 0x1c keyboard y and Y */ { 0x79, 0x59, 0x19 }, /* 0x1d keyboard z and Z */ { 0x7a, 0x5a, 0x1a }, /* 0x1e keyboard 1 and ! */ { 0x31, 0x21, 0x1b }, /* 0x1f keyboard 2 and @ */ { 0x32, 0x40, 0x1c }, /* 0x20 keyboard 3 and # */ { 0x33, 0x23, 0x1d }, /* 0x21 keyboard 4 and $ */ { 0x34, 0x24, 0x1e }, /* 0x22 keyboard 5 and % */ { 0x35, 0x25, 0x1f }, /* 0x23 keyboard 6 and % */ { 0x36, 0x5e, 0x20 }, /* 0x24 keyboard 7 and & */ { 0x37, 0x26, 0x21 }, /* 0x25 keyboard 8 and * */ { 0x38, 0x2a, 0x22 }, /* 0x26 keyboard 9 and ( */ { 0x39, 0x28, 0x23 }, /* 0x27 keyboard 0 and ) */ { 0x30, 0x29, 0x24 }, /* 0x28 keyboard Return (ENTER) */ { 0x0d, 0x0d, 0xff }, /* 0x29 keyboard ESCAPE */ { 0x1b, 0x1b, 0xff }, /* 0x2a keyboard DELETE (Backspace) */ { 0x7f, 0x7f, 0xff }, /* 0x2b keyboard Tab */ { 0x09, 0x09, 0xff }, /* 0x2c keyboard Spacebar */ { 0x20, 0x20, 0xff }, /* 0x2d keyboard - and (underscore) */ { 0x2d, 0x5f, 0xff }, /* 0x2e keyboard = and + */ { 0x3d, 0x2b, 0xff }, /* 0x2f keyboard [ and { */ { 0x5b, 0x7b, 0xff }, /* 0x30 keyboard ] and } */ { 0x5d, 0x7d, 0xff }, /* 0x31 keyboard \ and | */ { 0x5c, 0x7c, 0xff }, /* 0x32 keyboard non-US # and ~ */ { 0x60, 0x7e, 0xff }, /* 0x33 keyboard ; and : */ { 0x3b, 0x3a, 0xff }, /* 0x34 keyboard ' and " */ { 0x27, 0x22, 0xff }, /* 0x35 keyboard Grave Accent and Tilde */ { 0x60, 0x7e, 0xff }, /* ? */ /* 0x36 keyboard , and < */ { 0x2c, 0x3c, 0xff }, /* 0x37 keyboard . and > */ { 0x2e, 0x3e, 0xff }, /* 0x38 keyboard / and ? */ { 0x2f, 0x3f, 0xff } }; /* **++ ** associate_channels - Associate a uniqure channel for each pipe ** ** Functional description: ** ** This routine will pick assign additional channels and then associate ** each channel to a pipe. It will also pick up the pipe direction we will ** need that for later use. ** ** Calling convention: ** ** int associate_channels(struct dsc$descriptor_s *devname, ** short int *channels, int pipe_count, ** uint64 *pipe_handles, int *pipe_direction, ** int *pipe_type) ** ** Input parameters: ** ** struct dsc$descriptor_s *devname Pointer to a VMS device name ** shot int *channels Pointer to array of VMS channels ** int pipe_count Count of pipes for this device ** uint64 *pipe_handles Pointer to array of pipe handles ** int *pipe_direction Pointer to array to store pipe directiosn ** int *pipe_type Pointer to array to store pipe type ** ** Output parameters: ** ** channels Filled in with additional channels ** pipe_direction Filled in with pipe direction ** ** Return value: ** ** SS$_NORMAL - Worked ** SS$_XXXXX - Various failure status values ** ** Environment: ** ** User mode. ** **-- */ int associate_channels(struct dsc$descriptor_s *devname, short int *channels, int pipe_count, uint64 *pipe_handles, int *pipe_direction, int *pipe_type) { int i; int status; UG_IOSB iosb; for (i = 1; i < pipe_count; i++) { status = sys$assign(devname, &channels[i], 0, 0, 0); if (status != SS$_NORMAL) { break; } } if (status == SS$_NORMAL) { for (i = 0; i < pipe_count; i++) { status = sys$qiow(0, channels[i], IO$_SETMODE, &iosb, 0, 0, 0, 0, UG$_ASSOCIATE, &pipe_handles[i], 0, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { status = sys$qiow(0, channels[i], IO$_SENSEMODE, &iosb, 0, 0, &pipe_direction[i], 4, UG$_GET_PIPE_DIRECTION, pipe_handles[i], 0, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { status = sys$qiow(0, channels[i], IO$_SENSEMODE, &iosb, 0, 0, &pipe_type[i], 4, UG$_GET_PIPE_TYPE, pipe_handles[i], 0, 0); if (status == SS$_NORMAL) { if (iosb.status != SS$_NORMAL) { status = iosb.status; break; } } else { break; } } } else { break; } } else { break; status = iosb.status; } } else { break; } } } return(status); } /* **++ ** configure_device - Set device to known starting state ** ** Functional description: ** ** This routine will get the HID descriptor and HID report for the device. ** ** Calling convention: ** ** int configure_device (short int channel, uint64 pipe_handle) ** ** Input parameters: ** ** channel VMS channel associated to control pipe ** pipe_handle Pipe handle for control pipe ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL Worked ** SS$_XXXX Failure reasons ** USB$_XXXX Failure reasons ** ** Environment: ** ** User mode. ** **-- */ int configure_device(short int channel, uint64 pipe_handle) { int idle = 0; int status = SS$_NORMAL; DEVICE_REQUEST device_request; UG_IOSB iosb; typedef struct _hid_descriptor { unsigned char hiddscp$b_length; /* Size of this descriptor in bytes */ unsigned char hiddscp$b_descriptortype; /* HID descriptor type (assigned by USB) */ unsigned short int hiddscp$w_bcdhid; /* HID Class Specification release number in binary-coded decimal */ unsigned char hiddscp$b_countrycode; /* Hardware target country */ unsigned char hiddscp$b_numdescriptors; /* Number of HID class descriptors to follow */ unsigned char hiddscp$b_reportdescriptortype; /* Report descriptor type */ unsigned char hiddscp$b_descriptorlength1; /* Total length of report descriptor */ unsigned char hiddscp$b_descriptorlength2; /* Total length of report descriptor */ char hiddscp$b_fill_0_ [7]; } HID_DESC; HID_DESC desc; /* ** Read the hid descriptor we need that to read the report data. We will ** pick the size out of the report. */ device_request.ug$b_bmrequesttype = 0X81; // Device to host, interface device_request.ug$b_brequest = 0x06; // get descriprtor device_request.ug$w_wvalue = (0X21 << 8) | 0; device_request.ug$w_windex = 0; device_request.ug$w_wlength = sizeof(HID_DESC); status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, &device_request, sizeof(DEVICE_REQUEST), UG$_DEVICE_REQUEST, pipe_handle, &desc, USB$_SHORT_XFER_OK); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { report_size = (desc.hiddscp$b_descriptorlength2 << 8) | (desc.hiddscp$b_descriptorlength1); /* ** Get the idle rate */ device_request.ug$b_bmrequesttype = 0XA1; device_request.ug$b_brequest = 0x02; // GET_IDLE device_request.ug$w_wvalue = 0; device_request.ug$w_windex = 1; device_request.ug$w_wlength = 1; status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, &device_request, sizeof(DEVICE_REQUEST), UG$_DEVICE_REQUEST, pipe_handle, &idle, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { /* ** Try to set the idle rate to only interrupt when something ** changes the device is free to ignore this request */ device_request.ug$b_bmrequesttype = 0X21; device_request.ug$b_brequest = 0x0a; // SET_IDLE device_request.ug$w_wvalue = 0; device_request.ug$w_windex = 0; // rate Upper 8 bits Reporte ID lower device_request.ug$w_wlength = 0; status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, &device_request, sizeof(DEVICE_REQUEST), UG$_DEVICE_REQUEST, pipe_handle, 0, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { /* ** Get the Report Descriptor */ device_request.ug$b_bmrequesttype = 0X81; // Device to host, interface device_request.ug$b_brequest = 0x06; // get descriprtor device_request.ug$w_wvalue = (0X22 << 8) | 1; // Report descriptor for input device_request.ug$w_windex = 0; device_request.ug$w_wlength = report_size; status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, &device_request, sizeof(DEVICE_REQUEST), UG$_DEVICE_REQUEST, pipe_handle, &report_desc, USB$_SHORT_XFER_OK); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { #if defined HID_DISPLAY decode_report(&report_desc[0], report_size); #endif } else { printf("Cannot get Report Descriptor VMS status %08x USB status %08x\n", iosb.status, iosb.usb_status); status = iosb.status; } } else { printf("Cannot read Report Descriptor reason %08x\n", status); } } else { printf("Cannot set idle rate VMS status %08x USB status %08x\n", iosb.status, iosb.usb_status); status = iosb.status; } } else { printf("Could not set idle reason %08x\n", status); } } else { printf("Cannot read idle rate VMS status %08x USB status %08x\n", iosb.status, iosb.usb_status); status = iosb.status; } } else { printf("Cannot read device idle rate reason %08x\n", status); } } else { printf("Reading HID descriptor VMS status %08x USB status %08X\n", iosb.status, iosb.usb_status); status = iosb.status; } } else { printf("Cannot read HID DEscriptor reason %08x\n", status); } return(status); } /* **++ ** decode_keys - Decode the scan code data ** ** Functional description: ** ** This routine translates the HID keyboard data into ASCII data. ** ** Calling convention: ** ** int decode_keys (unsigned char *scan_buffer, int length, ** int *caps_lock, int *num_lock, int *scroll_lock, ** int buff_size, unsigned char *ascii_buffer, ** int *return_length) ** ** Input parameters: ** ** scan_buffer Pointer to buffer with scan codes first byte must be ** the modifier bits ** length Number of bytes in key buffer ** caps_lock Pointer to caps lock state flag ** num_lock Pointer to num lock state flag ** scroll_lock Pointer to num lock state flag ** buffer_length Size of ascii_data buffer ** ascii_data Pointer to buffer to hold decoded data. Returned ** ascii data can be larger than keys read in ** return_length Pointer to interger to recieve the number of bytes in ** ascii_data ** ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL - Worked ** SS$_NODATA - Nothing decoded ** SS$_BADPARAM - Buffer size to small ** SS$_TOOMUCHDATA - More data that buffer will hold user should ** increse the buffer size and reissue the call ** they should not use data return. ** ** Environment: ** ** User mode ** **-- */ int decode_keys(unsigned char *scan_buffer, int length, int *caps_lock, int *num_lock, int *scroll_lock, int buffer_length, unsigned char *ascii_buffer, int *return_length) { unsigned char c; int i = 0; int j = 0; int modifier_index; unsigned char modifiers; int status = SS$_NODATA; modifiers = scan_buffer[0]; if (buffer_length >= length) { for (i=1; i < length; i++) { /* Translater normal keyboard keys */ if ((scan_buffer[i] >= KEYBOARD_START) && (scan_buffer[i] <= KEYBOARD_END)) { modifier_index = 0; if ((modifiers & MODIFIER_KEY_LEFT_SHIFT) || (modifiers & MODIFIER_KEY_RIGHT_SHIFT) || (*caps_lock)) { modifier_index = 1; } if ((modifiers & MODIFIER_KEY_LEFT_CTRL) || (modifiers & MODIFIER_KEY_RIGHT_CTRL)) { modifier_index = 2; } if ((j+1) <= buffer_length) { c = usb_kbd_trans_table[scan_buffer[i]][modifier_index]; ascii_buffer[j++] = c; } else { status = SS$_TOOMUCHDATA; } } /* Translate editing keys */ if ((scan_buffer[i] >= EDIT_TABLE_START) && (scan_buffer[i] <= EDIT_TABLE_END)) { if ((j + EDIT_SEQUENCE_LENGTH) <= buffer_length) { strcpy((char *) &(ascii_buffer[j]), (const char *) usb_kbd_edit_table[scan_buffer[i] - EDIT_TABLE_START]); j = j + EDIT_SEQUENCE_LENGTH; } else { status = SS$_TOOMUCHDATA; } } /* Translate arrow keys */ if ((scan_buffer[i] >= ARROW_TABLE_START) && (scan_buffer[i] <= ARROW_TABLE_END)) { if ((j + ARROW_SEQUENCE_LENGTH) <= buffer_length) { strcpy((char *) &(ascii_buffer[j]), (const char *) usb_kbd_arrow_table[scan_buffer[i] - ARROW_TABLE_START]); j = j + ARROW_SEQUENCE_LENGTH; } else { status = SS$_TOOMUCHDATA; } } /* Translate keypad keys */ if ((scan_buffer[i] >= KEYPAD_TABLE_START) && (scan_buffer[i] <= KEYPAD_TABLE_END)) { if ((j + 1) <= buffer_length) { ascii_buffer[j++] = usb_kbd_keypad_table[scan_buffer[i] - KEYPAD_TABLE_START]; } else { status = SS$_TOOMUCHDATA; } } /* Translate special function keys */ switch (scan_buffer[i]) { case KEY_CAPS_LOCK: { if (*caps_lock) { *caps_lock = 0; } else { *caps_lock = 1; } break; } case KEY_KP_NUMLOCK: { if (*num_lock) { *num_lock = 0; } else { *num_lock = 1; } break; } case KEY_F1: case KEY_SCROLL_LOCK: { if (*scroll_lock) { *scroll_lock = 0; } else { *scroll_lock = 1; ascii_buffer[j++] = CONTROL_S; } break; } case LK_KEYPAD_COMMA: { ascii_buffer[j++] = ','; break; } } /* ** If we are going to overflow the users buffer return an error. ** We will return the amount of data we have acquired to date. */ if (status == SS$_TOOMUCHDATA) { *return_length = j; break; } } if (j > 0) { status = SS$_NORMAL; *return_length = j; } } else { status = SS$_BADPARAM; } return(status); } /* **++ ** get_channels - Get count of channels for the device ** ** Functional description: ** ** This routine will get the number of channels for the device, get all ** the pipe handles. Then it will get the device descriptor and we will check ** that the device and vendor id's are ok. ** ** Calling convention: ** ** int get_channels (short int *channels, int *pipe_count, ** uint64 *pipe_handles, ** unsigned short int vendor_id, ** unsigned short int product_id); ** ** Input parameters: ** ** None ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_IVDEVNAM - Wrong device for this test ** SS$_XXXX - Other failures ** SS$_NORMAL - Success ** ** Environment: ** ** User mode. ** **-- */ int get_channels(short int *channels, int *pipe_count, uint64 *pipe_handles, unsigned short int vendor_id, unsigned short int product_id) { int status; DEVICE_DESCRIPTOR device_descriptor; UG_IOSB iosb; /* ** Get the pipe count. */ status = sys$qiow(0, channels[0], IO$_SENSEMODE, &iosb, 0, 0, pipe_count, 4, UG$_GET_PIPE_COUNT, 0, 0, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { status = sys$qiow(0, channels[0], IO$_SENSEMODE, &iosb, 0, 0, pipe_handles, 8 * (*pipe_count), UG$_GET_PIPE_HANDLES, 0, 0, 0); if (status == SS$_NORMAL) { if(iosb.status == SS$_NORMAL) { status = sys$qiow(0, channels[0], IO$_SENSEMODE, &iosb, 0, 0, &device_descriptor, sizeof(DEVICE_DESCRIPTOR), UG$_GET_DEVICE_DESCRIPTOR, 0, 0, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { if ((device_descriptor.ug$w_idvendor == vendor_id) && (device_descriptor.ug$w_idproduct == product_id)) { status = SS$_NORMAL; } else { status = SS$_IVDEVNAM; } } else { status = iosb.status; } } } else { status = iosb.status; } } } else { status = iosb.status; } } return(status); } /* **++ ** get_data - Read and decode HID report ** ** Functional description: ** ** This code will read until it gets a scan report with data from the ** scanner or until an error is encoutered that cannot be ignored ** ** Calling convention: ** ** int get_data (DEVICE_DATA *device, int scan_data_length, ** unsigned char *data, int data_length, ** int *return_length) ** Input parameters: ** ** device - Pointer to device data block ** scan_data_length - Size of scan report from scanner ** data - ASCII decocded data from scan ** data_length - Size of buffer ** return_length - Number of ASCII characters decoded ** ** Output parameters: ** ** data - Decoded data ** return_length - Number of byte of valid data ** ** Return value: ** ** SS$_NORMAL - Worked ** SS$_BADPARAM - Buffer size or scan_data_length to large ** SS$_TOOMUCHDATA - Ascii data would not fit into supplied buffer ** if this happens the scan is invalid ** ** Environment: ** ** User mode ** **-- */ int get_data(DEVICE_DATA *device, int scan_data_length, unsigned char *data, int data_length, int *return_length) { unsigned char *scancodes = &device->interrupt_data[0]; int index = device->interrupt_pipe_index; int status; UG_IOSB iosb; *return_length = 0; if (scan_data_length < MAX_INTERRUPT_DATA) { do { status = sys$qiow(0, device->channels[index], IO$_READVBLK, &iosb, 0, 0, scancodes, scan_data_length, USB$_SHORT_XFER_OK, device->pipe_handles[index], 0, 0); if (status & SS$_NORMAL) { if (iosb.status & SS$_NORMAL) { status = decode_keys(scancodes, scan_data_length, &caps_lock, &num_lock, &scroll_lock, data_length, data, return_length); if (status == SS$_NODATA) { status = SS$_NORMAL; } } else { status = iosb.status; } } } while ((status & SS$_NORMAL) && (*return_length == 0)); } else { status = SS$_BADPARAM; } return(status); } /* **++ ** map_pipes - Walk pipes and find directions and type ** ** Functional description: ** ** Walk all the pipes looking for the interrupt pipe index. This is ** needed so we can target reads pipe. ** ** Calling convention: ** ** int map_pipes (DEVICE_DATA *device); ** ** Input parameters: ** ** None ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL - Worked ** SS$_XXXXX - Various failure reasons ** USB$_XXXX - Various USB failure reasons ** ** Environment: ** ** User mode. ** **-- */ int map_pipes(DEVICE_DATA *device) { int pipe_index; int pipe_type; int status; UG_IOSB iosb; /* ** The control pipe is always pipe zero so we can skip that one. Also we ** know the test device does not have an Isochronous pipe so we can skip ** that check. Finally, the test device only has an input interrupt pipe ** so if the pipe type is interrupt we are done no need to get direction. */ for (pipe_index = 1; pipe_index < device->pipe_count; pipe_index++) { status = sys$qiow(0, device->channels[pipe_index], IO$_SENSEMODE, &iosb, 0, 0, &pipe_type, 4, UG$_GET_PIPE_TYPE, device->pipe_handles[pipe_index], 0, 0, 0); if (status == SS$_NORMAL) { if (iosb.status == SS$_NORMAL) { if (pipe_type == UG$_PIPE_TYPE_INTERRUPT) { device->interrupt_pipe_index = pipe_index; } } else { status = iosb.status; break; } } else { break; } } return(status); } /* **++ ** open_barcode - Get device going ** ** Functional description: ** ** This routine will get as many additional channels as the device ** needs, map them to pipe handles and configure the device. ** ** Calling convention: ** ** int open_barcode (DEVICE_DATA *device, ** unsigned short int vendor_id, ** unsigned short int product_id); ** ** Input parameters: ** ** device Pointer to device data block ** vendor_id Unsigned integer with Vendor Id ** product_int Unsigned integer with Product Id ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL Worked ** SS$_XXXX Failed ** ** Environment: ** ** User mode ** **-- */ int open_barcode(DEVICE_DATA *device, unsigned short int vendor_id, unsigned short int product_id) { int status; status = get_channels(&device->channels[0], &device->pipe_count, &device->pipe_handles[0], vendor_id, product_id); if (status == SS$_NORMAL) { status = associate_channels(&device->device_name, &device->channels[0], device->pipe_count, &device->pipe_handles[0], &device->pipe_direction[0], &device->pipe_type[0]); if (status == SS$_NORMAL) { status = configure_device(device->channels[0], device->pipe_handles[0]); if (status == SS$_NORMAL) { status = map_pipes(device); if ( status != SS$_NORMAL) { printf("Unable to map pipes reason %08x\n", status); } } else { printf("Unable to configure device reason %08x\n", status); } } else { printf("Failed to associate channels\n"); } } else { printf("Failed to get channels\n"); } return(status); }