466 lines
9.8 KiB
C
466 lines
9.8 KiB
C
![]() |
/*
|
|||
|
* (C) Copyright 2003
|
|||
|
*
|
|||
|
* Thomas Frieden (ThomasF@hyperion-entertainment.com)
|
|||
|
*
|
|||
|
* See file CREDITS for list of people who contributed to this
|
|||
|
* project.
|
|||
|
*
|
|||
|
* 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
|
|||
|
*
|
|||
|
*/
|
|||
|
#include <common.h>
|
|||
|
#include <asm/processor.h>
|
|||
|
#include <asm/string.h>
|
|||
|
#include <devices.h>
|
|||
|
#include <pci.h>
|
|||
|
#include "memio.h"
|
|||
|
#include "catweasel.h"
|
|||
|
#include "cw4.h"
|
|||
|
#include "../menu/menu.h"
|
|||
|
|
|||
|
#define CATW_PCI_VENDOR 0xe159
|
|||
|
#define CATW_PCI_PRODUCT 0x0001
|
|||
|
|
|||
|
#define CATW4_SUBSYS_VENDOR 0x5213
|
|||
|
#define CATW4_SUBSYS_ID1 0x0002
|
|||
|
#define CATW4_SUBSYS_ID2 0x0003
|
|||
|
|
|||
|
#define CATW_KEY_DATA 0xd0
|
|||
|
#define CATW_KEY_STATUS 0xd4
|
|||
|
|
|||
|
#define CATW_KS_READY 0x80
|
|||
|
|
|||
|
#define CATW_NAME "amikbd"
|
|||
|
|
|||
|
#define CATW4_FILEID FileID('C','A','T','4')
|
|||
|
|
|||
|
#undef CATW_DEBUG
|
|||
|
#ifdef CATW_DEBUG
|
|||
|
#define dprintf(fmt,args...) printf (fmt ,##args)
|
|||
|
#else
|
|||
|
#define dprintf(fmt,args...)
|
|||
|
#endif
|
|||
|
|
|||
|
int catw_getc(void);
|
|||
|
int catw_testc(void);
|
|||
|
|
|||
|
static int catw_pci = -1;
|
|||
|
static unsigned long catw_iobase = 0;
|
|||
|
|
|||
|
static int catw_poll_delay = 20000;
|
|||
|
|
|||
|
static char catw_shift_state = 0;
|
|||
|
|
|||
|
static unsigned char catw_normal_xlate[0x70] =
|
|||
|
{ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|||
|
/* 00 - 0F */ '`','1','2','3','4','5','6','7','8','9','0','<EFBFBD>','\'','\\',0, '0',
|
|||
|
/* 10 - 1F */ 'q','w','e','r','t','z','u','i','o','p','<EFBFBD>','+', 0 ,'1','2','3',
|
|||
|
/* 20 - 2F */ 'a','s','d','f','g','h','j','k','l','<EFBFBD>','<EFBFBD>','#', 0 ,'4','5','6',
|
|||
|
/* 30 - 3F */ '<','y','x','c','v','b','n','m',',','.','-', 0 , 0 ,'7','8','9',
|
|||
|
/* 40 - 4F */ ' ', 8 , 9 , 13, 13, 27,127, 0 , 0 , 0 ,'-', 0 , 0 , 0 , 0 , 0 ,
|
|||
|
/* 50 - 5F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,'[',']','/','*','+', 0 ,
|
|||
|
/* 60 - 6F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
|
|||
|
};
|
|||
|
|
|||
|
static unsigned char catw_shifted_xlate[0x70] =
|
|||
|
{ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|||
|
/* 00 - 0F */ '~','!','"','<EFBFBD>','$','%','&','/','(',')','=','?','`','|', 0, '0',
|
|||
|
/* 10 - 1F */ 'Q','W','E','R','T','Z','U','I','O','P','<EFBFBD>','*', 0 ,'1','2','3',
|
|||
|
/* 20 - 2F */ 'A','S','D','F','G','H','J','K','L','<EFBFBD>','<EFBFBD>','^', 0 ,'4','5','6',
|
|||
|
/* 30 - 3F */ '>','Y','X','C','V','B','N','M',';',':','_', 0 , 0 ,'7','8','9',
|
|||
|
/* 40 - 4F */ ' ', 8 , 9 , 13, 13, 27,127, 0 , 0 , 0 ,'-', 0 , 0 , 0 , 0 , 0 ,
|
|||
|
/* 50 - 5F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,'{','}','/','*','+', 0 ,
|
|||
|
/* 60 - 6F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
|
|||
|
};
|
|||
|
|
|||
|
//"
|
|||
|
|
|||
|
#define CATW_BUFFER_SIZE 20
|
|||
|
static unsigned char catw_buffer[CATW_BUFFER_SIZE];
|
|||
|
static int catw_inptr = 0, catw_outptr = 0;
|
|||
|
|
|||
|
void catw_handle(int c)
|
|||
|
{
|
|||
|
int kup = (c&0x80);
|
|||
|
int key = (c&0x7f);
|
|||
|
|
|||
|
switch (key)
|
|||
|
{
|
|||
|
case 0x60:
|
|||
|
case 0x61:
|
|||
|
case 0x62:
|
|||
|
if (kup)
|
|||
|
catw_shift_state = 0;
|
|||
|
else
|
|||
|
catw_shift_state = 1;
|
|||
|
break;
|
|||
|
case 0x78:
|
|||
|
/* Reset */
|
|||
|
dprintf("Reset!\n");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
int catw_xlate(int c)
|
|||
|
{
|
|||
|
c &= 0x7f;
|
|||
|
|
|||
|
switch(c)
|
|||
|
{
|
|||
|
case 0x4C:
|
|||
|
return KEY_PREV_ITEM;
|
|||
|
case 0x4D:
|
|||
|
return KEY_NEXT_ITEM;
|
|||
|
case 0x4E:
|
|||
|
return KEY_NEXT_OPTION;
|
|||
|
case 0x4F:
|
|||
|
return KEY_PREV_OPTION;
|
|||
|
default:
|
|||
|
if (catw_shift_state)
|
|||
|
return catw_shifted_xlate[c];
|
|||
|
else
|
|||
|
return catw_normal_xlate[c];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static int catw_fpga_ready(void)
|
|||
|
{
|
|||
|
if ((in_byte(catw_iobase + 0x07) & 8) == 8) return 1;
|
|||
|
else return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int catw_config_done(void)
|
|||
|
{
|
|||
|
if ((in_byte(catw_iobase + 0x07) & 4) == 4) return 1;
|
|||
|
else return 0;
|
|||
|
}
|
|||
|
|
|||
|
static void catw_reset_fpga(void)
|
|||
|
{
|
|||
|
dprintf("Resetting fpga...\n");
|
|||
|
out_byte(catw_iobase + 0x02, 227);
|
|||
|
out_byte(catw_iobase + 0x03, 0);
|
|||
|
udelay(1000);
|
|||
|
out_byte(catw_iobase + 0x03, 65);
|
|||
|
dprintf("Done\n");
|
|||
|
}
|
|||
|
|
|||
|
static void *catw_get_config(uint32 *size)
|
|||
|
{
|
|||
|
*size = 59215;
|
|||
|
return &cw4[0];
|
|||
|
}
|
|||
|
|
|||
|
static int catw_program_fpga_config(void)
|
|||
|
{
|
|||
|
uint32 length;
|
|||
|
uint8 b;
|
|||
|
int i;
|
|||
|
int try;
|
|||
|
uint8 *config = (uint8*)catw_get_config(&length);
|
|||
|
|
|||
|
if (!config)
|
|||
|
{
|
|||
|
dprintf("Couldn't find core config\n");
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CATW_DEBUG
|
|||
|
dprintf("Found a config string of %d bytes\n", length);
|
|||
|
dprintf("starting with...\n");
|
|||
|
{
|
|||
|
int i;
|
|||
|
for (i=0; i<40; i++)
|
|||
|
{
|
|||
|
dprintf("%02x ", *(config+i));
|
|||
|
}
|
|||
|
dprintf("\n");
|
|||
|
dprintf("...\n");
|
|||
|
|
|||
|
for (i=0; i<40; i++)
|
|||
|
{
|
|||
|
dprintf("%02x ", *(config+length-40+i));
|
|||
|
}
|
|||
|
dprintf("\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
for (i=0; i<length-1; i++)
|
|||
|
{
|
|||
|
b = *(config+i);
|
|||
|
try = 0;
|
|||
|
|
|||
|
if ((b & 0x01) == 0x01)
|
|||
|
out_byte(catw_iobase + 0x03, 0x43);
|
|||
|
else
|
|||
|
out_byte(catw_iobase + 0x03, 0x41);
|
|||
|
|
|||
|
while (catw_fpga_ready() == 0)
|
|||
|
{
|
|||
|
udelay(2000);
|
|||
|
try++;
|
|||
|
dprintf("waiting for FPGA (try = %d)\n", try);
|
|||
|
if (try == 10)
|
|||
|
{
|
|||
|
dprintf("PANIC: FPGA failed on catw_fpga_ready()\n");
|
|||
|
dprintf("at byte offset %d\n", i);
|
|||
|
dprintf("byte written was %02x\n", b);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
out_byte(catw_iobase + 0xc0, b);
|
|||
|
}
|
|||
|
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int catw_kb_init(void)
|
|||
|
{
|
|||
|
int i;
|
|||
|
device_t catw_kbddev;
|
|||
|
int error;
|
|||
|
char *s;
|
|||
|
uint16 subsys_vendor, subsys_device;
|
|||
|
|
|||
|
/* Some init */
|
|||
|
catw_shift_state = 0;
|
|||
|
|
|||
|
/* Find the device */
|
|||
|
catw_pci = pci_find_device(CATW_PCI_VENDOR, CATW_PCI_PRODUCT, 0);
|
|||
|
if (catw_pci == -1)
|
|||
|
{
|
|||
|
dprintf("No Catweasel controller (0x%0x4, 0x%04x) attached\n", CATW_PCI_VENDOR, CATW_PCI_PRODUCT);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
/* Get IO base */
|
|||
|
for (i = 0; i < 6; i++)
|
|||
|
{
|
|||
|
pci_read_config_dword(catw_pci, PCI_BASE_ADDRESS_0+4*i, (u32 *)&catw_iobase);
|
|||
|
if (catw_iobase & 1)
|
|||
|
{
|
|||
|
/* Found the IO base */
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Check the iobase */
|
|||
|
if (catw_iobase & 1)
|
|||
|
{
|
|||
|
catw_iobase &= ~1;
|
|||
|
dprintf("I/O base: %p\n", (u32 *)catw_iobase);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
printf("Error: Unable to find I/O address range\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
pci_read_config_word(catw_pci, PCI_SUBSYSTEM_VENDOR_ID, &subsys_vendor);
|
|||
|
pci_read_config_word(catw_pci, PCI_SUBSYSTEM_ID, &subsys_device);
|
|||
|
|
|||
|
if (subsys_vendor == CATW4_SUBSYS_VENDOR &&
|
|||
|
((subsys_device == CATW4_SUBSYS_ID1) || (subsys_device == CATW4_SUBSYS_ID1)))
|
|||
|
{
|
|||
|
dprintf("Catweasel Mark IV detected\n");
|
|||
|
/* Send Mark IV initialisation sequence */
|
|||
|
out_byte(catw_iobase + 0x00, 0xF1);
|
|||
|
out_byte(catw_iobase + 0x01, 0x00);
|
|||
|
out_byte(catw_iobase + 0x02, 0xE3);
|
|||
|
out_byte(catw_iobase + 0x03, 0x41);
|
|||
|
out_byte(catw_iobase + 0x04, 0x00);
|
|||
|
out_byte(catw_iobase + 0x05, 0x00);
|
|||
|
out_byte(catw_iobase + 0x29, 0x00);
|
|||
|
out_byte(catw_iobase + 0x2B, 0x00);
|
|||
|
|
|||
|
#ifdef CATW_DEBUG
|
|||
|
if (catw_config_done())
|
|||
|
dprintf("FPGA already configured\n");
|
|||
|
else
|
|||
|
dprintf("FPGA Empty\n");
|
|||
|
#endif
|
|||
|
|
|||
|
catw_reset_fpga();
|
|||
|
if (catw_config_done())
|
|||
|
{
|
|||
|
printf("**PANIC** FPGA reset failed\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
#ifdef CATW_DEBUG
|
|||
|
else
|
|||
|
{
|
|||
|
dprintf("FPGA reset OK\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (0 == catw_program_fpga_config())
|
|||
|
{
|
|||
|
printf("**ERROR** FPGA Programming failed\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
if (catw_config_done())
|
|||
|
{
|
|||
|
printf("Catweasel Mark IV configured\n\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
printf("**ERROR** Catweasel Mark IV configuration failed\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
udelay(1000);
|
|||
|
}
|
|||
|
/* Catweasel mark III cannot work on Sam
|
|||
|
* it's a +5V only PCI card...
|
|||
|
else
|
|||
|
{
|
|||
|
dprintf("Catweasel Mark III detected\n");
|
|||
|
// Send initialisation sequence for Mark III
|
|||
|
out_byte(catw_iobase + 0x00, 0xf1);
|
|||
|
out_byte(catw_iobase + 0x01, 0x00);
|
|||
|
out_byte(catw_iobase + 0x02, 0x00);
|
|||
|
out_byte(catw_iobase + 0x04, 0x00);
|
|||
|
out_byte(catw_iobase + 0x05, 0x00);
|
|||
|
out_byte(catw_iobase + 0x29, 0x00);
|
|||
|
out_byte(catw_iobase + 0x2b, 0x00);
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
out_byte(catw_iobase + CATW_KEY_DATA, 0);
|
|||
|
|
|||
|
/* Register us as a possible keyboard device */
|
|||
|
memset(&catw_kbddev, 0, sizeof(catw_kbddev));
|
|||
|
strcpy(catw_kbddev.name, CATW_NAME);
|
|||
|
catw_kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
|
|||
|
catw_kbddev.putc = NULL;
|
|||
|
catw_kbddev.puts = NULL;
|
|||
|
catw_kbddev.getc = catw_getc;
|
|||
|
catw_kbddev.tstc = catw_testc;
|
|||
|
|
|||
|
s = getenv("catw_poll_delay");
|
|||
|
if (s)
|
|||
|
{
|
|||
|
catw_poll_delay = simple_strtol(s, NULL, 0) * 1000;
|
|||
|
}
|
|||
|
|
|||
|
error = device_register(&catw_kbddev);
|
|||
|
if (0 == error )
|
|||
|
{
|
|||
|
/* Check if we are stdin */
|
|||
|
if (0 == strcmp(getenv("stdin"), CATW_NAME))
|
|||
|
{
|
|||
|
if (overwrite_console())
|
|||
|
return 1;
|
|||
|
|
|||
|
error = console_assign(stdin,CATW_NAME);
|
|||
|
if (0 == error)
|
|||
|
{
|
|||
|
dprintf("Catweasel keyboard initialized 1\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dprintf("Catweasel keyboard initialized 2\n");
|
|||
|
return error;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
dprintf("Catweasel keyboard initialized 3\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
static void catw_push(unsigned char c)
|
|||
|
{
|
|||
|
if (catw_inptr == CATW_BUFFER_SIZE-1)
|
|||
|
{
|
|||
|
if (catw_outptr == 0) return;
|
|||
|
catw_inptr = 0;
|
|||
|
}
|
|||
|
else if (catw_inptr + 1 == catw_outptr)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
catw_buffer[++catw_inptr] = c;
|
|||
|
}
|
|||
|
|
|||
|
static int catw_pop(void)
|
|||
|
{
|
|||
|
if (catw_inptr == catw_outptr) return -1;
|
|||
|
if (catw_outptr >= CATW_BUFFER_SIZE-1)
|
|||
|
catw_outptr = 0;
|
|||
|
else
|
|||
|
++catw_outptr;
|
|||
|
|
|||
|
return (int)catw_buffer[catw_outptr];
|
|||
|
}
|
|||
|
|
|||
|
static void catw_poll(void)
|
|||
|
{
|
|||
|
int x;
|
|||
|
|
|||
|
x = in_byte(catw_iobase + CATW_KEY_STATUS);
|
|||
|
|
|||
|
if (x & CATW_KS_READY)
|
|||
|
{
|
|||
|
x = in_byte(catw_iobase + CATW_KEY_DATA);
|
|||
|
dprintf("got char: %x\n", x);
|
|||
|
catw_handle(x);
|
|||
|
|
|||
|
if (!(x&0x80))
|
|||
|
{
|
|||
|
x = catw_xlate(x);
|
|||
|
if (x)
|
|||
|
{
|
|||
|
dprintf("xlate: %x\n", x);
|
|||
|
catw_push((unsigned char)x);
|
|||
|
}
|
|||
|
}
|
|||
|
udelay(1000);
|
|||
|
out_byte(catw_iobase + CATW_KEY_DATA, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
int catw_getc(void)
|
|||
|
{
|
|||
|
int c;
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
udelay(catw_poll_delay);
|
|||
|
catw_poll();
|
|||
|
c = catw_pop();
|
|||
|
} while (c == -1);
|
|||
|
|
|||
|
return c;
|
|||
|
}
|
|||
|
|
|||
|
unsigned long long get_ticks(void);
|
|||
|
unsigned long ticks2usec(unsigned long ticks);
|
|||
|
|
|||
|
int catw_testc(void)
|
|||
|
{
|
|||
|
catw_poll();
|
|||
|
if (catw_inptr == catw_outptr) return 0;
|
|||
|
else return 1;
|
|||
|
}
|