| #include "lynq-irq.h" |
| #include "mbtk_type.h" |
| #include "mbtk_info_api.h" |
| #include "mbtk_log.h" |
| |
| |
| #include <ctype.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <pthread.h> |
| |
| #define _GNU_SOURCE |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <poll.h> |
| |
| #include <sys/ioctl.h> |
| #include <sys/stat.h> |
| #include <sys/sysmacros.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| |
| struct libirq_info { |
| unsigned int line; |
| unsigned int type; |
| int wake; |
| int fd; |
| irq_handler handler; |
| unsigned int used; |
| }; |
| |
| struct libirq_context { |
| unsigned int inited; |
| int fd; |
| pthread_t th; |
| struct libirq_info info[SC_LIBIRQ_MAX]; |
| }; |
| static struct libirq_context irq_ctx = {0}; |
| |
| #define irq_init() irq_ctx.inited |
| #define line_used(l) irq_ctx.info[l].used |
| #define irq_fd(l) irq_ctx.info[l].fd |
| #define libirq_fd() irq_ctx.fd |
| |
| static void *libirq_loop(void *arg) |
| { |
| unsigned int int_status = 0; |
| int fd = libirq_fd(); |
| int ret = 0; |
| int i; |
| |
| while(1) { |
| ret = ioctl(fd, SC_IRQ_GET_STATUS, &int_status); |
| if (ret < 0) { |
| LOGE("libirq_loop get status failed:%d", ret); |
| } else { |
| /* printf("libirq_loop get status :0x%x\n", int_status); */ |
| } |
| |
| for (i=0; i<SC_LIBIRQ_MAX; i++) { |
| if ((int_status & (1<<i)) && line_used(i) && irq_ctx.info[i].handler) { |
| irq_ctx.info[i].handler(); |
| |
| ret = ioctl(fd, SC_IRQ_CLEAR_STATUS, 0); |
| if (ret < 0) { |
| LOGE("libirq_loop clear status failed:%d", ret); |
| } |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static int libirq_init_thread(void) |
| { |
| int ret = 0; |
| pthread_attr_t attribute; |
| |
| pthread_attr_init(&attribute); |
| pthread_attr_setstacksize(&attribute, 32*1024); |
| |
| ret = pthread_create(&irq_ctx.th, &attribute, libirq_loop, NULL); |
| if(ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Add a handler for an interrupt line. |
| * |
| * line : The interrupt line |
| * handler : Function to be called when the IRQ occurs. |
| * trig_type : rising edge or fallling edge |
| * |
| * return 0 if succeed, others failed |
| */ |
| int sc_irq_install(unsigned int line, irq_handler handler, int trig_type) |
| { |
| int fd; |
| struct libirq_info *info; |
| char *usr_name; |
| int ret = 0; |
| |
| if ((line >= SC_LIBIRQ_MAX) || (handler == NULL) || (trig_type >= SC_LIBIRQ_TYPE_MAX)) |
| return -EINVAL; |
| |
| if (line_used(line)) |
| return -EEXIST; |
| |
| ret = asprintf(&usr_name, "%s%d", SC_IRQ_DEV, line); |
| if (ret < 0) { |
| return -ENOMEM; |
| } |
| |
| fd = open(usr_name, O_RDWR); |
| if(fd < 0) { |
| free(usr_name); |
| return -ENODEV; |
| } |
| irq_fd(line) = fd; |
| free(usr_name); |
| info = &irq_ctx.info[line]; |
| info->line = line; |
| info->type = trig_type; |
| info->handler = handler; |
| |
| if (ioctl(fd, SC_IRQ_INSTALL, trig_type) < 0) { |
| return -EPERM; |
| } |
| |
| line_used(line) = 1; |
| |
| if (!irq_init()) { |
| ret = libirq_init_thread(); |
| if (ret) { |
| LOGE("libirq_init_thread, err:%d", ret); |
| return ret; |
| } |
| |
| libirq_fd() = fd; |
| irq_init() = 1; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * free an interrupt allocated with sc_irq_install. |
| * |
| * line : The interrupt line |
| * |
| * return 0 if succeed, others failed |
| */ |
| int sc_irq_uninstall(unsigned int line) |
| { |
| int fd; |
| |
| if (line >= SC_LIBIRQ_MAX) |
| return -EINVAL; |
| |
| if (!line_used(line)) |
| return -ENODEV; |
| |
| if (ioctl(irq_fd(line), SC_IRQ_UNINSTALL, 0) < 0) { |
| return -EPERM; |
| } |
| |
| fd = libirq_fd(); |
| if (fd) |
| close(fd); |
| |
| line_used(line) = 0; |
| |
| return 0; |
| } |
| |
| /* |
| * set the irq trigger type for an irq. |
| * |
| * line : The interrupt line |
| * trig_type : edge or level type |
| * |
| * return 0 if succeed, others failed |
| */ |
| int sc_irq_set_type(unsigned int line, int trig_type) |
| { |
| struct libirq_info *info; |
| |
| if ((line >= SC_LIBIRQ_MAX) || (trig_type >= SC_LIBIRQ_TYPE_MAX)) |
| return -EINVAL; |
| |
| if (!line_used(line)) |
| return -EEXIST; |
| |
| info = &irq_ctx.info[line]; |
| if (info->type != trig_type) { |
| if (ioctl(irq_fd(line), SC_IRQ_SET_TYPE, trig_type) < 0) { |
| return -EPERM; |
| } |
| } |
| |
| info->type = trig_type; |
| |
| return 0; |
| } |
| |
| /* |
| * get the irq trigger type for an irq. |
| * |
| * line : The interrupt line |
| * trig_type : edge or level type |
| * |
| * return 0 if succeed, others failed |
| */ |
| int sc_irq_get_type(unsigned int line, int *trig_type) |
| { |
| struct libirq_info *info; |
| |
| if ((line >= SC_LIBIRQ_MAX) || !trig_type) |
| return -EINVAL; |
| |
| if (!line_used(line)) |
| return -EEXIST; |
| |
| info = &irq_ctx.info[line]; |
| *trig_type = info->type; |
| |
| return 0; |
| } |
| |
| /* |
| * control irq power management wakeup. |
| * |
| * line : The interrupt line |
| * en : enable/disable power management wakeup |
| * |
| * return 0 if succeed, others failed |
| */ |
| int sc_irq_set_wake(unsigned int line, int en) |
| { |
| struct libirq_info *info; |
| |
| if (line >= SC_LIBIRQ_MAX) |
| return -EINVAL; |
| |
| if (!line_used(line)) |
| return -EEXIST; |
| |
| info = &irq_ctx.info[line]; |
| if (info->wake != en) { |
| if (ioctl(irq_fd(line), SC_IRQ_SET_WAKE, en) < 0) { |
| return -EPERM; |
| } |
| } |
| |
| info->wake = en; |
| |
| return 0; |
| } |
| |
| /* |
| * get the irq awake status for an irq. |
| * |
| * line : The interrupt line |
| * en : enable/disable power management wakeup |
| * |
| * return 0 if succeed, others failed |
| */ |
| int sc_irq_get_wake(unsigned int line, int *en) |
| { |
| struct libirq_info *info; |
| unsigned int wake; |
| |
| if (line >= SC_LIBIRQ_MAX) |
| return -EINVAL; |
| |
| if (!line_used(line)) |
| return -EEXIST; |
| |
| if (ioctl(irq_fd(line), SC_IRQ_GET_WAKE, &wake) < 0) { |
| return -EPERM; |
| } |
| |
| info = &irq_ctx.info[line]; |
| info->wake = wake; |
| *en = wake; |
| |
| return 0; |
| } |
| |
| |
| |
| |
| /***************************************** |
| * @brief:lynq_irq_install |
| * @param count [IN]:2 |
| * @param sum [OUT]:NA |
| * @return :success 0, failed other |
| * @todo:NA |
| * @see:NA |
| * @warning:NA |
| ******************************************/ |
| |
| int lynq_irq_install(int line, irq_handler irq_test_handler, trig_type_e trig_type) |
| { |
| int ret; |
| if(trig_type < 0) |
| { |
| return -1; |
| } |
| #if defined(MBTK_PROJECT_T108) |
| |
| if (trig_type != 0 && trig_type != 1) |
| { |
| LOGE("lynq_irq_install error trig_type:%d", trig_type); |
| return -1; |
| } |
| |
| line = line-117; |
| |
| if (line < 0) |
| { |
| LOGE("lynq_irq_install error line:%d", line); |
| return -1; |
| } |
| |
| #endif |
| |
| ret = sc_irq_install(line, irq_test_handler, trig_type); |
| if (ret != 0) |
| { |
| LOGE("do_install_irq failed, ret:%d", ret); |
| return ret; |
| } |
| return 0; |
| } |
| |
| |
| /***************************************** |
| * @brief:lynq_irq_uninstall |
| * @param count [IN]:2 |
| * @param sum [OUT]:NA |
| * @return :success 0, failed other |
| * @todo:NA |
| * @see:NA |
| * @warning:NA |
| ******************************************/ |
| |
| int lynq_irq_uninstall(int line) |
| { |
| #if defined(MBTK_PROJECT_T108) |
| line = line-117; |
| #endif |
| |
| int ret; |
| ret = sc_irq_uninstall(line); |
| if (ret != 0) |
| { |
| LOGE("unistall failed, ret:%d", ret); |
| return ret; |
| } |
| LOGI("uninstall irq(%d) ok", line); |
| return 0; |
| } |
| |
| |
| /***************************************** |
| * @brief:lynq_irq_set_type |
| * @param count [IN]:2 |
| * @param sum [OUT]:NA |
| * @return :success 0, failed other |
| * @todo:NA |
| * @see:NA |
| * @warning:NA |
| ******************************************/ |
| int lynq_irq_set_type(int line, int trig_type) |
| { |
| #if defined(MBTK_PROJECT_T108) |
| line = line-117; |
| |
| if (trig_type != 0 && trig_type != 1) |
| { |
| LOGE("lynq_irq_set_type error trig_type:%d", trig_type); |
| return -1; |
| } |
| #endif |
| |
| int ret; |
| if(trig_type < 0) |
| { |
| return -1; |
| } |
| ret = sc_irq_set_type(line, trig_type); |
| if (ret != 0) |
| { |
| LOGE("set_type failed, ret:%d", ret); |
| return ret; |
| } |
| return 0; |
| |
| } |
| |
| /***************************************** |
| * @brief:lynq_irq_get_type |
| * @param count [IN]:1 |
| * @param sum [OUT]:NA |
| * @return :success >= 0, failed other |
| * @todo:NA |
| * @see:NA |
| * @warning:NA |
| ******************************************/ |
| int lynq_irq_get_type(int line) |
| { |
| #if defined(MBTK_PROJECT_T108) |
| line = line-117; |
| #endif |
| |
| int ret; |
| int trig_type; |
| ret = sc_irq_get_type(line, &trig_type); |
| if (ret != 0) |
| { |
| LOGE("get_type failed, ret:%d", ret); |
| return ret; |
| } |
| LOGI("get_type readback(%d)", trig_type); |
| return trig_type; |
| } |
| |
| |
| /***************************************** |
| * @brief:lynq_irq_set_wake |
| * @param count [IN]:2 |
| * @param sum [OUT]:NA |
| * @return :success 0, failed other |
| * @todo:NA |
| * @see:NA |
| * @warning:NA |
| ******************************************/ |
| int lynq_irq_set_wake(int line, int en) |
| { |
| #if defined(MBTK_PROJECT_T108) |
| line = line-117; |
| #endif |
| |
| int ret; |
| if((en != 0) && (en != 1)) |
| { |
| LOGE("wake_state is not 0 or 1"); |
| return -1; |
| } |
| |
| ret = sc_irq_set_wake(line, en); |
| if (ret != 0) |
| { |
| LOGE("set_wake failed, ret:%d", ret); |
| return ret; |
| } |
| return 0; |
| } |
| |
| /***************************************** |
| * @brief:lynq_irq_get_wake |
| * @param count [IN]:1 |
| * @param sum [OUT]:NA |
| * @return :success >= 0, failed other |
| * @todo:NA |
| * @see:NA |
| * @warning:NA |
| ******************************************/ |
| int lynq_irq_get_wake(int line) |
| { |
| #if defined(MBTK_PROJECT_T108) |
| line = line-117; |
| #endif |
| |
| int ret; |
| int en; |
| ret = sc_irq_get_wake(line, &en); |
| if (ret != 0) |
| { |
| LOGE("get_wake failed, ret:%d", ret); |
| return ret; |
| } |
| |
| LOGI("get_wake readback(%d)", en); |
| return en; |
| } |
| |
| |
| |