2005-04-16 15:20:36 -07:00
/*
* drivers / input / adbhid . c
*
* ADB HID driver for Power Macintosh computers .
*
* Adapted from drivers / macintosh / mac_keyb . c by Franz Sirl .
* drivers / macintosh / mac_keyb . c was Copyright ( C ) 1996 Paul Mackerras
* with considerable contributions from Ben Herrenschmidt and others .
*
* Copyright ( C ) 2000 Franz Sirl .
*
* Adapted to ADB changes and support for more devices by
* Benjamin Herrenschmidt . Adapted from code in MkLinux
* and reworked .
*
* Supported devices :
*
* - Standard 1 button mouse
* - All standard Apple Extended protocol ( handler ID 4 )
* - mouseman and trackman mice & trackballs
* - PowerBook Trackpad ( default setup : enable tapping )
* - MicroSpeed mouse & trackball ( needs testing )
* - CH Products Trackball Pro ( needs testing )
* - Contour Design ( Contour Mouse )
* - Hunter digital ( NoHandsMouse )
* - Kensignton TurboMouse 5 ( needs testing )
* - Mouse Systems A3 mice and trackballs < aidan @ kublai . com >
* - MacAlly 2 - buttons mouse ( needs testing ) < pochini @ denise . shiny . it >
*
* To do :
*
* Improve Kensington support .
* Split mouse / kbd
* Move to syfs
*/
# include <linux/config.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/notifier.h>
# include <linux/input.h>
# include <linux/adb.h>
# include <linux/cuda.h>
# include <linux/pmu.h>
# include <asm/machdep.h>
# ifdef CONFIG_PPC_PMAC
# include <asm/pmac_feature.h>
# endif
# ifdef CONFIG_PMAC_BACKLIGHT
# include <asm/backlight.h>
# endif
MODULE_AUTHOR ( " Franz Sirl <Franz.Sirl-kernel@lauterbach.com> " ) ;
# define KEYB_KEYREG 0 /* register # for key up/down data */
# define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
# define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
static int adb_message_handler ( struct notifier_block * , unsigned long , void * ) ;
static struct notifier_block adbhid_adb_notifier = {
. notifier_call = adb_message_handler ,
} ;
/* Some special keys */
# define ADB_KEY_DEL 0x33
# define ADB_KEY_CMD 0x37
# define ADB_KEY_CAPSLOCK 0x39
# define ADB_KEY_FN 0x3f
# define ADB_KEY_FWDEL 0x75
# define ADB_KEY_POWER_OLD 0x7e
# define ADB_KEY_POWER 0x7f
u8 adb_to_linux_keycodes [ 128 ] = {
/* 0x00 */ KEY_A , /* 30 */
/* 0x01 */ KEY_S , /* 31 */
/* 0x02 */ KEY_D , /* 32 */
/* 0x03 */ KEY_F , /* 33 */
/* 0x04 */ KEY_H , /* 35 */
/* 0x05 */ KEY_G , /* 34 */
/* 0x06 */ KEY_Z , /* 44 */
/* 0x07 */ KEY_X , /* 45 */
/* 0x08 */ KEY_C , /* 46 */
/* 0x09 */ KEY_V , /* 47 */
/* 0x0a */ KEY_102ND , /* 86 */
/* 0x0b */ KEY_B , /* 48 */
/* 0x0c */ KEY_Q , /* 16 */
/* 0x0d */ KEY_W , /* 17 */
/* 0x0e */ KEY_E , /* 18 */
/* 0x0f */ KEY_R , /* 19 */
/* 0x10 */ KEY_Y , /* 21 */
/* 0x11 */ KEY_T , /* 20 */
/* 0x12 */ KEY_1 , /* 2 */
/* 0x13 */ KEY_2 , /* 3 */
/* 0x14 */ KEY_3 , /* 4 */
/* 0x15 */ KEY_4 , /* 5 */
/* 0x16 */ KEY_6 , /* 7 */
/* 0x17 */ KEY_5 , /* 6 */
/* 0x18 */ KEY_EQUAL , /* 13 */
/* 0x19 */ KEY_9 , /* 10 */
/* 0x1a */ KEY_7 , /* 8 */
/* 0x1b */ KEY_MINUS , /* 12 */
/* 0x1c */ KEY_8 , /* 9 */
/* 0x1d */ KEY_0 , /* 11 */
/* 0x1e */ KEY_RIGHTBRACE , /* 27 */
/* 0x1f */ KEY_O , /* 24 */
/* 0x20 */ KEY_U , /* 22 */
/* 0x21 */ KEY_LEFTBRACE , /* 26 */
/* 0x22 */ KEY_I , /* 23 */
/* 0x23 */ KEY_P , /* 25 */
/* 0x24 */ KEY_ENTER , /* 28 */
/* 0x25 */ KEY_L , /* 38 */
/* 0x26 */ KEY_J , /* 36 */
/* 0x27 */ KEY_APOSTROPHE , /* 40 */
/* 0x28 */ KEY_K , /* 37 */
/* 0x29 */ KEY_SEMICOLON , /* 39 */
/* 0x2a */ KEY_BACKSLASH , /* 43 */
/* 0x2b */ KEY_COMMA , /* 51 */
/* 0x2c */ KEY_SLASH , /* 53 */
/* 0x2d */ KEY_N , /* 49 */
/* 0x2e */ KEY_M , /* 50 */
/* 0x2f */ KEY_DOT , /* 52 */
/* 0x30 */ KEY_TAB , /* 15 */
/* 0x31 */ KEY_SPACE , /* 57 */
/* 0x32 */ KEY_GRAVE , /* 41 */
/* 0x33 */ KEY_BACKSPACE , /* 14 */
/* 0x34 */ KEY_KPENTER , /* 96 */
/* 0x35 */ KEY_ESC , /* 1 */
/* 0x36 */ KEY_LEFTCTRL , /* 29 */
/* 0x37 */ KEY_LEFTMETA , /* 125 */
/* 0x38 */ KEY_LEFTSHIFT , /* 42 */
/* 0x39 */ KEY_CAPSLOCK , /* 58 */
/* 0x3a */ KEY_LEFTALT , /* 56 */
/* 0x3b */ KEY_LEFT , /* 105 */
/* 0x3c */ KEY_RIGHT , /* 106 */
/* 0x3d */ KEY_DOWN , /* 108 */
/* 0x3e */ KEY_UP , /* 103 */
/* 0x3f */ 0 ,
/* 0x40 */ 0 ,
/* 0x41 */ KEY_KPDOT , /* 83 */
/* 0x42 */ 0 ,
/* 0x43 */ KEY_KPASTERISK , /* 55 */
/* 0x44 */ 0 ,
/* 0x45 */ KEY_KPPLUS , /* 78 */
/* 0x46 */ 0 ,
/* 0x47 */ KEY_NUMLOCK , /* 69 */
/* 0x48 */ 0 ,
/* 0x49 */ 0 ,
/* 0x4a */ 0 ,
/* 0x4b */ KEY_KPSLASH , /* 98 */
/* 0x4c */ KEY_KPENTER , /* 96 */
/* 0x4d */ 0 ,
/* 0x4e */ KEY_KPMINUS , /* 74 */
/* 0x4f */ 0 ,
/* 0x50 */ 0 ,
/* 0x51 */ KEY_KPEQUAL , /* 117 */
/* 0x52 */ KEY_KP0 , /* 82 */
/* 0x53 */ KEY_KP1 , /* 79 */
/* 0x54 */ KEY_KP2 , /* 80 */
/* 0x55 */ KEY_KP3 , /* 81 */
/* 0x56 */ KEY_KP4 , /* 75 */
/* 0x57 */ KEY_KP5 , /* 76 */
/* 0x58 */ KEY_KP6 , /* 77 */
/* 0x59 */ KEY_KP7 , /* 71 */
/* 0x5a */ 0 ,
/* 0x5b */ KEY_KP8 , /* 72 */
/* 0x5c */ KEY_KP9 , /* 73 */
/* 0x5d */ KEY_YEN , /* 124 */
/* 0x5e */ KEY_RO , /* 89 */
/* 0x5f */ KEY_KPCOMMA , /* 121 */
/* 0x60 */ KEY_F5 , /* 63 */
/* 0x61 */ KEY_F6 , /* 64 */
/* 0x62 */ KEY_F7 , /* 65 */
/* 0x63 */ KEY_F3 , /* 61 */
/* 0x64 */ KEY_F8 , /* 66 */
/* 0x65 */ KEY_F9 , /* 67 */
/* 0x66 */ KEY_HANJA , /* 123 */
/* 0x67 */ KEY_F11 , /* 87 */
/* 0x68 */ KEY_HANGUEL , /* 122 */
/* 0x69 */ KEY_SYSRQ , /* 99 */
/* 0x6a */ 0 ,
/* 0x6b */ KEY_SCROLLLOCK , /* 70 */
/* 0x6c */ 0 ,
/* 0x6d */ KEY_F10 , /* 68 */
/* 0x6e */ KEY_COMPOSE , /* 127 */
/* 0x6f */ KEY_F12 , /* 88 */
/* 0x70 */ 0 ,
/* 0x71 */ KEY_PAUSE , /* 119 */
/* 0x72 */ KEY_INSERT , /* 110 */
/* 0x73 */ KEY_HOME , /* 102 */
/* 0x74 */ KEY_PAGEUP , /* 104 */
/* 0x75 */ KEY_DELETE , /* 111 */
/* 0x76 */ KEY_F4 , /* 62 */
/* 0x77 */ KEY_END , /* 107 */
/* 0x78 */ KEY_F2 , /* 60 */
/* 0x79 */ KEY_PAGEDOWN , /* 109 */
/* 0x7a */ KEY_F1 , /* 59 */
/* 0x7b */ KEY_RIGHTSHIFT , /* 54 */
/* 0x7c */ KEY_RIGHTALT , /* 100 */
/* 0x7d */ KEY_RIGHTCTRL , /* 97 */
/* 0x7e */ KEY_RIGHTMETA , /* 126 */
/* 0x7f */ KEY_POWER , /* 116 */
} ;
struct adbhid {
2005-09-15 02:01:41 -05:00
struct input_dev * input ;
2005-04-16 15:20:36 -07:00
int id ;
int default_id ;
int original_handler_id ;
int current_handler_id ;
int mouse_kind ;
unsigned char * keycode ;
char name [ 64 ] ;
char phys [ 32 ] ;
int flags ;
} ;
# define FLAG_FN_KEY_PRESSED 0x00000001
# define FLAG_POWER_FROM_FN 0x00000002
# define FLAG_EMU_FWDEL_DOWN 0x00000004
static struct adbhid * adbhid [ 16 ] ;
static void adbhid_probe ( void ) ;
static void adbhid_input_keycode ( int , int , int , struct pt_regs * ) ;
static void init_trackpad ( int id ) ;
static void init_trackball ( int id ) ;
static void init_turbomouse ( int id ) ;
static void init_microspeed ( int id ) ;
static void init_ms_a3 ( int id ) ;
static struct adb_ids keyboard_ids ;
static struct adb_ids mouse_ids ;
static struct adb_ids buttons_ids ;
# ifdef CONFIG_PMAC_BACKLIGHT
/* Exported to via-pmu.c */
int disable_kernel_backlight = 0 ;
# endif /* CONFIG_PMAC_BACKLIGHT */
/* Kind of keyboard, see Apple technote 1152 */
# define ADB_KEYBOARD_UNKNOWN 0
# define ADB_KEYBOARD_ANSI 0x0100
# define ADB_KEYBOARD_ISO 0x0200
# define ADB_KEYBOARD_JIS 0x0300
/* Kind of mouse */
# define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */
# define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */
# define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */
# define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */
# define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */
# define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */
# define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */
# define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */
# define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */
# define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */
static void
adbhid_keyboard_input ( unsigned char * data , int nb , struct pt_regs * regs , int apoll )
{
int id = ( data [ 0 ] > > 4 ) & 0x0f ;
if ( ! adbhid [ id ] ) {
printk ( KERN_ERR " ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x \n " ,
id , data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] ) ;
return ;
}
/* first check this is from register 0 */
if ( nb ! = 3 | | ( data [ 0 ] & 3 ) ! = KEYB_KEYREG )
return ; /* ignore it */
adbhid_input_keycode ( id , data [ 1 ] , 0 , regs ) ;
if ( ! ( data [ 2 ] = = 0xff | | ( data [ 2 ] = = 0x7f & & data [ 1 ] = = 0x7f ) ) )
adbhid_input_keycode ( id , data [ 2 ] , 0 , regs ) ;
}
static void
adbhid_input_keycode ( int id , int keycode , int repeat , struct pt_regs * regs )
{
struct adbhid * ahid = adbhid [ id ] ;
int up_flag ;
up_flag = ( keycode & 0x80 ) ;
keycode & = 0x7f ;
switch ( keycode ) {
case ADB_KEY_CAPSLOCK : /* Generate down/up events for CapsLock everytime. */
2005-09-15 02:01:41 -05:00
input_regs ( ahid - > input , regs ) ;
input_report_key ( ahid - > input , KEY_CAPSLOCK , 1 ) ;
input_report_key ( ahid - > input , KEY_CAPSLOCK , 0 ) ;
input_sync ( ahid - > input ) ;
2005-04-16 15:20:36 -07:00
return ;
# ifdef CONFIG_PPC_PMAC
case ADB_KEY_POWER_OLD : /* Power key on PBook 3400 needs remapping */
switch ( pmac_call_feature ( PMAC_FTR_GET_MB_INFO ,
NULL , PMAC_MB_INFO_MODEL , 0 ) ) {
case PMAC_TYPE_COMET :
case PMAC_TYPE_HOOPER :
case PMAC_TYPE_KANGA :
keycode = ADB_KEY_POWER ;
}
break ;
case ADB_KEY_POWER :
/* Fn + Command will produce a bogus "power" keycode */
if ( ahid - > flags & FLAG_FN_KEY_PRESSED ) {
keycode = ADB_KEY_CMD ;
if ( up_flag )
ahid - > flags & = ~ FLAG_POWER_FROM_FN ;
else
ahid - > flags | = FLAG_POWER_FROM_FN ;
} else if ( ahid - > flags & FLAG_POWER_FROM_FN ) {
keycode = ADB_KEY_CMD ;
ahid - > flags & = ~ FLAG_POWER_FROM_FN ;
}
break ;
case ADB_KEY_FN :
/* Keep track of the Fn key state */
if ( up_flag ) {
ahid - > flags & = ~ FLAG_FN_KEY_PRESSED ;
/* Emulate Fn+delete = forward delete */
if ( ahid - > flags & FLAG_EMU_FWDEL_DOWN ) {
ahid - > flags & = ~ FLAG_EMU_FWDEL_DOWN ;
keycode = ADB_KEY_FWDEL ;
break ;
}
} else
ahid - > flags | = FLAG_FN_KEY_PRESSED ;
/* Swallow the key press */
return ;
case ADB_KEY_DEL :
/* Emulate Fn+delete = forward delete */
if ( ahid - > flags & FLAG_FN_KEY_PRESSED ) {
keycode = ADB_KEY_FWDEL ;
if ( up_flag )
ahid - > flags & = ~ FLAG_EMU_FWDEL_DOWN ;
else
ahid - > flags | = FLAG_EMU_FWDEL_DOWN ;
}
break ;
# endif /* CONFIG_PPC_PMAC */
}
if ( adbhid [ id ] - > keycode [ keycode ] ) {
2005-09-15 02:01:41 -05:00
input_regs ( adbhid [ id ] - > input , regs ) ;
input_report_key ( adbhid [ id ] - > input ,
2005-04-16 15:20:36 -07:00
adbhid [ id ] - > keycode [ keycode ] , ! up_flag ) ;
2005-09-15 02:01:41 -05:00
input_sync ( adbhid [ id ] - > input ) ;
2005-04-16 15:20:36 -07:00
} else
printk ( KERN_INFO " Unhandled ADB key (scancode %#02x) %s. \n " , keycode ,
up_flag ? " released " : " pressed " ) ;
}
static void
adbhid_mouse_input ( unsigned char * data , int nb , struct pt_regs * regs , int autopoll )
{
int id = ( data [ 0 ] > > 4 ) & 0x0f ;
if ( ! adbhid [ id ] ) {
printk ( KERN_ERR " ADB HID on ID %d not yet registered \n " , id ) ;
return ;
}
/*
Handler 1 - - 100 cpi original Apple mouse protocol .
Handler 2 - - 200 cpi original Apple mouse protocol .
For Apple ' s standard one - button mouse protocol the data array will
contain the following values :
BITS COMMENTS
data [ 0 ] = dddd 1100 ADB command : Talk , register 0 , for device dddd .
data [ 1 ] = bxxx xxxx First button and x - axis motion .
data [ 2 ] = byyy yyyy Second button and y - axis motion .
Handler 4 - - Apple Extended mouse protocol .
For Apple ' s 3 - button mouse protocol the data array will contain the
following values :
BITS COMMENTS
data [ 0 ] = dddd 1100 ADB command : Talk , register 0 , for device dddd .
data [ 1 ] = bxxx xxxx Left button and x - axis motion .
data [ 2 ] = byyy yyyy Second button and y - axis motion .
data [ 3 ] = byyy bxxx Third button and fourth button . Y is additional
high bits of y - axis motion . XY is additional
high bits of x - axis motion .
MacAlly 2 - button mouse protocol .
For MacAlly 2 - button mouse protocol the data array will contain the
following values :
BITS COMMENTS
data [ 0 ] = dddd 1100 ADB command : Talk , register 0 , for device dddd .
data [ 1 ] = bxxx xxxx Left button and x - axis motion .
data [ 2 ] = byyy yyyy Right button and y - axis motion .
data [ 3 ] = ? ? ? ? ? ? ? ? unknown
data [ 4 ] = ? ? ? ? ? ? ? ? unknown
*/
/* If it's a trackpad, we alias the second button to the first.
NOTE : Apple sends an ADB flush command to the trackpad when
the first ( the real ) button is released . We could do
this here using async flush requests .
*/
switch ( adbhid [ id ] - > mouse_kind )
{
case ADBMOUSE_TRACKPAD :
data [ 1 ] = ( data [ 1 ] & 0x7f ) | ( ( data [ 1 ] & data [ 2 ] ) & 0x80 ) ;
data [ 2 ] = data [ 2 ] | 0x80 ;
break ;
case ADBMOUSE_MICROSPEED :
data [ 1 ] = ( data [ 1 ] & 0x7f ) | ( ( data [ 3 ] & 0x01 ) < < 7 ) ;
data [ 2 ] = ( data [ 2 ] & 0x7f ) | ( ( data [ 3 ] & 0x02 ) < < 6 ) ;
data [ 3 ] = ( data [ 3 ] & 0x77 ) | ( ( data [ 3 ] & 0x04 ) < < 5 )
| ( data [ 3 ] & 0x08 ) ;
break ;
case ADBMOUSE_TRACKBALLPRO :
data [ 1 ] = ( data [ 1 ] & 0x7f ) | ( ( ( data [ 3 ] & 0x04 ) < < 5 )
& ( ( data [ 3 ] & 0x08 ) < < 4 ) ) ;
data [ 2 ] = ( data [ 2 ] & 0x7f ) | ( ( data [ 3 ] & 0x01 ) < < 7 ) ;
data [ 3 ] = ( data [ 3 ] & 0x77 ) | ( ( data [ 3 ] & 0x02 ) < < 6 ) ;
break ;
case ADBMOUSE_MS_A3 :
data [ 1 ] = ( data [ 1 ] & 0x7f ) | ( ( data [ 3 ] & 0x01 ) < < 7 ) ;
data [ 2 ] = ( data [ 2 ] & 0x7f ) | ( ( data [ 3 ] & 0x02 ) < < 6 ) ;
data [ 3 ] = ( ( data [ 3 ] & 0x04 ) < < 5 ) ;
break ;
case ADBMOUSE_MACALLY2 :
data [ 3 ] = ( data [ 2 ] & 0x80 ) ? 0x80 : 0x00 ;
data [ 2 ] | = 0x80 ; /* Right button is mapped as button 3 */
nb = 4 ;
break ;
}
2005-09-15 02:01:41 -05:00
input_regs ( adbhid [ id ] - > input , regs ) ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , BTN_LEFT , ! ( ( data [ 1 ] > > 7 ) & 1 ) ) ;
input_report_key ( adbhid [ id ] - > input , BTN_MIDDLE , ! ( ( data [ 2 ] > > 7 ) & 1 ) ) ;
2005-04-16 15:20:36 -07:00
if ( nb > = 4 & & adbhid [ id ] - > mouse_kind ! = ADBMOUSE_TRACKPAD )
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , BTN_RIGHT , ! ( ( data [ 3 ] > > 7 ) & 1 ) ) ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
input_report_rel ( adbhid [ id ] - > input , REL_X ,
2005-04-16 15:20:36 -07:00
( ( data [ 2 ] & 0x7f ) < 64 ? ( data [ 2 ] & 0x7f ) : ( data [ 2 ] & 0x7f ) - 128 ) ) ;
2005-09-15 02:01:41 -05:00
input_report_rel ( adbhid [ id ] - > input , REL_Y ,
2005-04-16 15:20:36 -07:00
( ( data [ 1 ] & 0x7f ) < 64 ? ( data [ 1 ] & 0x7f ) : ( data [ 1 ] & 0x7f ) - 128 ) ) ;
2005-09-15 02:01:41 -05:00
input_sync ( adbhid [ id ] - > input ) ;
2005-04-16 15:20:36 -07:00
}
static void
adbhid_buttons_input ( unsigned char * data , int nb , struct pt_regs * regs , int autopoll )
{
int id = ( data [ 0 ] > > 4 ) & 0x0f ;
if ( ! adbhid [ id ] ) {
printk ( KERN_ERR " ADB HID on ID %d not yet registered \n " , id ) ;
return ;
}
2005-09-15 02:01:41 -05:00
input_regs ( adbhid [ id ] - > input , regs ) ;
2005-04-16 15:20:36 -07:00
switch ( adbhid [ id ] - > original_handler_id ) {
default :
case 0x02 : /* Adjustable keyboard button device */
{
int down = ( data [ 1 ] = = ( data [ 1 ] & 0xf ) ) ;
switch ( data [ 1 ] & 0x0f ) {
case 0x0 : /* microphone */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_SOUND , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x1 : /* mute */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_MUTE , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x2 : /* volume decrease */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_VOLUMEDOWN , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x3 : /* volume increase */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_VOLUMEUP , down ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
printk ( KERN_INFO " Unhandled ADB_MISC event %02x, %02x, %02x, %02x \n " ,
data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] ) ;
break ;
}
}
break ;
case 0x1f : /* Powerbook button device */
{
int down = ( data [ 1 ] = = ( data [ 1 ] & 0xf ) ) ;
# ifdef CONFIG_PMAC_BACKLIGHT
int backlight = get_backlight_level ( ) ;
# endif
/*
* XXX : Where is the contrast control for the passive ?
* - - Cort
*/
switch ( data [ 1 ] & 0x0f ) {
case 0x8 : /* mute */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_MUTE , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x7 : /* volume decrease */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_VOLUMEDOWN , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x6 : /* volume increase */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_VOLUMEUP , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0xb : /* eject */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_EJECTCD , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0xa : /* brightness decrease */
# ifdef CONFIG_PMAC_BACKLIGHT
if ( ! disable_kernel_backlight ) {
if ( down & & backlight > = 0 ) {
if ( backlight > BACKLIGHT_OFF )
set_backlight_level ( backlight - 1 ) ;
else
set_backlight_level ( BACKLIGHT_OFF ) ;
}
}
# endif /* CONFIG_PMAC_BACKLIGHT */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_BRIGHTNESSDOWN , down ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x9 : /* brightness increase */
# ifdef CONFIG_PMAC_BACKLIGHT
if ( ! disable_kernel_backlight ) {
if ( down & & backlight > = 0 ) {
if ( backlight < BACKLIGHT_MAX )
set_backlight_level ( backlight + 1 ) ;
else
set_backlight_level ( BACKLIGHT_MAX ) ;
}
}
# endif /* CONFIG_PMAC_BACKLIGHT */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_BRIGHTNESSUP , down ) ;
2005-04-16 15:20:36 -07:00
break ;
2005-05-01 08:58:41 -07:00
case 0xc : /* videomode switch */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_SWITCHVIDEOMODE , down ) ;
2005-05-01 08:58:41 -07:00
break ;
case 0xd : /* keyboard illumination toggle */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_KBDILLUMTOGGLE , down ) ;
2005-05-01 08:58:41 -07:00
break ;
case 0xe : /* keyboard illumination decrease */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_KBDILLUMDOWN , down ) ;
2005-05-01 08:58:41 -07:00
break ;
case 0xf :
switch ( data [ 1 ] ) {
case 0x8f :
case 0x0f :
/* keyboard illumination increase */
2005-09-15 02:01:41 -05:00
input_report_key ( adbhid [ id ] - > input , KEY_KBDILLUMUP , down ) ;
2005-05-01 08:58:41 -07:00
break ;
case 0x7f :
case 0xff :
/* keypad overlay toogle */
break ;
default :
printk ( KERN_INFO " Unhandled ADB_MISC event %02x, %02x, %02x, %02x \n " ,
data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] ) ;
break ;
}
break ;
default :
printk ( KERN_INFO " Unhandled ADB_MISC event %02x, %02x, %02x, %02x \n " ,
data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] ) ;
break ;
2005-04-16 15:20:36 -07:00
}
}
break ;
}
2005-09-15 02:01:41 -05:00
input_sync ( adbhid [ id ] - > input ) ;
2005-04-16 15:20:36 -07:00
}
static struct adb_request led_request ;
static int leds_pending [ 16 ] ;
static int leds_req_pending ;
static int pending_devs [ 16 ] ;
static int pending_led_start = 0 ;
static int pending_led_end = 0 ;
static DEFINE_SPINLOCK ( leds_lock ) ;
static void leds_done ( struct adb_request * req )
{
int leds = 0 , device = 0 , pending = 0 ;
unsigned long flags ;
spin_lock_irqsave ( & leds_lock , flags ) ;
if ( pending_led_start ! = pending_led_end ) {
device = pending_devs [ pending_led_start ] ;
leds = leds_pending [ device ] & 0xff ;
leds_pending [ device ] = 0 ;
pending_led_start + + ;
pending_led_start = ( pending_led_start < 16 ) ? pending_led_start : 0 ;
pending = leds_req_pending ;
} else
leds_req_pending = 0 ;
spin_unlock_irqrestore ( & leds_lock , flags ) ;
if ( pending )
adb_request ( & led_request , leds_done , 0 , 3 ,
ADB_WRITEREG ( device , KEYB_LEDREG ) , 0xff , ~ leds ) ;
}
static void real_leds ( unsigned char leds , int device )
{
unsigned long flags ;
spin_lock_irqsave ( & leds_lock , flags ) ;
if ( ! leds_req_pending ) {
leds_req_pending = 1 ;
spin_unlock_irqrestore ( & leds_lock , flags ) ;
adb_request ( & led_request , leds_done , 0 , 3 ,
ADB_WRITEREG ( device , KEYB_LEDREG ) , 0xff , ~ leds ) ;
return ;
} else {
if ( ! ( leds_pending [ device ] & 0x100 ) ) {
pending_devs [ pending_led_end ] = device ;
pending_led_end + + ;
pending_led_end = ( pending_led_end < 16 ) ? pending_led_end : 0 ;
}
leds_pending [ device ] = leds | 0x100 ;
}
spin_unlock_irqrestore ( & leds_lock , flags ) ;
}
/*
* Event callback from the input module . Events that change the state of
* the hardware are processed here .
*/
static int adbhid_kbd_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
struct adbhid * adbhid = dev - > private ;
unsigned char leds ;
switch ( type ) {
case EV_LED :
leds = ( test_bit ( LED_SCROLLL , dev - > led ) ? 4 : 0 )
| ( test_bit ( LED_NUML , dev - > led ) ? 1 : 0 )
| ( test_bit ( LED_CAPSL , dev - > led ) ? 2 : 0 ) ;
real_leds ( leds , adbhid - > id ) ;
return 0 ;
}
return - 1 ;
}
static int
adb_message_handler ( struct notifier_block * this , unsigned long code , void * x )
{
switch ( code ) {
case ADB_MSG_PRE_RESET :
case ADB_MSG_POWERDOWN :
/* Stop the repeat timer. Autopoll is already off at this point */
{
int i ;
for ( i = 1 ; i < 16 ; i + + ) {
if ( adbhid [ i ] )
2005-09-15 02:01:41 -05:00
del_timer_sync ( & adbhid [ i ] - > input - > timer ) ;
2005-04-16 15:20:36 -07:00
}
}
/* Stop pending led requests */
while ( leds_req_pending )
adb_poll ( ) ;
break ;
case ADB_MSG_POST_RESET :
adbhid_probe ( ) ;
break ;
}
return NOTIFY_DONE ;
}
2005-09-15 02:01:41 -05:00
static int
2005-04-16 15:20:36 -07:00
adbhid_input_register ( int id , int default_id , int original_handler_id ,
int current_handler_id , int mouse_kind )
{
2005-09-15 02:01:41 -05:00
struct adbhid * hid ;
struct input_dev * input_dev ;
int err ;
2005-04-16 15:20:36 -07:00
int i ;
if ( adbhid [ id ] ) {
printk ( KERN_ERR " Trying to reregister ADB HID on ID %d \n " , id ) ;
2005-09-15 02:01:41 -05:00
return - EEXIST ;
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:41 -05:00
adbhid [ id ] = hid = kzalloc ( sizeof ( struct adbhid ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! hid | | ! input_dev ) {
err = - ENOMEM ;
goto fail ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
}
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
sprintf ( hid - > phys , " adb%d:%d.%02x/input " , id , default_id , original_handler_id ) ;
2005-10-31 01:30:32 -05:00
hid - > input = input_dev ;
2005-09-15 02:01:41 -05:00
hid - > id = default_id ;
hid - > original_handler_id = original_handler_id ;
hid - > current_handler_id = current_handler_id ;
hid - > mouse_kind = mouse_kind ;
hid - > flags = 0 ;
input_dev - > private = hid ;
input_dev - > name = hid - > name ;
input_dev - > phys = hid - > phys ;
input_dev - > id . bustype = BUS_ADB ;
input_dev - > id . vendor = 0x0001 ;
input_dev - > id . product = ( id < < 12 ) | ( default_id < < 8 ) | original_handler_id ;
input_dev - > id . version = 0x0100 ;
2005-04-16 15:20:36 -07:00
switch ( default_id ) {
case ADB_KEYBOARD :
2005-09-15 02:01:41 -05:00
hid - > keycode = kmalloc ( sizeof ( adb_to_linux_keycodes ) , GFP_KERNEL ) ;
if ( ! hid - > keycode ) {
err = - ENOMEM ;
goto fail ;
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:41 -05:00
sprintf ( hid - > name , " ADB keyboard " ) ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
memcpy ( hid - > keycode , adb_to_linux_keycodes , sizeof ( adb_to_linux_keycodes ) ) ;
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO " Detected ADB keyboard, type " ) ;
switch ( original_handler_id ) {
default :
printk ( " <unknown>. \n " ) ;
2005-09-15 02:01:41 -05:00
input_dev - > id . version = ADB_KEYBOARD_UNKNOWN ;
2005-04-16 15:20:36 -07:00
break ;
case 0x01 : case 0x02 : case 0x03 : case 0x06 : case 0x08 :
case 0x0C : case 0x10 : case 0x18 : case 0x1B : case 0x1C :
case 0xC0 : case 0xC3 : case 0xC6 :
printk ( " ANSI. \n " ) ;
2005-09-15 02:01:41 -05:00
input_dev - > id . version = ADB_KEYBOARD_ANSI ;
2005-04-16 15:20:36 -07:00
break ;
case 0x04 : case 0x05 : case 0x07 : case 0x09 : case 0x0D :
case 0x11 : case 0x14 : case 0x19 : case 0x1D : case 0xC1 :
case 0xC4 : case 0xC7 :
printk ( " ISO, swapping keys. \n " ) ;
2005-09-15 02:01:41 -05:00
input_dev - > id . version = ADB_KEYBOARD_ISO ;
i = hid - > keycode [ 10 ] ;
hid - > keycode [ 10 ] = hid - > keycode [ 50 ] ;
hid - > keycode [ 50 ] = i ;
2005-04-16 15:20:36 -07:00
break ;
case 0x12 : case 0x15 : case 0x16 : case 0x17 : case 0x1A :
case 0x1E : case 0xC2 : case 0xC5 : case 0xC8 : case 0xC9 :
printk ( " JIS. \n " ) ;
2005-09-15 02:01:41 -05:00
input_dev - > id . version = ADB_KEYBOARD_JIS ;
2005-04-16 15:20:36 -07:00
break ;
}
for ( i = 0 ; i < 128 ; i + + )
2005-09-15 02:01:41 -05:00
if ( hid - > keycode [ i ] )
set_bit ( hid - > keycode [ i ] , input_dev - > keybit ) ;
input_dev - > evbit [ 0 ] = BIT ( EV_KEY ) | BIT ( EV_LED ) | BIT ( EV_REP ) ;
input_dev - > ledbit [ 0 ] = BIT ( LED_SCROLLL ) | BIT ( LED_CAPSL ) | BIT ( LED_NUML ) ;
input_dev - > event = adbhid_kbd_event ;
input_dev - > keycodemax = 127 ;
input_dev - > keycodesize = 1 ;
2005-04-16 15:20:36 -07:00
break ;
case ADB_MOUSE :
2005-09-15 02:01:41 -05:00
sprintf ( hid - > name , " ADB mouse " ) ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
input_dev - > evbit [ 0 ] = BIT ( EV_KEY ) | BIT ( EV_REL ) ;
input_dev - > keybit [ LONG ( BTN_MOUSE ) ] = BIT ( BTN_LEFT ) | BIT ( BTN_MIDDLE ) | BIT ( BTN_RIGHT ) ;
input_dev - > relbit [ 0 ] = BIT ( REL_X ) | BIT ( REL_Y ) ;
2005-04-16 15:20:36 -07:00
break ;
case ADB_MISC :
switch ( original_handler_id ) {
case 0x02 : /* Adjustable keyboard button device */
2005-09-15 02:01:41 -05:00
sprintf ( hid - > name , " ADB adjustable keyboard buttons " ) ;
input_dev - > evbit [ 0 ] = BIT ( EV_KEY ) | BIT ( EV_REP ) ;
set_bit ( KEY_SOUND , input_dev - > keybit ) ;
set_bit ( KEY_MUTE , input_dev - > keybit ) ;
set_bit ( KEY_VOLUMEUP , input_dev - > keybit ) ;
set_bit ( KEY_VOLUMEDOWN , input_dev - > keybit ) ;
2005-04-16 15:20:36 -07:00
break ;
case 0x1f : /* Powerbook button device */
2005-09-15 02:01:41 -05:00
sprintf ( hid - > name , " ADB Powerbook buttons " ) ;
input_dev - > evbit [ 0 ] = BIT ( EV_KEY ) | BIT ( EV_REP ) ;
set_bit ( KEY_MUTE , input_dev - > keybit ) ;
set_bit ( KEY_VOLUMEUP , input_dev - > keybit ) ;
set_bit ( KEY_VOLUMEDOWN , input_dev - > keybit ) ;
set_bit ( KEY_BRIGHTNESSUP , input_dev - > keybit ) ;
set_bit ( KEY_BRIGHTNESSDOWN , input_dev - > keybit ) ;
set_bit ( KEY_EJECTCD , input_dev - > keybit ) ;
set_bit ( KEY_SWITCHVIDEOMODE , input_dev - > keybit ) ;
set_bit ( KEY_KBDILLUMTOGGLE , input_dev - > keybit ) ;
set_bit ( KEY_KBDILLUMDOWN , input_dev - > keybit ) ;
set_bit ( KEY_KBDILLUMUP , input_dev - > keybit ) ;
2005-04-16 15:20:36 -07:00
break ;
}
2005-09-15 02:01:41 -05:00
if ( hid - > name [ 0 ] )
2005-04-16 15:20:36 -07:00
break ;
/* else fall through */
default :
printk ( KERN_INFO " Trying to register unknown ADB device to input layer. \n " ) ;
2005-09-15 02:01:41 -05:00
err = - ENODEV ;
goto fail ;
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:41 -05:00
input_dev - > keycode = hid - > keycode ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:41 -05:00
input_register_device ( input_dev ) ;
2005-04-16 15:20:36 -07:00
if ( default_id = = ADB_KEYBOARD ) {
/* HACK WARNING!! This should go away as soon there is an utility
* to control that for event devices .
*/
2005-09-15 02:01:41 -05:00
input_dev - > rep [ REP_DELAY ] = 500 ; /* input layer default: 250 */
input_dev - > rep [ REP_PERIOD ] = 66 ; /* input layer default: 33 */
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:41 -05:00
return 0 ;
fail : input_free_device ( input_dev ) ;
kfree ( hid ) ;
adbhid [ id ] = NULL ;
return err ;
2005-04-16 15:20:36 -07:00
}
static void adbhid_input_unregister ( int id )
{
2005-09-15 02:01:41 -05:00
input_unregister_device ( adbhid [ id ] - > input ) ;
2005-11-07 01:01:32 -08:00
kfree ( adbhid [ id ] - > keycode ) ;
2005-04-16 15:20:36 -07:00
kfree ( adbhid [ id ] ) ;
adbhid [ id ] = NULL ;
}
static u16
adbhid_input_reregister ( int id , int default_id , int org_handler_id ,
int cur_handler_id , int mk )
{
if ( adbhid [ id ] ) {
2005-09-15 02:01:41 -05:00
if ( adbhid [ id ] - > input - > id . product ! =
2005-04-16 15:20:36 -07:00
( ( id < < 12 ) | ( default_id < < 8 ) | org_handler_id ) ) {
adbhid_input_unregister ( id ) ;
adbhid_input_register ( id , default_id , org_handler_id ,
cur_handler_id , mk ) ;
}
} else
adbhid_input_register ( id , default_id , org_handler_id ,
cur_handler_id , mk ) ;
return 1 < < id ;
}
static void
adbhid_input_devcleanup ( u16 exist )
{
int i ;
for ( i = 1 ; i < 16 ; i + + )
if ( adbhid [ i ] & & ! ( exist & ( 1 < < i ) ) )
adbhid_input_unregister ( i ) ;
}
static void
adbhid_probe ( void )
{
struct adb_request req ;
int i , default_id , org_handler_id , cur_handler_id ;
u16 reg = 0 ;
adb_register ( ADB_MOUSE , 0 , & mouse_ids , adbhid_mouse_input ) ;
adb_register ( ADB_KEYBOARD , 0 , & keyboard_ids , adbhid_keyboard_input ) ;
adb_register ( ADB_MISC , 0 , & buttons_ids , adbhid_buttons_input ) ;
for ( i = 0 ; i < keyboard_ids . nids ; i + + ) {
int id = keyboard_ids . id [ i ] ;
adb_get_infos ( id , & default_id , & org_handler_id ) ;
/* turn off all leds */
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , KEYB_LEDREG ) , 0xff , 0xff ) ;
/* Enable full feature set of the keyboard
- > get it to send separate codes for left and right shift ,
control , option keys */
#if 0 /* handler 5 doesn't send separate codes for R modifiers */
if ( adb_try_handler_change ( id , 5 ) )
printk ( " ADB keyboard at %d, handler set to 5 \n " , id ) ;
else
# endif
if ( adb_try_handler_change ( id , 3 ) )
printk ( " ADB keyboard at %d, handler set to 3 \n " , id ) ;
else
printk ( " ADB keyboard at %d, handler 1 \n " , id ) ;
adb_get_infos ( id , & default_id , & cur_handler_id ) ;
reg | = adbhid_input_reregister ( id , default_id , org_handler_id ,
cur_handler_id , 0 ) ;
}
for ( i = 0 ; i < buttons_ids . nids ; i + + ) {
int id = buttons_ids . id [ i ] ;
adb_get_infos ( id , & default_id , & org_handler_id ) ;
reg | = adbhid_input_reregister ( id , default_id , org_handler_id ,
org_handler_id , 0 ) ;
}
/* Try to switch all mice to handler 4, or 2 for three-button
mode and full resolution . */
for ( i = 0 ; i < mouse_ids . nids ; i + + ) {
int id = mouse_ids . id [ i ] ;
int mouse_kind ;
adb_get_infos ( id , & default_id , & org_handler_id ) ;
if ( adb_try_handler_change ( id , 4 ) ) {
printk ( " ADB mouse at %d, handler set to 4 " , id ) ;
mouse_kind = ADBMOUSE_EXTENDED ;
}
else if ( adb_try_handler_change ( id , 0x2F ) ) {
printk ( " ADB mouse at %d, handler set to 0x2F " , id ) ;
mouse_kind = ADBMOUSE_MICROSPEED ;
}
else if ( adb_try_handler_change ( id , 0x42 ) ) {
printk ( " ADB mouse at %d, handler set to 0x42 " , id ) ;
mouse_kind = ADBMOUSE_TRACKBALLPRO ;
}
else if ( adb_try_handler_change ( id , 0x66 ) ) {
printk ( " ADB mouse at %d, handler set to 0x66 " , id ) ;
mouse_kind = ADBMOUSE_MICROSPEED ;
}
else if ( adb_try_handler_change ( id , 0x5F ) ) {
printk ( " ADB mouse at %d, handler set to 0x5F " , id ) ;
mouse_kind = ADBMOUSE_MICROSPEED ;
}
else if ( adb_try_handler_change ( id , 3 ) ) {
printk ( " ADB mouse at %d, handler set to 3 " , id ) ;
mouse_kind = ADBMOUSE_MS_A3 ;
}
else if ( adb_try_handler_change ( id , 2 ) ) {
printk ( " ADB mouse at %d, handler set to 2 " , id ) ;
mouse_kind = ADBMOUSE_STANDARD_200 ;
}
else {
printk ( " ADB mouse at %d, handler 1 " , id ) ;
mouse_kind = ADBMOUSE_STANDARD_100 ;
}
if ( ( mouse_kind = = ADBMOUSE_TRACKBALLPRO )
| | ( mouse_kind = = ADBMOUSE_MICROSPEED ) ) {
init_microspeed ( id ) ;
} else if ( mouse_kind = = ADBMOUSE_MS_A3 ) {
init_ms_a3 ( id ) ;
} else if ( mouse_kind = = ADBMOUSE_EXTENDED ) {
/*
* Register 1 is usually used for device
* identification . Here , we try to identify
* a known device and call the appropriate
* init function .
*/
adb_request ( & req , NULL , ADBREQ_SYNC | ADBREQ_REPLY , 1 ,
ADB_READREG ( id , 1 ) ) ;
if ( ( req . reply_len ) & &
( req . reply [ 1 ] = = 0x9a ) & & ( ( req . reply [ 2 ] = = 0x21 )
| | ( req . reply [ 2 ] = = 0x20 ) ) ) {
mouse_kind = ADBMOUSE_TRACKBALL ;
init_trackball ( id ) ;
}
else if ( ( req . reply_len > = 4 ) & &
( req . reply [ 1 ] = = 0x74 ) & & ( req . reply [ 2 ] = = 0x70 ) & &
( req . reply [ 3 ] = = 0x61 ) & & ( req . reply [ 4 ] = = 0x64 ) ) {
mouse_kind = ADBMOUSE_TRACKPAD ;
init_trackpad ( id ) ;
}
else if ( ( req . reply_len > = 4 ) & &
( req . reply [ 1 ] = = 0x4b ) & & ( req . reply [ 2 ] = = 0x4d ) & &
( req . reply [ 3 ] = = 0x4c ) & & ( req . reply [ 4 ] = = 0x31 ) ) {
mouse_kind = ADBMOUSE_TURBOMOUSE5 ;
init_turbomouse ( id ) ;
}
else if ( ( req . reply_len = = 9 ) & &
( req . reply [ 1 ] = = 0x4b ) & & ( req . reply [ 2 ] = = 0x4f ) & &
( req . reply [ 3 ] = = 0x49 ) & & ( req . reply [ 4 ] = = 0x54 ) ) {
if ( adb_try_handler_change ( id , 0x42 ) ) {
printk ( " \n ADB MacAlly 2-button mouse at %d, handler set to 0x42 " , id ) ;
mouse_kind = ADBMOUSE_MACALLY2 ;
}
}
}
printk ( " \n " ) ;
adb_get_infos ( id , & default_id , & cur_handler_id ) ;
reg | = adbhid_input_reregister ( id , default_id , org_handler_id ,
cur_handler_id , mouse_kind ) ;
}
adbhid_input_devcleanup ( reg ) ;
}
static void
init_trackpad ( int id )
{
struct adb_request req ;
unsigned char r1_buffer [ 8 ] ;
printk ( " (trackpad) " ) ;
adb_request ( & req , NULL , ADBREQ_SYNC | ADBREQ_REPLY , 1 ,
ADB_READREG ( id , 1 ) ) ;
if ( req . reply_len < 8 )
printk ( " bad length for reg. 1 \n " ) ;
else
{
memcpy ( r1_buffer , & req . reply [ 1 ] , 8 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 9 ,
ADB_WRITEREG ( id , 1 ) ,
r1_buffer [ 0 ] ,
r1_buffer [ 1 ] ,
r1_buffer [ 2 ] ,
r1_buffer [ 3 ] ,
r1_buffer [ 4 ] ,
r1_buffer [ 5 ] ,
0x0d ,
r1_buffer [ 7 ] ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 9 ,
ADB_WRITEREG ( id , 2 ) ,
0x99 ,
0x94 ,
0x19 ,
0xff ,
0xb2 ,
0x8a ,
0x1b ,
0x50 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 9 ,
ADB_WRITEREG ( id , 1 ) ,
r1_buffer [ 0 ] ,
r1_buffer [ 1 ] ,
r1_buffer [ 2 ] ,
r1_buffer [ 3 ] ,
r1_buffer [ 4 ] ,
r1_buffer [ 5 ] ,
0x03 , /*r1_buffer[6],*/
r1_buffer [ 7 ] ) ;
/* Without this flush, the trackpad may be locked up */
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( id ) ) ;
}
}
static void
init_trackball ( int id )
{
struct adb_request req ;
printk ( " (trackman/mouseman) " ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 00 , 0x81 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 01 , 0x81 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 02 , 0x81 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 03 , 0x38 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 00 , 0x81 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 01 , 0x81 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 02 , 0x81 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 1 ) , 03 , 0x38 ) ;
}
static void
init_turbomouse ( int id )
{
struct adb_request req ;
printk ( " (TurboMouse 5) " ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( id ) ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( 3 ) ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 9 ,
ADB_WRITEREG ( 3 , 2 ) ,
0xe7 ,
0x8c ,
0 ,
0 ,
0 ,
0xff ,
0xff ,
0x94 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( 3 ) ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 9 ,
ADB_WRITEREG ( 3 , 2 ) ,
0xa5 ,
0x14 ,
0 ,
0 ,
0x69 ,
0xff ,
0xff ,
0x27 ) ;
}
static void
init_microspeed ( int id )
{
struct adb_request req ;
printk ( " (Microspeed/MacPoint or compatible) " ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( id ) ) ;
/* This will initialize mice using the Microspeed, MacPoint and
other compatible firmware . Bit 12 enables extended protocol .
Register 1 Listen ( 4 Bytes )
0 - 3 Button is mouse ( set also for double clicking ! ! ! )
4 - 7 Button is locking ( affects change speed also )
8 - 11 Button changes speed
12 1 = Extended mouse mode , 0 = normal mouse mode
13 - 15 unused 0
16 - 23 normal speed
24 - 31 changed speed
Register 1 talk holds version and product identification information .
Register 1 Talk ( 4 Bytes ) :
0 - 7 Product code
8 - 23 undefined , reserved
24 - 31 Version number
Speed 0 is max . 1 to 255 set speed in increments of 1 / 256 of max .
*/
adb_request ( & req , NULL , ADBREQ_SYNC , 5 ,
ADB_WRITEREG ( id , 1 ) ,
0x20 , /* alt speed = 0x20 (rather slow) */
0x00 , /* norm speed = 0x00 (fastest) */
0x10 , /* extended protocol, no speed change */
0x07 ) ; /* all buttons enabled as mouse buttons, no locking */
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( id ) ) ;
}
static void
init_ms_a3 ( int id )
{
struct adb_request req ;
printk ( " (Mouse Systems A3 Mouse, or compatible) " ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 3 ,
ADB_WRITEREG ( id , 0x2 ) ,
0x00 ,
0x07 ) ;
adb_request ( & req , NULL , ADBREQ_SYNC , 1 , ADB_FLUSH ( id ) ) ;
}
static int __init adbhid_init ( void )
{
# ifndef CONFIG_MAC
if ( ( _machine ! = _MACH_chrp ) & & ( _machine ! = _MACH_Pmac ) )
return 0 ;
# endif
led_request . complete = 1 ;
adbhid_probe ( ) ;
notifier_chain_register ( & adb_client_list , & adbhid_adb_notifier ) ;
return 0 ;
}
static void __exit adbhid_exit ( void )
{
}
module_init ( adbhid_init ) ;
module_exit ( adbhid_exit ) ;