/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Joystick driver for the IF-SEGA2/PCI (I-O DATA) controller. * * By S. Suzuki, * * based code by E.Watanabe (ifsega.c : IF-SEGA/ISA joystick driver). * * Test program and informations provided by Saka (sp2p : analog joystick * emulation driver for Win9x DOS Session + IF-SEGA/ISA, IF-SEGA2/PCI). */ #include "allegro.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintdos.h" #ifndef ALLEGRO_DOS #error something is wrong with the makefile #endif /* prototype */ int _sg_pci_init(void); void _sg_pci_exit(void); unsigned long _sg_pci_ioin(unsigned long offset); void _sg_pci_ioout(unsigned long offset, unsigned long data); static int sg_pci_poll(void); static int sg_pci_poll1(void); static int sg_pci_poll_sub(int num, int base); static int sg_pci_poll_sub2(int base); static int sg_pci_poll_sub3(int num, int count, int base); static void sg_pci_button_init(int num); /* grobal */ static unsigned long PowerVR_Physical_Address; static unsigned long PowerVR_Linear_Address; static int PowerVR_Linear_Selector; JOYSTICK_DRIVER joystick_sg2 = { JOY_TYPE_IFSEGA_PCI, NULL, NULL, "IF-SEGA2/PCI", _sg_pci_init, _sg_pci_exit, sg_pci_poll1, NULL, NULL, NULL, NULL }; /* _sg_pci_init: * Initialises the driver. */ int _sg_pci_init(void) { static char *name_b[] = { "A", "B", "C", "X", "Y", "Z", "L", "R", "Start" }; int i, j; __dpmi_regs r; num_joysticks = 4; PowerVR_Physical_Address = 0; PowerVR_Linear_Address = 0; PowerVR_Linear_Selector = 0; r.d.eax = 0x0000b101; /* PCI BIOS - INSTALLATION CHECK */ r.d.edi = 0x00000000; __dpmi_int(0x1a, &r); if (r.d.edx != 0x20494350) { /* ' ICP' */ ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("PCI BIOS not installed")); return -1; } r.d.eax = 0x0000b102; /* PCI BIOS - FIND PCI DEVICE */ r.d.ecx = 0x00000046; /* device ID */ r.d.edx = 0x00001033; /* vendor ID */ r.d.esi = 0x00000000; /* device index */ __dpmi_int(0x1a, &r); if (r.h.ah != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("IF-SEGA2/PCI: device not found")); return -1; } r.d.eax = 0x0000b10a; /* READ CONFIGURATION DWORD */ /* BH = bus number */ /* BL = device/function number */ r.d.edi = 0x00000010; /* register number */ __dpmi_int(0x1a, &r); if (r.h.ah != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("IF-SEGA2/PCI: read configuration dword error")); return -1; } PowerVR_Physical_Address = r.d.ecx & 0xffff0000; if (_create_linear_mapping(&PowerVR_Linear_Address, PowerVR_Physical_Address, 0x10000) != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("IF-SEGA2/PCI: _create_linear_mapping error")); return -1; } if (_create_selector(&PowerVR_Linear_Selector, PowerVR_Linear_Address, 0x10000) != 0) { _remove_linear_mapping(&PowerVR_Linear_Address); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("IF-SEGA2/PCI: _create_selector error")); return -1; } for (i = 0; i < num_joysticks; i++) { joy[i].flags = JOYFLAG_ANALOGUE; joy[i].num_sticks = 2; for (j = 0; j < 2; j++) { joy[i].stick[j].flags = JOYFLAG_ANALOGUE | JOYFLAG_SIGNED; joy[i].stick[j].num_axis = 2; joy[i].stick[j].axis[0].name = get_config_text("X"); joy[i].stick[j].axis[1].name = get_config_text("Y"); joy[i].stick[j].name = get_config_text("Pad"); } joy[i].num_buttons = 9; for (j = 0; j < 9; j++) { joy[i].button[j].name = get_config_text(name_b[j]); } } return 0; } /* _sg_pci_exit: * Shuts down the driver. */ void _sg_pci_exit(void) { _remove_linear_mapping(&PowerVR_Linear_Address); _remove_selector(&PowerVR_Linear_Selector); } /* sg_pci_poll: * Common - Updates the joystick status variables. */ static int sg_pci_poll(void) { int num = 0; num = sg_pci_poll_sub(num, 0x000); /* IFSEGA 1P */ if (num < num_joysticks) num = sg_pci_poll_sub(num, 0x200); /* IFSEGA 2P */ while (num < num_joysticks) { sg_pci_button_init(num); num++; } return 0; } static int sg_pci_poll_sub(int num, int base) { int i; int j; int a; int b; int num1; int result; i = 0x40; result = 0; _sg_pci_ioout(base, 0x1f); do { _sg_pci_ioout(base + 0x100, 0x60); a = _sg_pci_ioin(base + 0x100); if ((a & 0x07) == 0x01 || (a & 0x07) == 0x04) break; } while (i--); if (a & 0x0c) result |= 0x08; if (a & 0x03) result |= 0x04; _sg_pci_ioout(base + 0x100, 0x20); a = _sg_pci_ioin(base + 0x100); if (a & 0x0c) result |= 0x02; if (a & 0x03) result |= 0x01; switch (result) { case 0x0b: /* Normal Pad , Twin Stick , etc.. */ /*outportb(base,0x1f); */ /*outportb(base+2,0xe0); */ /*a = inportb(base+2); // L 1 0 0 */ _sg_pci_ioout(base, 0x1f); _sg_pci_ioout(base + 0x100, 0xe0); a = _sg_pci_ioin(base + 0x100); joy[num].button[6].b = !(a & 0x08); /*outportb(base+2,0x80); */ /*a = inportb(base+2); // R X Y Z */ _sg_pci_ioout(base + 0x100, 0x80); a = _sg_pci_ioin(base + 0x100); joy[num].button[7].b = !(a & 0x08); joy[num].button[3].b = !(a & 0x04); joy[num].button[4].b = !(a & 0x02); joy[num].button[5].b = !(a & 0x01); /*outportb(base+2,0xc0); // Start A C B */ /*a = inportb(base+2); */ _sg_pci_ioout(base + 0x100, 0xc0); a = _sg_pci_ioin(base + 0x100); joy[num].button[8].b = !(a & 0x08); joy[num].button[0].b = !(a & 0x04); joy[num].button[2].b = !(a & 0x02); joy[num].button[1].b = !(a & 0x01); /*outportb(base+2,0xa0); */ /*a = inportb(base+2); // axis R L D U */ _sg_pci_ioout(base + 0x100, 0xa0); a = _sg_pci_ioin(base + 0x100); joy[num].stick[0].axis[0].d1 = !(a & 0x04); joy[num].stick[0].axis[0].d2 = !(a & 0x08); joy[num].stick[0].axis[1].d1 = !(a & 0x01); joy[num].stick[0].axis[1].d2 = !(a & 0x02); for (j = 0; j <= 1; j++) { if (joy[num].stick[0].axis[j].d1) joy[num].stick[0].axis[j].pos = -128; else { if (joy[num].stick[0].axis[j].d2) joy[num].stick[0].axis[j].pos = 128; else joy[num].stick[0].axis[j].pos = 0; } } joy[num].stick[1].axis[0].d1 = 0; joy[num].stick[1].axis[0].d2 = 0; joy[num].stick[1].axis[1].d1 = 0; joy[num].stick[1].axis[1].d2 = 0; joy[num].stick[1].axis[0].pos = 0; joy[num].stick[1].axis[1].pos = 0; num++; break; case 0x05: switch (sg_pci_poll_sub2(base)) { case 0x00: /* Multi Controller , Racing Controller , etc.. */ case 0x01: sg_pci_poll_sub3(num, sg_pci_poll_sub2(base) * 2, base); num++; break; case 0x04: /* Multi-Terminal 6 */ sg_pci_poll_sub2(base); sg_pci_poll_sub2(base); sg_pci_poll_sub2(base); num1 = num; i = 6 + 1; while (num < num_joysticks) { sg_pci_button_init(num); if (!(--i)) break; a = sg_pci_poll_sub2(base); b = sg_pci_poll_sub2(base) * 2; if (a == 0x0f) continue; /* no pad */ if ((a == 0x0e) && (b == 6)) { sg_pci_poll_sub2(base); /* Shuttle Mouse */ sg_pci_poll_sub2(base); sg_pci_poll_sub2(base); sg_pci_poll_sub2(base); sg_pci_poll_sub2(base); sg_pci_poll_sub2(base); continue; } sg_pci_poll_sub3(num, b, base); num++; } if (num == num1) num++; break; default: sg_pci_button_init(num); } break; case 0x03: /* Shuttle Mouse */ default: sg_pci_button_init(num); num++; } /*outportb(base+2,0x60); */ _sg_pci_ioout(base + 0x100, 0x60); return num; } static int sg_pci_poll_sub2(int base) { int i = 0x100; int a; int b; /*a = inportb(base+2); */ /*outportb(base+2, a^0x20); */ a = _sg_pci_ioin(base + 0x100); _sg_pci_ioout(base + 0x100, a ^ 0x20); do { /*b = inportb(base+2); */ b = _sg_pci_ioin(base + 0x100); if ((a & 0x10) != (b & 0x10)) break; } while (i--); return (b & 0x0f); } static int sg_pci_poll_sub3(int num, int count, int base) { int i; int a; a = sg_pci_poll_sub2(base); /* axis R L D U (digital) */ joy[num].stick[0].axis[0].d1 = !(a & 0x04); joy[num].stick[0].axis[0].d2 = !(a & 0x08); joy[num].stick[0].axis[1].d1 = !(a & 0x01); joy[num].stick[0].axis[1].d2 = !(a & 0x02); a = sg_pci_poll_sub2(base); /* Start A C B */ joy[num].button[8].b = !(a & 0x08); joy[num].button[0].b = !(a & 0x04); joy[num].button[2].b = !(a & 0x02); joy[num].button[1].b = !(a & 0x01); a = sg_pci_poll_sub2(base); /* R X T Z */ joy[num].button[7].b = !(a & 0x08); joy[num].button[3].b = !(a & 0x04); joy[num].button[4].b = !(a & 0x02); joy[num].button[5].b = !(a & 0x01); a = sg_pci_poll_sub2(base); /* L */ joy[num].button[6].b = !(a & 0x08); joy[num].stick[1].axis[0].d1 = 0; joy[num].stick[1].axis[0].d2 = 0; joy[num].stick[1].axis[1].d1 = 0; joy[num].stick[1].axis[1].d2 = 0; joy[num].stick[1].axis[0].pos = 0; joy[num].stick[1].axis[1].pos = 0; if (count -= 4) joy[num].stick[0].axis[0].pos = ((sg_pci_poll_sub2(base) << 4) | sg_pci_poll_sub2(base)) - 128; else { for (i = 0; i <= 1; i++) { if (joy[num].stick[0].axis[i].d1) joy[num].stick[0].axis[i].pos = -128; else { if (joy[num].stick[0].axis[i].d2) joy[num].stick[0].axis[i].pos = 128; else joy[num].stick[0].axis[i].pos = 0; } } return 0; } if (count -= 2) joy[num].stick[0].axis[1].pos = ((sg_pci_poll_sub2(base) << 4) | sg_pci_poll_sub2(base)) - 128; else { if (joy[num].stick[0].axis[1].d1) joy[num].stick[0].axis[1].pos = -128; else { if (joy[num].stick[0].axis[1].d2) joy[num].stick[0].axis[1].pos = 128; else joy[num].stick[0].axis[1].pos = 0; } return 0; } if (count -= 2) joy[num].stick[1].axis[0].pos = ((sg_pci_poll_sub2(base) << 4) | sg_pci_poll_sub2(base)) - 128; else return 0; if (count -= 2) joy[num].stick[1].axis[1].pos = ((sg_pci_poll_sub2(base) << 4) | sg_pci_poll_sub2(base)) - 128; return 0; } static void sg_pci_button_init(int num) { int i; for (i = 0; i < 9; i++) { joy[num].button[i].b = 0; } for (i = 0; i <= 1; i++) { joy[num].stick[i].axis[0].d1 = 0; joy[num].stick[i].axis[0].d2 = 0; joy[num].stick[i].axis[1].d1 = 0; joy[num].stick[i].axis[1].d2 = 0; joy[num].stick[i].axis[0].pos = 0; joy[num].stick[i].axis[1].pos = 0; } } /* sg_pci_poll1: * 1P - Updates the joystick status variables. */ static int sg_pci_poll1(void) { return sg_pci_poll(); } /* offset 0x0000 0x0100 0x0200 0x0300 data 0x00?? */ unsigned long _sg_pci_ioin(unsigned long offset) { unsigned long in_data; unsigned long data; unsigned long data2; data2 = 0xff00b000 | offset; data = 0x00004000 | data2; _farsetsel(PowerVR_Linear_Selector); _farnspokel(0x0058, data); _farnspokel(0x0058, data2); in_data = _farnspeekl(0x0058); _farnspokel(0x0058, data); in_data &= 0xff; return (in_data); } /* offset 0x0000 0x0100 0x0200 0x0300 data 0x00?? */ void _sg_pci_ioout(unsigned long offset, unsigned long data) { unsigned long data2; data2 = 0xffff7000 | offset | data; data = 0x00008000 | data2; _farsetsel(PowerVR_Linear_Selector); _farnspokel(0x0058, data); _farnspokel(0x0058, data2); _farnspokel(0x0058, data); }