Portable and maintable HD44780 driver files.

This commit is contained in:
blt
2000-02-21 11:24:09 +00:00
parent 6cefefd52c
commit e481f1311e
12 changed files with 978 additions and 0 deletions
+196
View File
@@ -0,0 +1,196 @@
/*
* 4-bit driver module for Hitachi HD44780 based LCD displays.
* The LCD is operated in it's 4 bit-mode to be connected to a single
* 8 bit-port.
*
* Copyright (c) 2000, 1999, 1995 Benjamin Tse <blt@Comports.com>
* 1999 Andrew McMeikan <andrewm@engineer.com>
* 1998 Richard Rognlie <rrognlie@gamerz.net>
* 1997 Matthias Prinke <m.prinke@trashcan.mcnet.de>
*
* The connections are:
* printer port LCD
* D0 (2) D4 (11)
* D1 (3) D5 (12)
* D2 (4) D6 (13)
* D3 (5) D7 (14)
* D4 (6) RS (4)
* D5 (7) RW (5) (LCD3 - 6) (optional - pull all LCD RW low)
* D6 (8) EN (6)
* D7 (9) EN2 (LCD2 - 6) (optional)
*
* Extended interface (including LCD3 above)
* STR (1) EN4
* LF (14) EN5
* INIT (16) EN6
* SEL (17) EN7
*
* Added support for up to 7 LCDs Jan 2000, Benjamin Tse
* Created modular driver Dec 1999, Benjamin Tse <blt@Comports.com>
*
* Based on Matthias Prinke's <m.prinke@trashcan.mcnet.de> lcd4.c module
* in lcdstat. This was in turn based on Benjamin Tse's lcdtime package
* which uses the LCD controller in its 8-bit mode.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
#include "hd44780-4bit.h"
#include "port.h"
#include "../../shared/str.h"
#include <sys/perm.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
// Generally, any function that accesses the LCD control lines needs to be
// implemented separately for each HW design. This is typically just
// HD44780_senddata
void lcdstat_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch);
#define RS 0x10
#define RW 0x20
#define EN1 0x40
#define EN2 0x80
#define EN3 0x20
static unsigned char EnMask[] = { EN1, EN2, EN3, STRB, LF, INIT, SEL };
static int EnMaskSize = sizeof(EnMask) / sizeof(unsigned char);
static unsigned int lptPort;
static int extIF = 0; // non-zero if extended interface
// initialisation function
int hd_init_4bit(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port)
{
// TODO: remove magic numbers below
char *argv[64];
int argc;
int i;
int displayID = EN1 | EN2;
lptPort = port;
hd44780_functions->senddata = lcdstat_HD44780_senddata;
// parse command-line arguments
argc = get_args(argv, args, 64);
for (i = 0; i < argc; ++i)
{
if (strcmp(argv[i], "-e") == 0 ||
strcmp(argv[i], "--extended") == 0)
{
extIF = 1;
if ((ioperm(port + 2, 1, 255)) == -1) {
fprintf(stderr, "HD44780_init: failed (%s)\n", strerror(errno));
return -1;
}
}
}
// powerup the lcd now
if (extIF)
{
displayID |= EN3;
port_out(lptPort + 2, 0 ^ OUTMASK);
}
port_out(lptPort, displayID | 0x03);
if (extIF) port_out(lptPort + 2,
(EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
hd44780_functions->uPause(1);
port_out(lptPort, 0x03);
if (extIF) port_out(lptPort + 2, 0 ^ OUTMASK);
hd44780_functions->uPause(4100);
port_out(lptPort, displayID | 0x03);
if (extIF) port_out(lptPort + 2,
(EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
hd44780_functions->uPause(1);
port_out(lptPort, 0x03);
if (extIF) port_out(lptPort + 2, 0 ^ OUTMASK);
hd44780_functions->uPause(100);
port_out(lptPort, displayID | 0x03);
if (extIF) port_out(lptPort + 2,
(EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
hd44780_functions->uPause(1);
port_out(lptPort, 0x03);
if (extIF) port_out(lptPort + 2, 0 ^ OUTMASK);
hd44780_functions->uPause(40);
// now in 8-bit mode... set 4-bit mode
port_out(lptPort,displayID | 0x02);
if (extIF) port_out(lptPort + 2,
(EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK);
hd44780_functions->uPause(1);
port_out(lptPort, 0x02);
if (extIF) port_out(lptPort + 2, 0 ^ OUTMASK);
hd44780_functions->uPause(40);
common_init(IF_4bit);
return 0;
}
// lcdstat_HD44780_senddata
void lcdstat_HD44780_senddata(unsigned char displayID,
unsigned char iflags,
unsigned char ch)
{
unsigned char dispID = 0, flags = 0;
unsigned char h = (ch >> 4) & 0x0f; // high and low nibbles
unsigned char l = ch & 0x0f;
if (iflags == RS_INSTR)
flags = 0;
else //if (iflags == RS_DATA)
flags = RS;
if (displayID <= 3)
{
if (displayID == 0)
dispID = EnMask[0] | EnMask[1] | EnMask[2];
else
dispID = EnMask[displayID - 1];
port_out(lptPort, flags | h);
hd44780_functions->uPause(2);
port_out(lptPort, dispID | flags | h);
hd44780_functions->uPause(4);
port_out(lptPort, flags | h);
port_out(lptPort, dispID | flags | l);
hd44780_functions->uPause(4);
port_out(lptPort, flags | l);
}
if (extIF && (displayID == 0 || displayID >= 4))
{
if (displayID == 0)
dispID = EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6];
else
dispID = EnMask[(displayID - 1) % EnMaskSize];
port_out(lptPort, flags | h);
hd44780_functions->uPause(2);
port_out(lptPort + 2, dispID ^ OUTMASK);
hd44780_functions->uPause(4);
port_out(lptPort + 2, 0 ^ OUTMASK);
port_out(lptPort, flags | l);
port_out(lptPort + 2, dispID ^ OUTMASK);
hd44780_functions->uPause(4);
port_out(lptPort + 2, 0 ^ OUTMASK);
}
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef HD_LCDSTAT_H
#define HD_LCDSTAT_H
#include "lcd.h" /* for lcd_logical_driver */
#include "hd44780-low.h" /* for HD44780_functions */
// initialise this particular driver
int hd_init_4bit(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port);
#endif
+53
View File
@@ -0,0 +1,53 @@
/*
* Low-level driver types, headers and names.
*
* To add support for a new driver in this file:
* 1. include your header file
* 2. Add a new connectionType
* 3. Add an entry in the connectionMapping structure
*/
#ifndef HD44780_DRIVERS_H
#define HD44780_DRIVERS_H
// hd44780 specific header files
#include "hd44780-4bit.h"
#include "hd44780-ext8bit.h"
#include "hd44780-serialLpt.h"
#include "hd44780-winamp.h"
// add new connection type header files here
enum connectionType { HD_4bit, HD_8bit, HD_serialLpt, HD_winamp,
// add new connection types here
HD_unknown };
static struct ConnectionMapping
{
enum connectionType type;
char *connectionTypeStr;
int (*init_fn)(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port);
const char *helpMsg;
} connectionMapping[] = {
// connectionType enumerator
// string to identify connection on command line
// your initialisation function
// help string for your particular connection
{ HD_4bit, "4bit", hd_init_4bit,
"\t-e\t--extended\tEnable three or more displays\n" },
{ HD_8bit, "8bit", hd_init_ext8bit,
"\tnone\n" },
{ HD_serialLpt, "serialLpt", hd_init_serialLpt,
"\tnone\n" },
{ HD_winamp, "winamp", hd_init_winamp,
"\t-e\t--extended\tEnable three or more displays\n" },
// add new connection types and their string specifier here
// default, end of structure element (do not delete)
{ HD_unknown, "", NULL, "" }
};
#endif
+109
View File
@@ -0,0 +1,109 @@
/*
* 8-bit driver module for Hitachi HD44780 based LCD displays.
* The LCD is operated in it's 8 bit-mode to be connected to a single
* PC parallel port.
*
* Copyright (c) 1999, 1995 Benjamin Tse <blt@Comports.com>
*
* The connections are:
* printer port LCD
* D0 (2) D0 (7)
* D1 (3) D1 (8)
* D2 (4) D2 (9)
* D3 (5) D3 (10)
* D4 (6) D4 (11)
* D5 (7) D5 (12)
* D6 (8) D6 (13)
* D7 (9) D7 (14)
* nSEL (17) -
* nSTRB (1) RS (4)
* nLF (14) RW (5) (LCD2 - 6) (optional - pull all LCD RW low)
* INIT (16) EN (6)
*
* Created modular driver Dec 1999, Benjamin Tse <blt@Comports.com>
*
* Based on the code in the lcdtime package which uses the LCD
* controller in its 8-bit mode.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
#include "hd44780-ext8bit.h"
#include "port.h"
#include "lcd_sem.h"
#include <sys/perm.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
// Generally, any function that accesses the LCD control lines needs to be
// implemented separately for each HW design. This is typically (but not
// restricted to):
// HD44780_senddata
void lcdtime_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch);
#define nRS nSTRB
#define nRW nLF
#define EN1 INIT
#define METER_OFF nSEL
#define SETUPLCD (METER_OFF | nRS)
#define CTRL (nRW | METER_OFF | nRS)
#define CHAR (nRW | METER_OFF)
static unsigned int lptPort;
static int semid;
// initialise the driver
int hd_init_ext8bit(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port)
{
lptPort = port;
semid = sem_get();
hd44780_functions->senddata = lcdtime_HD44780_senddata;
if ((ioperm(port + 2, 1, 255)) == -1) {
fprintf(stderr, "HD44780_init: failed (%s)\n", strerror(errno));
return -1;
}
common_init(IF_8bit);
return 0;
}
// lcdtime_HD44780_senddata
void lcdtime_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch)
{
unsigned char dispID = 0, portControl;
if (displayID == 1)
dispID |= EN1;
else //if (displayID == 0)
dispID |= EN1;
if (flags == RS_DATA)
portControl = CHAR;
else
portControl = CTRL;
sem_wait(semid);
port_out(lptPort + 2, SETUPLCD);
port_out(lptPort, ch);
port_out(lptPort + 2, dispID | portControl);
hd44780_functions->uPause(1);
port_out(lptPort + 2, portControl);
sem_signal(semid);
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef HD_EXT8BIT_H
#define HD_EXT8BIT_H
#include "lcd.h" /* for lcd_logical_driver */
#include "hd44780-low.h" /* for HD44780_functions */
// initialise this particular driver
int hd_init_ext8bit(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port);
#endif
+102
View File
@@ -0,0 +1,102 @@
// This header contains low level code to export from hd44780.c to "lower" HW
// implementation dependent files.
#ifndef HD_LOW_H
#define HD_LOW_H
enum ifWidth { IF_4bit, IF_8bit };
void common_init(enum ifWidth ifwidth);
// Structures holding pointers to HD44780 specific functions
typedef struct hwDependentFns
{
// microsec pauses
void (*uPause)(int microSecondsTenths);
// senddata to the LCD
// dispID - display to send data to (0 = all displays)
// flags - data or instruction command (RS_DATA | RS_INSTR)
// ch - character to display or instruction value
void (*senddata)(unsigned char dispID, unsigned char flags, unsigned char ch);
// position the cursor
// dispID - display to send data to (0 = all displays)
// DDaddr - display data address (see sect 2.5.2 of the LCD module FAQ)
void (*position)(int dispID, int DDaddr);
// toggle vertical autoscroll on all displays
// on - non-zero turns autoscroll on, zero value turns it off
void (*autoscroll)(int on);
} HD44780_functions; /* for want of a better name :-) */
extern HD44780_functions *hd44780_functions;
// commands for senddata
#define RS_DATA 0x00
#define RS_INSTR 0x01
#define CLEAR 0x01
#define HOMECURSOR 0x02
#define ENTRYMODE 0x04
#define E_MOVERIGHT 0x02
#define E_MOVELEFT 0x00
#define EDGESCROLL 0x01
#define NOSCROLL 0x00
#define ONOFFCTRL 0x08
#define DISPON 0x04
#define DISPOFF 0x00
#define CURSORON 0x02
#define CURSOROFF 0x00
#define CURSORBLINK 0x01
#define CURSORNOBLINK 0x00
#define CURSORSHIFT 0x10
#define SCROLLDISP 0x08
#define MOVECURSOR 0x00
#define MOVERIGHT 0x04
#define MOVELEFT 0x00
#define FUNCSET 0x20
#define IF_8BIT 0x10
#define IF_4BIT 0x00
#define TWOLINE 0x08
#define ONELINE 0x00
#define LARGECHAR 0x04 /* 5x11 characters */
#define SMALLCHAR 0x00 /* 5x8 characters */
#define SETCHAR 0x40
#define POSITION 0x80
// Parallel port pin definitions
// Output lines
#define nSTRB 0x01 /* negative logic */
#define STRB 0x01
#define nLF 0x02
#define LF 0x02
#define INIT 0x04 /* the only positive logic output line */
#define nSEL 0x08
#define SEL 0x08
#define OUTMASK 0x0B
// Input lines
#define nFAULT 0x08
#define FAULT 0x08
#define SELIN 0x10
#define PAPEREND 0x20
#define nACK 0x40
#define ACK 0x40
#define BUSY 0x80
#define INMASK 0x48
#endif
+173
View File
@@ -0,0 +1,173 @@
/*
* Serial LPT driver module for Hitachi HD44780 based LCD displays by
* Andrew McMeikan. The LCD is operated in it's 4 bit-mode through a
* 4094 shift register and supports a keypad.
*
* Copyright (c) 1999 Andrew McMeikan <andrewm@engineer.com>
* modular driver 1999 Benjamin Tse <blt@Comports.com>
*
* Full connection details at http://members.xoom.com/andrewmuck/LCD.htm
*
* printer port 4094/LCD
* D2 (4) EN (6 - LCD)
* D3 (5) D (2 - 4094)
* D4 (6) CLK (3 - 4094)
* +Vcc OE, STR (15, 1 - 4094)
* D7 (9) EN2 (6 - LCD2) (optional)
*
* 4094 LCD
* Q1 (4) D4 (11)
* Q2 (5) D5 (12)
* Q3 (6) D6 (13)
* Q4 (7) D7 (14)
* Q6 (13) RS (4)
* Gnd nRW (5)
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
#include "hd44780-serialLpt.h"
#include "port.h"
// Hardware specific functions
void lcdserLpt_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch);
static char lcdserLpt_HD44780_getkey(void);
void rawshift(unsigned char r);
void shiftreg(unsigned char displayID, unsigned char r);
#define RS 16
#define LCDDATA 8
#define LCDCLOCK 16
#define EN1 4
#define EN2 32
static unsigned int lp;
static char lastkey=0;
// Initialisation
int hd_init_serialLpt(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port)
{
int displayID = EN1 | EN2;
lp = port;
hd44780_functions->senddata = lcdserLpt_HD44780_senddata;
// TODO: enable keypad only if specified on command line
driver->getkey = lcdserLpt_HD44780_getkey;
// setup the lcd in 4 bit mode
shiftreg(displayID,3);
hd44780_functions->uPause(4100);
shiftreg(displayID,3);
hd44780_functions->uPause(100);
shiftreg(displayID,3);
hd44780_functions->uPause(40);
shiftreg(displayID,2);
hd44780_functions->uPause(40);
// set display type functions
lcdserLpt_HD44780_senddata(0,
RS_INSTR,
FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR);
// clear
lcdserLpt_HD44780_senddata(0, RS_INSTR, CLEAR);
hd44780_functions->uPause(1600);
// Now turn on the display
lcdserLpt_HD44780_senddata(displayID,
RS_INSTR,
ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK);
hd44780_functions->uPause(1600);
return 0;
}
void lcdserLpt_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch)
{
unsigned char dispID = 0,
portControl = 0,
h = ch >> 4,
l = ch & 15;
if (displayID == 1)
dispID |= EN1;
else if (displayID == 2)
dispID |= EN2;
else
dispID |= EN1 | EN2;
if (flags == RS_DATA)
portControl = RS;
else
portControl = 0;
shiftreg(displayID,flags | portControl | h);
shiftreg(displayID,flags | portControl | l);
/* TODO: instead of delay read keys here */
}
char lcdserLpt_HD44780_getkey()
{
// TODO: a keypad scan that does not use shift register
// define a key table
char keytr[]="ABCDEFGH";
int n;
rawshift(0); //send all line on shift register low
hd44780_functions->uPause(1);
if ((port_in(lp+1)&32)==0) //test if line back is low - if not return(0)
{ //else
//start walking a single zero across the eight lines
for(n=7;n>=0;n--)
{
rawshift(255 - (1<<n));
hd44780_functions->uPause(1);
if ((port_in(lp+1)&32)==0) // check if line back is low if yes debounce
{
if (lastkey==keytr[n])
return(0);
// printf("key is %c %d\n",keytr[n],n);
lastkey=keytr[n];
return(keytr[n]); //return correct key code.
}
}
} //else fall out and return(0) [too transient a keypress]
lastkey=0;
return(0);
}
/* this function sends r out onto the shift register */
void rawshift (unsigned char r)
{
int i;
for (i=7;i>=0;i--) /* MSB first */
{
port_out(lp,((r>>i)&1)*LCDDATA); /*set up data */
port_out(lp,(((r>>i)&1)*LCDDATA)|LCDCLOCK);/*rising edge of clock */
}
}
// displayID = value on parallel port to toggle the correct display
void shiftreg (unsigned char displayID, unsigned char r)
{
rawshift(r);
port_out(lp,displayID); //latch it, to correct display
port_out(lp,0);
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef HD_SERIALLPT_H
#define HD_SERIALLPT_H
#include "lcd.h" /* for lcd_logical_driver */
#include "hd44780-low.h" /* for HD44780_functions */
// initialise this particular driver
int hd_init_serialLpt(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port);
#endif
+109
View File
@@ -0,0 +1,109 @@
/*
* "Winamp" 8-bit driver module for Hitachi HD44780 based LCD displays.
* The LCD is operated in it's 8 bit-mode to be connected to a single
* PC parallel port.
*
* Copyright (c) 1999 Andrew McMeikan <andrewm@engineer.com>
* modular driver 1999-2000 Benjamin Tse <blt@Comports.com>
*
* The connections are:
* printer port LCD
* D0 (2) D0 (7)
* D1 (3) D1 (8)
* D2 (4) D2 (9)
* D3 (5) D3 (10)
* D4 (6) D4 (11)
* D5 (7) D5 (12)
* D6 (8) D6 (13)
* D7 (9) D7 (14)
* nSTRB (1) EN (6)
* nLF (14) nRW (5) (EN3 6 - LCD 3) (optional)
* INIT (16) RS (4)
* nSEL (17) EN2 (6 - LCD 2) (optional)
*
* Created modular driver Dec 1999, Benjamin Tse <blt@Comports.com>
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
#include "hd44780-winamp.h"
#include "port.h"
#include "../../shared/str.h"
#include <sys/perm.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
void lcdwinamp_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch);
#define EN1 STRB
#define EN2 SEL
#define EN3 LF
#define RS INIT
static unsigned char EnMask[] = { EN1, EN2, EN3 };
static int EnMaskSize = sizeof(EnMask) / sizeof(unsigned char);
static unsigned int lptPort;
static int extIF = 0; // non-zero if extended interface
// initialise the driver
int hd_init_winamp(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port)
{
// TODO: remove magic numbers below
char *argv[64];
int argc;
int i;
hd44780_functions->senddata = lcdwinamp_HD44780_senddata;
lptPort = port;
// parse command-line arguments
argc = get_args(argv, args, 64);
for (i = 0; i < argc; ++i)
if (strcmp(argv[i], "-e") == 0 ||
strcmp(argv[i], "--extended") == 0)
extIF = 1;
if ((ioperm(lptPort + 2, 1, 255)) == -1) {
fprintf(stderr, "HD44780_init: failed (%s)\n", strerror(errno));
return -1;
}
common_init(IF_8bit);
return 0;
}
// lcdwinamp_HD44780_senddata
void lcdwinamp_HD44780_senddata(unsigned char displayID,
unsigned char flags,
unsigned char ch)
{
unsigned char dispID = 0, portControl;
if (flags == RS_DATA)
portControl = RS;
else
portControl = 0;
if (displayID == 0)
dispID = EnMask[0] | EnMask [1] | ((extIF) ? EnMask[2] : 0);
else
dispID = EnMask[displayID - 1];
port_out(lptPort, ch);
port_out(lptPort + 2, (dispID | portControl) ^ OUTMASK);
hd44780_functions->uPause(1);
port_out(lptPort + 2, portControl ^ OUTMASK);
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef HD_WINAMP_H
#define HD_WINAMP_H
#include "lcd.h" /* for lcd_logical_driver */
#include "hd44780-low.h" /* for HD44780_functions */
// initialise this particular driver, args is probably not used but keep
// for consistency
int hd_init_winamp(HD44780_functions *hd44780_functions,
lcd_logical_driver *driver,
char *args,
unsigned int port);
#endif
+170
View File
@@ -0,0 +1,170 @@
/*
* lcd_sem.c -- semaphore code written for lcdtime and meter to mediate
* access to the parallel port.
*
* Written by Benjamin Tse (blt@mundil.cs.mu.edu.au); August,October 1995
*
* Functions in this file:
* getkey returns the key for the semaphore
* sem_get create the semaphore (and initialise) if one doesn't exist
* otherwise return its key
* sem_wait wait on the semaphore
* sem_signal signal on the semaphore
* sem_remove remove the semaphore
*
* Legal stuff: At no stage was this program written, assembled or compiled on
* any computer at the University of Melbourne, Australia. This program is
* Copyright (C) 1995 Benjamin Tse (blt@mundil.cs.mu.oz.au) and covered by
* GNU's GPL. In particular, this program is free software and comes WITHOUT
* ANY WARRANTY.
*
* $Id$
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* for semaphore functions */
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include "lcd_sem.h"
#define SEMAPHORE "portctrl"
#define SEMKEY 0x706f7274 /* semaphore key */
#define SEMCOUNT 1 /* number of semaphores to create */
#define WMODE 0660 /* access permissions */
#define SEM_SIGNAL 0,1,SEM_UNDO
#define SEM_WAIT 0,-1,SEM_UNDO
/* functions local to this file */
static key_t getkey(register char *p);
/* global variables */
static struct sembuf semaphore_wait = {SEM_WAIT};
static struct sembuf semaphore_signal = {SEM_SIGNAL};
static char rcsId[] = "$Id$";
/*
* getkey returns the key for the semaphore
*/
static key_t
getkey(register char *p)
{
return((key_t) SEMKEY);
}
/*
* create the semaphore if one doesn't exist and initialise it to 1, else
* return the semaphore set id
*/
int
sem_get(void)
{
int semid;
union semun semval;
if ((semid = semget(getkey(SEMAPHORE), SEMCOUNT,
IPC_CREAT | IPC_EXCL | WMODE)) < 0)
{
switch (errno)
{
case EEXIST:
/* semaphore set exists, get id and return it */
if ((semid = semget(getkey(SEMAPHORE), SEMCOUNT,
IPC_EXCL | WMODE)) < 0)
{
perror("semget");
exit(1);
}
return semid;
break;
case EACCES:
/* don't have permissions for semaphore, need to change key */
perror("semget, can't get permissions for semaphore");
exit(1);
break;
default:
perror("semget");
exit(1);
break;
}
}
else
{
/* initialise semaphore to 1 */
semval.val = 1;
if (semctl(semid, 0, SETVAL, semval) < 0)
{
perror("setval, can't initialise semaphore");
exit(1);
}
}
return semid;
}
/*
* wait on the semaphore
*/
int
sem_wait(int sid)
{
if (semop(sid, &semaphore_wait, 1) < -1)
{
perror(SEMAPHORE);
exit(1);
}
return 0;
}
/*
* signal on the semaphore
*/
int
sem_signal(int sid)
{
if (semop(sid, &semaphore_signal, 1) < -1)
{
perror(SEMAPHORE);
exit(1);
}
return 0;
}
/*
* remove the semaphore
*/
int
sem_remove(int sid)
{
int i;
union semun dummy;
if ((i = semctl(sid, 0, IPC_RMID, dummy)) < 0)
{
switch(i)
{
case EIDRM:
/* semaphore removed */
return 0;
break;
default:
perror("semctl, removing semaphore");
exit(1);
}
}
return 0;
}
+13
View File
@@ -0,0 +1,13 @@
/*
* header file for lcd semaphore operations
*/
#ifndef LCD_SEM_H
#define LCD_SEM_H
int sem_get(void);
int sem_wait(int sid);
int sem_signal(int sid);
int sem_remove(int sid);
#endif