/ src / hal / utils / upci.c
upci.c
  1  /*************************************************************************
  2  
  3   Copyright (C) 2007 John Kasunich (jmkasunich at fastmail dot fm)
  4  
  5   This library contains functions to scan the PCI bus, find a particular
  6   PCI card, and read or write memory and I/O locations on a PCI card.
  7  
  8  **************************************************************************
  9  
 10  This program is free software; you can redistribute it and/or
 11  modify it under the terms of version 2 of the GNU General
 12  Public License as published by the Free Software Foundation.
 13  This library is distributed in the hope that it will be useful,
 14  but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  GNU General Public License for more details.
 17  
 18  You should have received a copy of the GNU General Public
 19  License along with this library; if not, write to the Free Software
 20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 21  
 22  THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
 23  ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
 24  TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
 25  harming persons must have provisions for completely removing power
 26  from all motors, etc, before persons enter any danger area.  All
 27  machinery must be designed to comply with local and national safety
 28  codes, and the authors of this software can not, and do not, take
 29  any responsibility for such compliance.
 30  
 31  This code was written as part of the EMC HAL project.  For more
 32  information, go to www.linuxcnc.org.
 33  
 34  *************************************************************************/
 35  
 36  #define _GNU_SOURCE /* getline() */
 37  #include <stdlib.h>
 38  #include <stdio.h>
 39  #include <stdarg.h>
 40  #include <string.h>
 41  #include <fcntl.h>
 42  #include <errno.h>
 43  #include <sys/types.h>
 44  #include <unistd.h>
 45  #include <sys/io.h>
 46  #include <sys/mman.h>
 47  #include <linux/types.h>
 48  #include "upci.h"
 49  
 50  /************************************************************************/
 51  
 52  /* Assorted typedefs */
 53  
 54  /* this is an standarized struct that is present in the
 55     configuration space of every PCI card */
 56  struct cfg_info {
 57      __u16 vendor_id;
 58      __u16 device_id;
 59      __u16 command;
 60      __u16 status;
 61      __u32 class_rev;
 62      __u32 misc_0;
 63      __u32 base[6];
 64      __u32 cardbus;
 65      __u16 ss_vendor_id;
 66      __u16 ss_device_id;
 67      __u32 rom_addr;
 68      __u32 reserved[2];
 69      __u32 misc_1;
 70  };
 71  
 72  /* internal structs used by upci */
 73  struct region_info {
 74      enum upci_region_type type;
 75      __u32 base_addr;
 76      __u32 size;
 77      int region_is_mapped;
 78      void *mapped_ptr;
 79  };
 80  
 81  struct dev_info {
 82      struct upci_dev_info p;		/* public info */
 83      struct cfg_info cfg;		/* raw data from device */
 84      struct region_info regions[6];	/* region info */
 85  };
 86  
 87  /************************************************************************/
 88  
 89  #define MAX_DEVICES 100
 90  #define MAX_REGIONS (MAX_DEVICES*6)
 91  
 92  /* we get our info from the proc filesystem */
 93  #define DEVICES_FILE	"/proc/bus/pci/devices"
 94  #define DEVICE_FILE	"/proc/bus/pci/%02x/%02x.%01x"
 95  
 96  /* number of discovered devices */
 97  static int num_devs = 0;
 98  /* pointers to all discovered devices (others are null) */
 99  static struct dev_info *devices[MAX_DEVICES] = { NULL };
100  /* pointers to all mapped regions (others are null) */
101  static struct region_info *regions[MAX_REGIONS] = { NULL };
102  /* file descriptor for /dev/mem */
103  static int memfd = -1;
104  /* reference counters, increment each time a region is opened */
105  static int memaccess = 0;	/* non-zero if /dev/mem is open */
106  static int ioaccess = 0;	/* non-zero if iopl > 0 */
107  
108  /************************************************************************/
109  
110  static void errmsg(const char *funct, const char *fmt, ...)
111  {
112      va_list vp;
113  
114      va_start(vp, fmt);
115      fprintf(stderr, "ERROR in %s(): ", funct);
116      vfprintf(stderr, fmt, vp);
117      fprintf(stderr, "\n");
118      va_end(vp);
119  }
120  
121  void upci_reset(void)
122  {
123      int d, r;
124      struct dev_info *dev;
125      struct region_info *region;
126  
127      /* traverse list */
128      for ( d = 0 ; d < num_devs ; d++ ) {
129  	dev = devices[d];
130  	if ( dev != NULL ) {
131  	    for ( r = 0 ; r < 6 ; r++ ) {
132  		region = &(dev->regions[r]);
133  		if ( region->region_is_mapped ) {
134  		    /* unmap any mapped memory regions */
135  		    munmap ( region->mapped_ptr, region->size );
136  		}
137  	    }
138  	    /* free data structures */
139  	    free(dev);
140  	    devices[d] = NULL;
141  	}
142      }
143      /* release I/O port access */
144      if ( ioaccess ) {
145  	iopl(0);
146  	ioaccess = 0;
147      }
148      /* release raw memory access */
149      if ( memaccess ) {
150  	close (memfd);
151  	memaccess = 0;
152      }
153      num_devs = 0;
154  }
155  
156  int upci_scan_bus(void)
157  {
158      FILE *f;
159      char *lineptr;
160      size_t linelen;
161      int linenum, r, n;
162      struct dev_info *dev, *ndev;
163      struct cfg_info cfg;
164      __u32 vendordev;
165      __u16 busdevfunc;
166      char dev_fname[256];
167      int fd;
168  
169      /* delete any previous list */
170      upci_reset();
171      /* we use /proc as the source of all knowledge */
172      f = fopen(DEVICES_FILE, "r");
173      if (f == NULL) {
174  	errmsg(__func__, "opening '%s': %s", DEVICES_FILE, strerror(errno));
175  	goto cleanup1;
176      }
177      lineptr = NULL;
178      linelen = 0;
179      linenum = 0;
180      while ( 1 ) {
181  	if ( num_devs == MAX_DEVICES ) {
182  	    errmsg(__func__, "devices list full (%d entries)", num_devs);
183  	    /* return the ones that we already found, ignore others */
184  	    free(lineptr);
185  	    fclose(f);
186  	    return num_devs;
187  	}
188  	/* get a line */
189  	if(getline(&lineptr, &linelen, f) < 0) {
190  	    /* end of file, done */
191  	    free(lineptr);
192  	    fclose(f);
193  	    return num_devs;
194  	}
195  	++linenum;
196  	/* allocate a structure */
197  	dev = (struct dev_info *)(malloc(sizeof(struct dev_info)));
198  	if ( dev == NULL ) {
199  	    errmsg(__func__,"malloc failure");
200  	    goto cleanup2;
201  	}
202  	devices[num_devs++] = dev;
203  	n = sscanf(lineptr,
204  	    "%hx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
205  	    &busdevfunc, &vendordev, &(dev->p.irq),
206  	    &dev->p.base_addr[0],  &dev->p.base_addr[1], &dev->p.base_addr[2],
207  	    &dev->p.base_addr[3],  &dev->p.base_addr[4], &dev->p.base_addr[5],
208  	    &dev->p.rom_base_addr,
209  	    &dev->p.size[0], &dev->p.size[1], &dev->p.size[2],
210  	    &dev->p.size[3], &dev->p.size[4], &dev->p.size[5],
211  	    &dev->p.rom_size);
212  	if (n != 17) {
213  	    errmsg(__func__, "only %d items on %s line %d", n, DEVICES_FILE, linenum);
214  	    goto cleanup3;
215  	}
216  	/* separate the packed fields */
217  	dev->p.vendor_id = (vendordev >> 16) & 0xFFFF;
218  	dev->p.device_id =  vendordev & 0xFFFF;
219  	dev->p.bus = (busdevfunc >> 8) & 0x00FF;
220  	dev->p.dev = (busdevfunc >> 3) & 0x001F;
221  	dev->p.func = busdevfunc & 0x0007;
222  	/* fix up region info: remove embedded info in low bits,
223  	   copy to region_info structs, init various fields */
224  	for ( r = 0 ; r < 6 ; r++ ) {
225  	    if ( dev->p.base_addr[r] & 1 ) {
226  		/* region is I/O */
227  		dev->p.region_type[r] = UPCI_REG_IO;
228  		dev->p.base_addr[r] &= ~0x03;
229  	    } else {
230  		/* region is memory */
231  		dev->p.region_type[r] = UPCI_REG_MEM;
232  		dev->p.base_addr[r] &= ~0x0F;
233  	    }
234  	    dev->regions[r].type = dev->p.region_type[r];
235  	    dev->regions[r].base_addr = dev->p.base_addr[r];
236  	    dev->regions[r].size = dev->p.size[r];
237  	    dev->regions[r].region_is_mapped = 0;
238  	    dev->regions[r].mapped_ptr = NULL;
239  	}
240  	/* the subsystem info isn't stored in DEVICES_FILE, need to
241  	   look deeper to find it */
242  	snprintf(dev_fname, 255, DEVICE_FILE, dev->p.bus, dev->p.dev, dev->p.func);
243  	fd = open(dev_fname, O_RDONLY);
244  	if (fd < 0) {
245  	    errmsg(__func__, "opening '%s': %s", dev_fname, strerror(errno));
246  	    goto cleanup3;
247  	}
248  	n = read(fd, &cfg, sizeof(struct cfg_info));
249  	if ( n != sizeof(struct cfg_info) ) {
250  	    errmsg(__func__, "reading '%s': %s", dev_fname, strerror(errno));
251  	    goto cleanup4;
252  	}
253  	close(fd);
254  	dev->p.ss_vendor_id = cfg.ss_vendor_id;
255  	dev->p.ss_device_id = cfg.ss_device_id;
256  	dev->p.instance = 0;
257  	/* look for previous devices with the same vendor, device,
258  	   and subsystem codes.  start at end of list and work forward */
259  	n = num_devs - 2;
260  	while ( n >= 0 ) {
261  	    ndev = devices[n];
262  	    if (( dev->p.vendor_id == ndev->p.vendor_id ) &&
263  		( dev->p.device_id == ndev->p.device_id ) &&
264  		( dev->p.ss_vendor_id == ndev->p.ss_vendor_id ) &&
265  		( dev->p.ss_device_id == ndev->p.ss_device_id )) {
266  		/* found a match */
267  		dev->p.instance = ndev->p.instance + 1;
268  		/* don't need to look farther */
269  		break;
270  	    }
271  	    n--;
272  	}
273      }
274      /* loop never falls through, success returns from inside the loop */
275      /* errors jump here */
276  cleanup4:
277      close(fd);
278  cleanup3:
279      free(dev);
280      num_devs --;
281  cleanup2:
282      free(lineptr);
283      fclose(f);
284  cleanup1:
285      upci_reset();
286      return -1;
287  }
288  
289  int upci_print_device_info(int devnum)
290  {
291      struct upci_dev_info *dev;
292      int n;
293  
294      if (( devnum < 0 ) || ( devnum >= num_devs )) {
295  	errmsg(__func__, "device %d not found", devnum);
296  	return -1;
297      }
298      dev = &(devices[devnum]->p);
299      printf("PCI device %2d at bus/device/function %02x/%02x/%01x\n",
300  	devnum, dev->bus, dev->dev, dev->func );
301      printf("Vendor/Device/SSVendor/SSDevice: %04x/%04x/%04x/%04x\n",
302  	dev->vendor_id, dev->device_id, dev->ss_vendor_id, dev->ss_device_id );
303      for ( n = 0 ; n < 6 ; n++ ) {
304  	if ( dev->size[n] > 0 ) {
305  	    if ( dev->region_type[n] == UPCI_REG_IO ) {
306  		/* I/O region */
307  		printf("Region %d: I/O %u bytes at %04x\n",
308  		    n, dev->size[n], dev->base_addr[n] );
309  	    } else {
310  		/* memory region */
311  		printf("Region %d: MEM %u bytes at %08x\n",
312  		    n, dev->size[n], dev->base_addr[n] );
313  	    }
314  	}
315      }
316      return 0;
317  }
318  
319  int upci_get_device_info(struct upci_dev_info *p, int devnum)
320  {
321      if (( devnum < 0 ) || ( devnum >= num_devs )) {
322  	return -1;
323      }
324      if ( p == NULL ) {
325  	return -1;
326      }
327      /* copy from our private structure into the user's one */
328      *p = devices[devnum]->p;
329      return 0;
330  }
331  
332  int upci_find_device(struct upci_dev_info *p)
333  {
334      int n;
335      struct dev_info *dev;
336  
337      n = 0;
338      while ( n < num_devs ) {
339  	dev = devices[n];
340  	if (( dev->p.vendor_id == p->vendor_id ) &&
341  	    ( dev->p.device_id == p->device_id ) &&
342  	    ( dev->p.ss_vendor_id == p->ss_vendor_id ) &&
343  	    ( dev->p.ss_device_id == p->ss_device_id ) &&
344  	    ( dev->p.instance == p->instance )) {
345  	    /* found a match */
346  	    return n;
347  	}
348  	n++;
349      }
350      return -1;
351  }
352  
353  static int incr_io_usage ( void )
354  {
355      int retval, eno;
356  
357      /* make sure we can do I/O */
358      if ( ioaccess == 0 ) {
359  	/* enable access */
360  	/* this needs priviliges */
361  	if (seteuid(0) != 0) {
362  	    errmsg(__func__, "need root privilges (or setuid root)");
363  	    return -1;
364  	}
365  	/* do it */
366  	retval = iopl(3);
367  	eno = errno;
368  	/* drop priviliges */
369  	if(seteuid(getuid()) != 0)
370  	{
371  	    errmsg(__func__, "unable to drop root privileges");
372  	    /* Don't continue past this point, because following code may
373  	     * execute with unexpected privileges
374  	     */
375  	    _exit(99);
376  	}
377  	/* check result */
378  	if(retval < 0 || iopl(3) < 0) {
379  	    errmsg(__func__,"opening I/O ports: %s", strerror(eno));
380  	    return -1;
381  	}
382      }
383      /* increment reference count */
384      ioaccess++;
385      return 0;
386  }
387  
388  static void decr_io_usage ( void )
389  {
390      if ( ioaccess <= 0 ) {
391  	/* should not be calling decr if already zero */
392  	return;
393      }
394      /* decrement reference count */
395      ioaccess--;
396      if ( ioaccess == 0 ) {
397  	/* release I/O priveleges */
398  	iopl(0);
399      }
400  }
401  
402  static int incr_mem_usage ( void )
403  {
404      int eno;
405  
406      /* make sure /dev/mem is open */
407      if ( memaccess == 0 ) {
408  	/* open it */
409  	/* this needs priviliges */
410  	if (seteuid(0) != 0) {
411  	    errmsg(__func__, "need root privilges (or setuid root)");
412  	    return -1;
413  	}
414  	/* do it */
415  	memfd = open("/dev/mem", O_RDWR);
416  	eno = errno;
417  	/* drop priviliges */
418  	if(seteuid(getuid()) != 0)
419  	{
420  	    errmsg(__func__, "unable to drop root privileges");
421  	    /* Don't continue past this point, because following code may
422  	     * execute with unexpected privileges
423  	     */
424  	    _exit(99);
425  	}
426  	/* check result */
427  	if ( memfd < 0 ) {
428  	    errmsg(__func__,"can't open /dev/mem: %s", strerror(eno));
429  	    return -1;
430  	}
431      }
432      /* increment reference count */
433      memaccess++;
434      return 0;
435  }
436  
437  static void decr_mem_usage ( void )
438  {
439      if ( memaccess <= 0 ) {
440  	/* should not be calling decr if already zero */
441  	return;
442      }
443      /* decrement reference count */
444      memaccess--;
445      if ( memaccess == 0 ) {
446  	/* close /dev/mem */
447  	close(memfd);
448      }
449  }
450  
451  int upci_open_region(int devnum, int region_num)
452  {
453      struct dev_info *dev;
454      struct region_info *reg;
455      int rd;
456  
457      if (( devnum < 0 ) || ( devnum >= num_devs )) {
458  	errmsg(__func__, "device %d not found", devnum);
459  	return -1;
460      }
461      dev = devices[devnum];
462      if (( region_num < 0 ) || ( region_num >= 6 )) {
463  	errmsg(__func__, "bad region number %d", region_num);
464  	return -1;
465      }
466      reg = &(dev->regions[region_num]);
467      if ( reg->size == 0 ) {
468  	errmsg(__func__, "region %d not found in device %d",
469  	    region_num, devnum);
470  	return -1;
471      }
472      /* calculate region descriptor */
473      rd = devnum * 6 + region_num;
474      if ( reg->region_is_mapped ) {
475  	/* already open, nothing to do */
476  	return rd;
477      }
478      if ( reg->type == UPCI_REG_IO ) {
479  	/* region is IO, no mapping needed */
480  	/* update reference counter */
481  	if ( incr_io_usage() != 0 ) {
482  	    errmsg(__func__, "no I/O access");
483  	    return -1;
484  	}
485      } else {
486  	/* region is memory */
487  	/* update reference counter */
488  	if ( incr_mem_usage() != 0 ) {
489  	    return -1;
490  	}
491  	/* map the memory region */
492  	reg->mapped_ptr = mmap(0, reg->size, PROT_READ | PROT_WRITE,
493  	    MAP_SHARED, memfd, reg->base_addr);
494  	if ( reg->mapped_ptr == MAP_FAILED ) {
495  	    reg->mapped_ptr = NULL;
496  	    errmsg(__func__, "can't map /dev/mem for device %d, region %d: %s",
497  		devnum, region_num, strerror(errno));
498  	    decr_mem_usage();
499  	    return -1;
500  	}
501      }
502      /* mark region as mapped */
503      reg->region_is_mapped = 1;
504      regions[rd] = reg;
505      return rd;
506  }
507  
508  void upci_close_region(int rd)
509  {
510      struct region_info *reg;
511  
512      if ((rd < 0 ) || ( rd >= MAX_REGIONS )) return;
513      reg = regions[rd];
514      if ( reg == NULL ) return;
515      if ( reg->type == UPCI_REG_IO ) {
516  	/* region is IO, nothing to unmap */
517  	decr_io_usage();
518      } else {
519  	/* region is memory, unmap it */
520  	munmap ( reg->mapped_ptr, reg->size );
521  	decr_mem_usage();
522      }
523      /* mark region as unmapped */
524      reg->region_is_mapped = 0;
525      regions[rd] = NULL;
526  }
527  
528  __u8 upci_read_u8(int rd, __u32 offset)
529  {
530      struct region_info *reg;
531      int port;
532      volatile __u8 *ptr, data;
533  
534      /* test for out of range, not mapped, or offset beyond end of region */
535      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) || 
536  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return 0;
537      /* get the data */
538      if ( reg->type == UPCI_REG_IO ) {
539  	/* region is IO */
540  	port = reg->base_addr + offset;
541  	data = inb(port);
542      } else {
543  	/* region is memory */
544  	ptr = (__u8 *)(reg->mapped_ptr + offset);
545  	data = *ptr;
546      }
547      return data;
548  }
549  
550  __s8 upci_read_s8(int rd, __u32 offset)
551  {
552      struct region_info *reg;
553      int port;
554      volatile __s8 *ptr, data;
555  
556      /* test for out of range, not mapped, or offset beyond end of region */
557      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
558  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return 0;
559      /* get the data */
560      if ( reg->type == UPCI_REG_IO ) {
561  	port = reg->base_addr + offset;
562  	data = inb(port);
563      } else {
564  	ptr = (__s8 *)(reg->mapped_ptr + offset);
565  	data = *ptr;
566      }
567      return data;
568  }
569  
570  __u16 upci_read_u16(int rd, __u32 offset)
571  {
572      struct region_info *reg;
573      int port;
574      volatile __u16 *ptr, data;
575  
576      /* test for out of range, not mapped, or offset beyond end of region */
577      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
578  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return 0;
579      /* get the data */
580      if ( reg->type == UPCI_REG_IO ) {
581  	port = reg->base_addr + offset;
582  	data = inw(port);
583      } else {
584  	ptr = (__u16 *)(reg->mapped_ptr + offset);
585  	data = *ptr;
586      }
587      return data;
588  }
589  
590  __s16 upci_read_s16(int rd, __u32 offset)
591  {
592      struct region_info *reg;
593      int port;
594      volatile __s16 *ptr, data;
595  
596      /* test for out of range, not mapped, or offset beyond end of region */
597      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
598  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return 0;
599      /* get the data */
600      if ( reg->type == UPCI_REG_IO ) {
601  	port = reg->base_addr + offset;
602  	data = inw(port);
603      } else {
604  	ptr = (__s16 *)(reg->mapped_ptr + offset);
605  	data = *ptr;
606      }
607      return data;
608  }
609  
610  __u32 upci_read_u32(int rd, __u32 offset)
611  {
612      struct region_info *reg;
613      int port;
614      volatile __u32 *ptr, data;
615  
616      /* test for out of range, not mapped, or offset beyond end of region */
617      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
618  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return 0;
619      /* get the data */
620      if ( reg->type == UPCI_REG_IO ) {
621  	port = reg->base_addr + offset;
622  	data = inl(port);
623      } else {
624  	ptr = (__u32 *)(reg->mapped_ptr + offset);
625  	data = *ptr;
626      }
627      return data;
628  }
629  
630  __s32 upci_read_s32(int rd, __u32 offset)
631  {
632      struct region_info *reg;
633      int port;
634      volatile __s32 *ptr, data;
635  
636      /* test for out of range, not mapped, or offset beyond end of region */
637      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
638  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return 0;
639      /* get the data */
640      if ( reg->type == UPCI_REG_IO ) {
641  	port = reg->base_addr + offset;
642  	data = inl(port);
643      } else {
644  	ptr = (__s32 *)(reg->mapped_ptr + offset);
645  	data = *ptr;
646      }
647      return data;
648  }
649  
650  void upci_write_u8(int rd, __u32 offset, __u8 data)
651  {
652      struct region_info *reg;
653      int port;
654      volatile __u8 *ptr;
655  
656      /* test for out of range, not mapped, or offset beyond end of region */
657      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) || 
658  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return;
659      /* write the data */
660      if ( reg->type == UPCI_REG_IO ) {
661  	/* region is IO */
662  	port = reg->base_addr + offset;
663  	outb(data, port);
664      } else {
665  	/* region is memory */
666  	ptr = (__u8 *)(reg->mapped_ptr + offset);
667  	*ptr = data;
668      }
669      return;
670  }
671  
672  void upci_write_s8(int rd, __u32 offset, __s8 data)
673  {
674      struct region_info *reg;
675      int port;
676      volatile __s8 *ptr;
677  
678      /* test for out of range, not mapped, or offset beyond end of region */
679      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
680  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return;
681      /* write the data */
682      if ( reg->type == UPCI_REG_IO ) {
683  	port = reg->base_addr + offset;
684  	outb(data, port);
685      } else {
686  	ptr = (__s8 *)(reg->mapped_ptr + offset);
687  	*ptr = data;
688      }
689      return;
690  }
691  
692  void upci_write_u16(int rd, __u32 offset, __u16 data)
693  {
694      struct region_info *reg;
695      int port;
696      volatile __u16 *ptr;
697  
698      /* test for out of range, not mapped, or offset beyond end of region */
699      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
700  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return;
701      /* write the data */
702      if ( reg->type == UPCI_REG_IO ) {
703  	port = reg->base_addr + offset;
704  	outw(data, port);
705      } else {
706  	ptr = (__u16 *)(reg->mapped_ptr + offset);
707  	*ptr = data;
708      }
709      return;
710  }
711  
712  void upci_write_s16(int rd, __u32 offset, __s16 data)
713  {
714      struct region_info *reg;
715      int port;
716      volatile __s16 *ptr;
717  
718      /* test for out of range, not mapped, or offset beyond end of region */
719      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
720  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return;
721      /* write the data */
722      if ( reg->type == UPCI_REG_IO ) {
723  	port = reg->base_addr + offset;
724  	outw(data, port);
725      } else {
726  	ptr = (__s16 *)(reg->mapped_ptr + offset);
727  	*ptr = data;
728      }
729      return;
730  }
731  
732  void upci_write_u32(int rd, __u32 offset, __u32 data)
733  {
734      struct region_info *reg;
735      int port;
736      volatile __u32 *ptr;
737  
738      /* test for out of range, not mapped, or offset beyond end of region */
739      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
740  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return;
741      /* write the data */
742      if ( reg->type == UPCI_REG_IO ) {
743  	port = reg->base_addr + offset;
744  	outl(data, port);
745      } else {
746  	ptr = (__u32 *)(reg->mapped_ptr + offset);
747  	*ptr = data;
748      }
749      return;
750  }
751  
752  void upci_write_s32(int rd, __u32 offset, __s32 data)
753  {
754      struct region_info *reg;
755      int port;
756      volatile __s32 *ptr;
757  
758      /* test for out of range, not mapped, or offset beyond end of region */
759      if ((rd < 0 ) || ( rd >= MAX_REGIONS ) ||
760  	( (reg = regions[rd]) == NULL ) || ( offset > reg->size )) return;
761      /* write the data */
762      if ( reg->type == UPCI_REG_IO ) {
763  	port = reg->base_addr + offset;
764  	outl(data, port);
765      } else {
766  	ptr = (__s32 *)(reg->mapped_ptr + offset);
767  	*ptr = data;
768      }
769      return;
770  }