//---------------------------------------------------------------- // tryled.s // // This program demonstrates use of the Pentium processor's // i/o instructions, used to control the peripheral devices // attached to the PC system bus. In this example the LEDs // on a standard PC keyboard are turned on or off according // to settings of the lowest 3 bits typed as a command-line // argument. // // bit 0: controls LED for 'Scroll-Lock' // bit 1: controls LED for 'Num-Lock' // bit 2: controls LED for 'Caps-Lock' // // Example: tryled 7 # turn on all three LEDs // // NOTE: This demo program does NOT work with USB keyboards. // // programmer: ALLAN CRUSE // written on: 20 NOV 2003 //---------------------------------------------------------------- # manifest constants .equ IO_USER, 3 .equ KB_STAT, 0x64 .equ KB_DATA, 0x60 .equ LED_CMD, 0xED .equ TIMEOUT, 10000 .section .data ledval: .byte 7 # default value for LED settings .section .text #------------------------------------------------------------------ kb_ready: # # This helper function repeatedly inputs the keyboard controller's # status-register and returns as soon as the input-buffer is empty # (i.e., the controller can accept new data), or returns in case a # timeout threshhold has been reached. (The calling procedure can # test the ZF-flag to determine if the controller is 'ready'.) # pushl %eax # preserve caller's registers pushl %ecx movl $TIMEOUT, %ecx # initialize counter for timeout again: inb $KB_STAT, %al # input kb-controller's status testb $2, %al # check: is input-buffer full? loopnz again # yes, controller is still busy popl %ecx # restore caller's registers popl %eax ret #------------------------------------------------------------------ #------------------------------------------------------------------ main: enter $0, $0 # setup access to stackframe cmpl $1, 8(%ebp) # argc > 1? jle noarg # no, use default 'ledval' movl 12(%ebp), %esi # point ESI to argv movl 4(%esi), %esi # point ESI to argv[1] movb (%esi), %al # get argument's first character andb $7, %al # isolate the lowest 3 bits movb %al, ledval # save for control of the LEDs noarg: pushl $IO_USER # desired i/o privilege-level call iopl # call the runtime library addl $4, %esp # discard the parameter orl %eax, %eax # test: nonzero return-value? jnz finis # yes, unable to modify iopl call kb_ready # kb-controller ready for input? jnz finis # no, quit due to malfunction movb $LED_CMD, %al # command-code: modify LEDs outb %al, $KB_DATA # write to controller data-port call kb_ready # kb-controller ready for input? jnz finis # no, quit due to malfunction movb ledval, %al # value for new LED settings outb %al, $KB_DATA # write to controller data-port call kb_ready # kb-controller ready for input? jnz finis # no, quit due to malfunction finis: leave # restore caller's stackframe ret # exit back to the caller #------------------------------------------------------------------ .globl main # make program's entry visible