/* * Copyright (c) 2011-2013 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /************************************************************************ * g20gpio_status.c * * Utility for fetching AT91SAM9G20 or AT91SAM9G25 GPIO status values. * The G20 has 3 banks of 32 gpio lines: PA0-PA31, PB0-PB31 and PC0-PC31. * The G25 has 4 banks of gpio lines: PA0-PA31, PB0-PB18, PC0-PC31 and * PD0-PD21. Uses memory mapped IO. * ****************************************************/ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #include #include #include static const char * version_str = "2.07 20130604"; #define GPIO_BANKS_G20 3 /* PA0-31, PB0-31 and PC0-31 */ #define GPIO_BANKS_G25 4 /* PA0-31, PB0-18, PC0-31 and PD0-21 */ #define LINES_PER_BANK 32 #define MAP_SIZE 4096 /* assume to be power of 2 */ #define MAP_MASK (MAP_SIZE - 1) #define DEV_MEM "/dev/mem" #define GPIO_BANK_ORIGIN "/sys/class/gpio/gpiochip0" /* Earlier kernels (G20+G25) offset GPIO numbers by 32 so * /sys/class/gpio/gpiochip32 (a directory) was the lowest * numbered bank and corresponded to PIOA. Now (in lk 3.7) * /sys/class/gpio/gpiochip0 exists and corresponds to PIOA. */ struct mmap_state { void * mmap_ptr; off_t prev_mask_addrp; int mmap_ok; }; static unsigned int pio_psr[] = {0xfffff408, 0xfffff608, 0xfffff808, 0xfffffa08}; /* PIO status */ static unsigned int pio_osr[] = {0xfffff418, 0xfffff618, 0xfffff818, 0xfffffa18}; /* Output status */ static unsigned int pio_ifsr[] = {0xfffff428, 0xfffff628, 0xfffff828, 0xfffffa28}; /* Input filter status */ /* a.k.a. Glitch input filter status */ static unsigned int pio_odsr[] = {0xfffff438, 0xfffff638, 0xfffff838, 0xfffffa38}; /* Output data status */ static unsigned int pio_pdsr[] = {0xfffff43c, 0xfffff63c, 0xfffff83c, 0xfffffa3c}; /* Pin data status */ static unsigned int pio_imr[] = {0xfffff448, 0xfffff648, 0xfffff848, 0xfffffa48}; /* Interrupt mask */ static unsigned int pio_isr[] = {0xfffff44c, 0xfffff64c, 0xfffff84c, 0xfffffa4c}; /* Interrupt status */ static unsigned int pio_mdsr[] = {0xfffff458, 0xfffff658, 0xfffff858, 0xfffffa58}; /* Multi drive status */ static unsigned int pio_pusr[] = {0xfffff468, 0xfffff668, 0xfffff868, 0xfffffa68}; /* Pull-up status */ /* a.k.a. Pad pull-up status */ static unsigned int g25_pio_abcdsr1[] = {0xfffff470, 0xfffff670, 0xfffff870, 0xfffffa70}; /* Peripheral select 1 */ static unsigned int g25_pio_abcdsr2[] = {0xfffff474, 0xfffff674, 0xfffff874, 0xfffffa74}; /* Peripheral select 2 */ static unsigned int g20_pio_absr[] = {0xfffff478, 0xfffff678, 0xfffff878, 0xfffffa78}; /* AB status */ static unsigned int g25_pio_ifscsr[] = {0xfffff488, 0xfffff688, 0xfffff888, 0xfffffa88}; /* Input filter slow clock status */ static unsigned int g25_pio_scdr[] = {0xfffff48c, 0xfffff68c, 0xfffff88c, 0xfffffa8c}; /* Slow clock divider */ static unsigned int g25_pio_ppdsr[] = {0xfffff498, 0xfffff698, 0xfffff898, 0xfffffa98}; /* Pad pull-down status */ static unsigned int pio_owsr[] = {0xfffff4a8, 0xfffff6a8, 0xfffff8a8, 0xfffffaa8}; /* Output write status */ static unsigned int g25_pio_aimmr[] = {0xfffff4b8, 0xfffff6b8, 0xfffff8b8, 0xfffffab8}; /* Additional interrupt modes mask */ static unsigned int g25_pio_elsr[] = {0xfffff4c8, 0xfffff6c8, 0xfffff8c8, 0xfffffac8}; /* Edge/level status */ static unsigned int g25_pio_frlhsr[] = {0xfffff4d8, 0xfffff6d8, 0xfffff8d8, 0xfffffad8}; /*Fall/rise - low/high status */ static unsigned int g25_pio_locksr[] = {0xfffff4e0, 0xfffff6e0, 0xfffff8e0, 0xfffffae0}; /* Lock status */ static unsigned int g25_pio_wpmr[] = {0xfffff4e4, 0xfffff6e4, 0xfffff8e4, 0xfffffae4}; /* Write protect mask */ static unsigned int g25_pio_wpsr[] = {0xfffff4e8, 0xfffff6e8, 0xfffff8e8, 0xfffffae8}; /* Write protect status */ static unsigned int g25_pio_schmitt[] = {0xfffff500, 0xfffff700, 0xfffff900, 0xfffffb00}; /* Schmitt trigger */ /* static unsigned int g25_pio_delayr[] = {0xfffff510, 0xfffff710, 0xfffff910, * 0xfffffb10}; * N.B. Don't understand Atmel doco on this one (IO Delay register). */ static unsigned int g25_pio_driver1[] = {0xfffff514, 0xfffff714, 0xfffff914, 0xfffffb14}; /* IO drive 1 */ static unsigned int g25_pio_driver2[] = {0xfffff518, 0xfffff718, 0xfffff918, 0xfffffb18}; /* IO drive 2 */ static char argv0[512]; static const char * exe_name = "no_name"; static int for_g25 = 0; static int verbose = 0; static const char * driv_arr[] = {"HI_DRIVE", "ME_DRIVE", "LO_DRIVE", "Reserved (drive)"}; static int g25_pins_per_bank[] = {32, 19, 32, 22}; static const char * g20_pioa_trans[] = { /* pairs: 0 */ "SPI0_MISO", "MCDB0", "SPI0_MOSI", "MCCDB", "SPI0_SPCK", NULL, "SPI0_NPCS0", "MCDB3", "RTS2", "MCDB2", "CTS2", "MCDB1", "MCDA0", NULL, "MCCDA", NULL, /* pairs: 8 */ "MCCK", NULL, "MCDA1", NULL, "MCDA2", "ETX2", "MCDA3", "ETX3", "ETX0", NULL, "ETX1", NULL, "ERX0", NULL, "ERX1", NULL, /* pairs: 16 */ "ETXEN", NULL, "ERXDV", NULL, "ERXER", "ETX2", "ETXCK", NULL, "EMDC", NULL, "EMDIO", NULL, "ADTRG", "ETXER", "TWD", "ETX2", /* pairs: 24 */ "TWC", "ETX3", "TCLK0", "ERX2", "TIOA0", "ERX3", "TIOA1", "ERXCK", "TIOA2", "ECRS", "SCK1", "ECOL", "SCK2", "RXD4", "SCK0", "TXD4", }; static const char * g20_piob_trans[] = { /* pairs: 0 */ "SPI1_MISO", "TIOA3", "SPI1_MOSI", "TIOB3", "SPI1_SPCK", "TIOA4", "SPI1_NPCS0", "TIOA5", "TXD0", NULL, "RXD0", NULL, "TXD1", "TCLK1", "RXD1", "TCLK2", /* pairs: 8 */ "TXD2", NULL, "RXD2", NULL, "TXD3", "ISI_D8", "RXD3", "ISI_D9", "TXD5", "ISI_D10", "RXD5", "ISI_D11", "DRXD", NULL, "DTXD", NULL, /* pairs: 16 */ "TK0", "TCLK3", "TF0", "TCLK4", "TD0", "TIOB4", "RD0", "TIOB5", "RK0", "ISI_D0", "RF0", "ISI_D1", "DSR0", "ISI_D2", "DCD0", "ISI_D3", /* pairs: 24 */ "DTR0", "ISI_D4", "RIO", "ISI_D5", "RTS0", "ISI_D6", "CTS0", "ISI_D7", "RTS1", "ISI_PCK", "CTS1", "ISI_VSYNC", "PCK0", "ISI_HSYNC", "PCK1", "ISI_MCK", }; static const char * g20_pioc_trans[] = { /* pairs: 0 */ NULL, "SCK3", NULL, "PCK0", NULL, "PCK1", NULL, "SPI1_NPCS3", "A23", "SPI1_NPCS2", "A24", "SPI1_NPCS1", "TIOB2", "CFCE1", "TIOB1", "CFCE2", /* pairs: 8 */ "NCS4/CFCS0", "RTS3", "NCS5/CFCS1", "TIOB0", "A25/CFRNW", "CTS3", "NCS2", "SPIO0_NPCS1", "IRQ0", "NCS7", "FIQ", "NCS6", "NCS3/NANDCS", "IRQ2", "NWAIT", "IRQ1", /* pairs: 16 */ "D16", "SPI0_NPCS2", "D17", "SPI0_NPCS3", "D18", "SPI1_NPCS1", "D19", "SPI1_NPCS2", "D20", "SPI1_NPCS3", "D21", NULL, "D22", "TCLK5", "D23", NULL, /* pairs: 24 */ "D24", NULL, "D25", NULL, "D26", NULL, "D27", NULL, "D28", NULL, "D29", NULL, "D30", NULL, "D31", NULL, }; static const char * g25_pioa_trans[] = { /* triples: 0 */ "TXD0", "SPI1_NPCS1", NULL, "RXD0", "SPI0_NPCS2", NULL, "RTS0", "MCI1_DA1", "ETX0", "CTS0", "MCI1_DA2", "ETX1", "SCK0", "MCI1_DA3", "ETXER", "TXD1", NULL, NULL, "RXD1", NULL, NULL, "TXD2", "SPI0_NPCS1", NULL, /* triples: 8 */ "RXD2", "SPI1_NPCS0", NULL, "DRXD", NULL, NULL, "DTXD", NULL, NULL, "SPI0_MISO", "MCI1_DA0", NULL, "SPI0_MOSI", "MCI1_CDA", NULL, "SPI0_SPCK", "MCI1_CK", NULL, "SPI0_NPCS0", NULL, NULL, "MCI0_DA0", NULL, NULL, /* triples: 16 */ "MCI0_CDA", NULL, NULL, "MCI0_CK", NULL, NULL, "MCI0_DA1", NULL, NULL, "MCI0_DA2", NULL, NULL, "MCI0_DA3", NULL, NULL, "TIOA0", "SPI1_MISO", NULL, "TIOA1", "SPI1_MOSI", NULL, "TIOA2", "SPI1_SPCK", NULL, /* triples: 24 */ "TCLK0", "TK", NULL, "TCLK1", "TF", NULL, "TCLK2", "TD", NULL, "TIOB0", "RD", NULL, "TIOB1", "RK", NULL, "TIOB2", "RF", NULL, "TWD0", "SPI1_NPCS3", "EMDC", "TWCK0", "SPI1_NPCS2", "ETXEN", }; static const char * g25_piob_trans[] = { /* triples: 0 */ "ERX0", "RTS2", NULL, "ERX1", "CTS2", NULL, "ERXER", "SCK2", NULL, "ERXDV", "SPI0_NPCS3", NULL, "ETXCK", "TWD2", NULL, "EMDIO", "TWCK2", NULL, "EMDC", NULL, NULL, "ETXEN", NULL, NULL, /* triples: 8 */ "ETXER", NULL, NULL, "ETX0", "PCK1", NULL, "ETX1", "PCK0", NULL, "ETX2", "PWM0", NULL, "ETX3", "PWM1", NULL, "ERX2", "PWM2", NULL, "ERX3", "PWM3", NULL, "ERXCK", NULL, NULL, /* triples: 16 */ "ECRS", NULL, NULL, "ECOL", NULL, NULL, "IRQ", "ADTRG", NULL, }; static const char * g25_pioc_trans[] = { /* triples: 0 */ NULL, "ISI_D0", "TWD1", NULL, "ISI_D1", "TWCK1", NULL, "ISI_D2", "TIOA3", NULL, "ISI_D3", "TIOB3", NULL, "ISI_D4", "TCLK3", NULL, "ISI_D5", "TIOA4", NULL, "ISI_D6", "TIOB4", NULL, "ISI_D7", "TCLK4", /* triples: 8 */ NULL, "ISI_D8", "UTXD0", NULL, "ISI_D9", "URXD0", NULL, "ISI_D10", "PWM0", NULL, "ISI_D11", "PWM1", NULL, "ISI_PCK", "TIOA5", NULL, "ISI_VSYNC", "TIOB5", NULL, "ISI_HSYNC", "TCK5", NULL, "ISI_MCK", "PCK0", /* triples: 16 */ NULL, NULL, "UTXD1", NULL, NULL, "URXD1", NULL, NULL, "PWM0", NULL, NULL, "PWM1", NULL, NULL, "PWM2", NULL, NULL, "PWM3", NULL, "TXD3", NULL, NULL, "RXD3", NULL, /* triples: 24 */ NULL, "RTS3", NULL, NULL, "CTS3", NULL, NULL, "SCK3", NULL, NULL, NULL, "RTS1", NULL, NULL, "CTS1", NULL, NULL, "SCK1", NULL, NULL, NULL, "FIQ", NULL, "PCK1", }; static const char * g25_piod_trans[] = { /* triples: 0 */ "NANDOE", NULL, NULL, "NANDWE", NULL, NULL, "A21/NANDALE", NULL, NULL, "A22/NANDCLE", NULL, NULL, "NCS3", NULL, NULL, "NWAIT", NULL, NULL, "D16", NULL, NULL, "D17", NULL, NULL, /* triples: 8 */ "D18", NULL, NULL, "D19", NULL, NULL, "D20", NULL, NULL, "D21", NULL, NULL, "D22", NULL, NULL, "D23", NULL, NULL, "D24", NULL, NULL, "D25", "A20", NULL, /* triples: 16 */ "D26", "A23", NULL, "D27", "A24", NULL, "D28", "A25", NULL, "D29", "NCS2", NULL, "D30", "NCS4", NULL, "D31", "NCS5", NULL, }; static void usage(int hval) { if (1 == hval) { fprintf(stderr, "Usage: " "%s [-0] [-5] [-a] [-b ] [-B] [-e] [-h] [-i]\n" " [-p ] [-s] [-S] [-t] [-v] [-V] " "[-w]\n" " where:\n" " -0 force AT91SAM9G20 mode\n" " -5 force AT91SAM9G25 mode\n" " -a list all lines within a bank (def: " "'-p A')\n" " -b bit (line) number within port (0 to 31)\n" " -B brief ouput (e.g. 'psr=1 pusr*=0 ...'). " "Use twice\n" " for single line output; thrice for name " "only\n" " -e enumerate pin names with corresponding " "kernel pin.\n" " Use twice to list peripheral names for " "each pin\n" " -h print usage message, use twice for " "abbreviations\n" " -i read interrupt status register which " "clears it\n" " -p port bank ('A' to '%c') or gpio kernel " "line number\n" " 32 -> PA0, 33 -> PA1 ... 127 -> PC31%s\n" " -s summarize all lines in a bank, equivalent " "to\n" " '-a -BB -t'. Example: '%s -s -p C'\n" " -S show all selected line names within all " "banks.\n" " Use twice for appended '^' indicating " "pull-up\n" " Use thrice to indicate multi-drive\n" " -t translate peripheral type to functional " "name\n" " (e.g. %s)\n" " -v increase verbosity (multiple times for " "more)\n" " -V print version string then exit\n", exe_name, (for_g25 ? 'D' : 'B'), (for_g25 ? " ... 149 -> PD21" : ""), exe_name, (for_g25 ? "PC10 peri_c -> PWM0" : "PB4 peri_a -> TXD0")); if (for_g25) fprintf(stderr, " -w read write protect status register " "which clears it\n"); fprintf(stderr, "\nAT91SAM9G20 or AT91SAM9G25 GPIO fetch status program. " "Uses memory mapped\nIO to fetch PIO registers and shows " "settings for given line(s). Try\n'-hh' for more help. " "Currently in %s mode.\n", (for_g25 ? "AT91SAM9G25" : "AT91SAM9G20")); } else { if (for_g25) { fprintf(stderr, ">> AT91SAM9G25\n" "abcdsr1: peripheral select 1 [def: 0]\n" "abcdsr2: peripheral select 2 [def: 0 -> peri_a (if " "abcdsr1=0)]\n" "aimmr: additional interrupt mode mask [def: 0 -> " "disabled]]\n" "driver1: IO drive 1 [def: 0]\n" "driver2: IO drive 2 [def: 0 -> HI (if driver1=0)]\n" "elsr: edge/level status [def: 0 -> edge]\n" "frlhsr: fall/rise - low/high status [def: 0 -> " "falling or low]\n" "ifsr: input (glitch) filter status [def: 0 -> " "disabled]\n" "imr: interrupt mask [def: 0 -> disabled]\n" "isr: interrupt status [def: 0 -> no change]\n" "locksr: lock status [def: 0 -> unlocked]\n" "mdsr: multi drive status [def: 0 -> disabled: " "driven high+low]\n" "odsr: output data status [def: 0 -> level 0 to " "be driven]\n" "osr: output status [def: 0 -> line is pure " "input]\n" "owsr: output write status [def: 0 -> writing to " "odsr ignored]\n" "pdsr: pin data status [0 -> line is at level 0; " "1 -> level 1]\n" "ppdsr*: pad pull-down status [def: 1 -> disabled]\n" "psr: PIO status [0 -> peripheral active; 1 -> " "generic GPIO pin]\n" "pusr*: pad pull-up status [def: 0 -> enabled]\n" "scdr**: slow clock divider (debouncing) [def: 0; per " "PIO]\n" "schmitt*: schmitt trigger [def: 0 -> enabled]\n" "wpmr**: write protect mask [def: 0 -> PIO writeable]\n" "wpsr**: write protect status [def: 0 -> no violation " "on PIO]\n" ); fprintf(stderr, "\nAbbreviations with a trailing '*' have " "the corresponding function\nenabled when the value " "is 0 (i.e. negated logic). For example\n'pusr*=0' " "means the pull-up is enabled. The trailing '**' " "means\nthe register is per PIO bank rather than per " "GPIO line. An\nentry like 'isr=-1' means that isr " "(the interrupt status register)\nhas not been read.\n" ); } else { fprintf(stderr, ">> AT91SAM9G20\n" "absr: AB status [def: 0 -> peri_a]\n" "ifsr: input (glitch) filter status [def: 0 -> " "disabled]\n" "imr: interrupt mask [def: 0 -> disabled]\n" "isr: interrupt status [def: 0 -> no change]\n" "mdsr: multi drive status [def: 0 -> disabled: " "driven high+low]\n" "odsr: output data status [def: 0 -> level 0 to " "be driven]\n" "osr: output status [def: 0 -> line is pure " "input]\n" "owsr: output write status [def: 0 -> writing to " "odsr ignored]\n" "pdsr: pin data status [0 -> line is at level 0; " "1 -> level 1]\n" "psr: PIO status [0 -> peripheral active; 1 -> " "generic GPIO pin]\n" "pusr*: pad pull-up status [def: 0 -> enabled]\n" ); fprintf(stderr, "\nAbbreviations with a trailing '*' have " "the corresponding function\nenabled when the value " "is 0 (i.e. negated logic). For example\n'pusr*=0' " "means the pull-up is enabled. An entry like " "'isr=-1' means\nthat isr (the interrupt status " "register) has not been read.\n" ); } } } /* Since we map a whole page (MAP_SIZE) then that page may already be * mapped which means we can skip a munmap() and mmap() call. Returns * new or re-used pointer to mmapped page, or returns NULL if problem. */ static void * check_mmap(int mem_fd, unsigned int wanted_addr, struct mmap_state * msp) { off_t mask_addr; mask_addr = (wanted_addr & ~MAP_MASK); if ((0 == msp->mmap_ok) || (msp->prev_mask_addrp != mask_addr)) { if (msp->mmap_ok) { if (-1 == munmap(msp->mmap_ptr, MAP_SIZE)) { fprintf(stderr, "mmap_ptr=%p:\n", msp->mmap_ptr); perror(" munmap"); return NULL; } else if (verbose > 2) fprintf(stderr, "munmap() ok, mmap_ptr=%p\n", msp->mmap_ptr); } msp->mmap_ptr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, mask_addr); if ((void *)-1 == msp->mmap_ptr) { msp->mmap_ok = 0; fprintf(stderr, "addr=0x%x, mask_addr=0x%lx :\n", wanted_addr, mask_addr); perror(" mmap"); return NULL; } msp->mmap_ok = 1; msp->prev_mask_addrp = mask_addr; if (verbose > 2) fprintf(stderr, "mmap() ok, mask_addr=0x%lx, mmap_ptr=%p\n", mask_addr, msp->mmap_ptr); } return msp->mmap_ptr; } static char * translate_peri(char * b, int max_blen, int pioc_num, int bit_num, int peri_num) { const char * cp; if ((NULL == b) || (max_blen < 1)) return b; b[max_blen - 1] = '\0'; if ((bit_num < 0) || (bit_num > 31)) { snprintf(b, max_blen - 1, "bad bit_num=%d", bit_num); return b; } if (for_g25) { /* AT91SAM9G25 */ if ((peri_num < 0) || (peri_num > 3)) { snprintf(b, max_blen - 1, "bad peri_num=%d", peri_num); return b; } switch (pioc_num) { case 0: if ((peri_num < 3) && (cp = g25_pioa_trans[(3 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; case 1: if ((peri_num < 3) && (cp = g25_piob_trans[(3 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; case 2: if ((peri_num < 3) && (cp = g25_pioc_trans[(3 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; case 3: if ((peri_num < 3) && (cp = g25_piod_trans[(3 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; default: snprintf(b, max_blen - 1, "bad pioc_num=%d", pioc_num); return b; } } else { /* AT91SAM9G20 */ if ((peri_num < 0) || (peri_num > 1)) { snprintf(b, max_blen - 1, "bad peri_num=%d", peri_num); return b; } switch (pioc_num) { case 0: if ((cp = g20_pioa_trans[(2 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; case 1: if ((cp = g20_piob_trans[(2 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; case 2: if ((cp = g20_pioc_trans[(2 * bit_num) + peri_num])) snprintf(b, max_blen - 1, "%s", cp); else strncpy(b, "", max_blen - 1); return b; default: snprintf(b, max_blen - 1, "bad pioc_num=%d", pioc_num); return b; } } } static int g20_status(int mem_fd, unsigned int bit_mask, int bit_num, int brief, int interrupt, int translate, int pioc_num) { int psr, osr, ifsr, odsr, pdsr, imr, isr, mdsr, pusr, absr, owsr; void * mmap_ptr = (void *)-1; struct mmap_state mstat; void * ap; const char * cp = NULL; char b[32]; memset(&mstat, 0, sizeof(mstat)); mmap_ptr = check_mmap(mem_fd, pio_psr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_psr[pioc_num] & MAP_MASK); psr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" PIO status: %d (%s)\n", psr, (psr ? "PIO ACTIVE, peripheral inactive" : "peripheral ACTIVE")); mmap_ptr = check_mmap(mem_fd, pio_osr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_osr[pioc_num] & MAP_MASK); osr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" PIO output status: %d (%s)\n", osr, (osr ? "line enabled as output" : "line pure input")); mmap_ptr = check_mmap(mem_fd, pio_ifsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_ifsr[pioc_num] & MAP_MASK); ifsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" input filter status: %d (%s)\n", ifsr, (ifsr ? "glitch filter ENabled" : "glitch filter DISabled")); mmap_ptr = check_mmap(mem_fd, pio_odsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_odsr[pioc_num] & MAP_MASK); odsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" output data status: %d\n", odsr); mmap_ptr = check_mmap(mem_fd, pio_pdsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_pdsr[pioc_num] & MAP_MASK); pdsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" pin data status: %d\n", pdsr); mmap_ptr = check_mmap(mem_fd, pio_imr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_imr[pioc_num] & MAP_MASK); imr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" interrupt mask: %d (%s)\n", imr, (imr ? "ENabled" : "DISabled")); if (interrupt) { mmap_ptr = check_mmap(mem_fd, pio_isr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_isr[pioc_num] & MAP_MASK); isr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" interrupt status: %d (%s)\n", isr, (isr ? "input CHANGE" : "NO input change")); } else isr = -1; mmap_ptr = check_mmap(mem_fd, pio_mdsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_mdsr[pioc_num] & MAP_MASK); mdsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" multi driver status: %d (%s)\n", mdsr, (mdsr ? "enabled, pin driven when low" : "pin driven high and low")); mmap_ptr = check_mmap(mem_fd, pio_pusr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_pusr[pioc_num] & MAP_MASK); pusr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" pull-up status: %d (%s)\n", pusr, (pusr ? "DISabled" : "ENabled")); if (psr) { absr = -1; mmap_ptr = check_mmap(mem_fd, pio_owsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_owsr[pioc_num] & MAP_MASK); owsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" output write status: %d (%s)\n", owsr, (owsr ? "writing PIO_ODSR affects IO line" : "writing PIO_ODSR ignored")); } else { /* peripheral mode */ owsr = -1; mmap_ptr = check_mmap(mem_fd, g20_pio_absr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g20_pio_absr[pioc_num] & MAP_MASK); absr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) { if (translate) { b[0] = '\0'; translate_peri(b, sizeof(b), pioc_num, bit_num, absr); if (strlen(b) > 0) cp = b; } if (cp) printf(" %s [absr=%d]\n", cp, absr); else printf(" peripheral A B status: %d (%s)\n", absr, (absr ? "B" : "A")); } } if (brief) { if (1 == brief) printf("psr=%d pdsr=%d osr=%d odsr=%d mdsr=%d ifsr=%d imr=%d " "isr=%d pusr*=%d absr=%d owsr=%d\n", psr, pdsr, osr, odsr, mdsr, ifsr, imr, isr, pusr, absr, owsr); else { if (psr) { if (translate && (2 == pioc_num) && (bit_num < 4)) { snprintf(b, sizeof(b), "AD%d", bit_num); cp = b; } else cp = "GPIO"; } else if (translate) cp = translate_peri(b, sizeof(b), pioc_num, bit_num, absr); if (0 == strlen(cp)) { if (absr) cp = "PERI_B"; else cp = "PERI_A"; } if (2 == brief) { if (psr) printf(" %-2d: %s pdsr=%d osr=%d odsr=%d mdsr=%d " "ifsr=%d pusr*=%d\n", bit_num, cp, pdsr, osr, odsr, mdsr, ifsr, pusr); else printf(" %-2d: %s pdsr=%d mdsr=%d ifsr=%d pusr*=%d\n", bit_num, cp, pdsr, mdsr, ifsr, pusr); } else printf("\n"); } } if (mstat.mmap_ok) { if (-1 == munmap(mmap_ptr, MAP_SIZE)) { fprintf(stderr, "mmap_ptr=%p:\n", mmap_ptr); perror(" munmap"); return 1; } else if (verbose > 2) fprintf(stderr, "trailing munmap() ok, mmap_ptr=%p\n", mmap_ptr); } return 0; } static int g25_status(int mem_fd, unsigned int bit_mask, int bit_num, int brief, int interrupt, int translate, int pioc_num, int write_prot) { int psr, osr, ifsr, odsr, pdsr, imr, isr, mdsr, pusr, abcdsr1, abcdsr2; int owsr, ifscsr, scdr, ppdsr, aimmr, elsr, frlhsr, locksr, wpmr, wpsr; int schmitt, bn, driv, k; void * mmap_ptr = (void *)-1; struct mmap_state mstat; void * ap; unsigned int * reg_arr; const char * cp; char b[32]; memset(&mstat, 0, sizeof(mstat)); mmap_ptr = check_mmap(mem_fd, pio_psr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_psr[pioc_num] & MAP_MASK); psr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" PIO status: %d (%s)\n", psr, (psr ? "PIO ACTIVE, peripheral inactive" : "peripheral ACTIVE")); mmap_ptr = check_mmap(mem_fd, pio_osr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_osr[pioc_num] & MAP_MASK); osr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" PIO output status: %d (%s)\n", osr, (osr ? "line enabled as output" : "line pure input")); mmap_ptr = check_mmap(mem_fd, pio_ifsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_ifsr[pioc_num] & MAP_MASK); ifsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" input filter status: %d (%s)\n", ifsr, (ifsr ? "glitch filter ENabled" : "glitch filter DISabled")); mmap_ptr = check_mmap(mem_fd, pio_odsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_odsr[pioc_num] & MAP_MASK); odsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" output data status: %d\n", odsr); mmap_ptr = check_mmap(mem_fd, pio_pdsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_pdsr[pioc_num] & MAP_MASK); pdsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" pin data status: %d\n", pdsr); mmap_ptr = check_mmap(mem_fd, pio_imr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_imr[pioc_num] & MAP_MASK); imr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" interrupt mask: %d (%s)\n", imr, (imr ? "ENabled" : "DISabled")); if (interrupt) { mmap_ptr = check_mmap(mem_fd, pio_isr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_isr[pioc_num] & MAP_MASK); isr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" interrupt status: %d (%s)\n", isr, (isr ? "input CHANGE" : "NO input change")); } else isr = -1; mmap_ptr = check_mmap(mem_fd, pio_mdsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_mdsr[pioc_num] & MAP_MASK); mdsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" multi driver status: %d (%s)\n", mdsr, (mdsr ? "enabled, pin driven when low" : "pin driven high and low")); mmap_ptr = check_mmap(mem_fd, pio_pusr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_pusr[pioc_num] & MAP_MASK); pusr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" pad pull-up status: %d (%s)\n", pusr, (pusr ? "DISabled" : "ENabled")); if (psr) { abcdsr1 = -1; abcdsr2 = -1; mmap_ptr = check_mmap(mem_fd, pio_owsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (pio_owsr[pioc_num] & MAP_MASK); owsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" output write status: %d (%s)\n", owsr, (owsr ? "writing PIO_ODSR affects IO line" : "writing PIO_ODSR ignored")); } else { /* peripheral mode */ owsr = -1; mmap_ptr = check_mmap(mem_fd, g25_pio_abcdsr1[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_abcdsr1[pioc_num] & MAP_MASK); abcdsr1 = !!( *((unsigned int *)ap) & bit_mask); mmap_ptr = check_mmap(mem_fd, g25_pio_abcdsr2[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_abcdsr2[pioc_num] & MAP_MASK); abcdsr2 = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) { cp = NULL; k = (2 * abcdsr2) + abcdsr1; if (translate) { b[0] = '\0'; translate_peri(b, sizeof(b), pioc_num, bit_num, k); if (strlen(b) > 0) cp = b; } if (cp) printf(" %s [sr1:%d, sr2:%d]\n", cp, abcdsr1, abcdsr2); else printf(" peripheral %s function [sr1:%d, sr2:%d]\n", (abcdsr2 ? (abcdsr1 ? "D" : "C") : (abcdsr1 ? "B" : "A")), abcdsr1, abcdsr2); } } mmap_ptr = check_mmap(mem_fd, g25_pio_ifscsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_ifscsr[pioc_num] & MAP_MASK); ifscsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" input filter slow clock status: %d (%s)\n", ifscsr, (ifscsr ? "slow" : "master-fast")); if (ifscsr) { mmap_ptr = check_mmap(mem_fd, g25_pio_scdr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_scdr[pioc_num] & MAP_MASK); scdr = *((unsigned int *)ap) & 0x3fff; if (0 == brief) printf(" slow clock divider debouncing register: %d [0x%x]\n", scdr, scdr); } else scdr = -1; mmap_ptr = check_mmap(mem_fd, g25_pio_ppdsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_ppdsr[pioc_num] & MAP_MASK); ppdsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" pad pull down status: %d (%s)\n", ppdsr, (ppdsr ? "DISabled" : "ENabled")); mmap_ptr = check_mmap(mem_fd, g25_pio_aimmr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_aimmr[pioc_num] & MAP_MASK); aimmr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" additional interrupt modes mask: %d (%s)\n", aimmr, (aimmr ? "depends on ELSR+FRLHSR" : "Both edges")); mmap_ptr = check_mmap(mem_fd, g25_pio_elsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_elsr[pioc_num] & MAP_MASK); elsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" edge/level status: %d (%s detection)\n", elsr, (elsr ? "level" : "edge")); mmap_ptr = check_mmap(mem_fd, g25_pio_frlhsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_frlhsr[pioc_num] & MAP_MASK); frlhsr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" fall/rise - low/high status: %d (%s detection)\n", elsr, (elsr ? "rising edge or high level" : "falling edge or low level")); mmap_ptr = check_mmap(mem_fd, g25_pio_locksr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_locksr[pioc_num] & MAP_MASK); locksr = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" locked status: %d (%slocked)\n", locksr, (locksr ? "" : "not ")); mmap_ptr = check_mmap(mem_fd, g25_pio_wpmr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_wpmr[pioc_num] & MAP_MASK); wpmr = *(unsigned int *)ap; if (0 == brief) printf(" write protect mode: WPEN: %d (%s)\n", wpmr & 1, ((wpmr & 1) ? "ENabled" : "DISabled")); if (write_prot) { mmap_ptr = check_mmap(mem_fd, g25_pio_wpsr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_wpsr[pioc_num] & MAP_MASK); wpsr = *((unsigned int *)ap) & 0xffffff; if (0 == brief) printf(" write protect violation status: %d (%s), WPCSRC: " "0x%x\n", (wpsr & 1), ((wpsr & 1) ? "VIOLATED" : "NOT violated"), (wpsr >> 8) & 0xffff); } else wpsr = -1; mmap_ptr = check_mmap(mem_fd, g25_pio_schmitt[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (g25_pio_schmitt[pioc_num] & MAP_MASK); schmitt = !!( *((unsigned int *)ap) & bit_mask); if (0 == brief) printf(" schmitt trigger status: %d (%s)\n", schmitt, (schmitt ? "DISabled" : "ENabled ")); if (bit_num < 16) { reg_arr = g25_pio_driver1; bn = bit_num; } else { reg_arr = g25_pio_driver2; bn = bit_num & 0xf; } mmap_ptr = check_mmap(mem_fd, reg_arr[pioc_num], &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (reg_arr[pioc_num] & MAP_MASK); driv = (*((unsigned int *)ap) >> (2 * bn)) & 0x3; if (0 == brief) printf(" IO drive: %d (%s)\n", driv, driv_arr[driv]); if (1 == brief) { if (psr) { printf("psr=%d pdsr=%d osr=%d odsr=%d mdsr=%d ifsr=%d imr=%d " "isr=%d pusr*=%d ifscsr=%d\nscdr=%d ppdsr*=%d aimmr=%d " "elsr=%d frlhsr=%d locksr=%d wpmr=0x%x", psr, pdsr, osr, odsr, mdsr, ifsr, imr, isr, pusr, ifscsr, scdr, ppdsr, aimmr, elsr, frlhsr, locksr, wpmr); if (write_prot) printf(" wpsr=0x%x", wpsr); printf("\nschmitt*=%d io_driv=%d\n", schmitt, driv); } else { printf("psr=%d pdsr=%d osr=%d odsr=%d mdsr=%d ifsr=%d imr=%d " "isr=%d pusr*=%d abcdsr1=%d\nabcdsr2=%d owsr=%d " "ifscsr=%d scdr=%d ppdsr*=%d aimmr=%d elsr=%d " "frlhsr=%d\nlocksr=%d wpmr=0x%x", psr, pdsr, osr, odsr, mdsr, ifsr, imr, isr, pusr, abcdsr1, abcdsr2, owsr, ifscsr, scdr, ppdsr, aimmr, elsr, frlhsr, locksr, wpmr); if (write_prot) printf(" wpsr=0x%x", wpsr); printf(" schmitt*=%d io_driv=%d\n", schmitt, driv); } } else if (brief > 1) { if (psr) { if (translate && (1 == pioc_num) && (bit_num >= 6) && (bit_num < 18)) { k = (bit_num + 1) % 12; snprintf(b, sizeof(b), "AD%d", k); cp = b; } else cp = "GPIO"; } else { if (abcdsr1 & abcdsr2) { cp = "PERI_D"; k = 3; } else if (abcdsr1) { cp = "PERI_B"; k = 1; } else if (abcdsr2) { cp = "PERI_C"; k = 2; } else { cp = "PERI_A"; k = 0; } if (translate) { b[0] = '\0'; translate_peri(b, sizeof(b), pioc_num, bit_num, k); if (strlen(b) > 0) cp = b; } } if (2 == brief) { if (psr) printf(" %-2d: %s pdsr=%d osr=%d odsr=%d mdsr=%d ifsr=%d " "pusr*=%d%s\n", bit_num, cp, pdsr, osr, odsr, mdsr, ifsr, pusr, ((0 == ppdsr) ? " ppdsr*=0" : "")); else printf(" %-2d: %s pdsr=%d mdsr=%d ifsr=%d pusr*=%d%s\n", bit_num, cp, pdsr, mdsr, ifsr, pusr, ((0 == ppdsr) ? " ppdsr*=0" : "")); } else printf("\n"); } if (mstat.mmap_ok) { if (-1 == munmap(mmap_ptr, MAP_SIZE)) { fprintf(stderr, "mmap_ptr=%p:\n", mmap_ptr); perror(" munmap"); return 1; } else if (verbose > 2) fprintf(stderr, "trailing munmap() ok, mmap_ptr=%p\n", mmap_ptr); } return 0; } static int do_enumerate(int enum_val, int bank, int orig0) { int k, j, n, num; char b[16]; const char * cp; if (for_g25) { num = GPIO_BANKS_G25; if (1 == enum_val) { for (k = 0; k < LINES_PER_BANK; ++k) { for (j = 0; j < num; ++j) { if (((1 == j) && (k > 18)) || ((3 == j) && (k > 21))) printf("\t\t"); else { n = ((j + (! orig0)) * 32) + k; printf("%sP%c%d: %d ", (j ? "\t" : ""), 'A' + j, k, n); } } printf("\n"); } } else { /* '-ee' */ if ('\0' == bank) k = 0; else { k = bank - 'A'; if (k < num) num = k + 1; } for ( ; k < num; ++k) { printf("AT91SAM9G25: PIO %c:\n", 'A' + k); for (j = 0; j < LINES_PER_BANK; ++j) { if (((1 == k) && (j > 18)) || ((3 == k) && (j > 21))) break; cp = translate_peri(b, sizeof(b), k, j, 0); if ((1 == k) && (j >= 6) && (j < 18)) { n = (j + 1) % 12; printf(" P%c%d/AD%d: %s, ", 'A' + k, j, n, (strlen(cp) > 0) ? cp : "-"); } else printf(" P%c%d: %s, ", 'A' + k, j, (strlen(cp) > 0) ? cp : "-"); cp = translate_peri(b, sizeof(b), k, j, 1); printf("%s, ", (strlen(cp) > 0) ? cp : "-"); cp = translate_peri(b, sizeof(b), k, j, 2); printf("%s, -\n", (strlen(cp) > 0) ? cp : "-"); } } } } else { /* G20 */ num = GPIO_BANKS_G20; if (1 == enum_val) { for (k = 0; k < LINES_PER_BANK; ++k) { for (j = 0; j < num; ++j) { n = ((j + (! orig0)) * 32) + k; printf("%sP%c%d: %d ", (j ? "\t" : ""), 'A' + j, k, n); } printf("\n"); } } else { /* '-ee' */ if ('\0' == bank) k = 0; else { k = bank - 'A'; if (k < num) num = k + 1; } for ( ; k < num; ++k) { printf("AT91SAM9G20: PIO %c:\n", 'A' + k); for (j = 0; j < LINES_PER_BANK; ++j) { cp = translate_peri(b, sizeof(b), k, j, 0); printf(" P%c%d: %s, ", 'A' + k, j, (strlen(cp) > 0) ? cp : "-"); cp = translate_peri(b, sizeof(b), k, j, 1); printf("%s\n", (strlen(cp) > 0) ? cp : "-"); } } } } return 0; } static int do_show_all(int show_val) { int k, j, n, num, psr, abcdsr1, abcdsr2, absr, v; int res = 1; int mem_fd = -1; unsigned int bit_mask, addr; char b[32]; size_t blen = sizeof(b) - 1; void * mmap_ptr = (void *)-1; struct mmap_state mstat; void * ap; if ((mem_fd = open(DEV_MEM, O_RDWR | O_SYNC)) < 0) { perror("open of " DEV_MEM " failed"); return 1; } else if (verbose > 2) printf("open(" DEV_MEM "O_RDWR | O_SYNC) okay\n"); memset(&mstat, 0, sizeof(mstat)); if (2 == show_val) printf("Appended '^' indicates internal pull-up active\n\n"); else if (show_val > 2) printf("Appended '^' indicates multi-drive (open drain) " "mode\n\n"); if (for_g25) { num = GPIO_BANKS_G25; printf("PIN\tPio_A\t\tPio_B\t\tPio_C\t\tPio_D\n"); for (k = 0; k < LINES_PER_BANK; ++k) { printf("%d:\t", k); bit_mask = 1 << k; for (j = 0; j < num; ++j) { if (((1 == j) && (k > 18)) || ((3 == j) && (k > 21))) printf("\t\t"); else { mmap_ptr = check_mmap(mem_fd, pio_psr[j], &mstat); if (NULL == mmap_ptr) goto clean_up; ap = (unsigned char *)mmap_ptr + (pio_psr[j] & MAP_MASK); psr = !!( *((unsigned int *)ap) & bit_mask); if (psr) { if ((1 == j) && (k >= 6) && (k < 18)) snprintf(b, blen, "AD%d", ((k + 1) % 12)); else snprintf(b, blen, "%s", "GPIO"); } else { mmap_ptr = check_mmap(mem_fd, g25_pio_abcdsr1[j], &mstat); if (NULL == mmap_ptr) goto clean_up; ap = (unsigned char *)mmap_ptr + (g25_pio_abcdsr1[j] & MAP_MASK); abcdsr1 = !!( *((unsigned int *)ap) & bit_mask); mmap_ptr = check_mmap(mem_fd, g25_pio_abcdsr2[j], &mstat); if (NULL == mmap_ptr) goto clean_up; ap = (unsigned char *)mmap_ptr + (g25_pio_abcdsr2[j] & MAP_MASK); abcdsr2 = !!( *((unsigned int *)ap) & bit_mask); if (abcdsr1 & abcdsr2) n = 3; else if (abcdsr1) n = 1; else if (abcdsr2) { n = 2; } else n = 0; translate_peri(b, blen, j, k, n); if (strlen(b) < 1) snprintf(b, blen, "P%c%d: sel=%d", 'A' + j, k, n); } if (show_val > 1) { if (2 == show_val) addr = pio_pusr[j]; else addr = pio_mdsr[j]; mmap_ptr = check_mmap(mem_fd, addr, &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (addr & MAP_MASK); v = !!( *((unsigned int *)ap) & bit_mask); if (2 == show_val) v = ! v; /* pusr==0, implies pull-up active */ n = strlen(b); if (v && (n < (int)blen)) snprintf(b + n, blen - n, "%c", '^'); } n = strlen(b); printf("%s%s%s", (j ? "\t" : ""), b, ((n < 8) ? "\t" : "")); } } printf("\n"); } } else { /* G20 */ num = GPIO_BANKS_G20; printf("PIN\tPio_A\t\tPio_B\t\tPio_C\n"); for (k = 0; k < LINES_PER_BANK; ++k) { printf("%d:\t", k); bit_mask = 1 << k; for (j = 0; j < num; ++j) { mmap_ptr = check_mmap(mem_fd, pio_psr[j], &mstat); if (NULL == mmap_ptr) goto clean_up; ap = (unsigned char *)mmap_ptr + (pio_psr[j] & MAP_MASK); psr = !!( *((unsigned int *)ap) & bit_mask); if (psr) { if ((2 == j) && (k < 4)) snprintf(b, blen, "AD%d", k); else snprintf(b, blen, "%s", "GPIO"); } else { mmap_ptr = check_mmap(mem_fd, g20_pio_absr[j], &mstat); if (NULL == mmap_ptr) goto clean_up; ap = (unsigned char *)mmap_ptr + (g20_pio_absr[j] & MAP_MASK); absr = !!( *((unsigned int *)ap) & bit_mask); translate_peri(b, blen, j, k, absr); if (strlen(b) < 1) snprintf(b, blen, "P%c%d: sel=%d", 'A' + j, k, absr); } if (show_val > 1) { if (2 == show_val) addr = pio_pusr[j]; else addr = pio_mdsr[j]; mmap_ptr = check_mmap(mem_fd, addr, &mstat); if (NULL == mmap_ptr) return 1; ap = (unsigned char *)mmap_ptr + (addr & MAP_MASK); v = !!( *((unsigned int *)ap) & bit_mask); if (2 == show_val) v = ! v; /* pusr==0, implies pull-up active */ n = strlen(b); if (v && (n < (int)blen)) snprintf(b + n, blen - n, "%c", '^'); } n = strlen(b); printf("%s%s%s", (j ? "\t" : ""), b, ((n < 8) ? "\t" : "")); } printf("\n"); } } res = 0; clean_up: if (mem_fd >= 0) close(mem_fd); return res; } int main(int argc, char ** argv) { struct stat sb; int pioc_num, opt, k, num; int res = 0; int mem_fd = -1; int do_all = 0; int brief = 0; int brief_given = 0; int enumerate = 0; int do_help = 0; int interrupt = 0; int origin0 = 0; int translate = 0; int show_all = 0; int write_prot = 0; int knum = -1; int bit_num = -1; int ret = 0; unsigned int bit_mask; char ch; char bank = '\0'; if (argc > 0) { strncpy(argv0, argv[0], sizeof(argv0) - 1); argv0[sizeof(argv0) - 1] = '\0'; exe_name = basename(argv0); if ((0 == memcmp("g25", exe_name, 3)) || (0 == memcmp("G25", exe_name, 3))) for_g25 = 1; } while ((opt = getopt(argc, argv, "05ab:Behip:sStvVw")) != -1) { switch (opt) { case '0': for_g25 = 0; break; case '5': for_g25 = 1; break; case 'a': ++do_all; break; case 'b': k = atoi(optarg); if ((k < 0) || (k > 31)) { fprintf(stderr, "'-b' expects a bit number from 0 to 31\n"); exit(EXIT_FAILURE); } bit_num = k; break; case 'B': ++brief; ++brief_given; break; case 'e': ++enumerate; break; case 'h': ++do_help; break; case 'i': ++interrupt; break; case 'p': if (isalpha(*optarg)) { ch = toupper(*optarg); if ((ch >= 'A') && (ch <= 'D')) bank = ch; else { fprintf(stderr, "'-p' expects a letter ('A' to 'D')\n"); exit(EXIT_FAILURE); } } else if (isdigit(*optarg)) { k = atoi(optarg); if ((k < 0) || (k > 159)) { fprintf(stderr, "'-p' expects a letter or a number " "0 or greater\n"); exit(EXIT_FAILURE); } knum = k; } else { fprintf(stderr, "'-p' expects a letter ('A' to 'D') or " "a number\n"); exit(EXIT_FAILURE); } break; case 's': ++do_all; ++translate; brief += 2; break; case 'S': ++show_all; break; case 't': ++translate; break; case 'v': ++verbose; break; case 'V': printf("%s\n", version_str); exit(EXIT_SUCCESS); case 'w': ++write_prot; break; default: /* '?' */ do_help = 1; ret = 1; break; } } if (optind < argc) { if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); do_help = 1; ret = 1; } } if (do_help) { usage(do_help); exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } if (stat(GPIO_BANK_ORIGIN, &sb) >= 0) { if (verbose > 1) fprintf(stderr, "%s found so kernel pin numbers start at 0 " "(for PA0)\n", GPIO_BANK_ORIGIN); ++origin0; } else if (verbose > 2) fprintf(stderr, "%s not found so kernel pin numbers start at 32 " "(for PA0)\n", GPIO_BANK_ORIGIN); if (enumerate) return do_enumerate(enumerate, bank, origin0); if (show_all) return do_show_all(show_all); if (knum >= 0) { if (bit_num >= 0) { fprintf(stderr, "Give either '-p ' or ('-b ' and " "'-p ') but not both\n"); exit(EXIT_FAILURE); } if ((! origin0) && (knum < 32)) { fprintf(stderr, "since %s not found assume kernel pin numbers " "start at 32\n(for PA0) so %d is too low\n", GPIO_BANK_ORIGIN, knum); exit(EXIT_FAILURE); } } else if (bank) { if (do_all) knum = origin0 ? 0 : 32; else if (bit_num < 0) { if (write_prot) knum = origin0 ? 0 : 32; else { fprintf(stderr, "If '-p ' given then also need " "'-b '\n"); exit(EXIT_FAILURE); } } else knum = (((! origin0) + bank - 'A') * 32) + bit_num; } else { if (do_all) { printf(">>> Assuming bank A, use '-p ' to change\n"); knum = origin0 ? 0 : 32; } else { fprintf(stderr, "Need to give gpio line with '-p ' and/or " "'-b '\n"); usage(1); exit(EXIT_FAILURE); } } pioc_num = bank ? (bank - 'A') : ((knum - (origin0 ? 0 : 32)) / 32); if (bit_num < 0) bit_num = knum % 32; bit_mask = 1 << bit_num; if (do_all) { if (brief_given && (brief > brief_given)) brief = brief_given; } else { if (verbose) printf("P%c%d:\n", 'A' + pioc_num, bit_num); if (verbose > 1) printf(" bit_mask=0x%08x\n", bit_mask); } if ((0 == for_g25) && (pioc_num > 2)) { fprintf(stderr, "G20 doesn't have a bank D, exiting\n"); return 1; } if ((mem_fd = open(DEV_MEM, O_RDWR | O_SYNC)) < 0) { perror("open of " DEV_MEM " failed"); return 1; } else if (verbose > 2) printf("open(" DEV_MEM "O_RDWR | O_SYNC) okay\n"); if (for_g25) { if (do_all) { num = g25_pins_per_bank[pioc_num]; res = 0; if (brief > 1) printf("AT91SAM9G25: PIO %c:\n", 'A' + pioc_num); for (bit_num = 0; bit_num < num; ++bit_num) { bit_mask = 1 << bit_num; if (brief < 2) printf("P%c%d:\n", 'A' + pioc_num, bit_num); res = g25_status(mem_fd, bit_mask, bit_num, brief, interrupt, translate, pioc_num, write_prot); if (res) break; } } else res = g25_status(mem_fd, bit_mask, bit_num, brief, interrupt, translate, pioc_num, write_prot); } else { /* AT91SAM9G20 */ if (do_all) { res = 0; if (brief > 1) printf("AT91SAM9G20: PIO %c:\n", 'A' + pioc_num); for (bit_num = 0; bit_num < 32; ++bit_num) { bit_mask = 1 << bit_num; if (brief < 2) printf("P%c%d:\n", 'A' + pioc_num, bit_num); res = g20_status(mem_fd, bit_mask, bit_num, brief, interrupt, translate, pioc_num); if (res) break; } } else res = g20_status(mem_fd, bit_mask, bit_num, brief, interrupt, translate, pioc_num); } if (mem_fd >= 0) close(mem_fd); return res; }