text: /*         ______   ___    ___ 
   *        /\  _  \ /\_ \  /\_ \ 
   *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
   *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
   *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
   *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
   *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
   *                                           /\____/
   *                                           \_/__/
   *
   *      Joystick driver for the Gravis GamePad Pro.
   *
   *      By Marius Fodor, using information provided by Benji York.
   *
   *      See readme.txt for copyright information.
   */
  
  
  #include "allegro.h"
  #include "allegro/internal/aintern.h"
  #include "allegro/platform/aintdos.h"
  
  #ifndef ALLEGRO_DOS
     #error something is wrong with the makefile
  #endif
  
  
  
  /* driver functions */
  static int gpro_init(void); 
  static void gpro_exit(void); 
  static int gpro_poll(void);
  
  
  
  JOYSTICK_DRIVER joystick_gpro =
  {
     JOY_TYPE_GAMEPAD_PRO,
     empty_string,
     empty_string,
     "GamePad Pro",
     gpro_init,
     gpro_exit,
     gpro_poll,
     NULL, NULL,
     NULL, NULL
  };
  
  
  
  /* int read_gpp:
   *  Reads the GamePad Pro pointed to by pad_num (0 or 1) and returns its 
   *  status. Returns 1 if the GPP returned corrupt data, or if no GPP was 
   *  detected.
   *
   *  This code was converted from asm into C by Shawn Hargreaves, who didn't
   *  really understand the original, so any errors are very probable :-)
   */
  static int read_gpp(int pad_num)
  {
     int samples[50];
     int clock_mask, data_mask, data, old_data;
     int num_samples, timeout1, timeout2, sample_pos, c;
  
     if (pad_num == 0) {
        clock_mask = 0x10;
        data_mask = 0x20;
     }
     else {
        clock_mask = 0x40;
        data_mask = 0x80;
     }
  
     num_samples = 0;
     timeout1 = 0;
  
     DISABLE();
  
     old_data = inportb(0x201);
     data = 0;
  
     while (num_samples<50) {
        for (timeout2=0; timeout2<255; timeout2++) {
  	 data = inportb(0x201);
  	 if (data != old_data)
  	    break;
        }
  
        if (timeout2 == 255) {
  	 ENABLE();
  	 return 1;
        }
  
        if ((old_data & clock_mask) && (!(data & clock_mask))) {
  	 samples[num_samples] = (data & data_mask) ? 1 : 0;
  	 num_samples++;
        }
  
        old_data = data;
  
        if (timeout1++ == 200)
  	 break;
     }
  
     ENABLE();
  
     c = 0;
  
     for (sample_pos=1; sample_pos<num_samples; sample_pos++) {
        if (samples[sample_pos])
  	 c++;
        else
  	 c = 0;
  
        if (c == 5)
  	 break;
     };
  
     if (c != 5)
        return 1;
  
     sample_pos++;
     data = 0;
  
     for (c=0; c<14; c++) {
        if ((c&3) == 0)
  	 sample_pos++;
        data |= samples[sample_pos];
        data <<= 1;
        sample_pos++;
     }
  
     return data;
  }
  
  
  
  /* gpro_init:
   *  Initialises the driver.
   */
  static int gpro_init(void)
  {
     int i;
  
     if (read_gpp(0) == 1)
        return -1;
  
     if (read_gpp(1) == 1)
        num_joysticks = 1;
     else
        num_joysticks = 2;
  
     for (i=0; i<num_joysticks; i++) {
        joy[i].flags = JOYFLAG_DIGITAL;
  
        joy[i].num_sticks = 1;
        joy[i].stick[0].flags = JOYFLAG_DIGITAL | JOYFLAG_SIGNED;
        joy[i].stick[0].num_axis = 2;
        joy[i].stick[0].axis[0].name = get_config_text("X");
        joy[i].stick[0].axis[1].name = get_config_text("Y");
        joy[i].stick[0].name = get_config_text("Pad");
  
        joy[i].num_buttons = 10;
  
        joy[i].button[0].name = get_config_text("Red");
        joy[i].button[1].name = get_config_text("Yellow");
        joy[i].button[2].name = get_config_text("Green");
        joy[i].button[3].name = get_config_text("Blue");
        joy[i].button[4].name = get_config_text("L1");
        joy[i].button[5].name = get_config_text("R1");
        joy[i].button[6].name = get_config_text("L2");
        joy[i].button[7].name = get_config_text("R2");
        joy[i].button[8].name = get_config_text("Select");
        joy[i].button[9].name = get_config_text("Start");
     }
  
     return 0;
  }
  
  
  
  /* gpro_exit:
   *  Shuts down the driver.
   */
  static void gpro_exit(void)
  {
  }
  
  
  
  /* gpro_poll:
   *  Updates the joystick status variables.
   */
  static int gpro_poll(void)
  {
     int i, b, gpp, mask;
  
     for (i=0; i<num_joysticks; i++) {
        gpp = read_gpp(i);
  
        if (gpp == 1)
  	 return -1;
  
        joy[i].stick[0].axis[0].d1 = ((gpp & 0x02) != 0);
        joy[i].stick[0].axis[0].d2 = ((gpp & 0x04) != 0);
        joy[i].stick[0].axis[1].d1 = ((gpp & 0x10) != 0);
        joy[i].stick[0].axis[1].d2 = ((gpp & 0x08) != 0);
  
        for (b=0; b<2; b++) {
  	 if (joy[i].stick[0].axis[b].d1)
  	    joy[i].stick[0].axis[b].pos = -128;
  	 else if (joy[i].stick[0].axis[b].d2)
  	    joy[i].stick[0].axis[b].pos = 128;
  	 else
  	    joy[i].stick[0].axis[b].pos = 0;
        }
  
        mask = 0x20;
  
        for (b=0; b<10; b++) {
  	 joy[i].button[b].b = ((gpp & mask) != 0);
  	 mask <<= 1;
        }
     }
  
     return 0;
  }
  
  
  