pad.cpp

00001 /*    
00002         This file is part of ps2padlib.
00003 
00004         Copyright 2003, Alex Mole
00005 
00006     ps2padlib is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     ps2padlib is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with ps2padlib; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 */
00020 
00021 #include "pad.h"
00022 
00023 #include <stdlib.h>
00024 #include <fcntl.h>
00025 #include <unistd.h>
00026 #include <sys/ioctl.h>
00027 #include <math.h>
00028 #include <linux/ps2/dev.h>
00029 #include <memory.h>
00030 
00031 //#include <stdio.h>
00032 
00033 //the analogue sticks don't centre to zero- only to a relatively small range.
00034 //values smaller than DRIFT_TOLERANCE are treated as zero
00035 #define DRIFT_TOLERANCE         30
00036 
00037 
00038 padinfo_t pad[2];
00039 
00040 //the pad devices
00041 static const char *devices[2] = { PS2_DEV_PAD0, PS2_DEV_PAD1 };
00042 
00043 static int fd[2] = {-1,-1};
00044 static int flags[2] = { 0, 0 };
00045 
00046 
00047 typedef unsigned char u8;
00048 typedef signed char s8;
00049 typedef unsigned short u16;
00050 #define PACKED  __attribute__((packed))
00051 
00052 struct digital_data
00053 {
00054         u8      unknown0                        PACKED;
00055         u8      flags           : 4             PACKED;
00056         u8      type            : 4             PACKED;
00057         u16     buttons                         PACKED;
00058 } __attribute__((aligned(2)));
00059 
00060 struct dualshock2_data
00061 {
00062         u8      unknown0                        PACKED;
00063         u8      flags           : 4             PACKED;
00064         u8      type            : 4             PACKED;
00065         u16     buttons                         PACKED;
00066         u8      rx                                      PACKED;
00067         u8      ry                                      PACKED;
00068         u8      lx                                      PACKED;
00069         u8      ly                                      PACKED;
00070         u8      pright                          PACKED;
00071         u8      pleft                           PACKED;
00072         u8      pup                                     PACKED;
00073         u8      pdown                           PACKED;
00074         u8      ptri                            PACKED;
00075         u8      pcircle                         PACKED;
00076         u8      pcross                          PACKED;
00077         u8      psquare                         PACKED;
00078         u8      pl1                                     PACKED;
00079         u8      pr1                                     PACKED;
00080         u8      pl2                                     PACKED;
00081         u8      pr2                                     PACKED;
00082 } __attribute__((aligned(2)));
00083 
00084 union pad_data 
00085 {
00086         u8 buf[PS2PAD_DATASIZE];
00087         struct digital_data dig;
00088         struct dualshock2_data ds2;
00089 };
00090 
00091 
00092 static int getstat (int padnum)
00093 {
00094         int res;
00095         ioctl (fd[padnum], PS2PAD_IOCGETSTAT, &res);
00096         return res;
00097 }
00098 
00099 static int wait_stat_not_busy (int padnum)
00100 {
00101         int res;
00102         while ((res=getstat(padnum)) == PS2PAD_STAT_BUSY) {}
00103         return res;
00104 }
00105 
00106 
00107 static int actuator_supported (int padnum)
00108 {
00109         struct ps2pad_actinfo act_info;
00110 
00111         act_info.actno = -1;
00112         act_info.term = 0;
00113         act_info.result = 0;
00114         ioctl(fd[padnum], PS2PAD_IOCACTINFO, &act_info);
00115 
00116         return (act_info.result == 2);
00117 }
00118 
00119 
00120 static void enable_actuator(int padnum, int enable_small, int enable_big)
00121 {
00122         struct ps2pad_act act;
00123         
00124         act.len = 6;
00125         memset(act.data, -1, sizeof(act.data));
00126 
00127         if (enable_small && enable_big)
00128         {
00129                 act.data[0] = 0;
00130                 act.data[1] = 1;
00131         }
00132         else if (enable_small)
00133         {
00134                 act.data[0] = 0;
00135         }
00136         else if (enable_big)
00137         {
00138                 act.data[1] = 0;
00139         }
00140 
00141         ioctl(fd[padnum], PS2PAD_IOCSETACTALIGN, &act);
00142 }
00143 
00144 static void set_actuator(int padnum, unsigned char small_intensity, unsigned char big_intensity)
00145 {
00146         struct ps2pad_act act;
00147         
00148         act.len = 6;
00149         memset(act.data, -1, sizeof(act.data));
00150 
00151         if (small_intensity > 1)
00152                 small_intensity = 1;
00153 
00154         act.data[0] = small_intensity;  //Small shaker
00155         act.data[1] = big_intensity;    //Big shaker
00156         
00157         ioctl(fd[padnum], PS2PAD_IOCSETACT, &act);
00158 }
00159 
00160 
00161 
00162 static int setmode (int padnum, int mode, int lock)
00163 {
00164         struct ps2pad_mode pmode;
00165         pmode.offs = mode;
00166         pmode.lock = lock?3:2;
00167         return (ioctl (fd[padnum], PS2PAD_IOCSETMODE, &pmode) == 0);
00168 }
00169 
00170 
00171 static int pressure_supported (int padnum)
00172 {
00173         int pressmode;
00174         ioctl (fd[padnum], PS2PAD_IOCPRESSMODEINFO, &pressmode);
00175         return (pressmode == 1);
00176 }
00177 
00178 static int enterpressmode (int padnum)
00179 {
00180         return (ioctl (fd[padnum], PS2PAD_IOCENTERPRESSMODE) == 0);
00181 }
00182 
00183 static int exitpressmode (int padnum)
00184 {
00185         return (ioctl (fd[padnum], PS2PAD_IOCEXITPRESSMODE) == 0);
00186 }
00187                 
00188 
00189 static int init (int padnum, int initflags)
00190 {
00191         int mode, lock;
00192         int stat;       
00193 
00194         flags[padnum] = initflags;
00195         
00196         fd[padnum] = open (devices[padnum], O_RDONLY);
00197         if (fd[padnum] < 0) return 0;
00198 
00199         while ((stat = getstat(padnum)) == PS2PAD_STAT_BUSY) {}
00200         if (stat != PS2PAD_STAT_READY)
00201         {
00202                 //something went wrong...
00203                 close (fd[padnum]);
00204                 fd[padnum] = -1;
00205                 return 0;
00206         }
00207         
00208         mode = (initflags & PAD_INIT_ANALOGUE) ? 1 : 0;
00209         lock = (initflags & PAD_INIT_LOCK) ? 1 : 0;     
00210         if (!setmode (padnum, mode, lock))
00211         {
00212                 close (fd[padnum]);
00213                 fd[padnum] = -1;
00214                 return 0;
00215         }
00216         wait_stat_not_busy (padnum);
00217 
00218         if ((initflags & PAD_INIT_ANALOGUE) &&
00219                         (initflags & PAD_INIT_PRESSURE) &&
00220                          pressure_supported (padnum))
00221         {
00222                 if (!enterpressmode (padnum))
00223                 {
00224                         setmode (padnum, 0, 0);
00225                         close (fd[padnum]);
00226                         fd[padnum] = -1;
00227                         return 0;
00228                 }
00229                 
00230                 wait_stat_not_busy (padnum);
00231         }
00232                         
00233         //initialise the structure to zero
00234         memset (&pad[padnum], 0, sizeof(padinfo_t));
00235         
00236         //store initflags in pad data structure 
00237         pad[padnum].initflags = initflags;
00238         
00239         //set the actuator info in pad structure
00240         pad[padnum].actuator = actuator_supported (padnum);
00241 
00242         
00243         return 1;
00244 }
00245 
00246 
00247 int pad_init (int pads, int initflags)
00248 {
00249         if ((pads & PAD_0) && !init (0, initflags))
00250                 return 0;
00251         if ((pads & PAD_1) && !init (1, initflags))
00252                 return 0;
00253 
00254         return 1;
00255 }
00256 
00257 
00258 static float axis_to_float (int axisval)
00259 {
00260         if (abs(axisval-127) < DRIFT_TOLERANCE)
00261                 return 0.0f;
00262         return (((float)axisval) - 127.5f) * (1.0f / 127.5f);
00263 }
00264 
00265 static float press_to_float (int pressureval)
00266 {
00267         return ((float)pressureval) * (1.0f / 255.0f);
00268 }
00269 
00270 
00271 static void update (int padnum)
00272 {
00273         union pad_data data;
00274         int n;
00275         int changed, last;
00276         int status;
00277         
00278         //ignore requests for unopened pads
00279         if (fd[padnum] < 0)
00280                 return;
00281 
00282         //read the status
00283         do {
00284                 status = getstat (padnum);
00285         } while (status == PS2PAD_STAT_BUSY);
00286 
00287         n = read (fd[padnum], data.buf, sizeof(data));
00288         if (n <= 0)
00289                 return;
00290         
00291         //update the buttons
00292         last = pad[padnum].buttons;
00293         //buttons are inverted!
00294         pad[padnum].buttons = ~data.dig.buttons;
00295         changed = last ^ ~data.dig.buttons;
00296         pad[padnum].pressed = pad[padnum].buttons & changed;
00297         pad[padnum].released = last & changed;
00298 
00299         if (flags[padnum] & PAD_INIT_ANALOGUE)
00300         {
00301                 //update the analogue sticks
00302                 pad[padnum].axes[PAD_AXIS_LX] = axis_to_float (data.ds2.lx);
00303                 pad[padnum].axes[PAD_AXIS_LY] = axis_to_float (data.ds2.ly);
00304                 pad[padnum].axes[PAD_AXIS_RX] = axis_to_float (data.ds2.rx);
00305                 pad[padnum].axes[PAD_AXIS_RY] = axis_to_float (data.ds2.ry);
00306 
00307                 if (flags[padnum] & PAD_INIT_PRESSURE)
00308                 {
00309                         //update the button pressures
00310                         pad[padnum].pressures[PAD_PCROSS] = press_to_float (data.ds2.pcross);
00311                         pad[padnum].pressures[PAD_PTRI] = press_to_float (data.ds2.ptri);
00312                         pad[padnum].pressures[PAD_PCIRCLE] = press_to_float (data.ds2.pcircle);
00313                         pad[padnum].pressures[PAD_PSQUARE] = press_to_float (data.ds2.psquare);
00314                         pad[padnum].pressures[PAD_PUP] = press_to_float (data.ds2.pup);
00315                         pad[padnum].pressures[PAD_PDOWN] = press_to_float (data.ds2.pdown);
00316                         pad[padnum].pressures[PAD_PLEFT] = press_to_float (data.ds2.pleft);
00317                         pad[padnum].pressures[PAD_PRIGHT] = press_to_float (data.ds2.pright);
00318                         pad[padnum].pressures[PAD_PR1] = press_to_float (data.ds2.pr1);
00319                         pad[padnum].pressures[PAD_PR2] = press_to_float (data.ds2.pr2);
00320                         pad[padnum].pressures[PAD_PL1] = press_to_float (data.ds2.pl1);
00321                         pad[padnum].pressures[PAD_PL2] = press_to_float (data.ds2.pl2);
00322                 }
00323         }
00324 }
00325 
00326 void pad_update (int pads)
00327 {
00328         if (pads & PAD_0) update (0);
00329         if (pads & PAD_1) update (1);
00330 }
00331 
00332 
00333 static void cleanup (int padnum)
00334 {
00335         if (flags[padnum] & PAD_INIT_PRESSURE)
00336                 exitpressmode (padnum);
00337         setmode (padnum, 0, 0);
00338         wait_stat_not_busy (padnum);
00339         close (fd[padnum]);
00340         fd[padnum] = -1;
00341 }
00342 
00343 void pad_cleanup (int pads)
00344 {
00345         if (pads & PAD_0) cleanup (0);
00346         if (pads & PAD_1) cleanup (1);
00347 }
00348 
00349 

Generated on Sun May 18 21:45:08 2008 for PS2X by  doxygen 1.5.4