Files
BaS_gcc/usb/usb_kbd.c
2015-04-07 10:04:31 +00:00

1391 lines
48 KiB
C

/*
* (C) Copyright 2001
* Denis Peter, MPL AG Switzerland
*
* Part of this source has been derived from the Linux USB
* project.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
#include "usb.h"
//#define DEBUG_USBKBD
#ifdef DEBUG_USBKBD
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
#else
#define dbg(format, arg...) do { ; } while (0)
#endif /* DEBUG_USBKBD */
#define err(format, arg...) do { xprintf("ERROR: %s(): " format, __FUNCTION__, ##arg); } while (0)
#ifdef USE_COUNTRYCODE
static int usb_kbd_get_hid_desc(struct usb_device *dev);
#endif
/* under TOS Repeat keys are build by timer C so infinite (0) or 1000 is a good value */
#define REPEAT_RATE 0 // 40 /* 40msec -> 25cps */
#define MAX_VALUE_LOOKUP 0x90
#define MAX_VALUE_ATARI 0x75
#define NUM_LOCK 0x53
#define CAPS_LOCK 0x39
#define SCROLL_LOCK 0x47
/* Modifier bits */
#define LEFT_CNTR 0
#define LEFT_SHIFT 1
#define LEFT_ALT 2
#define LEFT_GUI 3
#define RIGHT_CNTR 4
#define RIGHT_SHIFT 5
#define RIGHT_ALT 6
#define RIGHT_GUI 7
/* HID bCountryCode */
#define CC_NOT 0
#define CC_ISO 13
#define CC_USA 33
#define CC_FRG 9
#define CC_FRA 8
#define CC_UK 32
#define CC_SPA 25
#define CC_ITA 14
#define CC_SWE 29
#define CC_SWF 27
#define CC_SWG 28
/* Language cookie */
#define USA 0 /* English */
#define FRG 1 /* German */
#define FRA 2 /* French */
#define UK 3 /* English */
#define SPA 4 /* Spanish */
#define ITA 5 /* Italian */
#define SWE 6 /* Swiss */
#define SWF 7 /* Swiss French */
#define SWG 8 /* Swiss German */
//extern _IOREC *iorec;
//extern void (**ikbdvec)();
static unsigned char *new_packet;
static unsigned char old_packet[8];
static unsigned char num_lock;
static unsigned char caps_lock;
static unsigned char scroll_lock;
static unsigned char old_modifier;
static union
{
struct
{
unsigned reserved1:3;
unsigned force_alt_shift:1;
unsigned right_shift_host:1;
unsigned left_shift_host:1;
unsigned alt_host:1;
unsigned ctrl_host:1;
unsigned key_forced:1;
unsigned reserved2:3;
unsigned altgr_usb:1;
unsigned shift_usb:1;
unsigned altgr_usb_break:1;
unsigned shift_usb_break:1;
} b;
unsigned short s;
} flags;
static unsigned char *leds;
static int kbd_installed;
static unsigned char usb_kbd_to_atari_scancode[] =
{
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20,
// E F G H I J K L
0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
// M(,) N O P Q(A) R S T
0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14,
// U V W(Z) X Y Z(W) 1 2
0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03,
// 3 4 5 6 7 8 9 0
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
// RET ESC BACK TAB SPACE -()) = [(^)
0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x0D, 0x1A,
// ]($) \(*) EUR1 ;(M) ' ` ,(;) .(:)
0x1B, 0x2B, 0x2B, 0x27, 0x28, 0x5B, 0x33, 0x34,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x35, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x41, 0x42, 0x43, 0x44, 0x62, 0x61, 0x49, 0x4C,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x4F, 0x52, 0x47, 0x45, 0x53, 0x55, 0x46, 0x4D,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x4B, 0x50, 0x48, 0x54, 0x65, 0x66, 0x4A, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67,
// KP8 KP9 KP0 KP. >< APP POWER KP=
0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x1D, 0x2A, 0x38, 0x56, 0x1D, 0x36, 0x38, 0x57 // virtual codes
};
static unsigned char usb_kbd_to_atari_fr_modifier[] =
{
/* This table can change host SHIFT & ALT states for each scancode, values */
/* are in hexa : bit 7: 1 for a valid entry */
/* bit 6: 1 for force CTRL */
/* bit 5: ALT, bit 4: SHIFT states for the AltGR table */
/* bit 3: ALT, bit 2: SHIFT states for the Shift table */
/* bit 1: ALT, bit 0: SHIFT states for the Unshift table */
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// E F G H I J K L
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// M(,) N O P Q(A) R S T
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// U V W(Z) X Y Z(W) 1 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4,
// 3 4 5 6 7 8 9 0
0x00, 0xB4, 0xA4, 0x94, 0x00, 0xA5, 0x84, 0xA4,
// RET ESC BACK TAB SPACE -()) = [(^)
0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xB4, 0x00,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x00, 0x00, 0x00, 0x95, 0x00, 0x95, 0x95, 0x00,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// KP8 KP9 KP0 KP. >< APP POWER KP=
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x00, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x00, 0xEA
};
static unsigned char usb_kbd_to_atari_fr_unshift[] =
{
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20,
// E F G H I J K L
0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
// M(,) N O P Q(A) R S T
0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14,
// U V W(Z) X Y Z(W) 1 2
0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03,
// 3 4 5 6 7 8 9 0
0x04, 0x05, 0x06, 0x0D, 0x08, 0x0D, 0x0A, 0x0B,
// RET ESC BACK TAB SPACE -()) = [(^)
0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x35, 0x1A,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x1B, 0x1B, 0x00, 0x27, 0x28, 0x00, 0x33, 0x34,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x09, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x41, 0x42, 0x43, 0x44, 0x62, 0x61, 0x62, 0x4C,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x4F, 0x52, 0x47, 0x45, 0x53, 0x47, 0x46, 0x4D,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x4B, 0x50, 0x48, 0x00, 0x65, 0x66, 0x4A, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67,
// KP8 KP9 KP0 KP. >< APP KP=
0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F
};
static unsigned char usb_kbd_to_atari_fr_shift[] =
{
/* Hexa values, 00: unused => use the Unshift table */
/* FF: invalid => no scancode */
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20,
// E F G H I J K L
0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
// M(,) N O P Q(A) R S T
0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14,
// U V W(Z) X Y Z(W) 1 2
0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03,
// 3 4 5 6 7 8 9 0
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
// RET ESC BACK TAB SPACE -()) = [(^)
0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x35, 0x1A,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x29, 0xFF, 0x00, 0x27, 0x28, 0x00, 0x33, 0x34,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x07, 0x3A, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x5A, 0x5B, 0x5C, 0x5D, 0x62, 0x61, 0x62, 0x4C,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x4F, 0x52, 0x47, 0x48, 0x53, 0x47, 0x50, 0x4D,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x4B, 0x50, 0x48, 0x00, 0x65, 0x66, 0x4A, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67,
// KP8 KP9 KP0 KP. >< APP KP=
0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F
};
static unsigned char usb_kbd_to_atari_fr_altgr[] =
{
/* Hexa values, 00: unused => use the Unshift table */
/* FF: invalid => no scancode */
// A(Q) B C D
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// E F G H I J K L
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// M(,) N O P Q(A) R S T
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// U V W(Z) X Y Z(W) 1 2
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B,
// 3 4 5 6 7 8 9 0
0x2B, 0x1A, 0x1A, 0x2B, 0x29, 0x28, 0x1A, 0x2B,
// RET ESC BACK TAB SPACE -()) = [(^)
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0x1B, 0xFF,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//PAUSE INS HOME PgUp DEL END PgDn ->
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// KP8 KP9 KP0 KP. >< APP KP=
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// F13, F14, F15 F16 F17 F18 F19 F20
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0xFF, 0xFF,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//VolUp Vold_packetn
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF
};
static unsigned char usb_kbd_to_atari_de_modifier[] =
{
/* This table can change host SHIFT & ALT states for each scancode, values */
/* are in hexa : bit 7: 1 for a valid entry */
/* bit 6: 1 for force CTRL */
/* bit 5: ALT, bit 4: SHIFT states for the AltGR table */
/* bit 3: ALT, bit 2: SHIFT states for the Shift table */
/* bit 1: ALT, bit 0: SHIFT states for the Unshift table */
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// E F G H I J K L
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// M(,) N O P Q(A) R S T
0x00, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00,
// U V W(Z) X Y Z(W) 1 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 3 4 5 6 7 8 9 0
0x00, 0x00, 0x00, 0x00, 0xB4, 0xA4, 0xA4, 0xB4,
// RET ESC BACK TAB SPACE -()) = [(^)
0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x00, 0x80, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x00, 0x00, 0x00, 0x81, 0x00, 0x95, 0x81, 0x00,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// KP8 KP9 KP0 KP. >< APP POWER KP=
0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x00, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x00, 0xEA
};
static unsigned char usb_kbd_to_atari_de_unshift[] =
{
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20,
// E F G H I J K L
0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
// M(,) N O P Q(A) R S T
0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14,
// U V W(Z) X Y Z(W) 1 2
0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03,
// 3 4 5 6 7 8 9 0
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
// RET ESC BACK TAB SPACE -()) = [(^)
0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x0D, 0x1A,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x1B, 0x29, 0x00, 0x27, 0x28, 0x29, 0x33, 0x34,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x35, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x41, 0x42, 0x43, 0x44, 0x63, 0x64, 0x62, 0x50,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x61, 0x52, 0x47, 0x48, 0x53, 0x47, 0x50, 0x4D,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x4B, 0x50, 0x48, 0x54, 0x65, 0x66, 0x4A, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67,
// KP8 KP9 KP0 KP. >< APP KP=
0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F
};
static unsigned char usb_kbd_to_atari_de_shift[] =
{
/* Hexa values, 00: unused => use the Unshift table */
/* FF: invalid => no scancode */
// A(Q) B C D
0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20,
// E F G H I J K L
0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
// M(,) N O P Q(A) R S T
0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14,
// U V W(Z) X Y Z(W) 1 2
0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03,
// 3 4 5 6 7 8 9 0
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
// RET ESC BACK TAB SPACE -()) = [(^)
0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x0D, 0x1A,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x1B, 0x0D, 0x00, 0x27, 0x28, 0x34, 0x33, 0x34,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0x35, 0x3A, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0x5A, 0x5B, 0x5C, 0x5D, 0x63, 0x64, 0x62, 0x50,
//PAUSE INS HOME PgUp DEL END PgDn ->
0x61, 0x52, 0x47, 0x48, 0x53, 0x47, 0x50, 0x4D,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0x4B, 0x50, 0x48, 0x54, 0x65, 0x66, 0x4A, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67,
// KP8 KP9 KP0 KP. >< APP KP=
0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00,
// F13, F14, F15 F16 F17 F18 F19 F20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
//VolUp Vold_packetn
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F
};
static unsigned char usb_kbd_to_atari_de_altgr[] =
{
/* Hexa values, 00: unused => use the Unshift table */
/* FF: invalid => no scancode */
// A(Q) B C D
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// E F G H I J K L
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// M(,) N O P Q(A) R S T
0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0xFF, 0xFF, 0xFF,
// U V W(Z) X Y Z(W) 1 2
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 3 4 5 6 7 8 9 0
0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0x27, 0x28, 0x28,
// RET ESC BACK TAB SPACE -()) = [(^)
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x2B, 0xFF,
// ]($) \(*) ;(M) ' ` ,(;) .(:)
0x2B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// /(!) CAPS F1 F2 F3 F4 F5 F6
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// F7 F8 F9 F10 F11 F12 PrtSc ScLoc
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//PAUSE INS HOME PgUp DEL END PgDn ->
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// <- DOWN UP NuLoc KP/ KP* KP- KP+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E,
// ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// KP8 KP9 KP0 KP. >< APP KP=
0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0xFF,
// F13, F14, F15 F16 F17 F18 F19 F20
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// F21 F22 F23 F24 EXEC HELP MENU SEL
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0xFF, 0xFF,
// STOP AGAIN UNDO CUT COPY PASTE FIND MUTE
0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//VolUp Vold_packetn
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF
};
static void *memscan(void *addr, int c, int size)
{
unsigned char *p = (unsigned char *) addr;
while (size)
{
if (*p == (char) c)
return (void *) p;
p++;
size--;
}
return (void *) p;
}
static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
/*
* deregistering the keyboard
*/
int usb_kbd_deregister(struct usb_device *dev)
{
dev->irq_handle = NULL;
if (new_packet != NULL)
{
driver_mem_free(new_packet);
new_packet = NULL;
}
if (leds != NULL)
{
driver_mem_free(leds);
leds = NULL;
}
kbd_installed = 0;
dbg("USB KBD deregistered\r\n");
return 1;
}
/* registering the keyboard */
int usb_kbd_register(struct usb_device *dev)
{
if(!kbd_installed && (dev->devnum != -1) && (usb_kbd_probe(dev, 0) == 1))
{ /* Ok, we found a keyboard */
//dbg("USB KBD found (iorec: 0x%x, USB: %d, devnum: %d)\r\n", iorec, dev->usbnum, dev->devnum);
num_lock = caps_lock = scroll_lock = old_modifier = 0;
flags.s = 0;
kbd_installed = 1;
dev->deregister = usb_kbd_deregister;
return 1;
}
/* no USB Keyboard found */
return -1;
}
/* search for keyboard and register it if found */
int drv_usb_kbd_init(void)
{
int i, j;
if(kbd_installed)
return -1;
/* scan all USB Devices */
for(j = 0; j < USB_MAX_BUS; j++)
{
for(i = 0; i < USB_MAX_DEVICE; i++)
{
struct usb_device *dev = usb_get_dev_index(i, j); /* get device */
if(dev == NULL)
break;
if(usb_kbd_register(dev) > 0)
return 1;
}
}
/* no USB Keyboard found */
return -1;
}
/**************************************************************************
* Low Level drivers
*/
/* set the LEDs. Since this is used in the irq routine, the control job
is issued with a timeout of 0. This means, that the job is queued without
waiting for job completion */
static void usb_kbd_setled(struct usb_device *dev)
{
struct usb_interface_descriptor *iface = &dev->config.if_desc[0];
unsigned char *pleds = (unsigned char *)(((unsigned long)leds + 3) & ~3);
if(scroll_lock != 0)
*pleds = 4;
else
*pleds = 0;
if(caps_lock != 0)
*pleds |= 2;
if(num_lock != 0)
*pleds |= 1;
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x200, iface->bInterfaceNumber, pleds, 1, 0);
}
static void usb_kbd_send_code(unsigned char code)
{
//if((iorec != NULL) && (ikbdvec != NULL))
// call_ikbdvec(code, iorec, ikbdvec);
}
/*
* Translate the scancode
*/
static int usb_kbd_translate(unsigned char scancode, unsigned char modifier, int pressed)
{
unsigned char keycode = 0;
unsigned char atari_modifier = 0;
#ifdef CONFIG_USB_INTERRUPT_POLLING
int level;
#endif
int type = USA;
(void) type; /* TODO: just for now - avoid compiler warning */
dbg("USB KBD scancode: 0x%02x, modifier:0x%02x, pressed: %d\r\n", scancode, modifier, pressed);
flags.b.force_alt_shift = 0;
if(scancode > MAX_VALUE_LOOKUP)
{
keycode = 0;
}
else
{
if(scancode == 0x8A) /* LEFT ALT */
{
keycode = 0x38; /* Alt Atari */
}
else
{
unsigned char *unshift_table = NULL;
unsigned char *shift_table = NULL;
unsigned char *altgr_table = NULL;
unsigned char *modifier_table = NULL;
unsigned long lang = USA;
//USB_COOKIE *p = usb_get_cookie('_AKP');
//if(p != NULL)
// lang = (p->v.l >> 8) & 0xFF;
#ifdef USE_COUNTRYCODE
switch(usb_kbd_hid_desc.bCountryCode)
{
case CC_USA: lang = USA; break;
case CC_FRG: lang = FRG; break;
case CC_FRA: lang = FRA; break;
case CC_UK: lang = UK; break;
case CC_SPA: lang = SPA; break;
case CC_ITA: lang = ITA; break;
case CC_SWE: lang = SWE; break;
case CC_SWF: lang = SWF; break;
case CC_SWG: lang = SWG; break;
}
#endif
switch(lang)
{
case FRA:
case SWF:
unshift_table = usb_kbd_to_atari_fr_unshift;
shift_table = usb_kbd_to_atari_fr_shift;
altgr_table = usb_kbd_to_atari_fr_altgr;
modifier_table = usb_kbd_to_atari_fr_modifier;
type = FRA;
break;
case FRG:
case SWG:
unshift_table = usb_kbd_to_atari_de_unshift;
shift_table = usb_kbd_to_atari_de_shift;
altgr_table = usb_kbd_to_atari_de_altgr;
modifier_table = usb_kbd_to_atari_de_modifier;
type = FRG;
break;
default:
unshift_table = usb_kbd_to_atari_scancode;
break;
}
if (modifier != old_modifier)
{
if (((modifier & (1 << LEFT_SHIFT)) != 0) || ((modifier & (1 << RIGHT_SHIFT)) != 0))
{
if (!flags.b.shift_usb)
{
flags.b.shift_usb = 1;
flags.b.shift_usb_break = 1;
}
}
else
{
flags.b.shift_usb = 0;
}
if ((modifier & (1 << RIGHT_ALT)) != 0)
{
if (!flags.b.altgr_usb)
{
flags.b.altgr_usb = 1;
flags.b.altgr_usb_break = 1;
}
}
else
{
flags.b.altgr_usb = 0;
}
old_modifier = modifier;
}
else if (pressed)
{
if (!flags.b.altgr_usb)
{
flags.b.altgr_usb_break = 0;
}
if (!flags.b.shift_usb)
{
flags.b.shift_usb_break = 0;
}
}
keycode = unshift_table[scancode];
if ((modifier & (1 << LEFT_ALT)) == 0)
{
/*
* This modifier table can change host SHIFT & ALT states for each scancode, values
* are in hexa : bit 7: 1 for a valid entry
* bit 6: 1 for force CTRL
* bit 5: ALT, bit 4: SHIFT states for the AltGR table
* bit 3: ALT, bit 2: SHIFT states for the Shift table
* bit 1: ALT, bit 0: SHIFT states for the Unshift table
*/
if (modifier_table != NULL)
{
atari_modifier = modifier_table[scancode];
}
else
{
atari_modifier = 0;
}
if ((atari_modifier & (1 << 7)) != 0)
{
flags.b.force_alt_shift = 1;
}
else
{
atari_modifier = 0;
}
if (flags.b.altgr_usb_break)
{
if (altgr_table[scancode])
{
keycode = altgr_table[scancode];
if ((atari_modifier & (1 << 6)) != 0)
{
atari_modifier = (atari_modifier >> 4) | (atari_modifier & (1 << 6));
}
else
{
atari_modifier >>= 4;
}
}
}
else if (flags.b.shift_usb_break)
{
if (shift_table[scancode])
{
keycode = shift_table[scancode];
if ((atari_modifier & (1 << 6)) != 0)
{
atari_modifier = (atari_modifier >> 2) | (atari_modifier & (1 << 6));
}
else
{
atari_modifier >>= 2;
}
}
}
}
}
}
dbg("USB KBD atari-%s keycode:0x%02x, modifier:0x%02x, flags:0x%04x\r\n", (type == FRA) ? "fr" : (type == FRG) ? "de" : "us", keycode, atari_modifier, flags.s);
if (keycode == 0x1D) /* CTRL */
{
if(pressed)
flags.b.ctrl_host = 1;
else
flags.b.ctrl_host = 0;
}
if(keycode == 0x36) /* RSHIFT */
{
if(pressed)
flags.b.right_shift_host = 1;
else
flags.b.right_shift_host = 0;
}
if(keycode == 0x2A) /* LSHIFT */
{
if(pressed)
flags.b.left_shift_host = 1;
else
flags.b.left_shift_host = 0;
}
#ifdef CONFIG_USB_INTERRUPT_POLLING
level = asm_set_ipl(7); /* mask interrupts for use call_ikbdvec() */
#endif
if(pressed && (flags.b.force_alt_shift))
{
flags.b.key_forced = 1;
if(((atari_modifier & (1 << 6)) != 0) && flags.b.ctrl_host)
usb_kbd_send_code(0x1D); /* CTRL */
if((atari_modifier & (1 << 0)) == 0)
{
if(flags.b.left_shift_host)
usb_kbd_send_code(0xAA); /* !LSHIFT */
if(flags.b.right_shift_host)
usb_kbd_send_code(0xB6); /* !RSHIFT */
}
else
{
if(!flags.b.left_shift_host)
usb_kbd_send_code(0x2A); /* LSHIFT */
if(!flags.b.right_shift_host && (keycode != 0x60)) /* < */
usb_kbd_send_code(0x36); /* RSHIFT */
}
if((atari_modifier & (1 << 1)) == 0)
{
if(flags.b.alt_host)
usb_kbd_send_code(0xB8); /* !ALT */
}
else
{
if(!flags.b.alt_host)
usb_kbd_send_code(0x38); /* ALT */
}
}
if((keycode !=0) && (keycode <= MAX_VALUE_ATARI))
usb_kbd_send_code(pressed ? keycode : keycode | 0x80);
if(!pressed && (flags.b.force_alt_shift))
{
flags.b.key_forced = 0;
if(((atari_modifier & (1 << 6)) != 0) && flags.b.ctrl_host)
usb_kbd_send_code(0x9D); /* !CTRL */
if((atari_modifier & (1 << 0)) == 0)
{
if(flags.b.left_shift_host)
usb_kbd_send_code(0x2A); /* LSHIFT */
if(flags.b.right_shift_host)
usb_kbd_send_code(0x36); /* RSHIFT */
}
else
{
if(!flags.b.left_shift_host)
usb_kbd_send_code(0xAA); /* !LSHIFT */
if(!flags.b.right_shift_host)
usb_kbd_send_code(0xB6); /* !RSHIFT */
}
if((atari_modifier & (1 << 1)) == 0)
{
if(flags.b.alt_host)
usb_kbd_send_code(0x38); /* ALT */
}
else
{
if(!flags.b.alt_host)
usb_kbd_send_code(0xB8); /* !ALT */
}
}
#ifdef CONFIG_USB_INTERRUPT_POLLING
asm_set_ipl(level);
#endif
if(pressed == 1)
{
if(scancode == NUM_LOCK)
{
num_lock = ~num_lock;
return 1;
}
if(scancode == CAPS_LOCK)
{
caps_lock = ~caps_lock;
return 1;
}
if(scancode == SCROLL_LOCK)
{
scroll_lock = ~scroll_lock;
return 1;
}
}
return 0;
}
/* Interrupt service routine */
static int usb_kbd_irq(struct usb_device *dev)
{
int i,res;
if((dev->irq_status != 0) || (dev->irq_act_len != 8))
{
dbg("USB KBD error %lX, len %d\r\n",dev->irq_status,dev->irq_act_len);
return 1;
}
res = 0;
for(i = 2; i < 8; i++)
{
if(old_packet[i] > 3 && memscan(&new_packet[2], old_packet[i], 6) == &new_packet[8])
{
res |= usb_kbd_translate(old_packet[i], new_packet[0], 0);
old_packet[0] = new_packet[0];
}
if(new_packet[i] > 3 && memscan(&old_packet[2], new_packet[i], 6) == &old_packet[8])
{
res |= usb_kbd_translate(new_packet[i], new_packet[0], 1);
old_packet[0] = new_packet[0];
}
}
if(new_packet[0] != old_packet[0]) /* modifier change */
{
unsigned char modifier_change = new_packet[0] ^ old_packet[0];
if(modifier_change & (1 << LEFT_CNTR))
res |= usb_kbd_translate(0x88, new_packet[0], (new_packet[0] & (1 << LEFT_CNTR)) ? 1 : 0);
if(modifier_change & (1 << LEFT_SHIFT))
res |= usb_kbd_translate(0x89, new_packet[0], (new_packet[0] & (1 << LEFT_SHIFT)) ? 1 : 0);
if(modifier_change & (1 << LEFT_ALT))
res |= usb_kbd_translate(0x8A, new_packet[0], (new_packet[0] & (1 << LEFT_ALT)) ? 1 : 0);
if(modifier_change & (1 << LEFT_GUI))
res |= usb_kbd_translate(0x8B, new_packet[0], (new_packet[0] & (1 << LEFT_GUI)) ? 1 : 0);
if(modifier_change & (1 << RIGHT_CNTR))
res |= usb_kbd_translate(0x8C, new_packet[0], (new_packet[0] & (1 << RIGHT_CNTR)) ? 1 : 0);
if(modifier_change & (1 << RIGHT_SHIFT))
res |= usb_kbd_translate(0x8D, new_packet[0], (new_packet[0] & (1 << RIGHT_SHIFT)) ? 1 : 0);
if(modifier_change & (1 << RIGHT_ALT))
res |= usb_kbd_translate(0x8E, new_packet[0], (new_packet[0] & (1 << RIGHT_ALT)) ? 1 : 0);
if(modifier_change & (1 << RIGHT_GUI))
res |= usb_kbd_translate(0x8F, new_packet[0], (new_packet[0] & (1 << RIGHT_GUI)) ? 1 : 0);
}
if(res == 1)
usb_kbd_setled(dev);
memcpy(&old_packet[0], &new_packet[0], 8);
return 1; /* install IRQ Handler again */
}
/*
* probes the USB device dev for keyboard type
*/
static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *iface;
struct usb_endpoint_descriptor *ep;
int pipe;
int maxp;
if (dev->descriptor.bNumConfigurations != 1)
{
dbg("device has more than one single configuration\r\n");
return 0;
}
iface = &dev->config.if_desc[ifnum];
if (iface->bInterfaceClass != USB_CLASS_HID)
{
dbg("device is not a HID device\r\n");
return 0;
}
if(iface->bInterfaceSubClass != 1)
{
dbg("device interface subclass != USB_SUB_HID_BOOT\r\n");
return 0;
}
if (iface->bInterfaceProtocol != USB_PROT_HID_KEYBOARD)
{
dbg("device is not a keyboard\r\n");
return 0;
}
if (iface->bNumEndpoints != 1)
{
dbg("device has %d endpoints instead of 1\r\n", iface->bNumEndpoints);
return 0;
}
ep = &iface->ep_desc[0];
if (!(ep->bEndpointAddress & 0x80))
{
dbg("ep->bEndpointAddress & 0x80 = 0x%x\r\n", ep->bEndpointAddress & 0x80);
return 0;
}
if ((ep->bmAttributes & 3) != 3)
{
dbg("ep->bmAttributes & 3 != 3 (%d)\r\n", ep->bmAttributes & 3);
return 0;
}
leds = (unsigned char *) driver_mem_alloc(8);
if (leds == NULL)
{
dbg("could not allocate memory for leds\r\n");
return 0;
}
new_packet = (unsigned char *) driver_mem_alloc(8);
if (new_packet == NULL)
{
dbg("could not allocate memory for new_packed\r\n");
driver_mem_free(leds);
return 0;
}
dbg("USB KBD found, set protocol...\r\n");
/* ok, we found a USB Keyboard, install it */
#ifdef USE_COUNTRYCODE
if(usb_kbd_get_hid_desc(dev) < 0)
usb_kbd_hid_desc.bCountryCode = CC_NOT;
#endif
usb_set_protocol(dev, iface->bInterfaceNumber, 0);
dbg("USB KBD found, set idle...\r\n");
usb_set_idle(dev, iface->bInterfaceNumber, REPEAT_RATE, 0);
memset(&new_packet[0], 0, 8);
memset(&old_packet[0], 0, 8);
pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe);
dev->irq_handle = usb_kbd_irq;
dbg("USB KBD enable interrupt pipe (maxp: %d)...\r\n", maxp);
usb_submit_int_msg(dev, pipe, &new_packet[0], maxp > 8 ? 8 : maxp, ep->bInterval);
return 1;
}
#ifdef USE_COUNTRYCODE
/*
* We parse each description item into this structure. Short items data
* values are expanded to 32-bit signed int, long items contain a pointer
* into the data area.
*/
struct hid_item
{
unsigned char format;
unsigned char size;
unsigned char type;
unsigned char tag;
union
{
unsigned char u_8;
char s_8;
unsigned short u_16;
short s_16;
unsigned long u_32;
long s_32;
unsigned char *longdata;
} data;
};
/* HID report item format */
#define HID_ITEM_FORMAT_SHORT 0
#define HID_ITEM_FORMAT_LONG 1
/* Special tag indicating long items */
#define HID_ITEM_TAG_LONG 15
#ifdef USB_KBD_DEBUG
void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
{
board_printf("USB_HID_DESC:\r\n");
board_printf(" bLenght 0x%x\r\n",hid->bLength);
board_printf(" bcdHID 0x%x\r\n",hid->bcdHID);
board_printf(" bCountryCode %d\r\n",hid->bCountryCode);
board_printf(" bNumDescriptors 0x%x\r\n",hid->bNumDescriptors);
board_printf(" bReportDescriptorType 0x%x\r\n",hid->bReportDescriptorType);
board_printf(" wDescriptorLength 0x%x\r\n",hid->wDescriptorLength);
}
/*
* Fetch a report description item from the data stream. We support long
* items, though they are not used yet.
*/
static int fetch_item(unsigned char *start, unsigned char *end, struct hid_item *item)
{
if((end - start) > 0)
{
unsigned char b = *start++;
item->type = (b >> 2) & 3;
item->tag = (b >> 4) & 15;
if(item->tag == HID_ITEM_TAG_LONG)
{
item->format = HID_ITEM_FORMAT_LONG;
if((end - start) >= 2)
{
item->size = *start++;
item->tag = *start++;
if((end - start) >= item->size)
{
item->data.longdata = start;
start += item->size;
return item->size;
}
}
}
else
{
item->format = HID_ITEM_FORMAT_SHORT;
item->size = b & 3;
switch(item->size)
{
case 0:
return item->size;
case 1:
if((end - start) >= 1)
{
item->data.u_8 = *start++;
return item->size;
}
break;
case 2:
if((end - start) >= 2)
{
item->data.u_16 = le16_to_cpu(*(unsigned short *)start);
start+=2;
return item->size;
}
case 3:
item->size++;
if((end - start) >= 4)
{
item->data.u_32 = le32_to_cpu(*(unsigned long *)start);
start+=4;
return item->size;
}
}
}
}
return -1;
}
#endif /* USB_KBD_DEBUG */
/*
* HID report descriptor item type (prefix bit 2,3)
*/
#define HID_ITEM_TYPE_MAIN 0
#define HID_ITEM_TYPE_GLOBAL 1
#define HID_ITEM_TYPE_LOCAL 2
#define HID_ITEM_TYPE_RESERVED 3
/*
* HID report descriptor main item tags
*/
#define HID_MAIN_ITEM_TAG_INPUT 8
#define HID_MAIN_ITEM_TAG_OUTPUT 9
#define HID_MAIN_ITEM_TAG_FEATURE 11
#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10
#define HID_MAIN_ITEM_TAG_END_COLLECTION 12
/*
* HID report descriptor main item contents
*/
#define HID_MAIN_ITEM_CONSTANT 0x001
#define HID_MAIN_ITEM_VARIABLE 0x002
#define HID_MAIN_ITEM_RELATIVE 0x004
#define HID_MAIN_ITEM_WRAP 0x008
#define HID_MAIN_ITEM_NONLINEAR 0x010
#define HID_MAIN_ITEM_NO_PREFERRED 0x020
#define HID_MAIN_ITEM_NULL_STATE 0x040
#define HID_MAIN_ITEM_VOLATILE 0x080
#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100
/*
* HID report descriptor collection item types
*/
#define HID_COLLECTION_PHYSICAL 0
#define HID_COLLECTION_APPLICATION 1
#define HID_COLLECTION_LOGICAL 2
/*
* HID report descriptor global item tags
*/
#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0
#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1
#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2
#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3
#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4
#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5
#define HID_GLOBAL_ITEM_TAG_UNIT 6
#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7
#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8
#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9
#define HID_GLOBAL_ITEM_TAG_PUSH 10
#define HID_GLOBAL_ITEM_TAG_POP 11
/*
* HID report descriptor local item tags
*/
#define HID_LOCAL_ITEM_TAG_USAGE 0
#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1
#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5
#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7
#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8
#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9
#define HID_LOCAL_ITEM_TAG_DELIMITER 10
#ifdef USB_KBD_DEBUG
static void usb_kbd_show_item(struct hid_item *item)
{
switch(item->type)
{
case HID_ITEM_TYPE_MAIN:
switch(item->tag)
{
case HID_MAIN_ITEM_TAG_INPUT: board_printf("Main Input"); break;
case HID_MAIN_ITEM_TAG_OUTPUT: board_printf("Main Output"); break;
case HID_MAIN_ITEM_TAG_FEATURE: board_printf("Main Feature"); break;
case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: board_printf("Main Begin Collection"); break;
case HID_MAIN_ITEM_TAG_END_COLLECTION: board_printf("Main End Collection"); break;
default: board_printf("Main reserved %d",item->tag); break;
}
break;
case HID_ITEM_TYPE_GLOBAL:
switch(item->tag)
{
case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: board_printf("- Global Usage Page"); break;
case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: board_printf("- Global Logical Minimum"); break;
case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: board_printf("- Global Logical Maximum"); break;
case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: board_printf("- Global physical Minimum"); break;
case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: board_printf("- Global physical Maximum"); break;
case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: board_printf("- Global Unit Exponent"); break;
case HID_GLOBAL_ITEM_TAG_UNIT: board_printf("- Global Unit"); break;
case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: board_printf("- Global Report Size"); break;
case HID_GLOBAL_ITEM_TAG_REPORT_ID: board_printf("- Global Report ID"); break;
case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: board_printf("- Global Report Count"); break;
case HID_GLOBAL_ITEM_TAG_PUSH: board_printf("- Global Push"); break;
case HID_GLOBAL_ITEM_TAG_POP: board_printf("- Global Pop"); break;
default: board_printf("- Global reserved %d",item->tag); break;
}
break;
case HID_ITEM_TYPE_LOCAL:
switch(item->tag)
{
case HID_LOCAL_ITEM_TAG_USAGE: board_printf("-- Local Usage"); break;
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: board_printf("-- Local Usage Minimum"); break;
case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: board_printf("-- Local Usage Maximum"); break;
case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX: board_printf("-- Local Designator Index"); break;
case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM: board_printf("-- Local Designator Minimum"); break;
case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM: board_printf("-- Local Designator Maximum"); break;
case HID_LOCAL_ITEM_TAG_STRING_INDEX: board_printf("-- Local String Index"); break;
case HID_LOCAL_ITEM_TAG_STRING_MINIMUM: board_printf("-- Local String Minimum"); break;
case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM: board_printf("-- Local String Maximum"); break;
case HID_LOCAL_ITEM_TAG_DELIMITER: board_printf("-- Local Delimiter"); break;
default: board_printf("-- Local reserved %d",item->tag); break;
}
break;
default:
board_printf("--- reserved %d",item->type);
break;
}
board_printf(" ");
switch(item->size)
{
case 1: board_printf("%d",item->data.u_8); break;
case 2: board_printf("%d",item->data.u_16); break;
case 4: board_printf("%ld",item->data.u_32); break;
}
board_printf("\r\n");
}
#endif /* USB_KBD_DEBUG */
static int usb_kbd_get_hid_desc(struct usb_device *dev)
{
unsigned char *buffer = (unsigned char *)driver_mem_alloc(256);
struct usb_descriptor_header *head;
struct usb_config_descriptor *config;
int index, len;
#ifdef USB_KBD_DEBUG
int i;
unsigned char *start, *end;
struct hid_item item;
#endif
if(buffer == NULL)
return -1;
if(usb_get_configuration_no(dev, &buffer[0], 0) == -1)
{
driver_mem_free(buffer);
return -1;
}
head = (struct usb_descriptor_header *)&buffer[0];
if(head->bDescriptorType!=USB_DT_CONFIG)
{
dbg(" ERROR: NOT USB_CONFIG_DESC %x\r\n",head->bDescriptorType);
driver_mem_free(buffer);
return -1;
}
index = head->bLength;
config = (struct usb_config_descriptor *)&buffer[0];
len = le16_to_cpu(config->wTotalLength);
/* Ok the first entry must be a configuration entry, now process the others */
head = (struct usb_descriptor_header *)&buffer[index];
while(index+1 < len)
{
if(head->bDescriptorType == USB_DT_HID)
{
dbg("HID desc found\r\n");
memcpy(&usb_kbd_hid_desc, &buffer[index],buffer[index]);
le16_to_cpus(&usb_kbd_hid_desc.bcdHID);
le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength);
#ifdef USB_KBD_DEBUG
usb_kbd_display_hid(&usb_kbd_hid_desc);
#endif
len = 0;
break;
}
index += head->bLength;
head = (struct usb_descriptor_header *)&buffer[index];
}
if(len > 0)
{
driver_mem_free(buffer);
return -1;
}
#ifdef USB_KBD_DEBUG
len = usb_kbd_hid_desc.wDescriptorLength;
if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0)
{
dbg("reading report descriptor failed\r\n");
driver_mem_free(buffer);
return -1;
}
dbg(" report descriptor (size %u, read %d)\r\n", len, index);
start = &buffer[0];
end = &buffer[len];
i = 0;
do
{
index = fetch_item(start, end, &item);
i += index;
i++;
if(index >= 0)
usb_kbd_show_item(&item);
start += index;
start++;
}
while(index >= 0);
#endif /* USB_KBD_DEBUG */
driver_mem_free(buffer);
return 0;
}
#endif /* USE_COUNTRYCODE */
/*
usb_get_report(dev, 0, 0, 1, &new_packet[0], 8);
*/