Subversion Repositories shark

Rev

Rev 1034 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
 *   Luca Abeni          <luca@gandalf.sssup.it>
 *   Mauro Marinoni      <mauro.marinoni@unipv.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/*
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


//#define __KEYB_DEBUG__
#define KEYB_TASK

#include <kernel/kern.h>
#include <kernel/int_sem.h>
#include <signal.h>

#include "../include/drivers/shark_input26.h"
#include "../include/drivers/shark_keyb26.h"

/* Devices */
extern int  atkbd_init(int soft);
extern int  atkbd_exit(void);

/* Handlers */
extern int  kbd_init(void);
extern int  kbd_exit(void);

/* Functions */
extern int  kbd_enable(void);
extern int  kbd_disable(void);
extern int  kbd_get(unsigned int *data, BYTE access);
extern void kbd_setleds(unsigned int led);
extern int  kbd_rate(unsigned int *delay, unsigned int *period);
extern void kbd_mksound(unsigned int hz, unsigned int ticks);

/*
 * The following tables contains the ascii code corresponding to the
 * scan codes, with shift & no shift...
 */

char keyTable     [TABLE_KEY_SIZE];
char keyShiftTable[TABLE_KEY_SIZE];
char keyAltGrTable[TABLE_KEY_SIZE];

BYTE useAltGr = FALSE;

/* Status variables */
static BYTE shift = FALSE;
static BYTE ctrl  = FALSE;
static BYTE alt   = FALSE;
static BYTE altgr = FALSE;

static BYTE capslock   = FALSE;
static BYTE numlock    = TRUE;
static BYTE scrolllock = FALSE;

/* Keyboard Flags (if shift, alt or control are pressed...); */
static BYTE keyFlag = 0x00;
static BYTE status;

/* Keyboard driver currently installed */
static int keyb_installed = FALSE;


#define MAX_KEY_EXC     50

static struct keyexctable
{
        KEY_EVT evt;
        void (*func) (KEY_EVT * k);
        unsigned char lock;
} keyExcTable[MAX_KEY_EXC];

static int lastExc;

/* Buffer used for the communication between the extern process & the user */

/* Buffer Ssize */
#define KEYBUFF_SIZE 256
/* Buffer Mask ( i=(i+1)&MASK is better than i=(i+1)%SIZE ) */
#define KEYBUFF_MASK 0xff

static KEY_EVT keybuff[KEYBUFF_SIZE];
static int keybuff_head = 1;
static int keybuff_tail = 0;
static internal_sem_t keybuff_mutex;
static int keybuff_mutex_init = 0;

#ifdef KEYB_TASK
/* keyboard task PID */
static PID keybpid;
#else
static void keyProc(void);
#endif

/*
 * Start keyProc Task or exec it as function
 */

void shark_kbd_exec(void)
{
#ifdef KEYB_TASK
        task_activate(keybpid);
#else
        keyProc();
#endif
}

/*
 * This function get a scan code, return an ascii code and set
 * the status vars in order to handle the special keys of the AT keyboard
 */

WORD scanCode(unsigned int c, int d)
{
        //printk("scanCode: c (%x) - d (%d)\n", c, d);

        /* KEY_EVT status setting */
        status = 1 << d;
       
        switch (c) {
                /* CapsLock pressed*/
                case KEY_CPSLOCK:
                        if (d == KEY_PRESSED) {
                                capslock = capslock ? FALSE : TRUE;
                                /* light the caps lock led */
                                kbd_setleds(scrolllock + (numlock << 1) + (capslock << 2));
                        }
                        return 0;
                /* NumLock pressed */
                case PAD_NUMLOCK:
                        if (d == KEY_PRESSED) {
                                numlock = numlock ? FALSE : TRUE;
                                /* light the num lock led */
                                kbd_setleds(scrolllock + (numlock << 1) + (capslock << 2));
                        }
                        return 0;
                /* ScrollLock pressed*/
                case EXT_SCRLOCK:
                        if (d == KEY_PRESSED) {
                                scrolllock = scrolllock ? FALSE : TRUE;
                                /* light the scroll lock led */
                                kbd_setleds(scrolllock + (numlock << 1) + (capslock << 2));
                        }
                        return 0;
                /* Shift pressed or released */
                case KEY_SHL:
                        if (d) {
                                shift = TRUE;
                                if (c == KEY_SHL)
                                        keyFlag |= SHFL_BIT;
                        } else {
                                keyFlag &= (!SHFL_BIT);
                                if (!(keyFlag & SHFR_BIT))
                                        shift = FALSE;
                        }
                        return 0;
                /* Shift pressed or released */
                case KEY_SHR:
                        if (d) {
                                shift = TRUE;
                                if (c == KEY_SHR)
                                        keyFlag |= SHFR_BIT;
                        } else {
                                keyFlag &= (!SHFR_BIT);
                                if (!(keyFlag & SHFL_BIT))
                                        shift = FALSE;
                        }
                        return 0;
                /* Control pressed or released */
                case KEY_CTRLL:
                        if (d) {
                                ctrl = TRUE;
                                keyFlag |= CNTL_BIT;
                        } else {
                                keyFlag &= (!CNTL_BIT);
                                if (!(keyFlag & CNTR_BIT))
                                        ctrl = FALSE;
                        }
                        return 0;
                /* Control pressed or released */
                case KEY_CTRLR:
                        if (d) {
                                ctrl = TRUE;
                                keyFlag |= CNTR_BIT;
                        } else {
                                keyFlag &= (!CNTR_BIT);
                                if (!(keyFlag & CNTL_BIT))
                                        ctrl = FALSE;
                        }
                        return 0;
                /* Alt Left pressed */
                case KEY_ALTL:
                        if (d) {
                                alt = TRUE;
                                keyFlag |= ALTL_BIT;
                        } else {
                                alt = FALSE;
                                keyFlag &= (!ALTL_BIT);
                        }
                        return 0;
                /* Alt Right (AltGr) pressed */
                case KEY_ALTR:
                        if (d) {
                                altgr = TRUE;
                                keyFlag |= ALTR_BIT;
                        } else {
                                altgr = FALSE;
                                keyFlag &= (!ALTR_BIT);
                                if ((!useAltGr) && (!(keyFlag & ALTL_BIT)))
                                        alt = FALSE;
                        }
                        return 0;
                /* Delete */
                case EXT_DEL:
                        return DELETE;
                case PAD_DEL:
                        if (numlock || shift)
                                return 0x18;
                        else
                                break;
                /* Pad Enter */
                case PAD_ENT:
                        return 0x0d;
                /* Pad Add */
                case PAD_PLUS:
                        return 0x2b;
                /* Pad Sub */
                case PAD_SUB:
                        return 0x2d;
                /* Pad Slash */
                case PAD_SLH:
                        return 0x2f;
                /* Numbers & simbols */
                case KEY_1: case KEY_2: case KEY_3: case KEY_4: case KEY_5:
                case KEY_6: case KEY_7: case KEY_8: case KEY_9: case KEY_0:
                case KEY_SUB: case KEY_PLUS: case KEY_BRL: case KEY_BRR:
                case KEY_COL: case KEY_API:  case KEY_TIL: case KEY_BSL:
                case KEY_LT:  case KEY_GT:   case KEY_SLH:
                        /* AlrGR enabled & pressed */
                        if (altgr && useAltGr) {
                                return keyAltGrTable[c];
                        }
                        /* Control Shift status */
                        if (shift)
                                return keyShiftTable[c];
                        else
                                return keyTable[c];
        }
       
        /* Pad Keys */
        if (numlock || shift)
                switch (c) {
                        case PAD_DEL:
                                return 0x18;
                        case PAD_INS:
                                return 0x30;
                        case PAD_END:
                                return 0x31;
                        case PAD_DOWN:
                                return 0x32;
                        case PAD_PGDW:
                                return 0x33;
                        case PAD_RIGHT:
                                return 0x34;
                        case PAD_5:
                                return 0x35;
                        case PAD_LEFT:
                                return 0x36;
                        case PAD_HOME:
                                return 0x37;
                        case PAD_UP:
                                return 0x38;
                        case PAD_PGUP:
                                return 0x39;
                }
       
        /* Characters keys */
        if (((c >= KEY_Q) && (c <= KEY_P)) ||
            ((c >= KEY_A) && (c <= KEY_L)) ||
            ((c >= KEY_Z) && (c <= KEY_M))) {
                /* AlrGR enabled & pressed */
                if (altgr && useAltGr) {
                        return keyAltGrTable[c];
                }
                /* Control CapsLock & Shift status */
                if (capslock) {
                        if (shift)
                                return keyTable[c];
                        else
                                return keyShiftTable[c];
                } else {
                        if (shift)
                                return keyShiftTable[c];
                        else
                                return keyTable[c];
                }
        }

        /* Remaining keys */
        if (c < TABLE_KEY_SIZE)
                /* Left 'low' keys (Esc, BackSpace, Space, ...) */
                return keyTable[c];
        else
                /* Default - Return as keycode */
                return (0xff00 | c);
}

#ifdef KEYB_TASK
TASK keyProc(void)
#else
static void keyProc(void)
#endif
{
        WORD code;
        BYTE found;
        KEY_EVT dt;
        int i, res;
        unsigned int dato;

#ifdef KEYB_TASK
        while (1) {
#endif
                res = kbd_get(&dato, NON_BLOCK);
                if (res >= 0) {
                        code = scanCode(dato, res);
                        if (code != 0) {
                                if (code & 0xff00)
                                        /* It's a scan code, set the right bit */
                                        dt.flag = (keyFlag | SCAN_BIT);
                                else
                                        /* Simply send the keyFlag status */
                                        dt.flag = keyFlag;
                                dt.status = status;
                                dt.ascii  = (BYTE) (code & 0x00FF);
                                dt.scan   = dato;
#ifdef __KEYB_DEBUG__
                                printk("shark_keyb.c: KEY_EVT ( %2x - %c - %2x - %1d)\n", dt.scan, dt.ascii, dt.flag, dt.status);
#endif
                                found = FALSE;
                                for (i = 0; i < MAX_KEY_EXC; i++) {
                                        if (keyExcTable[i].func == NULL)
                                                continue;
                                        if (((keyExcTable[i].evt.flag & ~SCAN_BIT) == (dt.flag & ~SCAN_BIT)) &&
                                            ((keyExcTable[i].evt.status & dt.status) != 0)) {
                                                if ((dt.flag & SCAN_BIT) != 0) {
                                                        if ((keyExcTable[i].evt.scan == dt.scan) && (keyExcTable[i].evt.scan != 0)) {
#ifdef __KEYB_DEBUG__
                                                                printk("shark_keyb.c: Key_Hook ( %2x - %2x - %1d) -> ( %2x - %2x - %1d)\n",
                                                                dt.scan, dt.ascii, dt.flag, dt.status,
                                                                keyExcTable[i].evt.scan, keyExcTable[i].evt.ascii, keyExcTable[i].evt.flag, keyExcTable[i].evt.status);
#endif
                                                                keyExcTable[i].func(&dt);
                                                                if (keyExcTable[i].lock == TRUE)
                                                                        found = TRUE;
                                                        }
                                                } else {
                                                        if ( ((keyExcTable[i].evt.scan == dt.scan) || (keyExcTable[i].evt.scan == 0)) &&
                                                        ((keyExcTable[i].evt.ascii == dt.ascii) || (keyExcTable[i].evt.ascii == 0)) ){
#ifdef __KEYB_DEBUG__
                                                                printk("shark_keyb.c: Key_Hook ( %2x - %2x - %1d) -> ( %2x - %2x - %1d)\n",
                                                                dt.scan, dt.ascii, dt.flag, dt.status,
                                                                keyExcTable[i].evt.scan, keyExcTable[i].evt.ascii, keyExcTable[i].evt.flag, keyExcTable[i].evt.status);
#endif
                                                                keyExcTable[i].func(&dt);
                                                                if (keyExcTable[i].lock == TRUE)
                                                                        found = TRUE;
                                                        }
                                                }
                                        }
                                }
                                /* when the port is full, data is lost */
                                if (!found) {
                                        if (keybuff_tail != keybuff_head) {
                                                internal_sem_wait(&keybuff_mutex);
                                                memcpy(&keybuff[keybuff_head], &dt, sizeof(KEY_EVT));
                                                keybuff_head = (keybuff_head+1) & KEYBUFF_MASK;
                                                internal_sem_post(&keybuff_mutex);
                                        }
                                }
                        }
                }
#ifdef KEYB_TASK
                task_endcycle();
        }
#endif
}

/* default function called on ctrl-c */
void default_ctrlChandler(KEY_EVT * k) {
        /* Useful or not to set the page to 0? */
        /*set_active_page(0);
        set_visual_page(0);
        cputs("Ctrl-C pressed!\n");*/

        exit(0);
}

/**** Start User Functions ****/

/* Function that returns the ascii code */
BYTE keyb_getch(BYTE wait)
{
        KEY_EVT ev;

        while(1) {
                if ( ((keybuff_tail+1) & KEYBUFF_MASK) != ((keybuff_head) & KEYBUFF_MASK) ) {
                        internal_sem_wait(&keybuff_mutex);
                        keybuff_tail = (keybuff_tail+1) & KEYBUFF_MASK;
                        memcpy(&ev, &keybuff[keybuff_tail], sizeof(KEY_EVT));
                        internal_sem_post(&keybuff_mutex);

#ifdef __KEYB_DEBUG__
                        printk("shark_keyb.c: GetChar ( %2x - %c - %2x - %1d)\n", ev.scan, ev.ascii, ev.flag, ev.status);
#endif
                        if (!isScanCode(&ev) && !isReleased(&ev)) {
                                return (ev.ascii);
                        } else {
                                if (wait != BLOCK)
                                        return 0;
                        }
                } else {
                        if (wait != BLOCK)
                                return 0;
                }
        }
}

/*
 * Function that returns a structure containing the flags status, the ascii
 * code, and the scan code
 */

int keyb_getcode(KEY_EVT * k, BYTE wait)
{
        while (1) {
                if ( ((keybuff_tail+1) & KEYBUFF_MASK) != ((keybuff_head) & KEYBUFF_MASK) ) {
                        internal_sem_wait(&keybuff_mutex);
                        keybuff_tail = (keybuff_tail+1) & KEYBUFF_MASK;
                        memcpy(k, &keybuff[keybuff_tail], sizeof(KEY_EVT));
                        internal_sem_post(&keybuff_mutex);

                        return(TRUE);
                } else {
                        if (wait != BLOCK)
                                return(FALSE);
                }
        }
}

/*
 * This call is used to link a function to a KEY_EVT
 */

int keyb_hook(KEY_EVT k, void (*f) (KEY_EVT * k), unsigned char l)
{
        int id = 0;

        if ((k.ascii == 0) && (k.scan == 0))
                return -1;

        while (keyExcTable[id].func != NULL) {
                id++;
                if (id >= MAX_KEY_EXC)
                        return -1;
        }

        keyExcTable[lastExc].func = f;
        keyExcTable[lastExc].evt = k;
        if (keyExcTable[lastExc].evt.status == 0)
                keyExcTable[lastExc].evt.status = KEY_PRESSED;

        keyExcTable[lastExc++].lock = l;

        return (lastExc-1);
}

/* Free a keyb_hook slot */
int keyb_unhook(int index)
{
        if (keyExcTable[index].func != NULL) {
                keyExcTable[index].func = NULL;
                return 0;
        }
        return -1;
}

/* This function disable the keyboard */
void inline keyb_disable(void)
{
        kbd_disable();
}

/* This function enable the keyboard */
void inline keyb_enable(void)
{
        kbd_enable();
}

/**** End User Functions ****/
int inline KEYB26_installed(void)
{
        return keyb_installed;
}

int KEYB26_init(KEYB_PARMS *s)
{
        KEYB_PARMS kparms = BASE_KEYB;
        WORD i;
        int status = 0;

#ifdef KEYB_TASK
        SOFT_TASK_MODEL base_m;
        TASK_MODEL *m;
#endif

        if (keyb_installed == TRUE) return 0;

        /* if a NULL is passed */
        if (s == NULL)
                s = &kparms;

        /* Reset keymap structures */
        for (i = 0; i < TABLE_KEY_SIZE; i++) {
                keyTable[i] = 0;
                keyShiftTable[i] = 0;
                keyAltGrTable[i] = 0;
        }

        /* keymap */
        if (s->keymap == (unsigned char)KEYB_DEFAULT) s->keymap = KEYMAP_US;
        keyb_set_map(s->keymap);

        /* KeyEvt Buffer Initialization */
        keybuff_head = 1;
        keybuff_tail = 0;
        if (keybuff_mutex_init==0) {
                internal_sem_init(&keybuff_mutex, 1);
                keybuff_mutex_init = 1;
        }

        /* remove all key pressed handlers */
        lastExc = 0;

        /* and add a ctrl-c handler if requested */
        if (s->ctrlcfunc == (void *) KEYB_DEFAULT)
                s->ctrlcfunc = (void *) default_ctrlChandler;
        if (s->ctrlcfunc != NULL) {
                KEY_EVT emerg;
                emerg.ascii  = 'c';
                emerg.scan   = KEY_C;
                emerg.status = KEY_PRESSED;
                emerg.flag   = CNTL_BIT;
                keyb_hook (emerg, s->ctrlcfunc, FALSE);
                emerg.flag   = CNTR_BIT;
                keyb_hook (emerg, s->ctrlcfunc, FALSE);
        }

#ifdef KEYB_TASK
        /* keyb task */
        if (s->tm == (TASK_MODEL *) KEYB_DEFAULT) {
                soft_task_default_model (base_m);
                soft_task_def_wcet (base_m, 2000);
                soft_task_def_met (base_m, 800);
                soft_task_def_period (base_m, 30000);
                soft_task_def_system (base_m);
                soft_task_def_nokill (base_m);
                soft_task_def_aperiodic (base_m);
                m = (TASK_MODEL *) & base_m;
        } else
                m = s->tm;

#ifdef __KEYB_DEBUG__
        printk(KERN_DEBUG "keyb task: %li %li %li %li\n", (long)s->pclass, (long)APERIODIC, (long)s->dline, (long)s->wcet);
#endif

        keybpid = task_create ("KeyTask", keyProc, m, NULL);
        if (keybpid == -1)
                return -1;
#endif

        if (INPUT26_installed() == FALSE)
                if (INPUT26_init()) {
                        printk(KERN_ERR "shark_keyb.c: Unable to open Input SubSystem.\n");
#ifdef KEYB_TASK
                        task_kill (keybpid);
#endif
                        return -1;
                }

        status = kbd_init();
        if (status) {
                printk(KERN_ERR "shark_keyb.c: Kbd_Init return: %d\n", status);
#ifdef KEYB_TASK
                task_kill (keybpid);
#endif
                return -1;
        }

       
        if (s->softrepeat == (int) KEYB_DEFAULT) {
                status = atkbd_init(1);
        } else {
                status = atkbd_init(s->softrepeat);
        }
        if (status) {
                printk(KERN_ERR "shark_keyb.c: AtKbd_Init return: %d\n", status);
#ifdef KEYB_TASK
                task_kill (keybpid);
#endif
                return -1;
        }

        kbd_setleds(scrolllock + (numlock << 1) + (capslock << 2));
        kbd_enable();

        keyb_installed = TRUE;
        return status;
}

/*
 * KEYB module cleanup
 * (must be called if it's needed to re-call keyb_init() with other parameters)
 * -1 -> ERROR
 */

int KEYB26_close(void)
{
#ifdef KEYB_TASK
        int free;
        SYS_FLAGS f;
#endif

        if (!keyb_installed)
                return -1;

        kbd_disable();

        atkbd_exit();
        kbd_exit();

#ifdef KEYB_TASK
        f = kern_fsave();
        free = (proc_table[keybpid].status == FREE);
        kern_frestore(f);
#ifdef __KEYB_DEBUG__
        printk(KERN_DEBUG "shark_keyb.c: KeyTask is %s.\n", free ? "killed" : "alive");
#endif
        if (free)
                task_kill (keybpid);
#endif

        keyb_installed = FALSE;

        return 0;
}