Index: uspace/srv/kbd/ctl/gxe_fb.c
===================================================================
--- uspace/srv/kbd/ctl/gxe_fb.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/ctl/gxe_fb.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -225,4 +225,9 @@
 }
 
+void kbd_ctl_set_ind(unsigned mods)
+{
+	(void) mods;
+}
+
 /**
  * @}
Index: uspace/srv/kbd/ctl/pc.c
===================================================================
--- uspace/srv/kbd/ctl/pc.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/ctl/pc.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -40,4 +40,5 @@
 #include <io/keycode.h>
 #include <kbd_ctl.h>
+#include <kbd_port.h>
 #include <gsp.h>
 
@@ -45,4 +46,19 @@
 	ds_s,
 	ds_e
+};
+
+enum special_code {
+	SC_ACK = 0xfa,
+	SC_NAK = 0xfe
+};
+
+enum lock_ind_bits {
+	LI_SCROLL	= 0x01,
+	LI_NUM		= 0x02,
+	LI_CAPS		= 0x04
+};
+
+enum kbd_command {
+	KBD_CMD_SET_LEDS = 0xed
 };
 
@@ -194,4 +210,11 @@
 	size_t map_length;
 
+	/*
+	 * ACK/NAK are returned as response to us sending a command.
+	 * We are not interested in them.
+	 */
+	if (scancode == SC_ACK || scancode == SC_NAK)
+		return;
+
 	if (scancode == 0xe0) {
 		ds = ds_e;
@@ -230,4 +253,20 @@
 }
 
+void kbd_ctl_set_ind(unsigned mods)
+{
+	uint8_t b;
+
+	b = 0;
+	if ((mods & KM_CAPS_LOCK) != 0)
+		b = b | LI_CAPS;
+	if ((mods & KM_NUM_LOCK) != 0)
+		b = b | LI_NUM;
+	if ((mods & KM_SCROLL_LOCK) != 0)
+		b = b | LI_SCROLL;
+
+	kbd_port_write(KBD_CMD_SET_LEDS);
+	kbd_port_write(b);
+}
+
 /**
  * @}
Index: uspace/srv/kbd/ctl/pl050.c
===================================================================
--- uspace/srv/kbd/ctl/pl050.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/ctl/pl050.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -258,4 +258,9 @@
 }
 
+void kbd_ctl_set_ind(unsigned mods)
+{
+	(void) mods;
+}
+
 /**
  * @}
Index: uspace/srv/kbd/ctl/stty.c
===================================================================
--- uspace/srv/kbd/ctl/stty.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/ctl/stty.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -224,4 +224,9 @@
 }
 
+void kbd_ctl_set_ind(unsigned mods)
+{
+	(void) mods;
+}
+
 /**
  * @}
Index: uspace/srv/kbd/ctl/sun.c
===================================================================
--- uspace/srv/kbd/ctl/sun.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/ctl/sun.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -72,4 +72,9 @@
 	if (key != 0)
 		kbd_push_ev(type, key);
+}
+
+void kbd_ctl_set_ind(unsigned mods)
+{
+	(void) mods;
 }
 
Index: uspace/srv/kbd/generic/kbd.c
===================================================================
--- uspace/srv/kbd/generic/kbd.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/generic/kbd.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -125,4 +125,7 @@
 			mods = mods ^ (mod_mask & ~lock_keys);
 			lock_keys = lock_keys | mod_mask;
+
+			/* Update keyboard lock indicator lights. */
+			kbd_ctl_set_ind(mods);
 		} else {
 			lock_keys = lock_keys & ~mod_mask;
Index: uspace/srv/kbd/include/kbd_ctl.h
===================================================================
--- uspace/srv/kbd/include/kbd_ctl.h	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/include/kbd_ctl.h	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -40,5 +40,5 @@
 extern void kbd_ctl_parse_scancode(int);
 extern int kbd_ctl_init(void);
-
+extern void kbd_ctl_set_ind(unsigned);
 
 #endif
Index: uspace/srv/kbd/include/kbd_port.h
===================================================================
--- uspace/srv/kbd/include/kbd_port.h	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/include/kbd_port.h	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -38,7 +38,10 @@
 #define KBD_PORT_H_
 
+#include <sys/types.h>
+
 extern int kbd_port_init(void);
 extern void kbd_port_yield(void);
 extern void kbd_port_reclaim(void);
+extern void kbd_port_write(uint8_t);
 
 #endif
Index: uspace/srv/kbd/port/dummy.c
===================================================================
--- uspace/srv/kbd/port/dummy.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/dummy.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -51,4 +51,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 /** @}
 */
Index: uspace/srv/kbd/port/gxemul.c
===================================================================
--- uspace/srv/kbd/port/gxemul.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/gxemul.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -78,4 +78,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 /** Process data sent when a key is pressed.
  *  
Index: uspace/srv/kbd/port/i8042.c
===================================================================
--- uspace/srv/kbd/port/i8042.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/i8042.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -160,4 +160,10 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	pio_write_8(&i8042->data, data);
+	wait_ready();
+}
+
 static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call)
 {
Index: uspace/srv/kbd/port/msim.c
===================================================================
--- uspace/srv/kbd/port/msim.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/msim.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -78,4 +78,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 static void msim_irq_handler(ipc_callid_t iid, ipc_call_t *call)
 {
Index: uspace/srv/kbd/port/pl050.c
===================================================================
--- uspace/srv/kbd/port/pl050.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/pl050.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -102,4 +102,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 static void pl050_irq_handler(ipc_callid_t iid, ipc_call_t *call)
 {
Index: uspace/srv/kbd/port/sgcn.c
===================================================================
--- uspace/srv/kbd/port/sgcn.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/sgcn.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -133,4 +133,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 /**
  * Handler of the "key pressed" event. Reads codes of all the pressed keys from
Index: uspace/srv/kbd/port/ski.c
===================================================================
--- uspace/srv/kbd/port/ski.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/ski.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -78,4 +78,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 /** Thread to poll Ski for keypresses. */
 static void *ski_thread_impl(void *arg)
Index: uspace/srv/kbd/port/sun.c
===================================================================
--- uspace/srv/kbd/port/sun.c	(revision 6ac14a70ed101ee9fa8379a5f9ef15a38f08aec5)
+++ uspace/srv/kbd/port/sun.c	(revision c145bc2fc737a941e2d7e0c94b3479d3c11bb93d)
@@ -71,4 +71,9 @@
 }
 
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
 /** @}
 */
