/ src / rtapi / uspace_rtapi_parport.cc
uspace_rtapi_parport.cc
  1  //    Copyright 2014 Jeff Epler
  2  //
  3  //    This program is free software; you can redistribute it and/or modify
  4  //    it under the terms of the GNU General Public License as published by
  5  //    the Free Software Foundation; either version 2 of the License, or
  6  //    (at your option) any later version.
  7  //
  8  //    This program is distributed in the hope that it will be useful,
  9  //    but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  //    GNU General Public License for more details.
 12  //
 13  //    You should have received a copy of the GNU General Public License
 14  //    along with this program; if not, write to the Free Software
 15  //    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 16  #include <errno.h>
 17  #include <fcntl.h>
 18  #include <linux/ppdev.h>
 19  #include <map>
 20  #include <rtapi.h>
 21  #include <rtapi_parport.h>
 22  #include "rtapi_uspace.hh"
 23  #include <stdio.h>
 24  #include <string.h>
 25  #include <sys/ioctl.h>
 26  #include <sys/stat.h>
 27  #include <sys/types.h>
 28  
 29  struct portinfo {
 30      int port_id;
 31      unsigned short base;
 32      unsigned short base_hi;
 33  };
 34  
 35  typedef std::map<unsigned short, portinfo> ParportMap;
 36  
 37  static ParportMap parports;
 38  
 39  static void map_parports() {
 40      for(int i=0; i<16; i++) {
 41          const char path_template[] = "/proc/sys/dev/parport/parport%d/base-addr";
 42          char path[sizeof(path_template)]; // noting that we stop before 100, so it'll fit
 43          snprintf(path, sizeof(path), path_template, i);
 44  
 45          FILE *f = fopen(path, "r");
 46          if(!f) {
 47              if(errno != ENOENT)
 48                  rtapi_print_msg(RTAPI_MSG_ERR, "fopen(%s): %s\n", path, strerror(errno));
 49              continue;
 50          }
 51          struct portinfo pi;
 52          pi.port_id = i;
 53          if(fscanf(f, "%hd %hd", &pi.base, &pi.base_hi) != 2) {
 54              rtapi_print_msg(RTAPI_MSG_ERR, "Failed to parse base-addr for port #%d\n", i);
 55              fclose(f);
 56              continue;
 57          }
 58          fclose(f);
 59  
 60          parports[i] = pi;
 61          parports[pi.base] = pi;
 62      }
 63  }
 64  
 65  int rtapi_parport_get(const char *mod_name, rtapi_parport_t *port, unsigned short base, unsigned short base_hi, unsigned int modes) {
 66      WITH_ROOT;
 67  
 68      memset(port, 0, sizeof(*port));
 69      port->fd = -1;
 70  
 71      if(parports.empty()) map_parports();
 72      ParportMap::iterator pi = parports.find(base);
 73      if(pi == parports.end()) {
 74          rtapi_print_msg(RTAPI_MSG_ERR, "Linux parallel port %c%d not found\n", base < 16 ? '#' : '@', base);
 75          if(base < 16)
 76              return -ENOENT;
 77          port->base = base;
 78          port->base_hi = base_hi;
 79          return 0;
 80      } else {
 81          port->base = pi->second.base;
 82          port->base_hi = pi->second.base_hi;
 83          const char port_template[] = "/dev/parport%d";
 84  
 85          char port_path[sizeof(port_template)];
 86          snprintf(port_path, sizeof(port_path), port_template, pi->second.port_id);
 87          port->fd = open(port_path, O_RDWR);
 88  
 89          if(port->fd < 0) {
 90              rtapi_print_msg(RTAPI_MSG_ERR, "open(%s): %s\n", port_path, strerror(errno));
 91              return -errno;
 92          }
 93  
 94          if(ioctl(port->fd, PPCLAIM) < 0) {
 95              rtapi_print_msg(RTAPI_MSG_ERR, "ioctl(%s, PPCLAIM): %s\n", port_path, strerror(errno));
 96              close(port->fd);
 97              port->fd = -1;
 98              return -errno;
 99          }
100  
101          int ppmodes = ~0;
102  
103          if(ioctl(port->fd, PPGETMODES, &modes) < 0) {
104              rtapi_print_msg(RTAPI_MSG_WARN, "ioctl(%s, PPGETMODES): %s\n", port_path, strerror(errno));
105          }
106  
107          if((modes & ppmodes) != modes)
108          {
109              rtapi_print_msg(RTAPI_MSG_WARN,
110                  "PARPORT: linux parport %s does not support mode %x.\n"
111                  "PARPORT: continuing anyway.\n",
112                  port_path, modes);
113          }
114  
115      }
116      return 0;
117  }
118  
119  void rtapi_parport_release(rtapi_parport_t *port) {
120      close(port->fd);
121      port->fd = -1;
122  }