#include #include #include #include #include #include #include #include #define SYSFS_GPIO_DIR "/sys/class/gpio" #define MAX_BUF 64 //#define DEBUG_ENABLE 0 //debug 1 #define DEFAULT_MD_LEN 128 #define PAGE_SIZE 0x1000 #define PAGE_SIZE_MASK (~(0xfff)) int debug; typedef struct tag_MMAP_Node { unsigned long Start_P; unsigned long Start_V; unsigned long length; unsigned long refcount; struct tag_MMAP_Node * next; }TMMAP_Node_t; TMMAP_Node_t * pTMMAPNode = NULL; int fd = -1; const char dev[]="/dev/mem"; jmp_buf *sigbus_jmp; // global /**************************************************************** * signal_handler ****************************************************************/ void signal_handler (int sig) { if (sig == SIGBUS) { //printf("signal_handler SIGBUS!\n"); if(sigbus_jmp) siglongjmp(*sigbus_jmp, 1); // no one to catch the error, so abort abort(); } } /**************************************************************** * set_handle ****************************************************************/ int set_handler() { struct sigaction act; memset (&act, 0, sizeof(act)); act.sa_sigaction = (void *)signal_handler; act.sa_flags = SA_SIGINFO; if (sigaction(SIGBUS, &act, 0)) { perror ("sigaction"); return -1; } return 0; } /**************************************************************** * memmap ****************************************************************/ void * memmap(unsigned long phy_addr, unsigned long size) { unsigned long phy_addr_in_page; unsigned long page_diff; unsigned long size_in_page; unsigned long value = 0; TMMAP_Node_t * pTmp; TMMAP_Node_t * pNew; void *addr=NULL; if(size == 0) { printf("memmap():size can't be zero!\n"); return NULL; } /* check if the physical memory space have been mmaped */ pTmp = pTMMAPNode; while(pTmp != NULL) { if( (phy_addr >= pTmp->Start_P) && ( (phy_addr + size) <= (pTmp->Start_P + pTmp->length) ) ) { pTmp->refcount++; /* referrence count increase by 1 */ return (void *)(pTmp->Start_V + phy_addr - pTmp->Start_P); } pTmp = pTmp->next; } /* not mmaped yet */ if(fd < 0) { /* dev not opened yet, so open it */ fd = open (dev, O_RDONLY); if(fd < 0) { printf("memmap():open %s error!\n", dev); return NULL; } } /* addr align in page_size(4K) */ phy_addr_in_page = phy_addr & PAGE_SIZE_MASK; page_diff = phy_addr - phy_addr_in_page; /* size in page_size */ size_in_page =((size + page_diff - 1) & PAGE_SIZE_MASK) + PAGE_SIZE; addr = mmap((void *)0, size_in_page, PROT_READ, MAP_SHARED, fd, phy_addr_in_page); if(addr == MAP_FAILED) { printf("memmap():mmap @ 0x%x error!\n", phy_addr_in_page); return NULL; } /* add this mmap to MMAP Node */ pNew = (TMMAP_Node_t *)malloc(sizeof(TMMAP_Node_t)); if(NULL == pNew) { printf("memmap():malloc new node failed!\n"); return NULL; } pNew->Start_P = phy_addr_in_page; pNew->Start_V = (unsigned long)addr; pNew->length = size_in_page; pNew->refcount = 1; pNew->next = NULL; if(pTMMAPNode == NULL) { pTMMAPNode = pNew; } else { pTmp = pTMMAPNode; while(pTmp->next != NULL) { pTmp = pTmp->next; } pTmp->next = pNew; } return (void *)(addr+page_diff); } /**************************************************************** * GetValueRegister ****************************************************************/ unsigned long GetValueRegister(unsigned long adress) { void *pMem = NULL; unsigned long value = -1; jmp_buf sigbus_jmpbuf; sigbus_jmp = &sigbus_jmpbuf; if(sigsetjmp(sigbus_jmpbuf, 1) == 0) { pMem = memmap(adress,DEFAULT_MD_LEN); if (pMem == NULL) { printf("memmap failed!\n"); return -1; } value = *(unsigned int*)pMem; } return value; } /**************************************************************** * parse_int ****************************************************************/ unsigned long parse_int (char *str) { long long result; char *endptr; result = strtoll(str, &endptr, 0); if (str == '\0' || *endptr != '\0') { fprintf(stderr, "\"%s\" is not a valid number\n", str); exit(EXIT_FAILURE); } return (unsigned long)result; } /**************************************************************** * gpio_get_value ****************************************************************/ int gpio_get_value(unsigned int gpio, unsigned long *value) { int fd, len; char buf[MAX_BUF]; char ch; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); fd = open(buf, O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("gpio/get-value"); return fd; } read(fd, &ch, 1); if (ch != '0') { *value = 1; } else { *value = 0; } close(fd); return 0; } /**************************************************************** * gpio_get_dir ****************************************************************/ int gpio_get_dir(unsigned int gpio, unsigned long *value) { int fd, len, i; char buf[MAX_BUF]; char ch[5]; len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio); fd = open(buf, O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("gpio/direction"); return fd; } i = read(fd, ch, 5); ch[i] = 0; if(!strncmp("in",ch,2)){*value = 0;} else if(!strncmp("out",ch,2)){*value = 1;} else {*value = -1;} close(fd); return 0; } /**************************************************************** * check_run ****************************************************************/ void check_run(unsigned char *runsh, int chkbit, int chkstat, int chkdirect) { if (chkbit==chkstat) { if(debug) { if (chkdirect==1) {printf("Direction: Output\n");} else {printf("Direction: Input\n");} printf("Check Level:%d Current Level:%d\n",chkstat,chkbit); printf("Run Script: %s\n", runsh);} system (runsh); } else if (chkstat==-1) { if(debug) { if (chkdirect==1) {printf("Direction: Output\n");} else {printf("Direction: Input\n");} printf("Check Level:%d Current Level:%d\n",chkstat,chkbit); printf("Run Script: %s\n", runsh);} system (runsh); } } /****************************************************************************** * show usage ******************************************************************************/ void show_sage(char *sPrgNm, int usgc) { const char gpiou[]="Usage : %s GPIO(gpioN) Status(on|off|both) 'Programm_run'.\n"; const char memu[]="Usage : %s GPIO_Base GPIO_Offset GPIO_Group GPIO_Bit Status(on|off|both) 'Programm_run'.\n"; switch (usgc) { case 1: printf(memu,sPrgNm); break; case 2: printf(gpiou,sPrgNm); break; default: printf(memu,sPrgNm); printf(gpiou,sPrgNm); exit(EXIT_FAILURE); } } //************************************************************ //************************************************************ //************************************************************ /**************************************************************** * main ****************************************************************/ int main(int argc, char *argv[]) { unsigned int gpio; int sfs = 0; char *stat = NULL; char *cmd = NULL; unsigned long GPIO_Base, GPIO_Offset; unsigned long adress = 0; unsigned long direct = 0; unsigned long value = 0; unsigned long OldValue= 0; int GPIO_Group, GPIO_Bit, old_bit, new_bit, status; if(set_handler()==-1) { printf("Set handler Error!\n"); return 0; } if ( (argc < 2)) { show_sage(argv[0], 0); exit(EXIT_FAILURE); } debug = (argv[0][strlen(argv[0])-1])- '0'; //debug ON if ((debug) == 1){ printf("Debug ON!\n"); } if ((sscanf (argv[1], "gpio%d", &gpio) == 1) || (!strncmp("gpio",argv[1],4))) { if (argc != 4) { show_sage(argv[0], 2); exit(EXIT_FAILURE);} sfs = 1; stat = malloc(strlen(argv[2])); strcpy(stat, argv[2]); //Status_on|off|both cmd = malloc(strlen(argv[3])); strcpy(cmd, argv[3]); //Programm_run gpio_get_value(gpio, &OldValue); //Save current value } else { if (argc != 7) { show_sage(argv[0], 1); exit(EXIT_FAILURE);} GPIO_Base=parse_int(argv[1]); //GPIO_Base GPIO_Offset=parse_int(argv[2]); //GPIO_Offset GPIO_Group=atoi(argv[3]); //GPIO_Group GPIO_Bit = atoi(argv[4]); //GPIO_Bit stat = malloc(strlen(argv[5])); strcpy(stat, argv[5]); //Status_on|off|both cmd = malloc(strlen(argv[6])); strcpy(cmd, argv[6]); //Programm_run } //Status if(!strcmp("on",stat)){status = 1;} //on = 1 else if(!strcmp("off",stat)){status = 0;} //off = 0 else if(!strcmp("both",stat)){status = -1;} //both = -1 (The script is executed twice) else {status = -1;} while(1) { if (sfs == 0) { adress=GPIO_Base+(GPIO_Group*GPIO_Offset)+0x3fc; value = GetValueRegister(adress); } else { gpio_get_value(gpio, &value); } if(OldValue!=value) { if (sfs == 0){ old_bit = (OldValue>>GPIO_Bit)&1; new_bit = (value>>GPIO_Bit)&1; if(old_bit!=new_bit) { adress=GPIO_Base+(GPIO_Group*GPIO_Offset)+0x400; direct = GetValueRegister(adress); direct = (direct>>GPIO_Bit)&1; adress=GPIO_Base+(GPIO_Group*GPIO_Offset)+(1<