Revision 799
Added by markw almost 7 years ago
firmware_legacy/usb/hid.c | ||
---|---|---|
//#include <stdio.h>
|
||
|
||
#include "usb.h"
|
||
#include "timer.h"
|
||
#include "hidparser.h"
|
||
#include "events.h"
|
||
#include "debug.h"
|
||
#include "usbhostslave.h"
|
||
#include "log.h"
|
||
|
||
/*
|
||
#include "printf.h"
|
||
extern unsigned char volatile * baseaddr;
|
||
extern int debug_pos;
|
||
*/
|
||
|
||
unsigned char kbd_led_state; // default: all leds off
|
||
unsigned char joysticks; // number of detected usb joysticks
|
||
|
||
//#define hid_debugf printf
|
||
|
||
uint16_t bs16(uint8_t * in)
|
||
{
|
||
uint16_t low = *in;
|
||
uint16_t high = *(in+1);
|
||
uint16_t res = (high<<8) | low;
|
||
return res;
|
||
}
|
||
|
||
uint8_t hid_get_joysticks(void) {
|
||
return joysticks;
|
||
}
|
||
|
||
//get HID report descriptor
|
||
static uint8_t hid_get_report_descr(usb_device_t *dev, uint8_t i, uint16_t size) {
|
||
// hid_debugf("%s(%x, if=%d, size=%d)", __FUNCTION__, dev->bAddress, iface, size);
|
||
|
||
uint8_t buf[size];
|
||
usb_hid_info_t *info = &(dev->hid_info);
|
||
uint8_t rcode = usb_ctrl_req( dev, HID_REQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
|
||
HID_DESCRIPTOR_REPORT, info->iface[i].iface_idx, size, buf);
|
||
|
||
if(!rcode) {
|
||
hid_debugf("HID report desc:");
|
||
//MWW hexdump(buf, size, 0);
|
||
|
||
// we got a report descriptor. Try to parse it
|
||
if(parse_report_descriptor(buf, size, &(info->iface[i].conf))) {
|
||
if(info->iface[i].conf.type == CONFIG_TYPE_JOYSTICK) {
|
||
//unsigned char * temp = baseaddr;
|
||
//baseaddr = (unsigned char volatile *)(40000 + atari_regbase);
|
||
//debug_pos=160;
|
||
//printf("Detected USB joystick #%d", joysticks);
|
||
hid_debugf("stick #%d", joysticks);
|
||
|
||
info->iface[i].device_type = HID_DEVICE_JOYSTICK;
|
||
info->iface[i].jindex = joysticks++;
|
||
//debug_pos=240;
|
||
//printf("assigned index #%d", info->iface[i].jindex);
|
||
//baseaddr = temp;
|
||
}
|
||
}
|
||
}
|
||
|
||
return rcode;
|
||
}
|
||
|
||
static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t duration ) {
|
||
// hid_debugf("%s(%x, if=%d id=%d, dur=%d)", __FUNCTION__, dev->bAddress, iface, reportID, duration);
|
||
|
||
return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID,
|
||
duration, iface, 0x0000, NULL));
|
||
}
|
||
|
||
static uint8_t hid_set_protocol(usb_device_t *dev, uint8_t iface, uint8_t protocol) {
|
||
// hid_debugf("%s(%x, if=%d proto=%d)", __FUNCTION__, dev->bAddress, iface, protocol);
|
||
|
||
return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol,
|
||
0x00, iface, 0x0000, NULL));
|
||
}
|
||
|
||
static uint8_t hid_set_report(usb_device_t *dev, uint8_t iface, uint8_t report_type, uint8_t report_id,
|
||
uint16_t nbytes, uint8_t* dataptr ) {
|
||
// hid_debugf("%s(%x, if=%d data=%x)", __FUNCTION__, dev->bAddress, iface, dataptr[0]);
|
||
|
||
return( usb_ctrl_req(dev, HID_REQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id,
|
||
report_type, iface, nbytes, dataptr));
|
||
}
|
||
|
||
/* todo: handle parsing in chunks */
|
||
static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len) {
|
||
usb_hid_info_t *info = &(dev->hid_info);
|
||
uint8_t rcode;
|
||
bool isGoodInterface = false;
|
||
|
||
union buf_u {
|
||
usb_configuration_descriptor_t conf_desc;
|
||
usb_interface_descriptor_t iface_desc;
|
||
usb_endpoint_descriptor_t ep_desc;
|
||
usb_hid_descriptor_t hid_desc;
|
||
uint8_t raw[len];
|
||
} buf, *p;
|
||
|
||
// usb_interface_descriptor
|
||
|
||
if(rcode = usb_get_conf_descr(dev, len, conf, &buf.conf_desc))
|
||
return rcode;
|
||
|
||
/* scan through all descriptors */
|
||
p = &buf;
|
||
//LOG("LenX:%d\n", p->conf_desc.bLength);
|
||
while(len > 0) {
|
||
hid_debugf("L%02d %02d %02d ",len, p->conf_desc.bLength, p->conf_desc.bDescriptorType);
|
||
|
||
switch(p->conf_desc.bDescriptorType) {
|
||
case USB_DESCRIPTOR_CONFIGURATION:
|
||
hid_debugf("conf descriptor size %d", p->conf_desc.bLength);
|
||
// we already had this, so we simply ignore it
|
||
break;
|
||
|
||
case USB_DESCRIPTOR_INTERFACE:
|
||
isGoodInterface = false;
|
||
hid_debugf("iface descriptor size %d class %d", p->iface_desc.bLength, p->iface_desc.bInterfaceClass);
|
||
|
||
/* check the interface descriptors for supported class */
|
||
|
||
// only HID interfaces are supported
|
||
if(p->iface_desc.bInterfaceClass == USB_CLASS_HID) {
|
||
hid_debugf("iface is HID");
|
||
// puts("iface is HID");
|
||
|
||
if(info->bNumIfaces < MAX_IFACES) {
|
||
// ok, let's use this interface
|
||
isGoodInterface = true;
|
||
|
||
info->iface[info->bNumIfaces].iface_idx = p->iface_desc.bInterfaceNumber;
|
||
info->iface[info->bNumIfaces].has_boot_mode = false;
|
||
info->iface[info->bNumIfaces].is_5200daptor = false;
|
||
info->iface[info->bNumIfaces].is_MCC = 0;
|
||
info->iface[info->bNumIfaces].key_state = 0;
|
||
info->iface[info->bNumIfaces].device_type = HID_DEVICE_UNKNOWN;
|
||
info->iface[info->bNumIfaces].conf.type = CONFIG_TYPE_NONE;
|
||
|
||
if(p->iface_desc.bInterfaceSubClass == HID_BOOT_INTF_SUBCLASS) {
|
||
hid_debugf("Iface %d is Boot sub class", info->bNumIfaces);
|
||
info->iface[info->bNumIfaces].has_boot_mode = true;
|
||
}
|
||
|
||
hid_debugf("HID protocol is ");
|
||
switch(p->iface_desc.bInterfaceProtocol) {
|
||
case HID_PROTOCOL_NONE:
|
||
hid_debugf("NONE");
|
||
break;
|
||
|
||
case HID_PROTOCOL_KEYBOARD:
|
||
hid_debugf("KEYBOARD");
|
||
info->iface[info->bNumIfaces].device_type = HID_DEVICE_KEYBOARD;
|
||
break;
|
||
|
||
case HID_PROTOCOL_MOUSE:
|
||
hid_debugf("MOUSE");
|
||
info->iface[info->bNumIfaces].device_type = HID_DEVICE_MOUSE;
|
||
break;
|
||
|
||
default:
|
||
hid_debugf("%d", p->iface_desc.bInterfaceProtocol);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case USB_DESCRIPTOR_ENDPOINT:
|
||
// hid_debugf("endpoint descriptor size %d", p->ep_desc.bLength);
|
||
|
||
if(isGoodInterface) {
|
||
|
||
// only interrupt in endpoints are supported
|
||
if ((p->ep_desc.bmAttributes & 0x03) == 3 && (p->ep_desc.bEndpointAddress & 0x80) == 0x80) {
|
||
hid_debugf("ep %d, ival = %dms",
|
||
p->ep_desc.bEndpointAddress & 0x0F, p->ep_desc.bInterval);
|
||
|
||
// Fill in the endpoint info structure
|
||
uint8_t epidx = info->bNumIfaces;
|
||
info->iface[epidx].interval = p->ep_desc.bInterval;
|
||
info->iface[epidx].ep.epAddr = (p->ep_desc.bEndpointAddress & 0x0F);
|
||
info->iface[epidx].ep.maxPktSize = p->ep_desc.wMaxPacketSize[0];
|
||
info->iface[epidx].ep.epAttribs = 0;
|
||
info->iface[epidx].ep.bmNakPower = USB_NAK_NOWAIT;
|
||
info->bNumIfaces++;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case HID_DESCRIPTOR_HID:
|
||
hid_debugf("hid desc size %d type %x", p->ep_desc.bLength, p->hid_desc.bDescrType);
|
||
|
||
if(isGoodInterface) {
|
||
// we need a report descriptor
|
||
if(p->hid_desc.bDescrType == HID_DESCRIPTOR_REPORT) {
|
||
uint16_t len = p->hid_desc.wDescriptorLength[0] +
|
||
256 * p->hid_desc.wDescriptorLength[1];
|
||
hid_debugf(" -> report desc size = %d", len);
|
||
|
||
info->iface[info->bNumIfaces].report_desc_size = len;
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
hid_debugf("unsupd desc type %d size %d", p->raw[1], p->raw[0]);
|
||
}
|
||
|
||
// advance to next descriptor
|
||
//LOG("Len:%d\n", p->conf_desc.bLength);
|
||
//timer_delay_msec(1000);
|
||
len -= p->conf_desc.bLength;
|
||
p = (union buf_u*)(p->raw + p->conf_desc.bLength);
|
||
}
|
||
|
||
if(len != 0) {
|
||
hid_debugf("Config underrun: %d", len);
|
||
return USB_ERROR_CONFIGURAION_SIZE_MISMATCH;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static uint8_t usb_hid_init(usb_device_t *dev) {
|
||
hid_debugf("%s(%x)", __FUNCTION__, dev->bAddress);
|
||
|
||
uint8_t rcode;
|
||
uint8_t i;
|
||
uint16_t vid, pid;
|
||
|
||
kbd_led_state = 0; // default: all leds off
|
||
|
||
usb_hid_info_t *info = &(dev->hid_info);
|
||
|
||
union {
|
||
usb_device_descriptor_t dev_desc;
|
||
usb_configuration_descriptor_t conf_desc;
|
||
} buf;
|
||
|
||
// reset status
|
||
info->bPollEnable = false;
|
||
info->bNumIfaces = 0;
|
||
|
||
for(i=0;i<MAX_IFACES;i++) {
|
||
info->iface[i].qNextPollTime = 0;
|
||
info->iface[i].ep.epAddr = i;
|
||
info->iface[i].ep.maxPktSize = 8;
|
||
info->iface[i].ep.epAttribs = 0;
|
||
info->iface[i].ep.bmNakPower = USB_NAK_MAX_POWER;
|
||
}
|
||
|
||
// try to re-read full device descriptor from newly assigned address
|
||
if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc ))
|
||
return rcode;
|
||
|
||
// save vid/pid for automatic hack later
|
||
vid = bs16(&buf.dev_desc.idVendorL);
|
||
pid = bs16(&buf.dev_desc.idProductL);
|
||
|
||
uint8_t num_of_conf = buf.dev_desc.bNumConfigurations;
|
||
hid_debugf("number of configurations: %d", num_of_conf);
|
||
|
||
for(i=0; i<num_of_conf; i++) {
|
||
if(rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), i, &buf.conf_desc))
|
||
return rcode;
|
||
|
||
uint16_t wTotalLength = bs16(&buf.conf_desc.wTotalLengthL);
|
||
hid_debugf("conf desc %d size %d", i, wTotalLength);
|
||
LOG("conf descriptor %d has total size %d", i, wTotalLength);
|
||
|
||
// parse directly if it already fitted completely into the buffer
|
||
usb_hid_parse_conf(dev, i, wTotalLength);
|
||
}
|
||
|
||
hid_debugf("here:%d vid:%x pid:%x",info->bNumIfaces,vid,pid);
|
||
|
||
// check if we found valid hid interfaces
|
||
if(!info->bNumIfaces) {
|
||
hid_debugf("no hid ifaces found");
|
||
|
||
if((vid == 0x45e) && (pid == 0x028e)) {
|
||
hid_debugf("hackn Torid\n");
|
||
info->bNumIfaces = 1;
|
||
info->iface[0].iface_idx = 0;
|
||
info->iface[0].has_boot_mode = false;
|
||
info->iface[0].is_5200daptor = false;
|
||
info->iface[0].is_MCC = 3;
|
||
info->iface[0].key_state = 0;
|
||
info->iface[0].device_type = HID_DEVICE_JOYSTICK;
|
||
info->iface[0].conf.type = CONFIG_TYPE_JOYSTICK;
|
||
info->iface[0].jindex = joysticks++;
|
||
info->iface[0].interval = 1;
|
||
info->iface[0].ep.epAddr = 1;
|
||
info->iface[0].ep.maxPktSize = 14;
|
||
info->iface[0].ep.epAttribs = 0;
|
||
info->iface[0].ep.bmNakPower = USB_NAK_NOWAIT;
|
||
|
||
/*info->iface[0].conf.joystick.button[0].byte_offset = 2;
|
||
info->iface[0].conf.joystick.button[0].bitmask;
|
||
info->iface[0].conf.joystick.axis[0].size;
|
||
info->iface[0].conf.joystick.axis[0].byte_offset;
|
||
info->iface[0].conf.joystick.axis[0].logical.min;
|
||
info->iface[0].conf.joystick.axis[0].logical.max;
|
||
*/
|
||
|
||
// joystick pos is expected to be an axis... it isn't...
|
||
// might be easier to directly create jmap for torid...
|
||
}
|
||
else
|
||
{
|
||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||
}
|
||
}
|
||
|
||
// Set Configuration Value
|
||
rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
|
||
|
||
// process all supported interfaces
|
||
for(i=0; i<info->bNumIfaces; i++) {
|
||
// no boot mode, try to parse HID report descriptor
|
||
if(!info->iface[i].has_boot_mode && !info->iface[i].is_MCC) {
|
||
|
||
hid_debugf("DESC %x ", info->iface[i].report_desc_size);
|
||
rcode = hid_get_report_descr(dev, i, info->iface[i].report_desc_size);
|
||
if(rcode) return rcode;
|
||
|
||
hid_debugf("TYPE%02x ", info->iface[i].device_type);
|
||
if(info->iface[i].device_type == CONFIG_TYPE_JOYSTICK) {
|
||
char k;
|
||
|
||
iprintf("Report: type = %d, id = %d, size = %d\n",
|
||
info->iface[i].conf.type,
|
||
info->iface[i].conf.report_id,
|
||
info->iface[i].conf.report_size);
|
||
|
||
for(k=0;k<2;k++)
|
||
iprintf("Axis%d: %d@%d %d->%d\n", k,
|
||
info->iface[i].conf.joystick.axis[k].size,
|
||
info->iface[i].conf.joystick.axis[k].byte_offset,
|
||
info->iface[i].conf.joystick.axis[k].logical.min,
|
||
info->iface[i].conf.joystick.axis[k].logical.max);
|
||
|
||
for(k=0;k<24;k++)
|
||
iprintf("Button%d: @%d/%d\n", k,
|
||
info->iface[i].conf.joystick.button[k].byte_offset,
|
||
info->iface[i].conf.joystick.button[k].bitmask);
|
||
}
|
||
|
||
|
||
// use fixed setup for known interfaces
|
||
if((vid == 0x0079) && (pid == 0x0011) && (i==0)) {
|
||
iprintf("hacking cheap NES pad\n");
|
||
|
||
// fixed setup for nes gamepad
|
||
info->iface[0].conf.joystick.button[0].byte_offset = 5;
|
||
info->iface[0].conf.joystick.button[0].bitmask = 32;
|
||
info->iface[0].conf.joystick.button[1].byte_offset = 5;
|
||
info->iface[0].conf.joystick.button[1].bitmask = 64;
|
||
info->iface[0].conf.joystick.button[2].byte_offset = 6;
|
||
info->iface[0].conf.joystick.button[2].bitmask = 16;
|
||
info->iface[0].conf.joystick.button[3].byte_offset = 6;
|
||
info->iface[0].conf.joystick.button[3].bitmask = 32;
|
||
}
|
||
|
||
if((vid == 0x04d8) && (pid == 0xf6ec) && (i==0)) {
|
||
iprintf("hacking 5200daptor\n");
|
||
|
||
info->iface[0].conf.joystick.button[2].byte_offset = 4;
|
||
info->iface[0].conf.joystick.button[2].bitmask = 0x40; // "Reset"
|
||
info->iface[0].conf.joystick.button[3].byte_offset = 4;
|
||
info->iface[0].conf.joystick.button[3].bitmask = 0x10; // "Start"
|
||
|
||
info->iface[0].is_5200daptor = true;
|
||
}
|
||
|
||
if((vid == 0x0079) && (pid == 0x0006) && (i==0)) {
|
||
iprintf("MCC classic\n");
|
||
|
||
info->iface[0].is_MCC = 1;
|
||
}
|
||
if((vid == 0x1a34) && (pid == 0x0809) && (i==0)) {
|
||
iprintf("MCC Xeox\n");
|
||
|
||
info->iface[0].is_MCC = 2;
|
||
}
|
||
}
|
||
|
||
rcode = hid_set_idle(dev, info->iface[i].iface_idx, 0, 0);
|
||
// MWW if (rcode && rcode != hrSTALL)
|
||
//printf("RCODE:%02x ",rcode);
|
||
if (rcode && rcode != OHS900_STATMASK_STALL_RXED)
|
||
return rcode;
|
||
|
||
//printf("BM ");
|
||
// enable boot mode
|
||
if(info->iface[i].has_boot_mode)
|
||
{
|
||
//printf("BM ");
|
||
hid_set_protocol(dev, info->iface[i].iface_idx, HID_BOOT_PROTOCOL);
|
||
}
|
||
}
|
||
|
||
iprintf("HID configured\n");
|
||
|
||
// update leds
|
||
for(i=0;i<MAX_IFACES;i++)
|
||
if(dev->hid_info.iface[i].device_type == HID_DEVICE_KEYBOARD)
|
||
{
|
||
// printf("LEDS ");
|
||
uint8_t res = hid_set_report(dev, dev->hid_info.iface[i].iface_idx, 2, 0, 1, &kbd_led_state);
|
||
// printf("LEDS res:%02x ", res);
|
||
}
|
||
|
||
info->bPollEnable = true;
|
||
return 0;
|
||
}
|
||
|
||
static uint8_t usb_hid_release(usb_device_t *dev) {
|
||
usb_hid_info_t *info = &(dev->hid_info);
|
||
|
||
iprintf("%s\n",__FUNCTION__);
|
||
|
||
uint8_t i;
|
||
// check if a joystick is released
|
||
for(i=0;i<info->bNumIfaces;i++) {
|
||
if(info->iface[i].device_type == HID_DEVICE_JOYSTICK) {
|
||
uint8_t c_jindex = info->iface[i].jindex;
|
||
hid_debugf("rel joystick #%d, renum", c_jindex);
|
||
|
||
event_digital_joystick(c_jindex, 0);
|
||
event_analog_joystick(c_jindex, 0,0);
|
||
|
||
// walk through all devices and search for sticks with a higher id
|
||
|
||
// search for all joystick interfaces on all hid devices
|
||
usb_device_t *dev = usb_get_devices();
|
||
uint8_t j;
|
||
for(j=0;j<USB_NUMDEVICES;j++) {
|
||
if(dev[j].bAddress && (dev[j].class == &usb_hid_class)) {
|
||
// search for joystick interfaces
|
||
uint8_t k;
|
||
for(k=0;k<MAX_IFACES;k++) {
|
||
if(dev[j].hid_info.iface[k].device_type == HID_DEVICE_JOYSTICK) {
|
||
if(dev[j].hid_info.iface[k].jindex > c_jindex) {
|
||
hid_debugf("dec jindex of dev #%d from %d to %d", j,
|
||
dev[j].hid_info.iface[k].jindex, dev[j].hid_info.iface[k].jindex-1);
|
||
|
||
dev[j].hid_info.iface[k].jindex--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// one less joystick in the system ...
|
||
joysticks--;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
#ifdef FIRMWARE_5200
|
||
// special 5200daptor button processing
|
||
static void handle_5200daptor(usb_hid_iface_info_t *iface, uint8_t *buf) {
|
||
|
||
// list of buttons that are reported as keys
|
||
static const struct {
|
||
uint8_t byte_offset; // offset of the byte within the report which the button bit is in
|
||
uint8_t mask; // bitmask of the button bit
|
||
uint8_t key_code[2]; // usb keycodes to be sent for joystick 0 and joystick 1
|
||
} button_map[] = {
|
||
{ 4, 0x10, 0x3a, 0x3d }, /* START -> f1/f4 */
|
||
{ 4, 0x20, 0x3b, 0x3e }, /* PAUSE -> f2/f5 */
|
||
{ 4, 0x40, 0x3c, 0x3f }, /* RESET -> f3/f6 */
|
||
{ 5, 0x01, 0x1e, 0x21 }, /* 1 -> 1/4 */
|
||
{ 5, 0x02, 0x1f, 0x22 }, /* 2 -> 2/5 */
|
||
{ 5, 0x04, 0x20, 0x23 }, /* 3 -> 3/6 */
|
||
{ 5, 0x08, 0x14, 0x15 }, /* 4 -> q/r */
|
||
{ 5, 0x10, 0x1a, 0x17 }, /* 5 -> w/t */
|
||
{ 5, 0x20, 0x08, 0x1c }, /* 6 -> e/y */
|
||
{ 5, 0x40, 0x04, 0x09 }, /* 7 -> a/f */
|
||
{ 5, 0x80, 0x16, 0x0a }, /* 8 -> s/g */
|
||
{ 6, 0x01, 0x07, 0x0b }, /* 9 -> d/h */
|
||
{ 6, 0x02, 0x1d, 0x19 }, /* * -> z/v */
|
||
{ 6, 0x04, 0x1b, 0x05 }, /* 0 -> x/b */
|
||
{ 6, 0x08, 0x06, 0x11 }, /* # -> c/n */
|
||
{ 0, 0x00, 0x00, 0x00 } /* ---- end ---- */
|
||
};
|
||
|
||
// keyboard events are only generated for the first
|
||
// two joysticks in the system
|
||
if(iface->jindex > 1) return;
|
||
|
||
// build map of pressed keys
|
||
uint8_t i;
|
||
uint16_t keys = 0;
|
||
for(i=0;button_map[i].mask;i++)
|
||
if(buf[button_map[i].byte_offset] & button_map[i].mask)
|
||
keys |= (1<<i);
|
||
|
||
// check if keys have changed
|
||
if(iface->key_state != keys) {
|
||
uint8_t buf[6] = { 0,0,0,0,0,0 };
|
||
uint8_t p = 0;
|
||
|
||
// report up to 6 pressed keys
|
||
for(i=0;(i<16)&&(p<6);i++)
|
||
if(keys & (1<<i))
|
||
buf[p++] = button_map[i].key_code[iface->jindex];
|
||
|
||
// iprintf("5200: %d %d %d %d %d %d\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
|
||
|
||
// generate key events
|
||
event_keyboard(0x00, buf);
|
||
|
||
// save current state of keys
|
||
iface->key_state = keys;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
// special MCC button processing
|
||
static void handle_MCC(usb_hid_iface_info_t *iface, uint32_t * jmap_ptr, uint8_t type) {
|
||
|
||
/*
|
||
[start or left&right shoulder2] - start
|
||
[select or left&right shoulder1] - select
|
||
[select] - option
|
||
[3] - reset
|
||
[2] - cold start
|
||
[1] - quick select
|
||
[4] - settings
|
||
|
||
MY MAPPING
|
||
[select] - select
|
||
[start] - start
|
||
[L1|R1|3] - fire!
|
||
[L2|R2|4] - option
|
||
[L2&R2] - reboot
|
||
[L1&R2] - reset
|
||
[1] - settings
|
||
[2] - disk menu
|
||
*/
|
||
/*
|
||
{ 4, 0x41, }, * START -> f8 [1]*
|
||
{ 5, 0x41, }, * START -> f8 [2]*
|
||
{ 6, 0x42, }, * PAUSE -> f9 [3]*
|
||
{ 7, 0x43, }, * RESET -> f10 [4]*
|
||
{ 8, 0x1e, }, * 1 -> 1/4 SH L1*
|
||
{ 9, 0x1f, }, * 2 -> 2/5 SH R1*
|
||
{ 10, 0x20 }, * 3 -> 3/6 SH L2 *
|
||
{ 11, 0x14 }, * 4 -> q/r SH R2*
|
||
{ 12, 0x1a }, * 5 -> w/t SELECT*
|
||
{ 13, 0x08 }, * 6 -> e/y START*
|
||
{ 14, 0x04 }, * 7 -> a/f STICK CLICK LEFT*
|
||
{ 15, 0x16 }, * 8 -> s/g STICK CLICK RIGHT*
|
||
*/
|
||
|
||
uint32_t jmap = *jmap_ptr;
|
||
*jmap_ptr&=0xf;
|
||
|
||
if (type == 2)
|
||
{
|
||
uint32_t mask = 0;
|
||
if (jmap&0x40) mask ^= 0xc0;
|
||
if (jmap&0x80) mask ^= 0x90;
|
||
if (jmap&0x10) mask ^= 0x50;
|
||
jmap ^= mask;
|
||
//x(left)=40 (old 80)
|
||
//y(up)=80 (old 10)
|
||
//a(down)=10 (old 40)
|
||
}
|
||
|
||
static const struct {
|
||
uint8_t bit1; // bit of the button bit (1<<bit)
|
||
uint8_t bit2; // bit of the button bit (1<<bit)
|
||
uint8_t key_code; // usb keycodes to be sent for all joysticks
|
||
uint8_t button_bit;
|
||
} button_map[] = {
|
||
#ifndef FIRMWARE_5200
|
||
{ 13, 13, 0x3f, 0 }, /* start -> f6 */
|
||
{ 12, 12, 0x40, 0 }, /* select -> f7 */
|
||
{ 10, 10, 0x41, 0 }, /* l2 -> f8 */
|
||
{ 11, 11, 0x41, 0 }, /* r2 -> f8 */
|
||
{ 7, 7, 0x41, 0 }, /* 4 -> f8 */
|
||
{ 10, 11, 0x43, 0 }, /* l2&r2 -> f10 */
|
||
{ 8, 11, 0x42, 0 }, /* l1&r2 -> f9 */
|
||
{ 6, 6, 0x00, 4 }, /* 3 -> fire */
|
||
#endif
|
||
#ifdef FIRMWARE_5200
|
||
{ 13, 13, 0x3a, 0 }, /* start -> f1 (start) */
|
||
{ 12, 12, 0x3b, 0 }, /* select -> f2 (pause) */
|
||
{ 10, 10, 0x00, 5 }, /* l2 -> fire2 */
|
||
{ 11, 11, 0x00, 5 }, /* r2 -> fire2 */
|
||
{ 6, 6, 0x00, 5 }, /* 3 -> fire2 */
|
||
{ 7, 7, 0x00, 4 }, /* 4 -> fire */
|
||
#endif
|
||
{ 4, 4, 0x45, 0 }, /* 1 -> f12 */
|
||
{ 5, 5, 0x44, 0 }, /* 2 -> f11 */
|
||
{ 14, 15, 0x29, 0 }, /* both sticks -> esc */
|
||
{ 8, 8, 0x00, 4 }, /* l1 -> fire */
|
||
{ 9, 9, 0x00, 4 }, /* r1 -> fire */
|
||
{ 10, 15, 0x43, 0 }, /* l2& rstick click -> f10 */
|
||
{ 9, 15, 0x42, 0 }, /* l1& rstick click -> f9 */
|
||
{ 0, 0, 0x00, 0 } /* ---- end ---- */
|
||
};
|
||
|
||
uint8_t buf[6] = { 0,0,0,0,0,0 };
|
||
uint8_t p = 0;
|
||
|
||
// report up to 6 pressed keys
|
||
// modify jmap buttons
|
||
int i;
|
||
for(i=0;button_map[i].bit1;i++)
|
||
{
|
||
uint32_t mask = 0;
|
||
mask |= 1<<button_map[i].bit1;
|
||
mask |= 1<<button_map[i].bit2;
|
||
|
||
if((jmap & mask) == mask)
|
||
{
|
||
if (p<6 && button_map[i].key_code)
|
||
{
|
||
buf[p++] = button_map[i].key_code;
|
||
}
|
||
|
||
if (button_map[i].button_bit)
|
||
{
|
||
*jmap_ptr |= 1<<button_map[i].button_bit;
|
||
}
|
||
}
|
||
}
|
||
// generate key events
|
||
event_keyboard(0x00, buf);
|
||
}
|
||
|
||
static uint8_t usb_hid_poll(usb_device_t *dev) {
|
||
usb_hid_info_t *info = &(dev->hid_info);
|
||
int8_t i;
|
||
|
||
if (!info->bPollEnable)
|
||
return 0;
|
||
|
||
for(i=0;i<info->bNumIfaces;i++) {
|
||
usb_hid_iface_info_t *iface = info->iface+i;
|
||
|
||
if(iface->device_type != HID_DEVICE_UNKNOWN) {
|
||
|
||
if (iface->qNextPollTime <= timer_get_msec()) {
|
||
// hid_debugf("poll %d...", iface->ep.epAddr);
|
||
|
||
uint16_t read = iface->ep.maxPktSize;
|
||
uint8_t buf[iface->ep.maxPktSize];
|
||
//hid_debugf("bytes:%d ep:%x",read,iface->ep);
|
||
uint8_t rcode =
|
||
usb_in_transfer(dev, &(iface->ep), &read, buf);
|
||
|
||
if (rcode) {
|
||
// MWW if (rcode != hrNAK)
|
||
if (rcode != OHS900_STATMASK_NAK_RXED)
|
||
hid_debugf("%s() error: %d", __FUNCTION__, rcode);
|
||
} else {
|
||
|
||
// successfully received some bytes
|
||
if(iface->has_boot_mode) {
|
||
if(iface->device_type == HID_DEVICE_MOUSE) {
|
||
// boot mouse needs at least three bytes
|
||
if(read >= 3) {
|
||
// forward all three bytes to the user_io layer
|
||
event_mouse(buf[0], buf[1], buf[2]);
|
||
}
|
||
}
|
||
|
||
if(iface->device_type == HID_DEVICE_KEYBOARD) {
|
||
// boot kbd needs at least eight bytes
|
||
if(read >= 8) {
|
||
event_keyboard(buf[0], buf+2);
|
||
}
|
||
}
|
||
}
|
||
|
||
if(iface->device_type == HID_DEVICE_JOYSTICK) {
|
||
hid_config_t *conf = &iface->conf;
|
||
//hid_debugf("JOY");
|
||
if(iface->is_MCC==3 || read >= conf->report_size) {
|
||
uint32_t jmap = 0;
|
||
uint16_t a[2];
|
||
uint8_t idx, i;
|
||
|
||
// hid_debugf("Joystick data:"); hexdump(buf, read, 0);
|
||
|
||
// two axes ...
|
||
if(iface->is_MCC==3)
|
||
{
|
||
/*14 bytes (0-13)
|
||
Left trigger: Byte 4: 0 (not pressed) to ff (pressed) - analogue
|
||
Right trigger: Byte 5: 0 (not pressed) to ff (pressed) - analogue
|
||
Left button: Byte 3: bit 0 (1=pressed)
|
||
Right button: Byte 3: bit 1 (2=pressed)
|
||
A button: Byte 3: bit 4 (0x10=pressed)
|
||
B button: Byte 3: bit 5 (0x20=pressed)
|
||
X button: Byte 3: bit 6 (0x40=pressed)
|
||
Y button: Byte 3: bit 7 (0x80=pressed)
|
||
Joy up: Byte 2: bit 0 (1=pressed)
|
||
Joy down: Byte 2: bit 1 (2=pressed)
|
||
Joy left: Byte 2: bit 2 (4=pressed)
|
||
Joy right: Byte 2: bit 3 (8=pressed)
|
||
Start: Byte 2: bit 4 (0x10=pressed)
|
||
Select: Byte 2: bit 5 (0x20=pressed)
|
||
Left hat LR: Byte 7: 0x80 - 0x7f (analogue - 2s comp left =-ve)
|
||
Left hat UD: Byte 9: 0x80 - 0x7f (analogue - 2s comp down=-ve)
|
||
Right hat LR: Byte b: 0x80 - 0x7f (analogue - 2s comp left =-ve)
|
||
Right hat UD: Byte d: 0x80 - 0x7f (analogue - 2s comp down=-ve)
|
||
left hat button: byte 2: bit 6 (0x40=pressed)
|
||
right hat button: byte 2: bit 7 (0x80=pressed)*/
|
||
|
||
if (buf[0]==00 && buf[1]==0x14)
|
||
{
|
||
if (buf[2]&1) jmap |= JOY_UP;
|
||
if (buf[2]&2) jmap |= JOY_DOWN;
|
||
if (buf[2]&4) jmap |= JOY_LEFT;
|
||
if (buf[2]&8) jmap |= JOY_RIGHT;
|
||
if (buf[3]&0x80) jmap |= 1<<4; //1
|
||
if (buf[3]&0x20) jmap |= 1<<5; //2
|
||
if (buf[3]&0x10) jmap |= 1<<6; //3
|
||
if (buf[3]&0x40) jmap |= 1<<7; //4
|
||
if (buf[3]&1) jmap |= 1<<8; //l1
|
||
if (buf[3]&2) jmap |= 1<<9; //r1
|
||
if (buf[4]&0x80) jmap |= 1<<10; //l2
|
||
if (buf[5]&0x80) jmap |= 1<<11; //r2
|
||
if (buf[2]&0x20) jmap |= 1<<12; //select
|
||
if (buf[2]&0x10) jmap |= 1<<13; //start
|
||
if (buf[2]&0x40) jmap |= 1<<14; //lstick click
|
||
if (buf[2]&0x80) jmap |= 1<<15; //rstick click
|
||
|
||
int8_t x = (char)buf[7];
|
||
int8_t y = (char)buf[9];
|
||
|
||
a[0] = 128+x;
|
||
a[1] = 127-y;
|
||
}
|
||
else
|
||
{
|
||
jmap = 0;
|
||
a[0] = 128;
|
||
a[1] = 128;
|
||
}
|
||
|
||
//for (i=0;i!=14;++i)
|
||
//{
|
||
// hid_debugf("%02x",buf[i]);
|
||
//}
|
||
//hid_debugf("=jmap:%x",jmap);
|
||
}
|
||
else
|
||
{
|
||
for(i=0;i<2;i++) {
|
||
a[i] = buf[conf->joystick.axis[i].byte_offset];
|
||
if(conf->joystick.axis[i].size == 16)
|
||
a[i] += (buf[conf->joystick.axis[i].byte_offset+1])<<8;
|
||
|
||
// scale to 0 -> 255 range. 99% of the joysticks already deliver that
|
||
if((conf->joystick.axis[i].logical.min != 0) ||
|
||
(conf->joystick.axis[i].logical.max != 255)) {
|
||
a[i] = ((a[i] - conf->joystick.axis[i].logical.min) * 255)/
|
||
(conf->joystick.axis[i].logical.max -
|
||
conf->joystick.axis[i].logical.min);
|
||
}
|
||
}
|
||
|
||
// iprintf("JOY X:%d Y:%d\n", a[0], a[1]);
|
||
|
||
// ... and twenty-four buttons
|
||
for(i=0;i<24;i++)
|
||
if(buf[conf->joystick.button[i].byte_offset] &
|
||
conf->joystick.button[i].bitmask) jmap |= (JOY_BTN1<<i);
|
||
}
|
||
|
||
if(a[0] < 64) jmap |= JOY_LEFT;
|
||
if(a[0] > 192) jmap |= JOY_RIGHT;
|
||
if(a[1] < 64) jmap |= JOY_UP;
|
||
if(a[1] > 192) jmap |= JOY_DOWN;
|
||
|
||
// iprintf("JOY D:%d\n", jmap);
|
||
|
||
idx = iface->jindex;
|
||
|
||
// check if joystick state has changed
|
||
if(jmap != iface->jmap) {
|
||
|
||
//unsigned char * temp = baseaddr;
|
||
//baseaddr = (unsigned char volatile *)(screen_address + atari_regbase);
|
||
//debug_pos=80;
|
||
//printf("jmap %d(%d) changed to %x\n", idx, iface->jindex,jmap);
|
||
//baseaddr = temp;
|
||
// iprintf("jmap %d changed to %x\n", idx, jmap);
|
||
iface->jmap = jmap;
|
||
|
||
// do special MCC treatment
|
||
if(iface->is_MCC)
|
||
handle_MCC(iface, &jmap, iface->is_MCC);
|
||
|
||
// and feed into joystick input system
|
||
event_digital_joystick(idx, jmap);
|
||
}
|
||
|
||
// also send analog values
|
||
event_analog_joystick(idx, a[0]-128, a[1]-128);
|
||
|
||
// do special 5200daptor treatment
|
||
#ifdef FIRMWARE_5200
|
||
if(iface->is_5200daptor)
|
||
handle_5200daptor(iface, buf);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
iface->qNextPollTime += iface->interval; // poll at requested rate
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
const usb_device_class_config_t usb_hid_class = {
|
||
usb_hid_init, usb_hid_release, usb_hid_poll };
|
||
|
firmware_legacy/usb/events.h | ||
---|---|---|
//#include "printf.h"
|
||
#include "regs.h"
|
||
|
||
#include "keycodes.h"
|
||
|
||
extern int debug_pos;
|
||
|
||
uint8_t kbbuf[6];
|
||
uint32_t jmaps[4];
|
||
|
||
int8_t analogx[4];
|
||
int8_t analogy[4];
|
||
|
||
void event_keyboard(uint8_t mod, uint8_t buf[])
|
||
{
|
||
//printf("Event keyboard:%d\n", mod);
|
||
/*int changed = 0;
|
||
|
||
if (lastmod!=i)
|
||
{
|
||
lastmod = i;
|
||
changed = 1;
|
||
}
|
||
int j;
|
||
for (j=0;j!=8;++j)
|
||
{
|
||
//printf("Event keyboard:%d = %x\n", j, buf[j]);
|
||
if (buf[j] != kbbuf[j])
|
||
{
|
||
changed = 1;
|
||
kbbuf[j] = buf[j];
|
||
}
|
||
}*/
|
||
|
||
/* usb modifer bits:
|
||
0 1 2 3 4 5 6 7
|
||
LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI
|
||
*/
|
||
|
||
// Convert changes into a serial of release/press notifications
|
||
int i=0;
|
||
for(i=0;i!=8;++i)
|
||
{
|
||
int bit = 1<<i;
|
||
uint32_t pressed = !!(bit&mod);
|
||
uint32_t ps2_key = ps2_modifier[i];
|
||
*zpu_out4 = (pressed<<16)|ps2_key;
|
||
}
|
||
|
||
// unpress old keys that are no longer pressed
|
||
for (i=0;i!=6;++i)
|
||
{
|
||
if (kbbuf[i]==MISS) continue;
|
||
|
||
uint32_t oldkey = usb2ps2[kbbuf[i]];
|
||
int j=0;
|
||
int found = 0;
|
||
for (j=0;j!=6;++j)
|
||
{
|
||
uint32_t newkey = usb2ps2[buf[i]];
|
||
if (oldkey==newkey) {found=1;break;}
|
||
}
|
||
|
||
if (!found)
|
||
{
|
||
*zpu_out4 = oldkey; // unpress
|
||
}
|
||
}
|
||
|
||
// press/hold new keys
|
||
for (i=0;i!=6;++i)
|
||
{
|
||
if (buf[i]==MISS) continue;
|
||
|
||
uint32_t newkey = usb2ps2[buf[i]];
|
||
|
||
// press new one
|
||
*zpu_out4 = (1<<16)|newkey;
|
||
}
|
||
|
||
for (i=0;i!=6;++i)
|
||
{
|
||
kbbuf[i] = buf[i]; // store
|
||
}
|
||
|
||
/* if (changed)
|
||
{
|
||
debug_pos = 120;
|
||
printf("KB:");
|
||
printf("%02x ",kbi);
|
||
for (j=0;j!=8;++j)
|
||
{
|
||
printf("%04x ",usb2ps2[kbbuf[j]]);
|
||
}
|
||
|
||
// lctrl:1, lshift:2, lalt:4, lwin:8, rctrl:10, rshift:20, altgr:40
|
||
uint32_t mod = kbi;
|
||
uint32_t key1 = usb2ps2[kbbuf[0]];
|
||
//uint32_t key2 = usb2ps2[kbbuf[1]];
|
||
//uint32_t key3 = usb2ps2[kbbuf[2]];
|
||
|
||
uint32_t res = (key3<<24) | (key2<<16) || (key1<<8) || mod;
|
||
*zpu_out4 = res;
|
||
}*/
|
||
}
|
||
void event_mouse(uint8_t a, uint8_t b, uint8_t c)
|
||
{
|
||
//printf("Event mouse:%d %d %d\n",a,b,c);
|
||
}
|
||
void event_digital_joystick(uint8_t idx, uint32_t jmap)
|
||
{
|
||
//printf("Event joystick:%d %x\n", idx,jmap);
|
||
/*if (jmaps[idx] != jmap)
|
||
{
|
||
jmaps[idx] = jmap;
|
||
debug_pos = 200 + idx*40;
|
||
printf("JOY:%d:%08x ",idx,jmap);
|
||
}*/
|
||
idx = idx&1;
|
||
if (idx == 0)
|
||
{
|
||
*zpu_out2 = jmap;
|
||
}
|
||
if (idx == 1)
|
||
{
|
||
*zpu_out3 = jmap;
|
||
}
|
||
}
|
||
void event_analog_joystick(uint8_t idx, int8_t x, int8_t y)
|
||
{
|
||
//printf("Event analog joystick:%d %d %d\n", idx,x,y);
|
||
idx = idx&1;
|
||
if (analogx[idx]!=x || analogy[idx]!=y)
|
||
{
|
||
analogx[idx] = x;
|
||
analogy[idx] = y;
|
||
//debug_pos = 360 + idx*40;
|
||
//printf("AJOY:%d:%d:%d ", idx,x,y);
|
||
|
||
uint32_t x0 = (uint8_t)analogx[0];
|
||
uint32_t y0 = (uint8_t)analogy[0];
|
||
uint32_t x1 = (uint8_t)analogx[1];
|
||
uint32_t y1 = (uint8_t)analogy[1];
|
||
|
||
uint32_t comb = (y1<<24)|(x1<<16)|(y0<<8) |x0;
|
||
*zpu_out5 = comb;
|
||
}
|
||
}
|
||
|
||
#define JOY_RIGHT 0x01
|
||
#define JOY_LEFT 0x02
|
||
#define JOY_DOWN 0x04
|
||
#define JOY_UP 0x08
|
||
#define JOY_BTN1 0x10
|
||
#define JOY_BTN2 0x20
|
||
#define JOY_BTN3 0x40
|
||
#define JOY_BTN4 0x80
|
||
#define JOY_MOVE (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
|
||
|
||
|
firmware_legacy/fat/diskio.h | ||
---|---|---|
/*-----------------------------------------------------------------------
|
||
/ PFF - Low level disk interface modlue include file (C)ChaN, 2009
|
||
/-----------------------------------------------------------------------*/
|
||
|
||
#ifndef _DISKIO
|
||
|
||
#include "integer.h"
|
||
|
||
|
||
/* Status of Disk Functions */
|
||
typedef BYTE DSTATUS;
|
||
|
||
|
||
/* Results of Disk Functions */
|
||
typedef enum {
|
||
RES_OK = 0, /* 0: Function succeeded */
|
||
RES_ERROR, /* 1: Disk error */
|
||
RES_NOTRDY, /* 2: Not ready */
|
||
RES_PARERR /* 3: Invalid parameter */
|
||
} DRESULT;
|
||
|
||
|
||
/*---------------------------------------*/
|
||
/* Prototypes for disk control functions */
|
||
|
||
DSTATUS disk_initialize (void);
|
||
DRESULT disk_readp (BYTE*, DWORD, WORD, WORD);
|
||
DRESULT disk_writep (const BYTE* buff, DWORD sofs, DWORD count);
|
||
void disk_writeflush();
|
||
|
||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||
|
||
/* Card type flags (CardType) */
|
||
#define CT_MMC 0x01 /* MMC ver 3 */
|
||
#define CT_SD1 0x02 /* SD ver 1 */
|
||
#define CT_SD2 0x04 /* SD ver 2 */
|
||
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
|
||
#define CT_BLOCK 0x08 /* Block addressing */
|
||
|
||
#define _DISKIO
|
||
#endif
|
firmware_legacy/pokey/uart.c | ||
---|---|---|
#include "uart.h"
|
||
|
||
#include "regs.h"
|
||
|
||
void actions();
|
||
|
||
int USART_Data_Needed()
|
||
{
|
||
int needed = 0==(0x10&(*zpu_pokey_irqen));
|
||
if (needed)
|
||
{
|
||
*zpu_pokey_irqen = 0x28;
|
||
*zpu_pokey_irqen = 0x38;
|
||
}
|
||
return needed;
|
||
}
|
||
|
||
int USART_Data_Ready()
|
||
{
|
||
int ready = 0==(0x20&(*zpu_pokey_irqen));
|
||
if (ready)
|
||
{
|
||
*zpu_pokey_irqen = 0x18;
|
||
*zpu_pokey_irqen = 0x38;
|
||
}
|
||
return ready;
|
||
}
|
||
|
||
void USART_Init( u08 value )
|
||
{
|
||
// value is pokey div + 6
|
||
*zpu_pokey_skctl = 0;
|
||
wait_us(10);
|
||
USART_Receive_Mode(); // turn of reset and listen to commands
|
||
*zpu_pokey_audctl = 0x78; // linked channels, fast clocked
|
||
*zpu_pokey_audf1 = 0x00;
|
||
*zpu_pokey_audf0 = value-6;
|
||
*zpu_pokey_audf3 = 0x00;
|
||
*zpu_pokey_audf2 = value-6;
|
||
|
||
*zpu_pokey_irqen = 0x00;
|
||
*zpu_pokey_irqen = 0x38;
|
||
}
|
||
|
||
void USART_Transmit_Byte( unsigned char data )
|
||
{
|
||
*zpu_pokey_serout = data;
|
||
|
||
// wait until next byte is needed
|
||
while (!USART_Data_Needed());
|
||
}
|
||
unsigned char USART_Receive_Byte( void )
|
||
{
|
||
// wait for data
|
||
while (!USART_Data_Ready())
|
||
{
|
||
actions();
|
||
}
|
||
|
||
u08 res = *zpu_pokey_serout; //serin at same address
|
||
return res;
|
||
}
|
||
|
||
void USART_Transmit_Mode()
|
||
{
|
||
*zpu_pokey_skctl = 0x23; // 010 for transmission
|
||
*zpu_pokey_skrest = 0xff;
|
||
*zpu_pokey_irqen = 0x28; // clear data needed
|
||
*zpu_pokey_irqen = 0x38;
|
||
}
|
||
|
||
void USART_Receive_Mode()
|
||
{
|
||
*zpu_pokey_skctl = 0x13; // 001 for receiving
|
||
*zpu_pokey_skrest = 0xff;
|
||
}
|
||
|
||
int USART_Framing_Error()
|
||
{
|
||
if (0x80&(*zpu_pokey_skctl))
|
||
{
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
void USART_Wait_Transmit_Complete()
|
||
{
|
||
while (1)
|
||
{
|
||
int ready = 0==(0x08&(*zpu_pokey_irqen));
|
||
if (ready)
|
||
{
|
||
*zpu_pokey_irqen = 0x30;
|
||
*zpu_pokey_irqen = 0x38;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
int USART_Command_Line()
|
||
{
|
||
return (1&(*zpu_sio));
|
||
}
|
||
|
firmware_legacy/linux/memory.h | ||
---|---|---|
#ifndef MEMORY_H
|
||
#define MEMORY_H
|
||
|
||
extern void* SDRAM_BASE;
|
||
extern void* SRAM_BASE;
|
||
extern void* CARTRIDGE_MEM;
|
||
extern void* FREEZER_RAM_MEM;
|
||
extern void* FREEZER_ROM_MEM;
|
||
|
||
#define HAVE_FREEZER_ROM_MEM 1
|
||
|
||
#define INIT_MEM
|
||
|
||
// Memory usage...
|
||
// 0x410000-0x44FFFF (0xc10000 in zpu space) = directory cache - 256k
|
||
// 0x450000-0x46FFFF (0xc50000 in zpu space) = freeze backup
|
||
// 0x700000-0x77FFFF (0xf00000 in zpu space) = os rom/basic rom
|
||
|
||
#define DIR_INIT_MEM (SDRAM_BASE + 0x410000)
|
||
#define DIR_INIT_MEMSIZE 262144
|
||
#define FREEZE_MEM (SDRAM_BASE + 0x450000)
|
||
|
||
// offset into SDRAM
|
||
#define ROM_OFS 0x700000
|
||
|
||
extern void* atari_regbase;
|
||
extern void* atari_regmirror;
|
||
extern void* zpu_regbase;
|
||
extern void* pokey_regbase;
|
||
|
||
void init_memory(void);
|
||
|
||
#endif
|
firmware_legacy/usb/usb.c | ||
---|---|---|
//#include <stdio.h>
|
||
|
||
#include "timer.h"
|
||
#include "usb.h"
|
||
#include "usbhostslave.h"
|
||
#include "debug.h"
|
||
#include "memory.h"
|
||
#include "printf.h"
|
||
#include "log.h"
|
||
|
||
extern unsigned char joysticks; // number of detected usb joysticks
|
||
usb_device_t devices[USB_NUMDEVICES];
|
||
|
||
/*#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
|
||
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
|
||
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
|
||
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
|
||
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
|
||
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
|
||
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
|
||
*/
|
||
|
||
typedef enum {tokSETUP,tokIN,tokOUT,tokINHS,tokOUTHS,tokISOIN,tokISOOUT} TOKEN;
|
||
|
||
static uint8_t outType;
|
||
static uint8_t controlAdj;
|
||
static uint8_t lineControlAdj;
|
||
|
||
#ifdef LINUX_BUILD
|
||
#define USBHOSTSLAVE_READ(ADDR) usbhostslave_read(ADDR)
|
||
#define USBHOSTSLAVE_WRITE(ADDR,VALUE) usbhostslave_write(ADDR,VALUE)
|
||
#else
|
||
#define USBHOSTSLAVE_READ(ADDR) usbhostslave[ADDR]
|
||
#define USBHOSTSLAVE_WRITE(ADDR,VALUE) usbhostslave[ADDR] = VALUE
|
||
#endif
|
||
|
||
void usb_reset_state() {
|
||
iprintf("%s\n",__FUNCTION__);
|
||
}
|
||
|
||
usb_device_t *usb_get_devices() {
|
||
return devices;
|
||
}
|
||
|
||
void usb_init(struct usb_host * host, int portnumber) {
|
||
iprintf("%s\n",__FUNCTION__);
|
||
|
||
joysticks = 0;
|
||
|
||
// MWW max3421e_init(); // init underlaying hardware layer
|
||
|
||
if (portnumber == 0)
|
||
{
|
||
host->addr = zpu_regbase + 0x800;
|
||
}
|
||
if (portnumber == 1)
|
||
{
|
||
host->addr = zpu_regbase + 0xc00;
|
||
}
|
||
usbhostslave = host->addr;
|
||
host->poll = 0;
|
||
host->delay = 0;
|
||
|
||
USBHOSTSLAVE_WRITE(OHS900_HOSTSLAVECTLREG, OHS900_HSCTLREG_RESET_CORE);
|
||
timer_delay_msec(1);
|
||
USBHOSTSLAVE_WRITE(OHS900_TXLINECTLREG, 0);
|
||
USBHOSTSLAVE_WRITE(OHS900_HOSTSLAVECTLREG, OHS900_HS_CTL_INIT);
|
||
USBHOSTSLAVE_WRITE(OHS900_SOFENREG, 0);
|
||
USBHOSTSLAVE_WRITE(OHS900_IRQ_ENABLE, 0);
|
||
|
||
host->usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||
|
||
outType = 0;
|
||
controlAdj = 0;
|
||
lineControlAdj = 0;
|
||
|
||
uint8_t i;
|
||
for(i=0;i<USB_NUMDEVICES;i++)
|
||
devices[i].bAddress = 0;
|
||
|
||
usb_reset_state();
|
||
}
|
||
|
||
uint8_t usb_set_address(usb_device_t *dev, ep_t *ep,
|
||
uint16_t *nak_limit) {
|
||
// printf(" %s(addr=%x, ep=%d)\n", __FUNCTION__, addr, ep);
|
||
*nak_limit = (1UL << ( ( ep->bmNakPower > USB_NAK_MAX_POWER ) ?
|
||
USB_NAK_MAX_POWER : ep->bmNakPower) ) - 1;
|
||
|
||
/*
|
||
printf("\nAddress: %x\n", addr);
|
||
printf(" EP: %d\n", ep);
|
||
printf(" NAK Power: %d\n",(*ppep)->bmNakPower);
|
||
printf(" NAK Limit: %d\n", nak_limit);
|
||
*/
|
||
|
||
USBHOSTSLAVE_WRITE(OHS900_TXADDRREG, dev->bAddress);
|
||
|
||
/* MWW (sets address and messes with mode - I plan to change mode on connect only...)
|
||
max3421e_write_u08( MAX3421E_PERADDR, dev->bAddress); // set peripheral address
|
||
uint8_t mode = max3421e_read_u08( MAX3421E_MODE );
|
||
|
||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device,
|
||
// reset them otherwise
|
||
max3421e_write_u08( MAX3421E_MODE,
|
||
(dev->lowspeed) ? mode | MAX3421E_LOWSPEED | bmHubPre :
|
||
mode & ~(MAX3421E_HUBPRE | MAX3421E_LOWSPEED));
|
||
*/
|
||
|
||
controlAdj = 0;
|
||
lineControlAdj = 0;
|
||
if (dev->parent) // via hub
|
||
{
|
||
controlAdj = dev->lowspeed ? OHS900_HCTLMASK_PREAMBLE_EN : 0;
|
||
lineControlAdj = dev->lowspeed ? 0 : OHS900_TXLCTL_MASK_FS_RATE;
|
||
lineControlAdj |= OHS900_TXLCTL_MASK_FS_POL; // hub always full speed polarity
|
||
}
|
||
else // direct
|
||
{
|
||
lineControlAdj = dev->lowspeed ? OHS900_TXLCTL_MASK_LSPD : OHS900_TXLCTL_MASK_FSPD;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* dispatch usb packet. Assumes peripheral address is set and relevant */
|
||
/* buffer is loaded/empty */
|
||
/* If NAK, tries to re-send up to nak_limit times */
|
||
/* If nak_limit == 0, do not count NAKs, exit after timeout */
|
||
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
|
||
/* return codes 0x00-0x0f are HRSLT (0x00 being success), 0xff means timeout */
|
||
uint8_t usb_dispatchPktWithData( TOKEN token, uint8_t ep, uint16_t nak_limit, uint8_t * data, uint16_t bytes_tosend, uint8_t * sndToggle) {
|
||
// printf(" %s(token=%x, ep=%d, nak_limit=%d tosend:%d)\n",
|
||
// __FUNCTION__, token, ep, nak_limit, bytes_tosend);
|
||
iprintf("SEND%02d ", bytes_tosend);
|
||
unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
|
||
uint8_t tmpdata;
|
||
uint8_t rcode = 0x00;
|
||
uint8_t retry_count = 0;
|
||
uint16_t nak_count = 0;
|
||
|
||
while( timeout > timer_get_msec() ) {
|
||
//MWW max3421e_write_u08( MAX3421E_HXFR, ( token|ep )); //launch the transfer
|
||
USBHOSTSLAVE_WRITE(OHS900_TXENDPREG, ep);
|
||
uint8_t control = OHS900_HCTLMASK_TRANS_REQ|controlAdj;
|
||
uint8_t line_control = 0;
|
||
uint8_t load_fifo = 0;
|
||
uint8_t wait_for_sof = OHS900_HCTLMASK_SOF_SYNC;
|
||
uint8_t expect_ack = 0;
|
||
switch (token)
|
||
{
|
||
case tokSETUP:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_SETUP);
|
||
iprintf("S ");
|
||
load_fifo = 1;
|
||
expect_ack = 1;
|
||
break;
|
||
case tokIN:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_IN);
|
||
iprintf("I ");
|
||
break;
|
||
case tokOUT:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0);
|
||
iprintf(*sndToggle ? "Data1 ":"Data0 ");
|
||
load_fifo = 1;
|
||
expect_ack = 1;
|
||
break;
|
||
case tokINHS:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_IN);
|
||
iprintf("HI ");
|
||
//wait_for_sof = 0;
|
||
break;
|
||
case tokOUTHS:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_OUT_DATA1);
|
||
iprintf("HO ");
|
||
load_fifo = 1;
|
||
//wait_for_sof = 0;
|
||
expect_ack = 1;
|
||
break;
|
||
case tokISOIN:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_IN);
|
||
control |= OHS900_HCTLMASK_ISO_EN;
|
||
break;
|
||
case tokISOOUT:
|
||
USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0);
|
||
*sndToggle = !*sndToggle; // No acks, toggle each time
|
||
load_fifo = 1;
|
||
control |= OHS900_HCTLMASK_ISO_EN;
|
||
break;
|
||
}
|
||
|
||
line_control |= lineControlAdj;
|
||
|
||
USBHOSTSLAVE_WRITE(OHS900_TXFIFOCONTROLREG, OHS900_FIFO_FORCE_EMPTY);
|
||
USBHOSTSLAVE_WRITE(OHS900_RXFIFOCONTROLREG, OHS900_FIFO_FORCE_EMPTY);
|
||
|
||
if (load_fifo && data)
|
||
{
|
||
|
||
//filling output FIFO
|
||
//MWW max3421e_write( MAX3421E_SNDFIFO, bytes_tosend, data );
|
||
uint16_t toSend = bytes_tosend;
|
||
uint8_t * dataToSend = data;
|
||
iprintf("FIFO:");
|
||
while (toSend--)
|
||
{
|
||
iprintf("%02x", *dataToSend);
|
||
USBHOSTSLAVE_WRITE(OHS900_HOST_TXFIFO_DATA, *dataToSend++);
|
||
}
|
||
iprintf(" ");
|
||
|
||
//set number of bytes
|
||
//MWW max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
|
||
}
|
||
|
||
{
|
||
rcode = USBHOSTSLAVE_READ(OHS900_HRXSTATREG);
|
||
// printf("Pre transfer rcode:%02x line:%02x ctrl:%02x", rcode, line_control, control);
|
||
}
|
||
|
||
USBHOSTSLAVE_WRITE(OHS900_TXLINECTLREG, line_control);
|
||
//USBHOSTSLAVE_WRITE(OHS900_HOST_TX_CTLREG, control|wait_for_sof);
|
||
USBHOSTSLAVE_WRITE(OHS900_HOST_TX_CTLREG, control);
|
||
|
||
rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||
|
||
// wait for transfer completion
|
||
//printf("Wait:%x %x ", timer_get_msec(), timeout);
|
||
while( timer_get_msec() < timeout ) {
|
||
//tmpdata = max3421e_read_u08( MAX3421E_HIRQ );
|
||
// MWW
|
||
tmpdata = USBHOSTSLAVE_READ(OHS900_IRQ_STATUS);
|
||
|
||
if( tmpdata & OHS900_INTMASK_TRANS_DONE ) {
|
||
//clear the interrupt
|
||
//max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );
|
||
// MWW
|
||
USBHOSTSLAVE_WRITE(OHS900_IRQ_STATUS, OHS900_INTMASK_TRANS_DONE);
|
||
rcode = 0x00;
|
||
|
||
iprintf("OK ");
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( rcode != 0x00 ) //exit if timeout
|
||
{
|
||
iprintf("TMOUT ");
|
||
return( rcode );
|
||
}
|
||
|
||
//analyze transfer result
|
||
//rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
|
||
//rcode = 0x00;
|
||
rcode = USBHOSTSLAVE_READ(OHS900_HRXSTATREG);
|
||
|
||
iprintf("R%02x ", rcode);
|
||
rcode &= ~OHS900_STATMASK_DATA_SEQ;
|
||
|
||
if (!expect_ack && rcode == 0x00)
|
||
{
|
||
iprintf("EMPTY! ");
|
||
//rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||
return rcode;
|
||
}
|
||
|
||
if (rcode&OHS900_STATMASK_ACK_RXED)
|
||
{
|
||
//set toggle value
|
||
// MWW: max3421e_write_u08(MAX3421E_HCTL,
|
||
// (pep->bmSndToggle) ? MAX3421E_SNDTOG1 : MAX3421E_SNDTOG0 );
|
||
*sndToggle = !*sndToggle; // Toggled on ack
|
||
iprintf("ACK ");
|
||
break;
|
||
}
|
||
else if (rcode&OHS900_STATMASK_NAK_RXED)
|
||
{
|
||
nak_count++;
|
||
if( nak_limit && ( nak_count == nak_limit ))
|
||
return( rcode );
|
||
}
|
||
else if (rcode&OHS900_STATMASK_RX_TMOUT)
|
||
{
|
||
retry_count++;
|
||
iprintf("Retry ");
|
||
if( retry_count == USB_RETRY_LIMIT )
|
||
return( rcode );
|
||
}
|
||
else if (rcode&(OHS900_STATMASK_CRC_ERROR|OHS900_STATMASK_BS_ERROR|OHS900_STATMASK_STALL_RXED))
|
||
{
|
||
return( rcode );
|
||
}
|
||
}
|
||
|
||
return( rcode&~(OHS900_STATMASK_ACK_RXED));
|
Also available in: Unified diff
EclaireXL has diverged a lot, use this for other platforms for now!