Linux Kernel 原始碼有一個 list.h , 它位於 linux/list.h . 它不只是在 kernel 可以使用, 在 linux user space 下也可以使用, 甚至於是 windows programming 也可以使用. 因為蠻好用的, 所以我把它介紹出來. 筆者會提供一個不錯的範例程式來介紹 list.h 裡面的 inline 函式 (巨集) 的使用方法; 這些 inline 函式 (巨集) 包括了:
1. INIT_LIST_HEAD(ptr);
2. void list_add_tail(struct list_head *neu, struct list_head *head);
3. void list_del(struct list_head *entry);
4. list_for_each_safe(pos, n, head)
5. list_entry(ptr, type, member)
思考步驟:
I. 首先你當然必須要 include "list.h" .
II. Global 變數 pl; 它是一個 list. 它是一個包含 struct list_head list 成員的結構. 另一個成員是 unsigned char c;
static struct pool_t {
struct list_head list;
unsigned char c;
} pl;
III. 在一切還未開始之前 呼叫
INIT_LIST_HEAD(&pl.list);
IV. 範例裡面包含了一個 Producer 執行緒 (main) 以及一個 Consumer 執行緒 (emit) . Producer 執行緒首先 allocate 一個 node (struct pool_t) ; 第2步是填上 node, e->c=ch; 第3步是將這個 node 使用 list_add_tail() 插入 pl 這個 list 的尾巴.
e = (struct pool_t *)malloc(sizeof(struct pool_t)); e->c = ch;
list_add_tail(&e->list, &pl.list);
V. Consumer 執行緒則是使用 list_for_each_safe() 巨集將 pl 裡面的每一個 node 拷貝出; 之後使用 list_del() 取出 (pop out) ; 最後是 free Producer allocate 之 memory. 注意: 在這裡一定要使用 list_for_each_safe() 而不能使用 list_for_each() , 原因是 我們在這個迴圈中使用了 list_del() .
n = 0;
list_for_each_safe(pos, q, &pl.list) {
e = list_entry(pos, struct pool_t, list);
memcpy(&buffer[n++], &e->c, sizeof(unsigned char));
list_del(pos)
free(e);
}
poolEmpty = 1;
VI. Threads 存取同一個 linked list 當然需要同步機制. 因此我們宣告 cPoolEmpty 條件變數, mPoolEmpty 互斥子以及 poolEmpty這個用來說明條件變數是否為真之 Predication.
static pthread_cond_t cPoolEmpty;
static int poolEmpty = 1;
static pthread_mutex_t mPoolEmpty = PTHREAD_MUTEX_INITIALIZER;
VII. Consumer 執行緒當然是靜靜地等待 Producer 執行緒的通知.
WAIT:
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
while (poolEmpty) pthread_cond_wait(&cPoolEmpty, &mPoolEmpty);
pthread_cleanup_pop(1);
VIII. Consumer 執行緒被喚醒之後:
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
n = 0;
list_for_each_safe(pos, q, &pl.list) {
e = list_entry(pos, struct pool_t, list); memcpy(&buffer[n++], &e->c, sizeof(unsigned char)); list_del(pos), free(e);
}
poolEmpty = 1;
pthread_cleanup_pop(1);
VIIII. 當 pl 不是 empty 時, Producer 執行緒 TELL Consumer 執行緒.
TELL_WAIT:
poolEmpty = 0; pthread_cond_signal(&cPoolEmpty);
e = (struct pool_t *)malloc(sizeof(struct pool_t));
memcpy(&e->c, &ch, sizeof(ch));
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
list_add_tail(&e->list, &pl.list);
poolEmpty = 0; pthread_cond_signal(&cPoolEmpty);
pthread_cleanup_pop(1);
範例
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <sys/mount.h> // for mount
#include <fcntl.h>
#include <signal.h>
#include <netinet/tcp.h>
#include <inttypes.h>
#include <sched.h>
#include <assert.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <termios.h>
#include <poll.h>
#include <linux/uinput.h>
#include <linux/input-event-codes.h>
#include <pthread.h>
struct pool_t {
struct list_head list;
unsigned char c;
};
static struct pool_t pl;
static pthread_t tEmit = 0;
static pthread_cond_t cPoolEmpty;
static int poolEmpty = 1;
static pthread_mutex_t mPoolEmpty = PTHREAD_MUTEX_INITIALIZER;
#define TTY_SERIAL "/dev/ttyMK0"
#define SELECT_EXPIRY_NINISECONDS 100ULL
#define ACTION_DOWN 1
#define ACTION_UP 0
#define _u1_ 0
#define _d1_ 1
#define _l1_ 2
#define _r1_ 3
#define _s1_ 4
#define _x1_ 5
#define _y1_ 6
#define _z1_ 7
#define _a1_ 8
#define _b1_ 9
#define _c1_ 10
#define _u2_ 11
#define _d2_ 12
#define _l2_ 13
#define _r2_ 14
#define _s2_ 15
#define _x2_ 16
#define _y2_ 17
#define _z2_ 18
#define _a2_ 19
#define _b2_ 20
#define _c2_ 21
#define _m_ 22
#define _w_ 23
#define _U1_ (1 << _u1_)
#define _D1_ (1 << _d1_)
#define _L1_ (1 << _l1_)
#define _R1_ (1 << _r1_)
#define _S1_ (1 << _s1_)
#define _X1_ (1 << _x1_)
#define _Y1_ (1 << _y1_)
#define _Z1_ (1 << _z1_)
#define _A1_ (1 << _a1_)
#define _B1_ (1 << _b1_)
#define _C1_ (1 << _c1_)
#define _U2_ (1 << _u2_)
#define _D2_ (1 << _d2_)
#define _L2_ (1 << _l2_)
#define _R2_ (1 << _r2_)
#define _S2_ (1 << _s2_)
#define _X2_ (1 << _x2_)
#define _Y2_ (1 << _y2_)
#define _Z2_ (1 << _z2_)
#define _A2_ (1 << _a2_)
#define _B2_ (1 << _b2_)
#define _C2_ (1 << _c2_)
#define _M_ (1 << _m_)
#define _W_ (1 << _w_)
struct code_t {
int index; int code; const char *name;
};
static struct code_t keypad_codes[] = {
{_u1_, KEY_UP, "P1_UP"},
{_d1_, KEY_DOWN, "P1_DW"},
{_l1_, KEY_LEFT, "P1_LF"},
{_r1_, KEY_RIGHT, "P1_RG"},
{_s1_, KEY_ENTER, "P1_ST"},
{_x1_, KEY_X, "P1_X "},
{_y1_, KEY_Y, "P1_Y "},
{_z1_, KEY_Z, "P1_Z "},
{_a1_, KEY_A, "P1_A "},
{_b1_, KEY_B, "P1_B "},
{_c1_, KEY_C, "P1_C "},
{_u2_, KEY_KP8, "P2_UP"},
{_d2_, KEY_KP2, "P2_DW"},
{_l2_, KEY_KP4, "P2_LF"},
{_r2_, KEY_KP6, "P2_RG"},
{_s2_, KEY_SPACE, "P2_ST"},
{_x2_, KEY_F4, "P2_X "},
{_y2_, KEY_F5, "P2_Y "},
{_z2_, KEY_F6, "P2_Z "},
{_a2_, KEY_F1, "P2_A "},
{_b2_, KEY_F8, "P2_B "},
{_c2_, KEY_F3, "P2_C "},
{_m_, KEY_M, "MD"},
{_w_, KEY_R, "RW"},
};
#define KEYPAD_KEYNUMBER (sizeof(keypad_codes)/sizeof(struct code_t))
static unsigned int uartNowEvents = 0;
static int uinputfd = -1;
static int ttyfd = -1;
static char ttyLine[1024] = {0};
static int ttyLineLength = 0;
#define PRINTF(f_, ...) \
sprintf(ttyLine, f_, ##__VA_ARGS__), \
ttyLineLength = strlen(ttyLine), \
ttyLine[ttyLineLength] = 0, \
write(ttyfd, (void *)ttyLine, ttyLineLength + 1)
static void emit(int fd, int type, int code, int val) {
struct input_event ie = {0};
ie.type = type; ie.code = code; ie.value = val;
write(fd, &ie, sizeof(ie));
}
static void CleanupLock(void *param) {
pthread_mutex_unlock((pthread_mutex_t *)param);
}
static void *EmitThread(void *param) {
unsigned char ch;
struct pool_t *e; // entry
struct list_head *pos, *q;
unsigned char buffer[1024 * 4] = {0};
int n = 0, i = 0;
/////////////////////////////
// Wait for somebody tell
WAIT:
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
while (poolEmpty) pthread_cond_wait(&cPoolEmpty, &mPoolEmpty);
pthread_cleanup_pop(1);
/////////////////////////////
// <need-fast>
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
n = 0;
list_for_each_safe(pos, q, &pl.list) {
e = list_entry(pos, struct pool_t, list); memcpy(&buffer[n++], &e->c, sizeof(unsigned char)); list_del(pos), free(e);
}
poolEmpty = 1;
pthread_cleanup_pop(1);
// </need-fast>
for (i = 0; i < n; i++) {
ch = buffer[i];
if (ch == (unsigned char)'U') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_DOWN);
if (ch == (unsigned char)'u') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_UP);
if (ch == (unsigned char)'D') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_DOWN);
if (ch == (unsigned char)'d') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_UP);
if (ch == (unsigned char)'L') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_DOWN);
if (ch == (unsigned char)'l') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_UP);
if (ch == (unsigned char)'R') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_DOWN);
if (ch == (unsigned char)'r') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_UP);
if (ch == (unsigned char)'S') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_DOWN);
if (ch == (unsigned char)'s') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_UP);
if (ch == (unsigned char)'X') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_DOWN);
if (ch == (unsigned char)'x') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_UP);
if (ch == (unsigned char)'Y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_DOWN);
if (ch == (unsigned char)'y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_UP);
if (ch == (unsigned char)'Z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_DOWN);
if (ch == (unsigned char)'z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_UP);
if (ch == (unsigned char)'A') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_DOWN);
if (ch == (unsigned char)'a') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_UP);
if (ch == (unsigned char)'B') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_DOWN);
if (ch == (unsigned char)'b') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_UP);
if (ch == (unsigned char)'C') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_DOWN);
if (ch == (unsigned char)'c') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_UP);
if (ch == (unsigned char)'H') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_DOWN);
if (ch == (unsigned char)'h') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_UP);
if (ch == (unsigned char)'I') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_DOWN);
if (ch == (unsigned char)'i') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_UP);
if (ch == (unsigned char)'J') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_DOWN);
if (ch == (unsigned char)'j') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_UP);
if (ch == (unsigned char)'K') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_DOWN);
if (ch == (unsigned char)'k') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_UP);
if (ch == (unsigned char)'T') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_DOWN);
if (ch == (unsigned char)'t') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_UP);
if (ch == (unsigned char)'O') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_DOWN);
if (ch == (unsigned char)'o') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_UP);
if (ch == (unsigned char)'P') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_DOWN);
if (ch == (unsigned char)'p') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_UP);
if (ch == (unsigned char)'Q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_DOWN);
if (ch == (unsigned char)'q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_UP);
if (ch == (unsigned char)'G') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_DOWN);
if (ch == (unsigned char)'g') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_UP);
if (ch == (unsigned char)'E') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_DOWN);
if (ch == (unsigned char)'e') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_UP);
if (ch == (unsigned char)'F') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_DOWN);
if (ch == (unsigned char)'f') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_UP);
if (ch == (unsigned char)'M') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_DOWN);
if (ch == (unsigned char)'m') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_UP);
if (ch == (unsigned char)'W') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_DOWN);
if (ch == (unsigned char)'w') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_UP);
emit(uinputfd, EV_SYN, SYN_REPORT, 0);
/////////////////////////////
//
usleep(1);
}
goto WAIT;
return 0;
}
static void onUartChar(unsigned char ch) {
struct pool_t *e;
if (ch != (unsigned char)'u' && ch != (unsigned char)'U' &&
ch != (unsigned char)'d' && ch != (unsigned char)'D' &&
ch != (unsigned char)'l' && ch != (unsigned char)'L' &&
ch != (unsigned char)'r' && ch != (unsigned char)'R' &&
ch != (unsigned char)'s' && ch != (unsigned char)'S' &&
ch != (unsigned char)'x' && ch != (unsigned char)'X' &&
ch != (unsigned char)'y' && ch != (unsigned char)'Y' &&
ch != (unsigned char)'z' && ch != (unsigned char)'Z' &&
ch != (unsigned char)'a' && ch != (unsigned char)'A' &&
ch != (unsigned char)'b' && ch != (unsigned char)'B' &&
ch != (unsigned char)'c' && ch != (unsigned char)'C' &&
ch != (unsigned char)'h' && ch != (unsigned char)'H' &&
ch != (unsigned char)'i' && ch != (unsigned char)'I' &&
ch != (unsigned char)'j' && ch != (unsigned char)'J' &&
ch != (unsigned char)'k' && ch != (unsigned char)'K' &&
ch != (unsigned char)'t' && ch != (unsigned char)'T' &&
ch != (unsigned char)'o' && ch != (unsigned char)'O' &&
ch != (unsigned char)'p' && ch != (unsigned char)'P' &&
ch != (unsigned char)'q' && ch != (unsigned char)'Q' &&
ch != (unsigned char)'g' && ch != (unsigned char)'G' &&
ch != (unsigned char)'e' && ch != (unsigned char)'E' &&
ch != (unsigned char)'f' && ch != (unsigned char)'F' &&
ch != (unsigned char)'m' && ch != (unsigned char)'M' &&
ch != (unsigned char)'w' && ch != (unsigned char)'W'
) return;
if (ch == (unsigned char)'u') { uartNowEvents &= ~_U1_; goto TELL_WAIT; }
if (ch == (unsigned char)'d') { uartNowEvents &= ~_D1_; goto TELL_WAIT; }
if (ch == (unsigned char)'l') { uartNowEvents &= ~_L1_; goto TELL_WAIT; }
if (ch == (unsigned char)'r') { uartNowEvents &= ~_R1_; goto TELL_WAIT; }
if (ch == (unsigned char)'s') { uartNowEvents &= ~_S1_; goto TELL_WAIT; }
if (ch == (unsigned char)'x') { uartNowEvents &= ~_X1_; goto TELL_WAIT; }
if (ch == (unsigned char)'y') { uartNowEvents &= ~_Y1_; goto TELL_WAIT; }
if (ch == (unsigned char)'z') { uartNowEvents &= ~_Z1_; goto TELL_WAIT; }
if (ch == (unsigned char)'a') { uartNowEvents &= ~_A1_; goto TELL_WAIT; }
if (ch == (unsigned char)'b') { uartNowEvents &= ~_B1_; goto TELL_WAIT; }
if (ch == (unsigned char)'c') { uartNowEvents &= ~_C1_; goto TELL_WAIT; }
if (ch == (unsigned char)'U') { uartNowEvents |= _U1_; goto TELL_WAIT; }
if (ch == (unsigned char)'D') { uartNowEvents |= _D1_; goto TELL_WAIT; }
if (ch == (unsigned char)'L') { uartNowEvents |= _L1_; goto TELL_WAIT; }
if (ch == (unsigned char)'R') { uartNowEvents |= _R1_; goto TELL_WAIT; }
if (ch == (unsigned char)'S') { uartNowEvents |= _S1_; goto TELL_WAIT; }
if (ch == (unsigned char)'X') { uartNowEvents |= _X1_; goto TELL_WAIT; }
if (ch == (unsigned char)'Y') { uartNowEvents |= _Y1_; goto TELL_WAIT; }
if (ch == (unsigned char)'Z') { uartNowEvents |= _Z1_; goto TELL_WAIT; }
if (ch == (unsigned char)'A') { uartNowEvents |= _A1_; goto TELL_WAIT; }
if (ch == (unsigned char)'B') { uartNowEvents |= _B1_; goto TELL_WAIT; }
if (ch == (unsigned char)'C') { uartNowEvents |= _C1_; goto TELL_WAIT; }
if (ch == (unsigned char)'h') { uartNowEvents &= ~_U2_; goto TELL_WAIT; }
if (ch == (unsigned char)'i') { uartNowEvents &= ~_D2_; goto TELL_WAIT; }
if (ch == (unsigned char)'j') { uartNowEvents &= ~_L2_; goto TELL_WAIT; }
if (ch == (unsigned char)'k') { uartNowEvents &= ~_R2_; goto TELL_WAIT; }
if (ch == (unsigned char)'t') { uartNowEvents &= ~_S2_; goto TELL_WAIT; }
if (ch == (unsigned char)'o') { uartNowEvents &= ~_X2_; goto TELL_WAIT; }
if (ch == (unsigned char)'p') { uartNowEvents &= ~_Y2_; goto TELL_WAIT; }
if (ch == (unsigned char)'q') { uartNowEvents &= ~_Z2_; goto TELL_WAIT; }
if (ch == (unsigned char)'g') { uartNowEvents &= ~_A2_; goto TELL_WAIT; }
if (ch == (unsigned char)'e') { uartNowEvents &= ~_B2_; goto TELL_WAIT; }
if (ch == (unsigned char)'f') { uartNowEvents &= ~_C2_; goto TELL_WAIT; }
if (ch == (unsigned char)'H') { uartNowEvents |= _U2_; goto TELL_WAIT; }
if (ch == (unsigned char)'I') { uartNowEvents |= _D2_; goto TELL_WAIT; }
if (ch == (unsigned char)'J') { uartNowEvents |= _L2_; goto TELL_WAIT; }
if (ch == (unsigned char)'K') { uartNowEvents |= _R2_; goto TELL_WAIT; }
if (ch == (unsigned char)'T') { uartNowEvents |= _S2_; goto TELL_WAIT; }
if (ch == (unsigned char)'O') { uartNowEvents |= _X2_; goto TELL_WAIT; }
if (ch == (unsigned char)'P') { uartNowEvents |= _Y2_; goto TELL_WAIT; }
if (ch == (unsigned char)'Q') { uartNowEvents |= _Z2_; goto TELL_WAIT; }
if (ch == (unsigned char)'G') { uartNowEvents |= _A2_; goto TELL_WAIT; }
if (ch == (unsigned char)'E') { uartNowEvents |= _B2_; goto TELL_WAIT; }
if (ch == (unsigned char)'F') { uartNowEvents |= _C2_; goto TELL_WAIT; }
if (ch == (unsigned char)'m') { uartNowEvents &= ~_M_; goto TELL_WAIT; }
if (ch == (unsigned char)'w') { uartNowEvents &= ~_W_; goto TELL_WAIT; }
if (ch == (unsigned char)'M') { uartNowEvents |= _M_; goto TELL_WAIT; }
if (ch == (unsigned char)'W') { uartNowEvents |= _W_; goto TELL_WAIT; }
TELL_WAIT:
e = (struct pool_t *)malloc(sizeof(struct pool_t));
memcpy(&e->c, &ch, sizeof(ch));
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
list_add_tail(&e->list, &pl.list);
poolEmpty = 0; pthread_cond_signal(&cPoolEmpty);
pthread_cleanup_pop(1);
return;
}
int main (int argc, char **argv) {
struct termios term, save;
int res, v, maxfd = 0;
fd_set rset;
struct timeval tv;
struct timespec start_time, now_time;
unsigned long long int start, now;
struct uinput_user_dev uidev = {0};
int i = 0;
char line[512];
uinputfd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (0 > uinputfd) exit(1);
if (ioctl(uinputfd, UI_SET_EVBIT, EV_KEY) < 0) exit(2);
for (i = 0; i < KEYPAD_KEYNUMBER; i++) {
if (ioctl(uinputfd, UI_SET_KEYBIT, keypad_codes[i].code) < 0)
exit(3);
}
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-serial");
uidev.id.bustype = BUS_VIRTUAL, uidev.id.vendor = 0x1, uidev.id.product = 0x1, uidev.id.version = 1;
if (write(uinputfd, &uidev, sizeof(uidev)) < 0) exit(4);
if(ioctl(uinputfd, UI_DEV_CREATE) < 0) exit(5);
sleep(1);
ttyfd = open(TTY_SERIAL, O_RDWR | O_NOCTTY | O_NDELAY);
if (0 > ttyfd) exit(6);
memset(&term, 0, sizeof(struct termios));
if (0 > tcgetattr(ttyfd, &term)) close(ttyfd), ttyfd = -1, exit(7);
memcpy((void *)&save, (void *)&term, sizeof(struct termios));
term.c_cflag |= B115200, term.c_cflag |= CLOCAL, term.c_cflag |= CREAD, term.c_cflag &= ~PARENB, term.c_cflag &= ~CSTOPB;
term.c_cflag &= ~CSIZE, term.c_cflag |= CS8, term.c_iflag = IGNPAR, term.c_cc[VMIN] = 1, term.c_cc[VTIME] = 0;
term.c_iflag = 0, term.c_oflag = 0, term.c_lflag = 0;
cfsetispeed(&term, B115200), cfsetospeed(&term, B115200);
if (0 > tcsetattr(ttyfd, TCSANOW, &term)) close(ttyfd), ttyfd = -1, exit(8);
if (0 > (v = fcntl(ttyfd, F_GETFL, 0))) close(ttyfd), ttyfd = -1, exit(9);
if (0 > fcntl(ttyfd, F_SETFL, v | O_NONBLOCK)) close(ttyfd), ttyfd = -1, exit(10);
if (0 > tcflush(ttyfd, TCIFLUSH)) close(ttyfd), ttyfd = -1, exit(11);
clock_gettime(CLOCK_MONOTONIC, &start_time);
start = start_time.tv_sec * 1000 + start_time.tv_nsec / 1000000;
INIT_LIST_HEAD(&pl.list);
pthread_cond_init(&cPoolEmpty, NULL);
pthread_create(&tEmit, NULL, EmitThread, 0);
for (;;) {
FD_ZERO(&rset);
FD_SET(ttyfd, &rset);
maxfd = 0;
if (maxfd < ttyfd) maxfd = ttyfd;
memset(&tv, 0, sizeof(tv));
tv.tv_sec = SELECT_EXPIRY_NINISECONDS / 1000;
tv.tv_usec = (SELECT_EXPIRY_NINISECONDS % 1000) * 1000;
//res = select(maxfd + 1, &rset, 0, 0, &tv);
res = select(maxfd + 1, &rset, 0, 0, 0);
if (0 > res) close(ttyfd), ttyfd = -1, exit(12);
if (0 == res) continue;
if (FD_ISSET(ttyfd, &rset)) {
clock_gettime(CLOCK_MONOTONIC, &now_time);
now = now_time.tv_sec * 1000 + now_time.tv_nsec / 1000000;
res = read(ttyfd, (void *)line, sizeof(line));
if (0 >= res) close(ttyfd), ttyfd = -1, exit(13);
for (i = 0; i < res; i++) {
onUartChar(line[i]);
}
if (now - start >= SELECT_EXPIRY_NINISECONDS) {
}
}
}
tcsetattr(ttyfd, TCSANOW, &save);
close(ttyfd), ttyfd = -1;
sleep(1);
ioctl(uinputfd, UI_DEV_DESTROY);
close(uinputfd), uinputfd = -1;
return 0;
}
- list.h
-
#ifndef __LIST_H #define __LIST_H /* This file is from Linux Kernel (include/linux/list.h) * and modified by simply removing hardware prefetching of list items. * Here by copyright, credits attributed to wherever they belong. * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu) */ /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *neu, struct list_head *prev, struct list_head *next) { next->prev = neu; neu->next = next; neu->prev = prev; prev->next = neu; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *neu, struct list_head *head) { __list_add(neu, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *neu, struct list_head *head) { __list_add(neu, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); //entry->next = (void *) 0; //entry->prev = (void *) 0; entry->next = 0; entry->prev = 0; } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif
list.h 可以用於 C++ 嗎?
list.h 可以用於 C++ 嗎? 可以, 但需要修改 new 這個關鍵字. 以下是筆者修改之後的版本. 關鍵字 new 改為 neu .
#ifndef __LIST_H
#define __LIST_H
/* This file is from Linux Kernel (include/linux/list.h)
* and modified by simply removing hardware prefetching of list items.
* Here by copyright, credits attributed to wherever they belong.
* Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu)
*/
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *neu,
struct list_head *prev,
struct list_head *next)
{
next->prev = neu;
neu->next = next;
neu->prev = prev;
prev->next = neu;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *neu, struct list_head *head)
{
__list_add(neu, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *neu, struct list_head *head)
{
__list_add(neu, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
//entry->next = (void *) 0;
//entry->prev = (void *) 0;
entry->next = 0;
entry->prev = 0;
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif
Email: jasonc@mail2000.com.tw . 請尊重原創, 使用圖文時載明出處. 謝謝.
-
(Finished)
