/* I/O port access * Copyright (C) 2009 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include static int op = 0; /* Operation, 0 = read, 1 = write. */ static int size = 1; /* Operation size in bytes. */ static int rcode = 0; /* If set, inX exits with return value. */ static int rhex = 0; /* If set, print result in hex. */ static struct option long_options[] = { { "code", 0, 0, 'c' }, { "read", 0, 0, 'r' }, { "size", 1, 0, 's' }, { "write", 0, 0, 'w' }, { "hex", 0, 0, 'x' }, { NULL, 0, 0, 0 }, }; static const char *options = "crs:w"; static void usage () { printf ("\n\ Usage:\n\ inb|inw|inl [--options] address\n\ outb|outw|outl [--options] address data\n\ Options:\n\ --code Exit with status code instead of printing value (inX only).\n\ --hex Print hex instead of decimal (inX only).\n\ --read Perform a read (in) operation.\n\ --write Perform a write (out) operation.\n\ --size N Set size to N bytes where N = 1, 2 or 4.\n\ \n\ For detailed information, see the manual page inb(1).\n\ "); } static unsigned get_int_or_die (const char *); int main (int argc, char *argv[]) { int c, option_index; char *p; unsigned addr = 0; unsigned data = 0; /* Find out how the program was invoked. */ p = strrchr (argv[0], '/'); if (p == NULL) p = argv[0]; else p++; if (strncasecmp (p, "inb", 3) == 0) { op = 0; size = 1; } else if (strncasecmp (p, "outb", 4) == 0) { op = 1; size = 1; } else if (strncasecmp (p, "inw", 3) == 0) { op = 0; size = 2; } else if (strncasecmp (p, "outw", 4) == 0) { op = 1; size = 2; } else if (strncasecmp (p, "inl", 3) == 0) { op = 0; size = 4; } else if (strncasecmp (p, "outl", 4) == 0) { op = 1; size = 4; } /* Parse command line arguments. */ while (1) { option_index = 0; c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 'c': rcode = 1; break; case 'r': op = 0; break; case 's': size = get_int_or_die (optarg); if (!(size == 1 || size == 2 || size == 4)) { fprintf (stderr, "%s: size can only be 1, 2 or 4.\n", optarg); exit (1); } break; case 'w': op = 1; break; case 'x': rhex = 1; break; case 0: fprintf (stderr, "internal error in getopt_long\n"); exit (1); default: usage (); exit (1); } } /* Parse the address (for read/write) and data (for writes). */ if (optind >= argc) { missing: fprintf (stderr, "%s: missing parameter, see --help or man page\n", argv[0]); exit (1); } addr = get_int_or_die (argv[optind++]); if (op == 1) { if (optind >= argc) goto missing; data = get_int_or_die (argv[optind++]); } if (optind != argc) { fprintf (stderr, "%s: extra parameters on command line, see --help or man page\n", argv[0]); exit (1); } /* Raise our privilege level. */ if (iopl (3) == -1) { fprintf (stderr, "iopl failed: You may need to run as root or give the process the CAP_SYS_RAWIO\ncapability. On non-x86 architectures, this operation probably isn't possible.\n"); perror ("iopl"); exit (1); } /* Perform the operation. */ switch (op) { case 0: switch (size) { case 1: data = inb (addr); break; case 2: data = inw (addr); break; case 4: data = inl (addr); break; } break; case 1: switch (size) { case 1: outb (data, addr); break; case 2: outw (data, addr); break; case 4: outl (data, addr); break; } break; } if (op == 0) { if (rcode == 0) { if (rhex == 0) printf ("%d\n", data); else printf ("%x\n", data); } else exit (data); } exit (0); } static unsigned get_int_or_die (const char *str) { char *endp; unsigned r; errno = 0; r = strtoul (str, &endp, 0); if ((errno == ERANGE && r == ULONG_MAX) || (errno != 0 && r == 0)) { perror (str); exit (1); } if (str == endp) { fprintf (stderr, "expecting a number, but found an empty string\n"); exit (1); } if (*endp != '\0') { fprintf (stderr, "%s: trailing garbage after number\n", str); exit (1); } return r; }