/ src / rtapi / rtapi_parport.h
rtapi_parport.h
  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  #ifndef RTAPI_PARPORT_H
 17  #define RTAPI_PARPORT_H
 18  
 19  #include <rtapi.h>
 20  #include <rtapi_io.h>
 21  #include <linux/parport.h>
 22  
 23  #define RTAPI_PARPORT_DATA_PORT(t) (t->base + 0)
 24  #define RTAPI_PARPORT_STATUS_PORT(t) (t->base + 1)
 25  #define RTAPI_PARPORT_CONTROL_PORT(t) (t->base + 2)
 26  #define RTAPI_PARPORT_EPP_ADDR_PORT(t) (t->base + 3)
 27  #define RTAPI_PARPORT_EPP_DATA_PORT(t) (t->base + 4)
 28  #define RTAPI_PARPORT_ECR_PORT(t) (t->base_hi + 2)
 29  
 30  typedef struct rtapi_parport_t
 31  {
 32      unsigned short base;
 33      unsigned short base_hi;
 34  #ifdef __KERNEL__
 35      struct pardevice *linux_dev;
 36      void *region;
 37      void *region_hi;
 38  #else
 39      int fd;
 40  #endif
 41  } rtapi_parport_t;
 42  
 43  RTAPI_BEGIN_DECLS
 44  
 45  static inline int rtapi_parport_data_read(rtapi_parport_t *t) {
 46      return rtapi_inb(RTAPI_PARPORT_DATA_PORT(t));
 47  }
 48  
 49  static inline int rtapi_parport_control_read(rtapi_parport_t *t) {
 50      return rtapi_inb(RTAPI_PARPORT_CONTROL_PORT(t));
 51  }
 52  
 53  static inline int rtapi_parport_status_read(rtapi_parport_t *t) {
 54      return rtapi_inb(RTAPI_PARPORT_STATUS_PORT(t));
 55  }
 56  
 57  static inline unsigned char rtapi_parport_epp_data_readb(rtapi_parport_t *t) {
 58      return rtapi_inb(RTAPI_PARPORT_EPP_DATA_PORT(t));
 59  }
 60  
 61  static inline unsigned long rtapi_parport_epp_data_readl(rtapi_parport_t *t) {
 62      return rtapi_inl(RTAPI_PARPORT_EPP_DATA_PORT(t));
 63  }
 64  
 65  static inline unsigned long rtapi_parport_ecr_read(rtapi_parport_t *t) {
 66      return rtapi_inb(RTAPI_PARPORT_ECR_PORT(t));
 67  }
 68  
 69  
 70  static inline void rtapi_parport_data_write(rtapi_parport_t *t, unsigned char v) {
 71      rtapi_outb(v, RTAPI_PARPORT_DATA_PORT(t));
 72  }
 73  
 74  static inline void rtapi_parport_control_write(rtapi_parport_t *t, unsigned char v) {
 75      rtapi_outb(v, RTAPI_PARPORT_CONTROL_PORT(t));
 76  }
 77  
 78  static inline void rtapi_parport_status_write(rtapi_parport_t *t, unsigned char v) {
 79      rtapi_outb(v, RTAPI_PARPORT_STATUS_PORT(t));
 80  }
 81  
 82  static inline void rtapi_parport_epp_addr_write(rtapi_parport_t *t, unsigned char v) {
 83      rtapi_outb(v, RTAPI_PARPORT_EPP_ADDR_PORT(t));
 84  }
 85  
 86  static inline void rtapi_parport_epp_data_writeb(rtapi_parport_t *t, unsigned char v) {
 87      rtapi_outb(v, RTAPI_PARPORT_EPP_DATA_PORT(t));
 88  }
 89  
 90  static inline void rtapi_parport_epp_data_writel(rtapi_parport_t *t, unsigned long v) {
 91      rtapi_outl(v, RTAPI_PARPORT_EPP_DATA_PORT(t));
 92  }
 93  
 94  static inline void rtapi_parport_ecr_write(rtapi_parport_t *t, unsigned char v) {
 95      rtapi_outb(v, RTAPI_PARPORT_EPP_ADDR_PORT(t));
 96  }
 97  
 98  #ifdef __KERNEL__
 99  static int
100  rtapi_parport_get(const char *name, rtapi_parport_t *port,
101          unsigned short base, unsigned short base_hi, unsigned int modes)
102  {
103      int retval = 0;
104      struct parport *linux_port = 0;
105      memset(port, 0, sizeof(rtapi_parport_t));
106  
107      // I/O addresses 1..16 are assumed to be linux parport numbers
108      if(base < 16) {
109          linux_port = parport_find_number(base);
110          if(!linux_port)
111          {
112              rtapi_print_msg(RTAPI_MSG_ERR,
113                      "PARPORT: ERROR: linux parport %d not found\n",
114                      base);
115              return -ENODEV;
116          }
117      } else {
118          linux_port = parport_find_base(base);
119      }
120  
121      if(linux_port)
122      {
123          if((modes & linux_port->modes) != modes)
124          {
125              rtapi_print_msg(RTAPI_MSG_WARN,
126                  "PARPORT: linux parport %s does not support mode %x.\n"
127                  "PARPORT: continuing anyway.\n",
128                  linux_port->name, modes);
129          }
130          rtapi_print_msg(RTAPI_MSG_INFO,
131                    "PARPORT: Using Linux parport %s at ioaddr=0x%lx:0x%lx\n",
132                    linux_port->name, linux_port->base, linux_port->base_hi);
133          port->linux_dev = parport_register_device(linux_port,
134                  name, NULL, NULL, NULL, 0, NULL);
135  
136          if(!port->linux_dev)
137          {
138              parport_put_port(linux_port);
139              rtapi_print_msg(RTAPI_MSG_ERR,
140                  "PARPORT: ERROR: port %s register failed\n", linux_port->name);
141              return -EIO;
142          }
143  
144          retval = parport_claim(port->linux_dev);
145          if(retval < 0)
146          {
147              parport_put_port(linux_port);
148              parport_unregister_device(port->linux_dev);
149              rtapi_print_msg(RTAPI_MSG_ERR,
150                  "PARPORT: ERROR: port %s claim failed\n", linux_port->name);
151              return retval;
152          }
153  
154          port->base = linux_port->base;
155          if(linux_port->base_hi > 0) {
156              port->base_hi = linux_port->base_hi;
157          } else if(base_hi != (unsigned short)-1) {
158              if(base_hi == 0) base_hi = port->base + 0x400;
159              rtapi_print_msg(RTAPI_MSG_DBG,
160                  "PARPORT: DEBUG: linux reports no ioaddr_hi, using 0x%x",
161                  base_hi);
162              port->region_hi =
163                  rtapi_request_region(base_hi, 3, name);
164              if(port->region_hi) {
165                  rtapi_print_msg(RTAPI_MSG_DBG,
166                      "PARPORT: DEBUG: got requested region starting at 0x%x",
167                      base_hi);
168                  port->base_hi = base_hi;
169              } else {
170                  rtapi_print_msg(RTAPI_MSG_DBG,
171                      "PARPORT: DEBUG: did not get requested region starting at 0x%x",
172                      base_hi);
173              }
174          }
175          parport_put_port(linux_port);
176      } else {
177          if(base_hi == 0) base_hi = base + 0x400;
178  
179          port->base = base;
180          rtapi_print_msg(RTAPI_MSG_INFO,
181                    "Using direct parport at ioaddr=0x%x:0x%x\n", base, base_hi);
182  
183          // SPP access needs only 3 bytes, but EPP needs 8.  Allocating 8
184          // is likely to always be OK, and it simplifies things (since the
185          // exact allocation size is also needed at deallocation).
186          port->region = rtapi_request_region(base, 8, name);
187          if(!port->region)
188          {
189              rtapi_print_msg(RTAPI_MSG_ERR,
190                  "PARPORT: ERROR: request_region(0x%x) failed\n", base);
191              return -EBUSY;
192          }
193  
194          if(base_hi != (unsigned short)-1)
195          {
196              port->base_hi = base_hi;
197              port->region_hi =
198                  rtapi_request_region(base_hi, 3, name);
199              if(!port->region_hi)
200              {
201                  rtapi_print_msg(RTAPI_MSG_ERR,
202                      "PARPORT: ERROR: request_region(0x%x) failed\n", base_hi);
203                  rtapi_release_region(port->base, 8);
204                  return -EBUSY;
205              }
206          }
207      }
208      return 0;
209  }
210  
211  static void rtapi_parport_release(rtapi_parport_t *port)
212  {
213      if(port->linux_dev)
214      {
215          rtapi_print_msg(RTAPI_MSG_INFO,
216  	    "PARPORT: Releasing Linux parport at ioaddr=0x%lx:0x%lx\n",
217  	    port->linux_dev->port->base, port->linux_dev->port->base_hi);
218          parport_release(port->linux_dev);
219          parport_unregister_device(port->linux_dev);
220      }
221      if(port->region) {
222          rtapi_print_msg(RTAPI_MSG_INFO,
223  	    "PARPORT: Releasing I/O region ioaddr=0x%x\n", port->base);
224  	rtapi_release_region(port->base, 8);
225      }
226      if(port->region_hi) {
227          rtapi_print_msg(RTAPI_MSG_INFO,
228  	    "PARPORT: Releasing high I/O region ioaddr=0x%x\n",
229                  port->base_hi);
230  	rtapi_release_region(port->base_hi, 3);
231      }
232      memset(port, 0, sizeof(rtapi_parport_t));
233  }
234  #else
235  int rtapi_parport_get(const char *mod_name, rtapi_parport_t *port, unsigned short base, unsigned short base_hi, unsigned int modes);
236  void rtapi_parport_release(rtapi_parport_t *port);
237  #endif
238  
239  RTAPI_END_DECLS
240  
241  #endif