diff --git a/ChangeLog b/ChangeLog
index 5f7cee2..c682aa8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,7 @@ v0.5dev (ongoing development)
* sed1520: Add an option for inverted segment mapping (idea by R. Buchert)
* Fix build if compiled with --enable-permissive-menu-goto (#3599609)
* glcd driver: Add direct support for framebuffer with paged memory layout
+ + hd44780: Added 'raspberrypi' connection type (P. Corner)
v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
diff --git a/acinclude.m4 b/acinclude.m4
index 6a66dcb..3cc9b6c 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -228,6 +228,15 @@ dnl else
if test "$x_ac_have_i2c" = yes; then
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-i2c.o"
fi
+dnl The hd4470-rpi driver only works on a Raspberry Pi,
+dnl which is an ARM platform. Require people to compile on
+dnl (or for) ARM to get it.
+ case $host in
+ arm*-*-linux*)
+ HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-rpi.o"
+ AC_DEFINE([WITH_RASPBERRYPI],[1],[Define if you are using a Raspberry Pi.])
+ ;;
+ esac
DRIVERS="$DRIVERS hd44780${SO}"
actdrivers=["$actdrivers hd44780"]
;;
diff --git a/docs/lcdproc-user/drivers/hd44780.docbook b/docs/lcdproc-user/drivers/hd44780.docbook
index ff3bf8a..21b7535 100644
--- a/docs/lcdproc-user/drivers/hd44780.docbook
+++ b/docs/lcdproc-user/drivers/hd44780.docbook
@@ -155,6 +155,12 @@ Last but not least, for special purposes, there are even more connection types:
ethlcd:
Display connected via TCP to PoE powered ethlcd device ( )
+
+
+ raspberrypi:
+ LCD connected to the GPIO header of a Raspberry Pi
+
+
@@ -2953,6 +2959,161 @@ software adjustable contrast and brightness (backlight).
+
+Raspberry Pi
+
+This connection type supports a single LCD connected to the GPIO header P1
+on a Raspberry Pi.
+
+It supports a switchable backlight connected to pin P1-11 by default. Use
+the switch circuit as described in .
+
+
+ The signal level on the GPIO pins is 3.3 V and they are said not to
+ be 5 V tolerant. Therefore the R/W pin of the display must
+ be wired to GND to prevent 5V logic appearing on the GPIO
+ pins. For the same reason the backlight cicuit from must not be
+ used.
+ Powering a LCD that uses 5 V from pin P1-02 will work. Powering a
+ LCD from 3.3 V (pin P1-01) will only work if it is designed for 3.3 V
+ operation.
+
+
+
+HD44780: Default pin mapping for Raspberry Pi
+
+
+
+
+
+
+
+
+ Connector
+ <->
+ LCD
+
+
+ Pin Name
+ Pin Number
+ Name
+ Pin
+
+
+
+
+ GPIO18
+ P1-12
+
+ D7
+ 14
+
+
+ GPIO23
+ P1-16
+
+ D6
+ 13
+
+
+ GPIO24
+ P1-18
+
+ D5
+ 12
+
+
+ GPIO25
+ P1-22
+
+ D4
+ 11
+
+
+ GPIO08
+ P1-24
+
+ EN
+ 6
+
+
+ GPIO07
+ P1-26
+
+ RS
+ 4
+
+
+ GND
+ P1-06
+
+ RW
+ 5
+
+
+ GPIO17
+ P1-11
+
+ BL
+ Backlight (optional)
+
+
+
+
+
+GPIO07 and GPIO08 used for RS and EN signal are also used by the SPI
+bus. If you loaded the SPI driver you will need to assign them to a different
+GPIO, e.g. GPIO04 and GPIO22.
+
+
+Special Raspberry Pi configuration options
+
+This connection driver can be configured to use other pins than the
+one described in the table
+above. Using the pin_<name>
+ configuration option, any LCD pin can be assigned
+to any GPIO pin.
+
+
+ The values for the pin_<name>
+ configuration option are the number part from the
+ GPIO signal name, not the pin number from the header connector! To find
+ out which signal is routed to which connector pin refer to the RPi Low-level peripherals
+ description.
+
+
+The connection driver contains a check for possible signal names. You
+will receive an error message if you try to assign a pin to a signal that is
+not available on connector P1 or P5.
+
+
+HD44780: Alternate configuration for Raspberry Pi GPIO pins
+
+
+
+
+
+
+
+
+
+
@@ -3008,6 +3169,7 @@ This can be done by specifying --enable-drivers=all or by inclu
ConnectionType =
{
+
4bit |
8bit |
winamp |
@@ -3018,14 +3180,18 @@ This can be done by specifying --enable-drivers=all or by inclu
vdr-lcd |
vdr-wakeup |
pertelian |
- bwctusb |
- lcd2usb |
- usb4all |
lis2 |
mplay |
- i2c |
+ usblcd |
+ bwctusb |
+ lcd2usb |
+ usbtiny |
+ uss720 |
+ usb4all |
ftdi |
- usblcd
+ i2c |
+ ethlcd |
+ raspberrypi
}
@@ -3079,11 +3245,23 @@ This can be done by specifying --enable-drivers=all or by inclu
vdr-wakeup
VDR-Wakeup module "vdr-wakeup"
-
pertelian
Pertelian X2040 LCD display ( )
+
+
+ lis2
+ LIS2 from VLSystem ( )
+
+
+ mplay
+ MPlay Blast from VLSystem ( )
+
+
+ usblcd
+ USBLCD adapter from Adams IT Services ( )
+
bwctusb
BWCT USB device "bwctusb" ( )
@@ -3092,35 +3270,37 @@ This can be done by specifying --enable-drivers=all or by inclu
lcd2usb
Till Harbaum's LCD2USB ( )
-
- USB-4-all
- The USB-4-all controller board from Sprut ( )
-
usbtiny
Dick Streefland's USBtiny ( )
- lis2
- LIS2 from VLSystem ( )
+ uss720
+ Belkin USS-720 USB-to-IEEE 1284 Bridge
- mplay
- MPlay Blast from VLSystem ( )
+ USB-4-all
+ The USB-4-all controller board from Sprut ( )
ftdi
Display connected to a dual channel FTDI 2232D USB chip
-
- usblcd
- USBLCD adapter from Adams IT Services ( )
-
i2c
LCD driven by PCF8574(A)/PCA9554(A) connected via I2 C
+
+
+ ethlcd
+ ethlcd device ( )
+
+
+
+ raspberrypi
+ LCD connected to the GPIO header of a Raspberry Pi
+
diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am
index 4022197..6a982cf 100644
--- a/server/drivers/Makefile.am
+++ b/server/drivers/Makefile.am
@@ -95,7 +95,7 @@ EXTRA_glcd_SOURCES = glcd-t6963.c t6963_low.c t6963_low.h glcd-png.c glcd-serdis
glcdlib_SOURCES = lcd.h lcd_lib.h glcdlib.h glcdlib.c report.h
glk_SOURCES = lcd.h glk.c glk.h glkproto.c glkproto.h report.h
hd44780_SOURCES = lcd.h lcd_lib.h hd44780.h hd44780.c hd44780-drivers.h hd44780-low.h hd44780-charmap.h report.h adv_bignum.h
-EXTRA_hd44780_SOURCES = hd44780-4bit.c hd44780-4bit.h hd44780-ext8bit.c hd44780-ext8bit.h lcd_sem.c lcd_sem.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-serial.c hd44780-serial.h hd44780-winamp.c hd44780-winamp.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-lis2.c hd44780-lis2.h hd44780-i2c.c hd44780-i2c.h hd44780-ftdi.c hd44780-ftdi.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-uss720.c hd44780-uss720.h hd44780-usblcd.c hd44780-usblcd.h hd44780-usb4all.c hd44780-usb4all.h port.h lpt-port.h timing.h
+EXTRA_hd44780_SOURCES = hd44780-4bit.c hd44780-4bit.h hd44780-ext8bit.c hd44780-ext8bit.h lcd_sem.c lcd_sem.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-serial.c hd44780-serial.h hd44780-winamp.c hd44780-winamp.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-lis2.c hd44780-lis2.h hd44780-i2c.c hd44780-i2c.h hd44780-ftdi.c hd44780-ftdi.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-uss720.c hd44780-uss720.h hd44780-usblcd.c hd44780-usblcd.h hd44780-usb4all.c hd44780-usb4all.h port.h hd44780-rpi.c hd44780-rpi.h lpt-port.h timing.h
i2500vfd_SOURCES = lcd.h i2500vfd.c i2500vfd.h glcd_font5x8.h report.h
icp_a106_SOURCES = lcd.h lcd_lib.h icp_a106.c icp_a106.h report.h
imon_SOURCES = lcd.h lcd_lib.h hd44780-charmap.h imon.h imon.c report.h adv_bignum.h
diff --git a/server/drivers/hd44780-drivers.h b/server/drivers/hd44780-drivers.h
index 4c58cac..9471dac 100644
--- a/server/drivers/hd44780-drivers.h
+++ b/server/drivers/hd44780-drivers.h
@@ -35,7 +35,10 @@
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
#endif
-# include "hd44780-usblcd.h"
+#include "hd44780-usblcd.h"
+#ifdef WITH_RASPBERRYPI
+# include "hd44780-rpi.h"
+#endif
/* add new connection type header files to the correct section above or here */
@@ -81,6 +84,9 @@ static const ConnectionMapping connectionMapping[] = {
/* TCP socket connection types */
#ifdef WITH_ETHLCD
{ "ethlcd", HD44780_CT_ETHLCD, IF_TYPE_TCP, hd_init_ethlcd },
+#endif
+#ifdef WITH_RASPBERRYPI
+ { "raspberrypi", HD44780_CT_RASPBERRYPI, IF_TYPE_PARPORT, hd_init_rpi },
#endif
/* add new connection types in the correct section above or here */
diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h
index 448a1a5..7c6bb22 100644
--- a/server/drivers/hd44780-low.h
+++ b/server/drivers/hd44780-low.h
@@ -53,6 +53,7 @@
#define HD44780_CT_USBLCD 19
#define HD44780_CT_USBTINY 20
#define HD44780_CT_USB4ALL 21
+#define HD44780_CT_RASPBERRYPI 22
/**@}*/
/** \name Symbolic names for interface types
@@ -104,7 +105,7 @@ typedef struct ConnectionMapping {
int if_type;
/** Pointer to connection type's initialization function */
int (*init_fn) (Driver *drvthis);
-} ConnectionMapping;
+} ConnectionMapping;
/**
@@ -153,6 +154,9 @@ typedef struct hd44780_private_data {
#ifdef WITH_ETHLCD
int sock; /**< socket for TCP devices */
#endif
+#ifdef WITH_RASPBERRYPI
+ struct rpi_gpio_map *rpi_gpio; /**< GPIO pin mapping for Raspberry Pi */
+#endif
int charmap; /**< index of currently used charmap */
diff --git a/server/drivers/hd44780-rpi.c b/server/drivers/hd44780-rpi.c
new file mode 100644
index 0000000..9470a1e
--- /dev/null
+++ b/server/drivers/hd44780-rpi.c
@@ -0,0 +1,458 @@
+/** \file server/drivers/hd44780-rpi.c
+ * \c rpi connection type of \c hd44780 driver for Hitachi HD44780 based LCD
+ * displays connected to the GPIO pins on the Raspberry Pi.
+ *
+ * The LCD is operated in its 4 bit-mode. R/W (5) on the LCD MUST be hard wired
+ * low to prevent 5V logic appearing on the GPIO pins.
+ *
+ * The default connections are:
+ * header(GPIO) LCD
+ * P1-12 (18) D7 (14)
+ * P1-16 (23) D6 (13)
+ * P1-18 (24) D5 (12)
+ * P1-22 (25) D4 (11)
+ * P1-24 (8) EN (6)
+ * GND R/W (5)
+ * P1-26 (7) RS (4)
+ * P1-11 (17) BL (backlight optional)
+ *
+ * Mappings can be set in the config file using the key-words:
+ * pin_EN, pin_RS, pin_D7, pin_D6, pin_D5, pin_D4, pin_BL
+ * in the [HD44780] section.
+ *
+ * Only a single LCD is currently supported.
+ */
+
+/*-
+ * Copyright (c) 2012-2013 Paul Corner
+ * 2013 warhog (Conditional ARM test)
+ * 2013 Serac
+ * (Backlight & Rev2 board support)
+ *
+ * The code to access the GPIO on a Raspberry Pi draws on an example program
+ * by Dom and Gert van Loo from:
+ * http://elinux.org/Rpi_Low-level_peripherals#GPIO_Driving_Example_.28C.29
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+/* Default GPIO pin assignment */
+#define RPI_DEF_D7 18
+#define RPI_DEF_D6 23
+#define RPI_DEF_D5 24
+#define RPI_DEF_D4 25
+#define RPI_DEF_RS 7
+#define RPI_DEF_EN 8
+#define RPI_DEF_BL 17
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "hd44780-rpi.h"
+#include "hd44780-low.h"
+#include "report.h"
+
+void lcdrpi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
+void lcdrpi_HD44780_backlight(PrivateData *p, unsigned char state);
+void lcdrpi_HD44780_close(PrivateData *p);
+
+/**
+ * Pointer to the memory mapped GPIO registers. Note the pointer type is
+ * (unsigned int) not (char). This is important when calculating offset
+ * adresses!
+ *
+ * This pointer is outside PrivataData as it needs to be volatile!
+ */
+static volatile unsigned int *gpio_map = NULL;
+
+/*
+ * Two different board revisions are currently in widespread use. The
+ * GPIO mappings differ slightly - Not enough to kill a system yet.
+ * Future models *may* have extra pins added or reassigned to other
+ * functions. Having a revision dependent mapping gives the user fair
+ * warning if they mess up.
+ */
+static const int gpio_pins_R1[GPIO_PINS] = {
+ 0, 1, -1, -1, 4, -1, -1, 7,
+ 8, 9, 10, 11, -1, -1, 14, 15,
+ -1, 17, 18, -1, -1, 21, 22, 23,
+ 24, 25, -1, -1, -1, -1, -1, -1
+};
+
+static const int gpio_pins_R2[GPIO_PINS] = {
+ -1, -1, -1, 3, 4, -1, -1, 7,
+ 8, 9, 10, 11, -1, -1, 14, 15,
+ -1, 17, 18, -1, -1, -1, 22, 23,
+ /* 28-31 accessible via P5 */
+ 24, 25, -1, 27, 28, 29, 30, 31
+};
+
+
+/**
+ * Maps a memory region to the address space of the BM2835 GPIO controller.
+ * \param drvthis Pointer to driver structure.
+ * \return 0 on success, -1 on error.
+ */
+static int
+setup_io(Driver *drvthis)
+{
+ int mem_fd = 0;
+
+ if (gpio_map != NULL) {
+ report(RPT_ERR, "setup_io: IO already in use");
+ return -1;
+ }
+
+ if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
+ report(RPT_ERR, "setup_io: can not open /dev/mem");
+ return -1;
+ }
+
+ gpio_map = (unsigned int *) mmap(NULL,
+ GPIO_BLOCK_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ mem_fd,
+ GPIO_BASE);
+
+ if ((long) gpio_map < 0) {
+ report(RPT_ERR, "setup_io: mmap error %s", strerror(errno));
+ close(mem_fd);
+ return -1;
+ }
+ close(mem_fd);
+
+ debug(RPT_INFO, "setup_io: finished");
+ return 0;
+}
+
+
+/**
+ * Check if LCDd runs on a Raspberry Pi board and which revision (Rev 1 or
+ * Rev 2) it is.
+ * \param drvthis Pointer to driver structure.
+ * \return Pointer to a GPIO mapping table or NULL on error.
+ */
+static int const *
+check_board_rev(Driver *drvthis)
+{
+ FILE *fp;
+ char buf[80];
+ char hw[8];
+ unsigned int rev = 0;
+
+ if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) {
+ report(RPT_ERR, "check_board_rev: Can not open /proc/cpuinfo");
+ return NULL;
+ }
+
+ while (!feof(fp)) {
+ fgets(buf, sizeof(buf), fp);
+ sscanf(buf, "Hardware : %7s", hw);
+ sscanf(buf, "Revision : %x", &rev);
+ }
+ fclose(fp);
+
+ /* On boards that have been overvolted, the MSB will be set */
+ rev &= 0x00ff;
+
+ if (strcmp(hw, "BCM2708") != 0 || rev == 0) {
+ report(RPT_ERR, "check_board_rev: This board is not recognized as a Raspberry Pi!");
+ return NULL;
+ }
+
+ /* Rev 1 boards will be 0x002 or 0x003 (not sure if 0x001 ever existed
+ * in the wild). */
+ if (rev < 4) {
+ report(RPT_INFO, "check_board_rev: Revision 1 board detected");
+ return gpio_pins_R1;
+ }
+ /* Currently, Rev 2 boards are 0x004, 0x005, or 0x006. This will need
+ * updating as new revisions are released, but it is unlikely that P1
+ * will change. */
+ if (rev > 3) {
+ report(RPT_INFO, "check_board_rev: Revision 2 board detected");
+ return gpio_pins_R2;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Check user provided GPIO pin configuration.
+ * \param drvthis Pointer to driver structure.
+ * \param pin Number of the GPIO pin to use.
+ * \param allowed_pins Pointer to array of allowed GPIO pins (depends on
+ * board revision).
+ * \param used_pins Pointer to array of pin usage status.
+ * \return 0 on success, -1 on error.
+ */
+static int
+check_pin(Driver *drvthis, int pin, const int *allowed_pins, int *used_pins)
+{
+ /* Check for errors */
+ if (pin >= GPIO_PINS || pin < 0) {
+ report(RPT_ERR, "check_pin: GPIO pin %i out of range", pin);
+ return -1;
+ }
+ if (allowed_pins[pin] < 0) {
+ report(RPT_ERR, "check_pin: Use of GPIO pin %i not allowed", pin, allowed_pins[pin]);
+ return -1;
+ }
+ if (used_pins[pin] == 1) {
+ report(RPT_ERR, "check_pin: GPIO pin %i already used", pin);
+ return -1;
+ }
+
+ /* Mark used */
+ used_pins[pin] = 1;
+
+ return 0;
+}
+
+
+/**
+ * Configures a GPIO pin: Disable pull-up/down and set it up as output.
+ * \param drvthis Pointer to driver structure.
+ * \param gpio Number of the GPIO pin to use.
+ */
+static void
+setup_gpio(Driver *drvthis, int gpio)
+{
+ volatile int i;
+
+#define GPPUP gpio_map + 37
+#define GPPUDCLK gpio_map + 38
+
+ /* Disable pull-up/down */
+ *(GPPUP) &= ~3;
+
+ /*
+ * After writing to the GPPUD register, need to wait 150 cycles as per
+ * p101 BCM2835.pdf. The following while loop uses approx five
+ * instructions plus another two to load the counter. Note: the int
+ * must be volatile or gcc will optimize loop out.
+ */
+ i = 30;
+ while (--i);
+
+ /* Enable Pull-up/down clock register for the pin */
+ *(GPPUDCLK + (gpio / 32)) = 1 << (gpio % 32);
+
+ /* Another 150 cycle wait required after a write to GPPUDCLK */
+ i = 30;
+ while (--i);
+
+ /* Write again to GPPUD and disable clock */
+ *(GPPUP) &= ~3;
+ *(GPPUDCLK + (gpio / 32)) = 0;
+
+ /*
+ * Now configure the pin as output: This reads the complete GPSELx
+ * register, clears all bits for the selected pin, enables it as
+ * output, and writes back the register.
+ */
+ *(gpio_map + (gpio / 10)) =
+ (*(gpio_map + (gpio / 10)) & ~(7 << ((gpio % 10) * 3))) | (1 << ((gpio % 10) * 3));
+}
+
+
+/**
+ * Free resources used by this connection type.
+ * \param p Pointer to driver's PrivateData structure.
+ */
+void
+lcdrpi_HD44780_close(PrivateData *p)
+{
+ /* Configure all pins as input */
+ INP_GPIO(p->rpi_gpio->en);
+ INP_GPIO(p->rpi_gpio->rs);
+ INP_GPIO(p->rpi_gpio->d7);
+ INP_GPIO(p->rpi_gpio->d6);
+ INP_GPIO(p->rpi_gpio->d5);
+ INP_GPIO(p->rpi_gpio->d4);
+ if (p->have_backlight)
+ INP_GPIO(p->backlight_bit);
+
+ /* Unmap and free memory */
+ if (gpio_map != NULL)
+ munmap((caddr_t) gpio_map, GPIO_BLOCK_SIZE);
+ if (p->rpi_gpio != NULL)
+ free(p->rpi_gpio);
+ p->rpi_gpio = NULL;
+}
+
+/**
+ * Initialize the driver.
+ * \param drvthis Pointer to driver structure.
+ * \retval 0 Success.
+ * \retval -1 Error.
+ */
+int
+hd_init_rpi(Driver *drvthis)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ const int *allowed_gpio_pins = NULL;
+ int used_pins[GPIO_PINS] = {};
+
+ if ((allowed_gpio_pins = check_board_rev(drvthis)) == NULL)
+ return -1;
+
+ /* Get GPIO configuration */
+ p->rpi_gpio = malloc(sizeof(struct rpi_gpio_map));
+ if (p->rpi_gpio == NULL) {
+ report(RPT_ERR, "hd_init_rpi: unable to allocate memory");
+ return -1;
+ }
+
+ p->rpi_gpio->en = drvthis->config_get_int(drvthis->name, "pin_EN", 0, RPI_DEF_EN);
+ p->rpi_gpio->rs = drvthis->config_get_int(drvthis->name, "pin_RS", 0, RPI_DEF_RS);
+ p->rpi_gpio->d7 = drvthis->config_get_int(drvthis->name, "pin_D7", 0, RPI_DEF_D7);
+ p->rpi_gpio->d6 = drvthis->config_get_int(drvthis->name, "pin_D6", 0, RPI_DEF_D6);
+ p->rpi_gpio->d5 = drvthis->config_get_int(drvthis->name, "pin_D5", 0, RPI_DEF_D5);
+ p->rpi_gpio->d4 = drvthis->config_get_int(drvthis->name, "pin_D4", 0, RPI_DEF_D4);
+
+ debug(RPT_INFO, "hd_init_rpi: Pin EN mapped to GPIO%d", p->rpi_gpio->en);
+ debug(RPT_INFO, "hd_init_rpi: Pin RS mapped to GPIO%d", p->rpi_gpio->rs);
+ debug(RPT_INFO, "hd_init_rpi: Pin D4 mapped to GPIO%d", p->rpi_gpio->d4);
+ debug(RPT_INFO, "hd_init_rpi: Pin D5 mapped to GPIO%d", p->rpi_gpio->d5);
+ debug(RPT_INFO, "hd_init_rpi: Pin D6 mapped to GPIO%d", p->rpi_gpio->d6);
+ debug(RPT_INFO, "hd_init_rpi: Pin D7 mapped to GPIO%d", p->rpi_gpio->d7);
+
+ if (check_pin(drvthis, p->rpi_gpio->en, allowed_gpio_pins, used_pins) ||
+ check_pin(drvthis, p->rpi_gpio->rs, allowed_gpio_pins, used_pins) ||
+ check_pin(drvthis, p->rpi_gpio->d7, allowed_gpio_pins, used_pins) ||
+ check_pin(drvthis, p->rpi_gpio->d6, allowed_gpio_pins, used_pins) ||
+ check_pin(drvthis, p->rpi_gpio->d5, allowed_gpio_pins, used_pins) ||
+ check_pin(drvthis, p->rpi_gpio->d4, allowed_gpio_pins, used_pins)) {
+ free(p->rpi_gpio);
+ return -1;
+ }
+
+ if (p->have_backlight) { /* Backlight setup is optional */
+ p->backlight_bit = drvthis->config_get_int(drvthis->name, "pin_BL", 0, RPI_DEF_BL);
+ debug(RPT_INFO, "hd_init_rpi: Backlight mapped to GPIO%d", p->backlight_bit);
+
+ if (check_pin(drvthis, p->backlight_bit, allowed_gpio_pins, used_pins) != 0) {
+ report(RPT_WARNING, "hd_init_rpi: Invalid backlight configuration - disabling backlight");
+ p->have_backlight = 0;
+ }
+ }
+
+ /* Now that configuration should be correct, set up the GPIO pins */
+ if (setup_io(drvthis) < 0) {
+ report(RPT_ERR, "hd_init_rpi: Failed to set up GPIO");
+ free(p->rpi_gpio);
+ return -1;
+ }
+
+ setup_gpio(drvthis, p->rpi_gpio->en);
+ setup_gpio(drvthis, p->rpi_gpio->rs);
+ setup_gpio(drvthis, p->rpi_gpio->d7);
+ setup_gpio(drvthis, p->rpi_gpio->d6);
+ setup_gpio(drvthis, p->rpi_gpio->d5);
+ setup_gpio(drvthis, p->rpi_gpio->d4);
+
+ p->hd44780_functions->senddata = lcdrpi_HD44780_senddata;
+ p->hd44780_functions->close = lcdrpi_HD44780_close;
+
+ if (p->have_backlight) {
+ setup_gpio(drvthis, p->backlight_bit);
+ p->hd44780_functions->backlight = lcdrpi_HD44780_backlight;
+ }
+
+ /* Setup the lcd in 4 bit mode: Send (FUNCSET | IF_8BIT) three times
+ * followed by (FUNCSET | IF_4BIT) using four nibbles. Timing is not
+ * exactly what is required by HD44780. */
+ p->hd44780_functions->senddata(p, 0, RS_INSTR, 0x33);
+ p->hd44780_functions->uPause(p, 4100);
+ p->hd44780_functions->senddata(p, 0, RS_INSTR, 0x32 );
+ p->hd44780_functions->uPause(p, 150);
+
+ common_init(p, IF_4BIT);
+
+ return 0;
+}
+
+
+/**
+ * Send data or commands to the display.
+ * \param p Pointer to driver's private data structure.
+ * \param displayID ID of the display (or 0 for all) to send data to.
+ * \param flags Defines whether to end a command or data.
+ * \param ch The value to send.
+ */
+void
+lcdrpi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
+{
+ /* Only one display is (currently) supported */
+ if (displayID > 1) {
+ return;
+ }
+ /* Safeguard: This should never happen */
+ if (gpio_map == NULL) {
+ return;
+ }
+
+ if (flags == RS_INSTR) {
+ SET_GPIO(p->rpi_gpio->rs, 0);
+ }
+ else { /* flags == RS_DATA */
+ SET_GPIO(p->rpi_gpio->rs, 1);
+ }
+ /* Clear data lines ready for nibbles */
+ SET_GPIO(p->rpi_gpio->d7, 0);
+ SET_GPIO(p->rpi_gpio->d6, 0);
+ SET_GPIO(p->rpi_gpio->d5, 0);
+ SET_GPIO(p->rpi_gpio->d4, 0);
+ p->hd44780_functions->uPause(p, 50);
+
+ /* Output upper nibble first */
+ SET_GPIO(p->rpi_gpio->d7, (ch & 0x80));
+ SET_GPIO(p->rpi_gpio->d6, (ch & 0x40));
+ SET_GPIO(p->rpi_gpio->d5, (ch & 0x20));
+ SET_GPIO(p->rpi_gpio->d4, (ch & 0x10));
+ p->hd44780_functions->uPause(p, 50);
+
+ /* Data is clocked on the falling edge of EN */
+ SET_GPIO(p->rpi_gpio->en, 1);
+ p->hd44780_functions->uPause(p, 50);
+ SET_GPIO(p->rpi_gpio->en, 0);
+ p->hd44780_functions->uPause(p, 50);
+
+ /* Do same for lower nibble */
+ SET_GPIO(p->rpi_gpio->d7, 0);
+ SET_GPIO(p->rpi_gpio->d6, 0);
+ SET_GPIO(p->rpi_gpio->d5, 0);
+ SET_GPIO(p->rpi_gpio->d4, 0);
+ p->hd44780_functions->uPause(p, 50);
+ SET_GPIO(p->rpi_gpio->d7, (ch & 0x08));
+ SET_GPIO(p->rpi_gpio->d6, (ch & 0x04));
+ SET_GPIO(p->rpi_gpio->d5, (ch & 0x02));
+ SET_GPIO(p->rpi_gpio->d4, (ch & 0x01));
+ p->hd44780_functions->uPause(p, 50);
+ SET_GPIO(p->rpi_gpio->en, 1);
+ p->hd44780_functions->uPause(p, 50);
+ SET_GPIO(p->rpi_gpio->en, 0);
+ p->hd44780_functions->uPause(p, 50);
+}
+
+
+/**
+ * Turn display backlight on or off.
+ * \param p Pointer to driver's private data structure.
+ * \param state New backlight status.
+ */
+void
+lcdrpi_HD44780_backlight(PrivateData *p, unsigned char state)
+{
+ if (p->backlight_bit > -1 && p->backlight_bit < 32)
+ SET_GPIO(p->backlight_bit, (state == BACKLIGHT_ON) ? 1 : 0);
+}
diff --git a/server/drivers/hd44780-rpi.h b/server/drivers/hd44780-rpi.h
new file mode 100644
index 0000000..99847eb
--- /dev/null
+++ b/server/drivers/hd44780-rpi.h
@@ -0,0 +1,36 @@
+#ifndef HD_LCDRPI_H
+#define HD_LCDRPI_H
+
+#include "lcd.h" /* for Driver */
+
+/* initialize this particular driver */
+int hd_init_rpi(Driver *drvthis);
+
+/**
+ * rpi_gpio_map is addressed through the hd44780_private_data struct. Data
+ * stored here is used for mapping physical GPIO pins to BCM2835 gpio. */
+struct rpi_gpio_map {
+ int en;
+ int rs;
+ int d7;
+ int d6;
+ int d5;
+ int d4;
+};
+
+/** Peripheral base address of the BCM2835 */
+#define BCM2835_PERI_BASE 0x20000000
+/** GPIO register start address */
+#define GPIO_BASE BCM2835_PERI_BASE + 0x200000
+/** Length of register space */
+#define GPIO_BLOCK_SIZE 180
+/** The Pi has 32 GPIO pins */
+#define GPIO_PINS 32
+
+
+/** Setup a GPIO pin as input */
+#define INP_GPIO(g) *(gpio_map+((g)/10)) &= ~(7<<(((g)%10)*3))
+/** Sets or clears a GPIO pin */
+#define SET_GPIO(g,a) *(gpio_map+((a)?7:10))=1<<((g)%32);
+
+#endif // HD_LCDRPI_H