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 }