//以下是学习完韦东山老师视屏教程后所做学习记录
中断方式取得按键值:
 #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h> static struct class *thirddrv_class;
static struct class_device *thirddrv_class_dev; volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat; volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
static volatile int ev_press = ; struct pin_desc{
unsigned int pin;
unsigned int key_val;
}; /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val; struct pin_desc pins_desc[] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
}; /*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
struct pin_desc * pindesc = (struct pin_desc *)dev_id;
unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval)
{
/* 松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按下 */
key_val = pindesc->key_val;
} ev_press = ; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_RETVAL(IRQ_HANDLED);
} static int third_drv_open(struct inode *inode, struct file *file)
{
/* 配置GPF0,2为输入引脚 */
/* 配置GPG3,11为输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[]);
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[]);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[]);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[]); return ;
} ssize_t third_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
if (size != )
return -EINVAL; /* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press); /* 如果有按键动作, 返回键值 */
copy_to_user(buf, &key_val, );
ev_press = ; return ;
} int third_drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, &pins_desc[]);
free_irq(IRQ_EINT2, &pins_desc[]);
free_irq(IRQ_EINT11, &pins_desc[]);
free_irq(IRQ_EINT19, &pins_desc[]);
return ;
} static struct file_operations sencod_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_close,
}; int major;
static int third_drv_init(void)
{
major = register_chrdev(, "third_drv", &sencod_drv_fops); thirddrv_class = class_create(THIS_MODULE, "third_drv"); thirddrv_class_dev = class_device_create(thirddrv_class, NULL, MKDEV(major, ), NULL, "buttons"); /* /dev/buttons */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, );
gpfdat = gpfcon + ; gpgcon = (volatile unsigned long *)ioremap(0x56000060, );
gpgdat = gpgcon + ; return ;
} static void third_drv_exit(void)
{
unregister_chrdev(major, "third_drv");
class_device_unregister(thirddrv_class_dev);
class_destroy(thirddrv_class);
iounmap(gpfcon);
iounmap(gpgcon);
return ;
} module_init(third_drv_init); module_exit(third_drv_exit); MODULE_LICENSE("GPL");

driver Code

测试用例:

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> /* thirddrvtest
*/
int main(int argc, char **argv)
{
int fd;
unsigned char key_val; fd = open("/dev/buttons", O_RDWR);
if (fd < )
{
printf("can't open!\n");
} while ()
{
read(fd, &key_val, );
printf("key_val = 0x%x\n", key_val);
} return ;
}

drvtest Code

以上是采用中断方式的写法。

下面学习了poll机制后,做了改进:

drv Code

测试用例如下:

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h> /* forthdrvtest
*/
int main(int argc, char **argv)
{
int fd;
unsigned char key_val;
int ret; struct pollfd fds[]; fd = open("/dev/buttons", O_RDWR);
if (fd < )
{
printf("can't open!\n");
} fds[].fd = fd;
fds[].events = POLLIN;
while ()
{
ret = poll(fds, , );
if (ret == )
{
printf("time out\n");
}
else
{
read(fd, &key_val, );
printf("key_val = 0x%x\n", key_val);
}
} return ;
}

drvtest view

小总结:

  查询方式:消耗资源,高达90%以上

  中断:read()

  poll:指定超时时间

都是应用程序主动去读。

下面通过异步通知来改进。

先做一个简单的测试

 #include <stdio.h>
#include <signal.h>
void my_signal_fun(int signum)
{
static int cnt = ;
printf("signal = %d,%d times",signum,++cnt);
} int main(int argc,char *argv)
{
signal(SIGUSR1,my_signal_fun);
while()
{
sleep();
}
return ;
}

signal Code

要点:  1.注册一个信号处理函数

     2.谁发?发给谁?怎么发?

目标:按下按键是,驱动程序通知应用程序,

    1、应用程序要注册信号处理函数。

    2、驱动程序发信号给应用程序  (应用程序要告诉驱动PID号)

    3、怎么发?

用到signal、fcntl

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h> static struct class *fifthdrv_class;
static struct class_device *fifthdrv_class_dev; volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat; volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /* 中断事件标志, 中断服务程序将它置1,fifth_drv_read将它清0 */
static volatile int ev_press = ; static struct fasync_struct *button_async; struct pin_desc{
unsigned int pin;
unsigned int key_val;
}; /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val; struct pin_desc pins_desc[] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
}; /*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
struct pin_desc * pindesc = (struct pin_desc *)dev_id;
unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval)
{
/* 松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按下 */
key_val = pindesc->key_val;
} ev_press = ; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ kill_fasync (&button_async, SIGIO, POLL_IN); return IRQ_RETVAL(IRQ_HANDLED);
} static int fifth_drv_open(struct inode *inode, struct file *file)
{
/* 配置GPF0,2为输入引脚 */
/* 配置GPG3,11为输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[]);
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[]);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[]);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[]); return ;
} ssize_t fifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
if (size != )
return -EINVAL; /* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press); /* 如果有按键动作, 返回键值 */
copy_to_user(buf, &key_val, );
ev_press = ; return ;
} int fifth_drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, &pins_desc[]);
free_irq(IRQ_EINT2, &pins_desc[]);
free_irq(IRQ_EINT11, &pins_desc[]);
free_irq(IRQ_EINT19, &pins_desc[]);
return ;
} static unsigned fifth_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = ;
poll_wait(file, &button_waitq, wait); // 不会立即休眠 if (ev_press)
mask |= POLLIN | POLLRDNORM; return mask;
} static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: fifth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
} static struct file_operations sencod_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = fifth_drv_open,
.read = fifth_drv_read,
.release = fifth_drv_close,
.poll = fifth_drv_poll,
.fasync = fifth_drv_fasync,
}; int major;
static int fifth_drv_init(void)
{
major = register_chrdev(, "fifth_drv", &sencod_drv_fops); fifthdrv_class = class_create(THIS_MODULE, "fifth_drv"); fifthdrv_class_dev = class_device_create(fifthdrv_class, NULL, MKDEV(major, ), NULL, "buttons"); /* /dev/buttons */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, );
gpfdat = gpfcon + ; gpgcon = (volatile unsigned long *)ioremap(0x56000060, );
gpgdat = gpgcon + ; return ;
} static void fifth_drv_exit(void)
{
unregister_chrdev(major, "fifth_drv");
class_device_unregister(fifthdrv_class_dev);
class_destroy(fifthdrv_class);
iounmap(gpfcon);
iounmap(gpgcon);
return ;
} module_init(fifth_drv_init); module_exit(fifth_drv_exit); MODULE_LICENSE("GPL");

driver Code

测试用例:

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h> /* fifthdrvtest
*/
int fd; void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, );
printf("key_val: 0x%x\n", key_val);
} int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags; signal(SIGIO, my_signal_fun); fd = open("/dev/buttons", O_RDWR);
if (fd < )
{
printf("can't open!\n");
} fcntl(fd, F_SETOWN, getpid()); Oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, Oflags | FASYNC); while ()
{
sleep();
} return ;
}

drvtest code

fcntl(fd, F_SETOWN, getpid());   //告诉内核,发给谁

Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC); //改变fasync标记,最终会调用驱动的faync>faync_helper : 初始化/释放fasync_struct

目前,我们这个按键驱动程序已经较完善。

现在我们想让这个驱动同一时间只有一个app可以打开。

如果用一个变量来控制的话,会存在漏洞,分析:

linux是一个多任务的系统,修改一个值的时候有三个过程:1、读出;2、修改;3、写回

修改代码不是一个原子操作,引入原子变量。

笔记如下:

1. 原子操作
原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
常用原子操作函数举例:
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
atomic_read(atomic_t *v); //返回原子变量的值
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。

2. 信号量
信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。
当获取不到信号量时,进程进入休眠等待状态。

定义信号量
struct semaphore sem;
初始化信号量
void sema_init (struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem);//初始化为0

static DECLARE_MUTEX(button_lock); //定义互斥锁

获得信号量
void down(struct semaphore * sem);
int down_interruptible(struct semaphore * sem);
int down_trylock(struct semaphore * sem);
释放信号量
void up(struct semaphore * sem);

3. 阻塞
阻塞操作
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。

fd = open("...", O_RDWR | O_NONBLOCK);

加上按键防抖动就完美:

 #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h> static struct class *sixthdrv_class;
static struct class_device *sixthdrv_class_dev; volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat; volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat; static struct timer_list buttons_timer; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
static volatile int ev_press = ; static struct fasync_struct *button_async; struct pin_desc{
unsigned int pin;
unsigned int key_val;
}; /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val; struct pin_desc pins_desc[] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
}; static struct pin_desc *irq_pd; //static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1 static DECLARE_MUTEX(button_lock); //定义互斥锁 /*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 10ms后启动定时器 */
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/);
return IRQ_RETVAL(IRQ_HANDLED);
} static int sixth_drv_open(struct inode *inode, struct file *file)
{
#if 0
if (!atomic_dec_and_test(&canopen))
{
atomic_inc(&canopen);
return -EBUSY;
}
#endif if (file->f_flags & O_NONBLOCK)
{
if (down_trylock(&button_lock))
return -EBUSY;
}
else
{
/* 获取信号量 */
down(&button_lock);
} /* 配置GPF0,2为输入引脚 */
/* 配置GPG3,11为输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[]);
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[]);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[]);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[]); return ;
} ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
if (size != )
return -EINVAL; if (file->f_flags & O_NONBLOCK)
{
if (!ev_press)
return -EAGAIN;
}
else
{
/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);
} /* 如果有按键动作, 返回键值 */
copy_to_user(buf, &key_val, );
ev_press = ; return ;
} int sixth_drv_close(struct inode *inode, struct file *file)
{
//atomic_inc(&canopen);
free_irq(IRQ_EINT0, &pins_desc[]);
free_irq(IRQ_EINT2, &pins_desc[]);
free_irq(IRQ_EINT11, &pins_desc[]);
free_irq(IRQ_EINT19, &pins_desc[]);
up(&button_lock);
return ;
} static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = ;
poll_wait(file, &button_waitq, wait); // 不会立即休眠 if (ev_press)
mask |= POLLIN | POLLRDNORM; return mask;
} static int sixth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: sixth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
} static struct file_operations sencod_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = sixth_drv_open,
.read = sixth_drv_read,
.release = sixth_drv_close,
.poll = sixth_drv_poll,
.fasync = sixth_drv_fasync,
}; int major; static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval; if (!pindesc)
return; pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval)
{
/* 松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按下 */
key_val = pindesc->key_val;
} ev_press = ; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ kill_fasync (&button_async, SIGIO, POLL_IN);
} static int sixth_drv_init(void)
{
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
//buttons_timer.expires = 0;
add_timer(&buttons_timer); major = register_chrdev(, "sixth_drv", &sencod_drv_fops); sixthdrv_class = class_create(THIS_MODULE, "sixth_drv"); /* 为了让mdev根据这些信息来创建设备节点 */
sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, ), NULL, "buttons"); /* /dev/buttons */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, );
gpfdat = gpfcon + ; gpgcon = (volatile unsigned long *)ioremap(0x56000060, );
gpgdat = gpgcon + ; return ;
} static void sixth_drv_exit(void)
{
unregister_chrdev(major, "sixth_drv");
class_device_unregister(sixthdrv_class_dev);
class_destroy(sixthdrv_class);
iounmap(gpfcon);
iounmap(gpgcon);
return ;
} module_init(sixth_drv_init); module_exit(sixth_drv_exit); MODULE_LICENSE("GPL");

driver Code

测试程序:

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h> /* sixthdrvtest
*/
int fd; void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, );
printf("key_val: 0x%x\n", key_val);
} int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags; //signal(SIGIO, my_signal_fun); fd = open("/dev/buttons", O_RDWR);
if (fd < )
{
printf("can't open!\n");
return -;
} //fcntl(fd, F_SETOWN, getpid()); //Oflags = fcntl(fd, F_GETFL); //fcntl(fd, F_SETFL, Oflags | FASYNC); while ()
{
ret = read(fd, &key_val, );
printf("key_val: 0x%x, ret = %d\n", key_val, ret);
//sleep(5);
} return ;
}

驱动:

linux-2.6内核驱动学习——jz2440之按键的更多相关文章

  1. linux-2.6内核驱动学习——jz2440之输入子系统

    如果按照上一篇记录的那样,只有本公司的人或者自己才能使用驱动.想写出一个通用的驱动程序,让其他应用程序来无缝移植,需要使用现成的驱动——输入子系统. /drivers/input/input.c #d ...

  2. Linux内核驱动学习(八)GPIO驱动模拟输出PWM

    文章目录 前言 原理图 IO模拟输出PWM 设备树 驱动端 调试信息 实验结果 附录 前言 上一篇的学习中介绍了如何在用户空间直接操作GPIO,并写了一个脚本可以产生PWM.本篇的学习会将写一个驱动操 ...

  3. linux内核驱动学习指南

    1. 参考链接 小白的博客 ONE_Tech 你为什么看不懂Linux内核驱动源码? 求教怎么学习linux内核驱动

  4. Linux内核驱动学习(六)GPIO之概览

    文章目录 前言 功能 如何使用 设备树 API 总结 前言 GPIO(General Purpose Input/Output)通用输入/输出接口,是十分灵活软件可编程的接口,功能强大,十分常用,SO ...

  5. Linux内核驱动学习(三)字符型设备驱动之初体验

    Linux字符型设备驱动之初体验 文章目录 Linux字符型设备驱动之初体验 前言 框架 字符型设备 程序实现 cdev kobj owner file_operations dev_t 设备注册过程 ...

  6. Linux内核驱动学习(十)Input子系统详解

    文章目录 前言 框架 如何实现`input device` 设备驱动? 头文件 注册input_dev设备 上报按键值 dev->open()和dev->close() 其他事件类型,处理 ...

  7. Linux内核驱动学习(九)GPIO外部输入的处理

    文章目录 前言 设备树 两个结构体 gpio_platform_data gpio_demo_device 两种方式 轮询 外部中断 总结 附录 前言 前面是如何操作GPIO进行输出,这里我重新实现了 ...

  8. Linux内核驱动学习(一)编写最简单Linux内核模块HelloWorld

    文章目录 准备工作 什么是内核模块 编写 hello.c 模块编译 相关指令 测试结果 模块加载 模块卸载 准备工作 在进行以下操作前,首先我准备了一台电脑,并且安装了虚拟机,系统是Ubuntu16. ...

  9. Linux内核驱动学习(七)应用层直接操作GPIO

    文章目录 简介 原理图 节点 设置为输出 设置为输入 映射关系 debugfs pwm demo 简介 前面通过libgpio的方式介绍了内核空间对GPIO进行操作的接口,其做了较好的封装,同时Lin ...

随机推荐

  1. 多张报表导出到一个多sheet页excel

     业务需求: 通过勾选不同的报表名称,然后直接执行导出excel.并且这些报表需要统一导入到一个excel的多个sheet页中,并且对某些报表可能需要增加一些类似'已审核'之类的图片(展现时并没有 ...

  2. android 每个块半径不同的扇形图,自定义view

    1.首先看效果图 2.自定义PieChartView,继承自View,下边为PieChartView代码 package com.yingjinbao.im.peach.customview; imp ...

  3. frame shiro 认证示例及原理简述

    shiro 认证流程 1.创建一个 javaSE 的maven项目(quickstart),并添加依赖 <dependency> <groupId>junit</grou ...

  4. CentOS6.4 下安装 jdk1.7.0_67

    1.卸载系统自带的jdk 1.1.查看该操作系统上是否已经安装了jdk [root@xhTest-1 ~]# rpm -qa | grep jdk 1.2.删除系统自带的jdk [root@xhTes ...

  5. [C# | WinCE | Solution] 在 WinCE 上访问 SSL 加密后的 WCF SOAP 服务接口出现“未能与远程服务器建立信任关系”

    Scenario: 服务器的 SOAP 使用了 GeoTrust 签名的 EV 证书,WinCE调用时出现“未能与远程服务器建立信任关系”的错误.原因是该 WinCE 设备信任的证书包括 Global ...

  6. 使用Github的高级搜索功能

    使用Github的高级搜索功能 1. 首先,提供Github高级搜索帮助页面 https://help.github.com/categories/search/ 2. 搜索语法 https://he ...

  7. AD用户登录验证,遍历OU(LDAP)

    先安装python-ldap模块 1.验证AD用户登录是否成功 import sqlite3,ldap domainname='cmr\\' username='zhangsan' ldapuser ...

  8. 铁乐学python-面向对象的更多说明

    以下内容摘自授课老师的博客http://www.cnblogs.com/Eva-J/ 面向对象的更多说明 面向对象的软件开发 很多人在学完了python的class机制之后,遇到一个生产中的问题,还是 ...

  9. Android点击事件

    Android点击事件 备注 全局实现View.OnClickListener 或许需要将MainActivity设置为public 注册事件 btn_login.setOnClickListener ...

  10. Centos7 教程收集ing

    CentOS7 常用命令集合 https://blog.csdn.net/o0darknessyy0o/article/details/52072054#t1 1.centOS7下实践查询版本/CPU ...