diff --git a/docs/man/man9/hostmot2.9 b/docs/man/man9/hostmot2.9
index ecad0ee..e4f4c76 100644
--- a/docs/man/man9/hostmot2.9
+++ b/docs/man/man9/hostmot2.9
@@ -100,7 +100,7 @@ Best to try loading it and see what the detection order is.
 
 The format of each board's config string is:
 
-.B [firmware=\fIF\fB] [num_encoders=\fIN\fB] [num_pwmgens=\fIN\fB] [num_3pwmgens=\fIN\fB] [num_stepgens=\fIN\fB] [enable_raw]
+.B [firmware=\fIF\fB] [num_encoders=\fIN\fB] [num_pwmgens=\fIN\fB] [num_3pwmgens=\fIN\fB] [num_stepgens=\fIN\fB] [num_leds==\fIN\fB] [enable_raw]
 .RS
 .TP
 \fBfirmware\fR [optional]
@@ -144,6 +144,10 @@ Only enable the first N stepgens.  If N is -1, all stepgens are enabled.
 If N is 0, no stepgens are enabled.  If N is greater than the number of
 stepgens available in the firmware, the board will fail to register.
 .TP
+\fBnum_leds\fR [optional, default: -1]
+Only enable the first N of the LEDs on the FPGA board. If N is -1, then HAL
+pins for all the LEDs will be created. If N=0 then no pins will be added.
+.TP
 \fBenable_raw\fR [optional]
 If specified, this turns on a raw access mode, whereby a user can peek and
 poke the firmware from HAL.  See Raw Mode below.
@@ -496,6 +500,17 @@ instances have this parameter.
 value of the GPIO will be the inverse of the value on the "out" HAL pin.
 Only full GPIO pins and IO pins used as outputs by active module instances
 have this parameter.
+
+.SH led
+
+Creates HAL pins for the LEDs on the FPGA board. 
+
+Pins: 
+
+(bit in) CR<NN>: The pins are numbered from CR01 upwards with the name 
+corresponding to the PCB silkscreen. Setting the bit to "true" or 1 lights
+the led. 
+
 .SH Watchdog
 
 The HostMot2 firmware may include a watchdog Module; if it does, the
diff --git a/src/Makefile b/src/Makefile
index 711ad8d..35ece20 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -670,6 +670,7 @@ hostmot2-objs :=                          \
     hal/drivers/mesa-hostmot2/stepgen.o   \
     hal/drivers/mesa-hostmot2/watchdog.o  \
     hal/drivers/mesa-hostmot2/pins.o      \
+	hal/drivers/mesa-hostmot2/led.o       \
     hal/drivers/mesa-hostmot2/tram.o      \
     hal/drivers/mesa-hostmot2/raw.o       \
     hal/drivers/mesa-hostmot2/bitfile.o   \
diff --git a/src/hal/drivers/mesa-hostmot2/hostmot2.c b/src/hal/drivers/mesa-hostmot2/hostmot2.c
index 77d2ffb..bfe6985 100644
--- a/src/hal/drivers/mesa-hostmot2/hostmot2.c
+++ b/src/hal/drivers/mesa-hostmot2/hostmot2.c
@@ -114,6 +114,7 @@ static void hm2_write(void *void_hm2, long period) {
 	hm2_tp_pwmgen_write(hm2); // update Three Phase PWM registers if needed
     hm2_stepgen_write(hm2);   // update stepgen registers if needed
     hm2_encoder_write(hm2);   // update ctrl register if needed
+    hm2_led_write(hm2);	      // Update on-board LEDs
     hm2_raw_write(hm2);
 }
 
@@ -174,6 +175,7 @@ const char *hm2_get_general_function_name(int gtag) {
         case HM2_GTAG_PWMGEN:          return "PWMGen";
         case HM2_GTAG_TRANSLATIONRAM:  return "TranslationRAM";
         case HM2_GTAG_TPPWM:		   return "ThreePhasePWM";
+        case HM2_GTAG_LED:             return "LED";
         default: {
             static char unknown[100];
             rtapi_snprintf(unknown, 100, "(unknown-gtag-%d)", gtag);
@@ -193,6 +195,7 @@ static int hm2_parse_config_string(hostmot2_t *hm2, char *config_string) {
     hm2->config.num_pwmgens = -1;
 	hm2->config.num_tp_pwmgens = -1;
     hm2->config.num_stepgens = -1;
+    hm2->config.num_leds = -1;
     hm2->config.enable_raw = 0;
     hm2->config.firmware = NULL;
 
@@ -227,6 +230,10 @@ static int hm2_parse_config_string(hostmot2_t *hm2, char *config_string) {
             token += 13;
             hm2->config.num_stepgens = simple_strtol(token, NULL, 0);
 
+        } else if (strncmp(token, "num_leds=", 9) == 0) {
+            token += 9;
+            hm2->config.num_leds = simple_strtol(token, NULL, 0);
+
         } else if (strncmp(token, "enable_raw", 10) == 0) {
             hm2->config.enable_raw = 1;
 
@@ -634,6 +641,10 @@ static int hm2_parse_module_descriptors(hostmot2_t *hm2) {
                 md_accepted = hm2_tp_pwmgen_parse_md(hm2, md_index);
                 break;
                 
+            case HM2_GTAG_LED:
+                md_accepted = hm2_led_parse_md(hm2, md_index);
+                break;
+                
             default:
                 HM2_WARN(
                     "MD %d: %dx %s v%d: ignored\n",
@@ -687,6 +698,7 @@ static void hm2_cleanup(hostmot2_t *hm2) {
     hm2_watchdog_cleanup(hm2);
     hm2_pwmgen_cleanup(hm2);
     hm2_tp_pwmgen_cleanup(hm2);
+    hm2_led_cleanup(hm2);
     // free all the tram entries
     hm2_tram_cleanup(hm2);
 }
diff --git a/src/hal/drivers/mesa-hostmot2/hostmot2.h b/src/hal/drivers/mesa-hostmot2/hostmot2.h
index ef69603..8987894 100644
--- a/src/hal/drivers/mesa-hostmot2/hostmot2.h
+++ b/src/hal/drivers/mesa-hostmot2/hostmot2.h
@@ -101,6 +101,7 @@ char **argv_split(gfp_t gfp, const char *str, int *argcp);
 #define HM2_GTAG_PWMGEN           (6)
 #define HM2_GTAG_TRANSLATIONRAM  (11)
 #define HM2_GTAG_TPPWM			 (19)
+#define HM2_GTAG_LED            (128)
 
 
 
@@ -633,7 +634,26 @@ typedef struct {
     u32 *reset_reg;
 } hm2_watchdog_t;
 
+//
+// On-board LEDs
+//
+
+typedef struct {
+        hal_bit_t *led;
+    } hm2_led_instance_t ;
+
+typedef struct {
+    
+    int num_instances ;
 
+    hm2_led_instance_t *instance ;
+    
+    u32 written_buff ;
+    
+    u32 led_addr;
+    u32 *led_reg;
+    
+} hm2_led_t ;
 
 
 // 
@@ -684,6 +704,7 @@ typedef struct {
         int num_pwmgens;
         int num_tp_pwmgens;
         int num_stepgens;
+        int num_leds;
         int enable_raw;
         char *firmware;
     } config;
@@ -715,7 +736,7 @@ typedef struct {
     hm2_stepgen_t stepgen;
     hm2_ioport_t ioport;
     hm2_watchdog_t watchdog;
-    
+    hm2_led_t led;
     hm2_raw_t *raw;
 
     struct list_head list;
@@ -877,6 +898,14 @@ void hm2_watchdog_force_write(hostmot2_t *hm2);
 
 
 // 
+// LED functions
+//
+
+int hm2_led_parse_md(hostmot2_t *hm2, int md_index);
+void hm2_led_write(hostmot2_t *hm2);
+void hm2_led_cleanup(hostmot2_t *hm2);
+
+// 
 // the raw interface lets you peek and poke the hostmot2 instance from HAL
 //
 
diff --git a/src/hal/drivers/mesa-hostmot2/led.c b/src/hal/drivers/mesa-hostmot2/led.c
new file mode 100644
index 0000000..e952235
--- /dev/null
+++ b/src/hal/drivers/mesa-hostmot2/led.c
@@ -0,0 +1,162 @@
+
+//
+//    Copyright (C) 2010 Andy Pugh
+
+//    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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+//
+
+// Onboard LED driver for the Mesa FPGA cards
+
+
+#include <linux/slab.h>
+
+#include "rtapi.h"
+#include "rtapi_app.h"
+#include "rtapi_string.h"
+#include "rtapi_math.h"
+
+#include "hal.h"
+
+#include "hal/drivers/mesa-hostmot2/hostmot2.h"
+
+int hm2_led_parse_md(hostmot2_t *hm2, int md_index) {
+    
+    hm2_module_descriptor_t *md = &hm2->md[md_index];
+    int r;
+    int led_count;
+    
+    
+    // 
+    // some standard sanity checks
+    //
+    
+    if (!hm2_md_is_consistent_or_complain(hm2, md_index, 0, 1, 4, 0x0000)) {
+        HM2_ERR("inconsistent Module Descriptor!\n");
+        return -EINVAL;
+    }
+    
+    
+    // Choose the max number of LEDs from the board ID
+    if (strcmp(hm2->idrom.board_name, "hm2_7i43")) {
+        led_count = 8;
+    }
+    else if (strcmp(hm2->idrom.board_name, "hm2_5i20")) {
+        led_count = 8;
+    }
+    else if (strcmp(hm2->idrom.board_name, "hm2_5i22")) {
+        led_count = 8;
+    }
+    else if (strcmp(hm2->idrom.board_name, "hm2_5i23")) {
+        led_count = 2;
+    }
+    else if (strcmp(hm2->idrom.board_name, "hm2_4i65")) {
+        led_count = 8;
+    }
+    else if (strcmp(hm2->idrom.board_name, "hm2_4i68")) {
+        led_count = 4;
+    }
+    else if (strcmp(hm2->idrom.board_name, "hm2_3x20")) {
+        led_count = 0; // Without knowing how it works, don't try
+    }
+    else {
+        led_count = 8;
+        HM2_ERR("Unknown board type %s, Defaulting to 8 onboard LEDs", hm2->idrom.board_name);
+    }
+    
+    if (led_count == 0 || hm2->config.num_leds == 0) return 0;
+    
+    if (hm2->config.num_leds > led_count) {
+        hm2->config.num_leds = led_count;
+        HM2_ERR( "There are only %d LEDs on this board type, defaulting to %d\n", led_count, hm2->config.num_leds );
+    }
+    else if (hm2->config.num_leds == -1) {
+        hm2->config.num_leds = led_count;
+    }
+    
+    // 
+    // looks good, start initializing
+    // 
+    
+    
+    // allocate the module-global HAL shared memory
+    hm2->led.instance = (hm2_led_instance_t *)hal_malloc(hm2->config.num_leds * sizeof(hm2_led_instance_t));
+    if (hm2->led.instance == NULL) {
+        HM2_ERR("out of memory!\n");
+        r = -ENOMEM;
+        goto fail0;
+    }
+    hm2->led.led_reg = (u32 *)kmalloc( sizeof(u32), GFP_KERNEL);
+    if (hm2->led.led_reg == NULL) {
+        HM2_ERR("out of memory!\n");
+        r = -ENOMEM;
+        goto fail0;
+    }
+    
+    hm2->led.led_addr = md->base_address;
+    
+    // export to HAL
+    // FIXME: r hides the r in enclosing function, and it returns the wrong thing
+    {
+        int i;
+        char name[HAL_NAME_LEN];
+        for (i = 0 ; i < hm2->config.num_leds ; i++) {
+            rtapi_snprintf(name, HAL_NAME_LEN, "%s.led.CR%02d", hm2->llio->name, i + 1 );
+            r = hal_pin_bit_new(name, HAL_IN, &(hm2->led.instance[i].led), hm2->llio->comp_id);
+            if (r < 0) {
+                HM2_ERR("error adding pin '%s', aborting\n", name);
+                goto fail1;
+            }
+        }
+        return 1;
+        
+    fail1:
+        
+        kfree(hm2->led.led_reg);
+        
+    fail0:
+        return r;
+        
+    }
+}
+
+void hm2_led_write(hostmot2_t *hm2) {
+    u32 regval = 0;
+    int i;
+    
+    for (i = 0 ; i < hm2->config.num_leds; i++ ) {
+        if (*hm2->led.instance[i].led == true) {
+            regval |= 1; 
+        }
+        
+        regval = (regval | *hm2->led.instance[i].led) << 1;
+
+    }
+    
+    regval = regval << (31 - hm2->config.num_leds); // The leds are in the high-order bits
+
+    if (regval != hm2->led.written_buff) {
+        HM2_PRINT_NO_LL("regval = %X\n", regval);
+        *hm2->led.led_reg = regval;
+        hm2->led.written_buff = regval;
+        hm2->llio->write(hm2->llio, hm2->led.led_addr, hm2->led.led_reg, sizeof(u32));
+    }
+}
+
+void hm2_led_cleanup(hostmot2_t *hm2) {
+if (hm2->led.led_reg != NULL) {
+    kfree(hm2->led.led_reg);
+    hm2->led.led_reg = NULL;
+    }
+}
\ No newline at end of file
