锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <mach/irqs.h>
#include <mach/regs-gpio.h>
#include "../ioctl_new.h"
static spinlock_t wiegand_lock;
static int wiegand_in = 0;
static int wiegand_in_cur = 0;
static int wiegand_in_stime = 0;
static int wiegand_in1_stime = 0;
static int wiegand_in2_stime = 0;
static unsigned char wiegand_data[40];
static WIEGAND_TYPE wiegand_mode;
inline void wiegand_delay(int microseconds)
{
int i;
while (microseconds--)
{
for (i=0; i<65; i++) __asm("NOP");
}
}
static int wiegand_gettickcount(void)
{
static int __start_time = 0; //second
struct timeval tv;
do_gettimeofday(&tv);
if (__start_time == 0)
__start_time = tv.tv_sec;
return ((tv.tv_sec - __start_time) * 1000 + tv.tv_usec / 1000);
}
inline void wiegand_minus_interrupt(void)
{
if (wiegand_in != WGNSTAT_RECVFULL)
{
if (wiegand_gettickcount() - wiegand_in_stime >= 100)
wiegand_in_cur = 0;
wiegand_in_stime = wiegand_gettickcount();
wiegand_data[wiegand_in_cur++] = 0;
if (wiegand_in_cur >= 34)
wiegand_in = WGNSTAT_RECVFULL;
else if (wiegand_in_cur >= 26)
wiegand_in = WGNSTAT_RECV26;
}
}
inline void wiegand_plus_interrupt(void)
{
if (wiegand_in != WGNSTAT_RECVFULL)
{
if (wiegand_gettickcount() - wiegand_in_stime >= 100)
wiegand_in_cur = 0;
wiegand_in_stime = wiegand_gettickcount();
wiegand_data[wiegand_in_cur++] = 1;
if (wiegand_in_cur >= 34)
wiegand_in = WGNSTAT_RECVFULL;
else if (wiegand_in_cur >= 26)
wiegand_in = WGNSTAT_RECV26;
}
}
static irqreturn_t wiegand_minus1_interrupt(int irq, void *dev_id)
{
spin_lock(&wiegand_lock);
// printk("wiegand_minus1_interrupt\n");
if (wiegand_gettickcount() - wiegand_in2_stime > 200)
{
wiegand_minus_interrupt();
wiegand_in1_stime = wiegand_in_stime;
}
spin_unlock(&wiegand_lock);
return IRQ_HANDLED;
}
static irqreturn_t wiegand_plus1_interrupt(int irq, void *dev_id)
{
spin_lock(&wiegand_lock);
// printk("wiegand_plus1_interrupt\n");
if (wiegand_gettickcount() - wiegand_in2_stime > 200)
{
wiegand_plus_interrupt();
wiegand_in1_stime = wiegand_in_stime;
}
spin_unlock(&wiegand_lock);
return IRQ_HANDLED;
}
static int wiegand_open(struct inode * inode, struct file * filp);
static int wiegand_release(struct inode * inode,struct file * filp);
static ssize_t wiegand_read(struct file *flip, char *buf, size_t len, loff_t *pos);
static ssize_t wiegand_write(struct file *flip, const char *buf, size_t len, loff_t *pos);
static long wiegand_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static struct file_operations wiegand_fops = {
owner: THIS_MODULE,
open: wiegand_open,
release: wiegand_release,
read: wiegand_read,
write: wiegand_write,
unlocked_ioctl: wiegand_ioctl,
};
static struct miscdevice wiegand_dev = {
WIEGAND_MINOR,
WIEGAND_MODULE_NAME,
&wiegand_fops
};
static void config_wiegand_pins(void)
{
s3c2410_gpio_cfgpin(WGNIN_0, WGNIN_0_CON);
s3c2410_gpio_cfgpin(WGNIN_1, WGNIN_1_CON);
s3c2410_gpio_cfgpin(WGNOUT0, WGNOUT0_CON);
s3c2410_gpio_cfgpin(WGNOUT1, WGNOUT1_CON);
#if 0
if (request_irq(WGNIN_0_IRQ_NUM, &wiegand_minus1_interrupt,
IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
WIEGAND_IRQ_MINUS,
&wiegand_dev)
|| request_irq(WGNIN_1_IRQ_NUM, &wiegand_plus1_interrupt,
IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
WIEGAND_IRQ_PLUS,
&wiegand_dev))
{
printk("WIEGAND request_irq Fail\n");
}
#endif
}
static int wiegand_open(struct inode * inode, struct file * filp)
{
config_wiegand_pins();
return 0;
}
static int wiegand_release(struct inode * inode,struct file * filp)
{
#if 0
free_irq(WGNIN_0_IRQ_NUM, &wiegand_dev);
free_irq(WGNIN_1_IRQ_NUM, &wiegand_dev);
#endif
return 0;
}
static ssize_t wiegand_read(struct file *flip, char *buf, size_t len, loff_t *pos)
{
int result;
spin_lock(&wiegand_lock);
if (wiegand_in == WGNSTAT_NONE || len > sizeof(wiegand_data) || (wiegand_gettickcount() - wiegand_in_stime > 1800)) //500
{
wiegand_in = WGNSTAT_NONE;
spin_unlock(&wiegand_lock);
return 0;
}
if (len > wiegand_in_cur)
len = wiegand_in_cur;
result = copy_to_user(buf, wiegand_data, len);
wiegand_in = WGNSTAT_NONE;
wiegand_in_cur = 0;
spin_unlock(&wiegand_lock);
return len;
}
static ssize_t wiegand_write(struct file *flip, const char *buf, size_t len, loff_t *pos)
{
int i;
char data[40];
if (len > sizeof(data))
return 0;
i = copy_from_user(data, buf, len);
for (i=0; i<len; i++)
{
if (data[i] == 0)
{
WGNOUT0_1; wiegand_delay(wiegand_mode.dwTpw); WGNOUT0_0;
}
else
{
WGNOUT1_1; wiegand_delay(wiegand_mode.dwTpw); WGNOUT1_0;
}
wiegand_delay(wiegand_mode.dwTpi);
}
return len;
}
static long wiegand_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int result = 0;
spin_lock(&wiegand_lock);
switch(cmd)
{
case WIEGAND_MODE_SET:
result = copy_from_user(&wiegand_mode, (void*)arg, sizeof(WIEGAND_TYPE));
break;
}
spin_unlock(&wiegand_lock);
return (result == sizeof(WIEGAND_TYPE) ? 0 : -1);
}
static int __init s3c2416_wiegand_init(void)
{
int ret = 0;
ret = misc_register(&wiegand_dev);
if (ret)
{
printk("probuck s3c2416 WIEGAND Driver" WIEGAND_DRIVER_VERSION "Fail\n");
goto exit_sb3kt_wiegand_init;
}
spin_lock_init(&wiegand_lock);
printk("probuck s3c2416 WIEGAND Driver" WIEGAND_DRIVER_VERSION "\n");
exit_sb3kt_wiegand_init:
return ret;
}
static void __exit s3c2416_wiegand_cleanup(void)
{
misc_deregister(&wiegand_dev);
}
module_init(s3c2416_wiegand_init);
module_exit(s3c2416_wiegand_cleanup);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("s3c2416 WIEGAND Driver");
MODULE_SUPPORTED_DEVICE("s3c2416 WIEGAND");
]]>
銆銆淇″彿閲忓湪鍒涘緩鏃墮渶瑕佽緗竴涓垵濮嬪鹼紝琛ㄧず鍚屾椂鍙互鏈夊嚑涓換鍔″彲浠ヨ闂淇″彿閲忎繚鎶ょ殑鍏變韓璧勬簮錛屽垵濮嬪間負1灝卞彉鎴愪簰鏂ラ攣錛圡utex錛夛紝鍗沖悓鏃跺彧鑳芥湁涓涓換鍔″彲浠ヨ闂俊鍙烽噺淇濇姢鐨勫叡浜祫婧愩?br />
銆銆涓涓換鍔¤鎯寵闂叡浜祫婧愶紝棣栧厛蹇呴』寰楀埌淇″彿閲忥紝鑾峰彇淇″彿閲忕殑鎿嶄綔灝嗘妸淇″彿閲忕殑鍊煎噺1錛岃嫢褰撳墠淇″彿閲忕殑鍊間負璐熸暟錛岃〃鏄庢棤娉曡幏寰椾俊鍙烽噺錛岃浠誨姟蹇呴』鎸傝搗鍦ㄨ淇″彿閲忕殑絳夊緟闃熷垪絳夊緟璇ヤ俊鍙烽噺鍙敤錛涜嫢褰撳墠淇″彿閲忕殑鍊間負闈炶礋鏁幫紝琛ㄧず鍙互鑾峰緱淇″彿閲忥紝鍥犺屽彲浠ョ珛鍒昏闂璇ヤ俊鍙烽噺淇濇姢鐨勫叡浜祫婧愩?br />
銆銆褰撲換鍔¤闂畬琚俊鍙烽噺淇濇姢鐨勫叡浜祫婧愬悗錛屽繀欏婚噴鏀句俊鍙烽噺錛岄噴鏀句俊鍙烽噺閫氳繃鎶婁俊鍙烽噺鐨勫煎姞1瀹炵幇錛屽鏋滀俊鍙烽噺鐨勫間負闈炴鏁幫紝琛ㄦ槑鏈変換鍔$瓑寰呭綋鍓嶄俊鍙烽噺錛屽洜姝ゅ畠涔熷敜閱掓墍鏈夌瓑寰呰淇″彿閲忕殑浠誨姟銆?br />
淇″彿閲忕殑API鏈夛細
DECLARE_MUTEX(name)
璇ュ畯澹版槑涓涓俊鍙烽噺name騫跺垵濮嬪寲瀹冪殑鍊間負1錛屽嵆澹版槑涓涓簰鏂ラ攣銆?br />
//鍦↙inux2.6.26涓病鎵懼埌璇ュ畯
DECLARE_MUTEX_LOCKED(name)
璇ュ畯澹版槑涓涓簰鏂ラ攣name錛屼絾鎶婂畠鐨勫垵濮嬪艱緗負0錛屽嵆閿佸湪鍒涘緩鏃跺氨澶勫湪宸查攣鐘舵併傚洜姝ゅ浜庤繖縐嶉攣錛屼竴鑸槸鍏堥噴鏀懼悗鑾峰緱銆?br />
void sema_init (struct semaphore *sem, int val);
璇ュ嚱鐢ㄤ簬鏁板垵濮嬪寲璁劇疆淇″彿閲忕殑鍒濆鹼紝瀹冭緗俊鍙烽噺sem鐨勫間負val銆?br />
void init_MUTEX (struct semaphore *sem);
璇ュ嚱鏁扮敤浜庡垵濮嬪寲涓涓簰鏂ラ攣錛屽嵆瀹冩妸淇″彿閲弒em鐨勫艱緗負1銆?br />
void init_MUTEX_LOCKED (struct semaphore *sem);
璇ュ嚱鏁頒篃鐢ㄤ簬鍒濆鍖栦竴涓簰鏂ラ攣錛屼絾瀹冩妸淇″彿閲弒em鐨勫艱緗負0錛屽嵆涓寮濮嬪氨澶勫湪宸查攣鐘舵併?br />
void down(struct semaphore * sem);
璇ュ嚱鏁扮敤浜庤幏寰椾俊鍙烽噺sem錛屽畠浼氬鑷寸潯鐪狅紝鍥犳涓嶈兘鍦ㄤ腑鏂笂涓嬫枃錛堝寘鎷琁RQ涓婁笅鏂囧拰softirq涓婁笅鏂囷級浣跨敤璇ュ嚱鏁般傝鍑芥暟灝嗘妸sem鐨勫煎噺1錛屽鏋滀俊鍙烽噺sem鐨勫奸潪璐燂紝灝辯洿鎺ヨ繑鍥烇紝鍚﹀垯璋冪敤鑰呭皢琚寕璧鳳紝鐩村埌鍒殑浠誨姟閲婃斁璇ヤ俊鍙烽噺鎵嶈兘緇х畫榪愯銆?br />
int down_interruptible(struct semaphore * sem);
璇ュ嚱鏁板姛鑳戒笌down綾諱技錛屼笉鍚屼箣澶勪負錛宒own涓嶄細琚俊鍙鳳紙signal錛夋墦鏂紝浣哾own_interruptible鑳借淇″彿鎵撴柇錛屽洜姝よ鍑芥暟鏈夎繑鍥炲兼潵鍖哄垎鏄甯歌繑鍥炶繕鏄淇″彿涓柇錛屽鏋滆繑鍥?錛岃〃紺鴻幏寰椾俊鍙烽噺姝e父榪斿洖錛屽鏋滆淇″彿鎵撴柇錛岃繑鍥?EINTR銆?br />
int down_trylock(struct semaphore * sem);
璇ュ嚱鏁拌瘯鐫鑾峰緱淇″彿閲弒em錛屽鏋滆兘澶熺珛鍒昏幏寰楋紝瀹冨氨鑾峰緱璇ヤ俊鍙烽噺騫惰繑鍥?錛屽惁鍒欙紝琛ㄧず涓嶈兘鑾峰緱淇″彿閲弒em錛岃繑鍥炲間負闈?鍊箋傚洜姝わ紝瀹冧笉浼氬鑷磋皟鐢ㄨ呯潯鐪狅紝鍙互鍦ㄤ腑鏂笂涓嬫枃浣跨敤銆?br />
void up(struct semaphore * sem);
璇ュ嚱鏁伴噴鏀句俊鍙烽噺sem錛屽嵆鎶妔em鐨勫煎姞1錛屽鏋渟em鐨勫間負闈炴鏁幫紝琛ㄦ槑鏈変換鍔$瓑寰呰淇″彿閲忥紝鍥犳鍞ら啋榪欎簺絳夊緟鑰呫?nbsp;
澶存枃浠?
#include <linux/semaphore.h>
/*
* Copyright (c) 2008 Intel Corporation
* Author: Matthew Wilcox <willy@linux.intel.com>
*
* Distributed under the terms of the GNU GPL, version 2
*
* Please see kernel/semaphore.c for documentation of these functions
*/
#ifndef __LINUX_SEMAPHORE_H
#define __LINUX_SEMAPHORE_H
#include <linux/list.h>
#include <linux/spinlock.h>
/* Please don't access any members of this structure directly */
struct semaphore {
spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
#define __SEMAPHORE_INITIALIZER(name, n) \
{ \
.lock = __SPIN_LOCK_UNLOCKED((name).lock), \
.count = n, \
.wait_list = LIST_HEAD_INIT((name).wait_list), \
}
#define __DECLARE_SEMAPHORE_GENERIC(name, count) \
struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1)
static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}
#define init_MUTEX(sem) sema_init(sem, 1)
#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
extern void down(struct semaphore *sem);
extern int __must_check down_interruptible(struct semaphore *sem);
extern int __must_check down_killable(struct semaphore *sem);
extern int __must_check down_trylock(struct semaphore *sem);
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
extern void up(struct semaphore *sem);
#endif /* __LINUX_SEMAPHORE_H */
]]>
銆銆鑷棆閿佷笌浜掓枼閿佹湁鐐圭被浼鹼紝鍙槸鑷棆閿佷笉浼氬紩璧瘋皟鐢ㄨ呯潯鐪狅紝濡傛灉鑷棆閿佸凡緇忚鍒殑鎵ц鍗曞厓淇濇寔錛岃皟鐢ㄨ呭氨涓鐩村驚鐜湪閭i噷鐪嬫槸鍚﹁鑷棆閿佺殑淇濇寔鑰呭凡緇忛噴鏀句簡閿侊紝"鑷棆"涓璇嶅氨鏄洜姝よ屽緱鍚嶃?br />
銆銆鐢變簬鑷棆閿佷嬌鐢ㄨ呬竴鑸繚鎸侀攣鏃墮棿闈炲父鐭紝鍥犳閫夋嫨鑷棆鑰屼笉鏄潯鐪犳槸闈炲父蹇呰鐨勶紝鑷棆閿佺殑鏁堢巼榪滈珮浜庝簰鏂ラ攣銆?br />
銆銆淇″彿閲忓拰璇誨啓淇″彿閲忛傚悎浜庝繚鎸佹椂闂磋緝闀跨殑鎯呭喌錛屽畠浠細瀵艱嚧璋冪敤鑰呯潯鐪狅紝鍥犳鍙兘鍦ㄨ繘紼嬩笂涓嬫枃浣跨敤錛坃trylock鐨勫彉縐嶈兘澶熷湪涓柇涓婁笅鏂囦嬌鐢級錛岃岃嚜鏃嬮攣閫傚悎浜庝繚鎸佹椂闂撮潪甯哥煭鐨勬儏鍐碉紝瀹冨彲浠ュ湪浠諱綍涓婁笅鏂囦嬌鐢ㄣ?br />
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍙湪榪涚▼涓婁笅鏂囪闂紝浣跨敤淇″彿閲忎繚鎶よ鍏變韓璧勬簮闈炲父鍚堥傦紝濡傛灉瀵瑰叡宸瘋祫婧愮殑璁塊棶鏃墮棿闈炲父鐭紝鑷棆閿佷篃鍙互銆備絾鏄鏋滆淇濇姢鐨勫叡浜祫婧愰渶瑕佸湪涓柇涓婁笅鏂囪闂紙鍖呮嫭搴曞崐閮ㄥ嵆涓柇澶勭悊鍙ユ焺鍜岄《鍗婇儴鍗寵蔣涓柇錛夛紝灝卞繀欏諱嬌鐢ㄨ嚜鏃嬮攣銆?br />
銆銆鑷棆閿佷繚鎸佹湡闂存槸鎶㈠崰澶辨晥鐨勶紝鑰屼俊鍙烽噺鍜岃鍐欎俊鍙烽噺淇濇寔鏈熼棿鏄彲浠ヨ鎶㈠崰鐨勩傝嚜鏃嬮攣鍙湁鍦ㄥ唴鏍稿彲鎶㈠崰鎴朣MP鐨勬儏鍐典笅鎵嶇湡姝i渶瑕侊紝鍦ㄥ崟CPU涓斾笉鍙姠鍗犵殑鍐呮牳涓嬶紝鑷棆閿佺殑鎵鏈夋搷浣滈兘鏄┖鎿嶄綔銆?br />
銆銆璺熶簰鏂ラ攣涓鏍鳳紝涓涓墽琛屽崟鍏冭鎯寵闂鑷棆閿佷繚鎶ょ殑鍏變韓璧勬簮錛屽繀欏誨厛寰楀埌閿侊紝鍦ㄨ闂畬鍏變韓璧勬簮鍚庯紝蹇呴』閲婃斁閿併傚鏋滃湪鑾峰彇鑷棆閿佹椂錛屾病鏈変換浣曟墽琛屽崟鍏冧繚鎸佽閿侊紝閭d箞灝嗙珛鍗沖緱鍒伴攣錛涘鏋滃湪鑾峰彇鑷棆閿佹椂閿佸凡緇忔湁淇濇寔鑰咃紝閭d箞鑾峰彇閿佹搷浣滃皢鑷棆鍦ㄩ偅閲岋紝鐩村埌璇ヨ嚜鏃嬮攣鐨勪繚鎸佽呴噴鏀句簡閿併?br />
銆銆鏃犺鏄簰鏂ラ攣錛岃繕鏄嚜鏃嬮攣錛屽湪浠諱綍鏃跺埢錛屾渶澶氬彧鑳芥湁涓涓繚鎸佽咃紝涔熷氨璇達紝鍦ㄤ換浣曟椂鍒繪渶澶氬彧鑳芥湁涓涓墽琛屽崟鍏冭幏寰楅攣銆?br />
鑷棆閿佺殑API鏈夛細
spin_lock_init(x)
璇ュ畯鐢ㄤ簬鍒濆鍖栬嚜鏃嬮攣x銆傝嚜鏃嬮攣鍦ㄧ湡姝d嬌鐢ㄥ墠蹇呴』鍏堝垵濮嬪寲銆傝瀹忕敤浜庡姩鎬佸垵濮嬪寲銆?br />
DEFINE_SPINLOCK(x)
璇ュ畯澹版槑涓涓嚜鏃嬮攣x騫跺垵濮嬪寲瀹冦傝瀹忓湪2.6.11涓涓嬈¤瀹氫箟錛屽湪鍏堝墠鐨勫唴鏍鎬腑騫舵病鏈夎瀹忋?br />
SPIN_LOCK_UNLOCKED
璇ュ畯鐢ㄤ簬闈欐佸垵濮嬪寲涓涓嚜鏃嬮攣銆?br />
DEFINE_SPINLOCK(x)絳夊悓浜巗pinlock_t x = SPIN_LOCK_UNLOCKED
spin_is_locked(x)
璇ュ畯鐢ㄤ簬鍒ゆ柇鑷棆閿亁鏄惁宸茬粡琚煇鎵ц鍗曞厓淇濇寔錛堝嵆琚攣錛夛紝濡傛灉鏄紝榪斿洖鐪燂紝鍚﹀垯榪斿洖鍋囥?br />
spin_unlock_wait(x)
璇ュ畯鐢ㄤ簬絳夊緟鑷棆閿亁鍙樺緱娌℃湁琚換浣曟墽琛屽崟鍏冧繚鎸侊紝濡傛灉娌℃湁浠諱綍鎵ц鍗曞厓淇濇寔璇ヨ嚜鏃嬮攣錛岃瀹忕珛鍗寵繑鍥烇紝鍚﹀垯灝嗗驚鐜湪閭i噷錛岀洿鍒拌鑷棆閿佽淇濇寔鑰呴噴鏀俱?br />
spin_trylock(lock)
璇ュ畯灝藉姏鑾峰緱鑷棆閿乴ock錛屽鏋滆兘绔嬪嵆鑾峰緱閿侊紝瀹冭幏寰楅攣騫惰繑鍥炵湡錛屽惁鍒欎笉鑳界珛鍗寵幏寰楅攣錛岀珛鍗寵繑鍥炲亣銆傚畠涓嶄細鑷棆絳夊緟lock琚噴鏀俱?br />
spin_lock(lock)
璇ュ畯鐢ㄤ簬鑾峰緱鑷棆閿乴ock錛屽鏋滆兘澶熺珛鍗寵幏寰楅攣錛屽畠灝遍┈涓婅繑鍥烇紝鍚﹀垯錛屽畠灝嗚嚜鏃嬪湪閭i噷錛岀洿鍒拌鑷棆閿佺殑淇濇寔鑰呴噴鏀撅紝榪欐椂錛屽畠鑾峰緱閿佸茍榪斿洖銆傛諱箣錛屽彧鏈夊畠鑾峰緱閿佹墠榪斿洖銆?br />
spin_lock_irqsave(lock, flags)
璇ュ畯鑾峰緱鑷棆閿佺殑鍚屾椂鎶婃爣蹇楀瘎瀛樺櫒鐨勫間繚瀛樺埌鍙橀噺flags涓茍澶辨晥鏈湴涓柇銆?br />
spin_lock_irq(lock)
璇ュ畯綾諱技浜巗pin_lock_irqsave錛屽彧鏄瀹忎笉淇濆瓨鏍囧織瀵勫瓨鍣ㄧ殑鍊箋?br />
spin_lock_bh(lock)
璇ュ畯鍦ㄥ緱鍒拌嚜鏃嬮攣鐨勫悓鏃跺け鏁堟湰鍦拌蔣涓柇銆?br />
spin_unlock(lock)
璇ュ畯閲婃斁鑷棆閿乴ock錛屽畠涓巗pin_trylock鎴杝pin_lock閰嶅浣跨敤銆傚鏋渟pin_trylock榪斿洖鍋囷紝琛ㄦ槑娌℃湁鑾峰緱鑷棆閿侊紝鍥犳涓嶅繀浣跨敤spin_unlock閲婃斁銆?br />
spin_unlock_irqrestore(lock, flags)
璇ュ畯閲婃斁鑷棆閿乴ock鐨勫悓鏃訛紝涔熸仮澶嶆爣蹇楀瘎瀛樺櫒鐨勫間負鍙橀噺flags淇濆瓨鐨勫箋傚畠涓巗pin_lock_irqsave閰嶅浣跨敤銆?br />
spin_unlock_irq(lock)
璇ュ畯閲婃斁鑷棆閿乴ock鐨勫悓鏃訛紝涔熶嬌鑳芥湰鍦頒腑鏂傚畠涓巗pin_lock_irq閰嶅搴旂敤銆?br />
spin_unlock_bh(lock)
璇ュ畯閲婃斁鑷棆閿乴ock鐨勫悓鏃訛紝涔熶嬌鑳芥湰鍦扮殑杞腑鏂傚畠涓巗pin_lock_bh閰嶅浣跨敤銆?br />
spin_trylock_irqsave(lock, flags)
璇ュ畯濡傛灉鑾峰緱鑷棆閿乴ock錛屽畠涔熷皢淇濆瓨鏍囧織瀵勫瓨鍣ㄧ殑鍊煎埌鍙橀噺flags涓紝騫朵笖澶辨晥鏈湴涓柇錛屽鏋滄病鏈夎幏寰楅攣錛屽畠浠涔堜篃涓嶅仛銆?br />銆銆鍥犳濡傛灉鑳藉绔嬪嵆鑾峰緱閿侊紝瀹冪瓑鍚屼簬spin_lock_irqsave錛屽鏋滀笉鑳借幏寰楅攣錛屽畠絳夊悓浜巗pin_trylock銆傚鏋滆瀹忚幏寰楄嚜鏃嬮攣lock錛岄偅闇瑕佷嬌鐢╯pin_unlock_irqrestore鏉ラ噴鏀俱?br />
spin_trylock_irq(lock)
璇ュ畯綾諱技浜巗pin_trylock_irqsave錛屽彧鏄瀹忎笉淇濆瓨鏍囧織瀵勫瓨鍣ㄣ傚鏋滆瀹忚幏寰楄嚜鏃嬮攣lock錛岄渶瑕佷嬌鐢╯pin_unlock_irq鏉ラ噴鏀俱?br />
spin_trylock_bh(lock)
璇ュ畯濡傛灉鑾峰緱浜嗚嚜鏃嬮攣錛屽畠涔熷皢澶辨晥鏈湴杞腑鏂傚鏋滃緱涓嶅埌閿侊紝瀹冧粈涔堜篃涓嶅仛銆傚洜姝わ紝濡傛灉寰楀埌浜嗛攣錛屽畠絳夊悓浜巗pin_lock_bh錛屽鏋滃緱涓嶅埌閿侊紝瀹冪瓑鍚屼簬spin_trylock銆傚鏋滆瀹忓緱鍒頒簡鑷棆閿侊紝闇瑕佷嬌鐢╯pin_unlock_bh鏉ラ噴鏀俱?br />
spin_can_lock(lock)
璇ュ畯鐢ㄤ簬鍒ゆ柇鑷棆閿乴ock鏄惁鑳藉琚攣錛屽畠瀹為檯鏄痵pin_is_locked鍙栧弽銆傚鏋渓ock娌℃湁琚攣錛屽畠榪斿洖鐪燂紝鍚﹀垯錛岃繑鍥炲亣銆傝瀹忓湪2.6.11涓涓嬈¤瀹氫箟錛屽湪鍏堝墠鐨勫唴鏍鎬腑騫舵病鏈夎瀹忋?nbsp;
銆銆鑾峰緱鑷棆閿佸拰閲婃斁鑷棆閿佹湁濂藉嚑涓増鏈紝鍥犳璁╄鑰呯煡閬撳湪浠涔堟牱鐨勬儏鍐典笅浣跨敤浠涔堢増鏈殑鑾峰緱鍜岄噴鏀鵑攣鐨勫畯鏄潪甯稿繀瑕佺殑銆?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍙湪榪涚▼涓婁笅鏂囪闂拰杞腑鏂笂涓嬫枃璁塊棶錛岄偅涔堝綋鍦ㄨ繘紼嬩笂涓嬫枃璁塊棶鍏變韓璧勬簮鏃訛紝鍙兘琚蔣涓柇鎵撴柇錛屼粠鑰屽彲鑳借繘鍏ヨ蔣涓柇涓婁笅鏂囨潵瀵硅淇濇姢鐨勫叡浜祫婧愯闂紝鍥犳瀵逛簬榪欑鎯呭喌錛屽鍏變韓璧勬簮鐨勮闂繀欏諱嬌鐢╯pin_lock_bh鍜宻pin_unlock_bh鏉ヤ繚鎶ゃ?nbsp;
銆銆褰撶劧浣跨敤spin_lock_irq鍜宻pin_unlock_irq浠ュ強spin_lock_irqsave鍜宻pin_unlock_irqrestore涔熷彲浠ワ紝瀹冧滑澶辨晥浜嗘湰鍦扮‖涓柇錛屽け鏁堢‖涓柇闅愬紡鍦頒篃澶辨晥浜嗚蔣涓柇銆備絾鏄嬌鐢╯pin_lock_bh鍜宻pin_unlock_bh鏄渶鎭板綋鐨勶紝瀹冩瘮鍏朵粬涓や釜蹇?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍙湪榪涚▼涓婁笅鏂囧拰tasklet鎴杢imer涓婁笅鏂囪闂紝閭d箞搴旇浣跨敤涓庝笂闈㈡儏鍐電浉鍚岀殑鑾峰緱鍜岄噴鏀鵑攣鐨勫畯錛屽洜涓簍asklet鍜宼imer鏄敤杞腑鏂疄鐜扮殑銆?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍙湪涓涓猼asklet鎴杢imer涓婁笅鏂囪闂紝閭d箞涓嶉渶瑕佷換浣曡嚜鏃嬮攣淇濇姢錛屽洜涓哄悓涓涓猼asklet鎴杢imer鍙兘鍦ㄤ竴涓狢PU涓婅繍琛岋紝鍗充嬌鏄湪SMP鐜涓嬩篃鏄姝ゃ傚疄闄呬笂tasklet鍦ㄨ皟鐢╰asklet_schedule鏍囪鍏墮渶瑕佽璋冨害鏃跺凡緇忔妸璇asklet緇戝畾鍒板綋鍓岰PU錛屽洜姝ゅ悓涓涓猼asklet鍐充笉鍙兘鍚屾椂鍦ㄥ叾浠朇PU涓婅繍琛屻?nbsp;
銆銆timer涔熸槸鍦ㄥ叾琚嬌鐢╝dd_timer娣誨姞鍒皌imer闃熷垪涓椂宸茬粡琚府瀹氬埌褰撳墠CPU錛屾墍浠ュ悓涓涓猼imer緇濅笉鍙兘榪愯鍦ㄥ叾浠朇PU涓娿傚綋鐒跺悓涓涓猼asklet鏈変袱涓疄渚嬪悓鏃惰繍琛屽湪鍚屼竴涓狢PU灝辨洿涓嶅彲鑳戒簡銆?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍙湪涓や釜鎴栧涓猼asklet鎴杢imer涓婁笅鏂囪闂紝閭d箞瀵瑰叡浜祫婧愮殑璁塊棶浠呴渶瑕佺敤spin_lock鍜宻pin_unlock鏉ヤ繚鎶わ紝涓嶅繀浣跨敤_bh鐗堟湰錛屽洜涓哄綋tasklet鎴杢imer榪愯鏃訛紝涓嶅彲鑳芥湁鍏朵粬tasklet鎴杢imer鍦ㄥ綋鍓岰PU涓婅繍琛屻?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍙湪涓涓蔣涓柇錛坱asklet鍜宼imer闄ゅ錛変笂涓嬫枃璁塊棶錛岄偅涔堣繖涓叡浜祫婧愰渶瑕佺敤spin_lock鍜宻pin_unlock鏉ヤ繚鎶わ紝鍥犱負鍚屾牱鐨勮蔣涓柇鍙互鍚屾椂鍦ㄤ笉鍚岀殑CPU涓婅繍琛屻?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍦ㄤ袱涓垨澶氫釜杞腑鏂笂涓嬫枃璁塊棶錛岄偅涔堣繖涓叡浜祫婧愬綋鐒舵洿闇瑕佺敤spin_lock鍜宻pin_unlock鏉ヤ繚鎶わ紝涓嶅悓鐨勮蔣涓柇鑳藉鍚屾椂鍦ㄤ笉鍚岀殑CPU涓婅繍琛屻?nbsp;
銆銆濡傛灉琚繚鎶ょ殑鍏變韓璧勬簮鍦ㄨ蔣涓柇錛堝寘鎷瑃asklet鍜宼imer錛夋垨榪涚▼涓婁笅鏂囧拰紜腑鏂笂涓嬫枃璁塊棶錛岄偅涔堝湪杞腑鏂垨榪涚▼涓婁笅鏂囪闂湡闂達紝鍙兘琚‖涓柇鎵撴柇錛屼粠鑰岃繘鍏ョ‖涓柇涓婁笅鏂囧鍏變韓璧勬簮榪涜璁塊棶錛屽洜姝わ紝鍦ㄨ繘紼嬫垨杞腑鏂笂涓嬫枃闇瑕佷嬌鐢╯pin_lock_irq鍜宻pin_unlock_irq鏉ヤ繚鎶ゅ鍏變韓璧勬簮鐨勮闂?nbsp;
銆銆鑰屽湪涓柇澶勭悊鍙ユ焺涓嬌鐢ㄤ粈涔堢増鏈紝闇渚濇儏鍐佃屽畾錛屽鏋滃彧鏈変竴涓腑鏂鐞嗗彞鏌勮闂鍏變韓璧勬簮錛岄偅涔堝湪涓柇澶勭悊鍙ユ焺涓粎闇瑕乻pin_lock鍜宻pin_unlock鏉ヤ繚鎶ゅ鍏變韓璧勬簮鐨勮闂氨鍙互浜嗐?nbsp;
銆銆鍥犱負鍦ㄦ墽琛屼腑鏂鐞嗗彞鏌勬湡闂達紝涓嶅彲鑳借鍚屼竴CPU涓婄殑杞腑鏂垨榪涚▼鎵撴柇銆備絾鏄鏋滄湁涓嶅悓鐨勪腑鏂鐞嗗彞鏌勮闂鍏變韓璧勬簮錛岄偅涔堥渶瑕佸湪涓柇澶勭悊鍙ユ焺涓嬌鐢╯pin_lock_irq鍜宻pin_unlock_irq鏉ヤ繚鎶ゅ鍏變韓璧勬簮鐨勮闂?nbsp;
銆銆鍦ㄤ嬌鐢╯pin_lock_irq鍜宻pin_unlock_irq鐨勬儏鍐典笅錛屽畬鍏ㄥ彲浠ョ敤spin_lock_irqsave鍜宻pin_unlock_irqrestore鍙栦唬錛岄偅鍏蜂綋搴旇浣跨敤鍝竴涓篃闇瑕佷緷鎯呭喌鑰屽畾錛屽鏋滃彲浠ョ‘淇″湪瀵瑰叡浜祫婧愯闂墠涓柇鏄嬌鑳界殑錛岄偅涔堜嬌鐢╯pin_lock_irq鏇村ソ涓浜涖?nbsp;
銆銆鍥犱負瀹冩瘮spin_lock_irqsave瑕佸揩涓浜涳紝浣嗘槸濡傛灉浣犱笉鑳界‘瀹氭槸鍚︿腑鏂嬌鑳斤紝閭d箞浣跨敤spin_lock_irqsave鍜宻pin_unlock_irqrestore鏇村ソ錛屽洜涓哄畠灝嗘仮澶嶈闂叡浜祫婧愬墠鐨勪腑鏂爣蹇楄屼笉鏄洿鎺ヤ嬌鑳戒腑鏂?nbsp;
銆銆褰撶劧錛屾湁浜涙儏鍐典笅闇瑕佸湪璁塊棶鍏變韓璧勬簮鏃跺繀欏諱腑鏂け鏁堬紝鑰岃闂畬鍚庡繀欏諱腑鏂嬌鑳斤紝榪欐牱鐨勬儏褰嬌鐢╯pin_lock_irq鍜宻pin_unlock_irq鏈濂姐?nbsp;
銆銆闇瑕佺壒鍒彁閱掕鑰咃紝spin_lock鐢ㄤ簬闃繪鍦ㄤ笉鍚孋PU涓婄殑鎵ц鍗曞厓瀵瑰叡浜祫婧愮殑鍚屾椂璁塊棶浠ュ強涓嶅悓榪涚▼涓婁笅鏂囦簰鐩告姠鍗犲鑷寸殑瀵瑰叡浜祫婧愮殑闈炲悓姝ヨ闂紝鑰屼腑鏂け鏁堝拰杞腑鏂け鏁堝嵈鏄負浜嗛樆姝㈠湪鍚屼竴CPU涓婅蔣涓柇鎴栦腑鏂鍏變韓璧勬簮鐨勯潪鍚屾璁塊棶銆?nbsp;
銆銆
#include <linux/spinlock.h>
澶存枃浠?
#include<linux/spinlock_types.h>
#ifndef __LINUX_SPINLOCK_TYPES_H
#define __LINUX_SPINLOCK_TYPES_H
/*
* include/linux/spinlock_types.h - generic spinlock type definitions
* and initializers
*
* portions Copyright 2005, Red Hat, Inc., Ingo Molnar
* Released under the General Public License (GPL).
*/
//瀵圭О澶氬鐞嗗櫒
#if defined(CONFIG_SMP)
#include <asm/spinlock_types.h>
#else
#include <linux/spinlock_types_up.h>
#endif
#include <linux/lockdep.h>
typedef struct {
raw_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
} spinlock_t;
#define SPINLOCK_MAGIC 0xdead4ead
typedef struct {
raw_rwlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
} rwlock_t;
#define RWLOCK_MAGIC 0xdeaf1eed
#define SPINLOCK_OWNER_INIT ((void *)-1L)
# define __SPIN_LOCK_UNLOCKED(lockname) \
(spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \
SPIN_DEP_MAP_INIT(lockname) }
#define __RW_LOCK_UNLOCKED(lockname) \
(rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \
RW_DEP_MAP_INIT(lockname) }
/*
* SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and
* are hence deprecated.
* Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or
* __SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate.
*/
#define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(old_style_spin_init)
#define RW_LOCK_UNLOCKED __RW_LOCK_UNLOCKED(old_style_rw_init)
#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
#define DEFINE_RWLOCK(x) rwlock_t x = __RW_LOCK_UNLOCKED(x)
#endif /* __LINUX_SPINLOCK_TYPES_H */
銆銆
]]>
1.softirq
閫傜敤浜庢ц兘鏁忔劅鐨勫瓙緋葷粺
2.tasklet
寤虹珛鍦╯oftirq涔嬩笂,浣跨敤鏇寸畝鍗?br />softirq鐨勪笉鍚屽疄渚嬪彲榪愯鍦ㄤ笉鍚岀殑澶勭悊鍣ㄤ笂,鑰宼asklet鍒欎笉鍏佽
蹇呴』浣跨敤define DECLARE_TASKLET 澹版槑tasklet
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
void short_do_tasklet(unsigned long);
DECLARE_TASKLET(short_do_tasklet,short_tasklet,0);
3. 宸ヤ綔闃熷垪(work queue)
struct work_struct my_work; //瀹氫箟涓涓伐浣滈槦鍒?/span>
void my_work_func(unsigned long); //瀹氫箟涓涓鐞嗗嚱鏁?/span>
澶存枃浠?br />#include <linux/interrupt.h>
/* Tasklets --- multithreaded analogue of BHs.
Main feature differing them of generic softirqs: tasklet
is running only on one CPU simultaneously.
Main feature differing them of BHs: different tasklets
may be run simultaneously on different CPUs.
Properties:
* If tasklet_schedule() is called, then tasklet is guaranteed
to be executed on some cpu at least once after this.
* If the tasklet is already scheduled, but its excecution is still not
started, it will be executed only once.
* If this tasklet is already running on another CPU (or schedule is called
from tasklet itself), it is rescheduled for later.
* Tasklet is strictly serialized wrt itself, but not
wrt another tasklets. If client needs some intertask synchronization,
he makes it with spinlocks.
*/
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
浣跨敤紺轟緥:
static atomic_t fpstatues;
static atomic_t has_image = {0};
static void gc0303_vsync_do_tasklet(ulong data)
{
ulong curr = gettickcount();
debug("curr:%lu",curr);
if (atomic_read(&fpstatues)==0)
{
s3c2410_dma_ctrl(DMACH_XD0, S3C2410_DMAOP_FLUSH);
gc0303_dma_buf.dma_addr = img_phys;
gc0303_dma_buf.size = bmp_w*bmp_h;
s3c2410_dma_enqueue(DMACH_XD0,
(void *)&gc0303_dma_buf,
gc0303_dma_buf.dma_addr,
gc0303_dma_buf.size);
atomic_set(&fpstatues,1);
}
}
DECLARE_TASKLET(gc0303_vsync_tasklet,gc0303_vsync_do_tasklet,0);
static irqreturn_t gc0303_vsync_handler(int irq,void* dev_id)
{
if (atomic_read(&fpstatues)==1)
{
s3c2410_dma_ctrl(DMACH_XD0, S3C2410_DMAOP_START);
}
//璋冨害gc0303_vsync_tasklet
tasklet_schedule(&gc0303_vsync_tasklet);
return IRQ_HANDLED;
}
tasklet鏄綔涓轟腑鏂笅鍗婇儴鐨勪竴涓緢濂界殑閫夋嫨錛屽畠鍦ㄦц兘鍜屾槗鐢ㄦт箣闂存湁鐫寰堝ソ鐨勫鉤琛°傝緝涔嬩簬softirq錛宼asklet涓嶉渶瑕佽冭檻SMP涓嬬殑騫惰闂錛岃屽張姣攚orkqueues鏈夌潃鏇村ソ鐨勬ц兘銆?br />tasklet閫氬父浣滀負紜腑鏂殑涓嬪崐閮ㄦ潵浣跨敤錛屽湪紜腑鏂腑璋冪敤tasklet_schedule(t)銆傛瘡嬈$‖涓柇閮戒細瑙﹀彂涓嬈asklet_schedule(t)錛屼絾鏄瘡嬈′腑鏂畠鍙細鍚戝叾涓殑涓涓狢PU娉ㄥ唽錛岃屼笉鏄墍鏈夌殑CPU銆傚畬鎴愭敞鍐屽悗鐨則asklet鐢眛asklet_action()鏉ユ墽琛岋紝鍦⊿MP鐜涓嬶紝瀹冧繚璇佸悓涓鏃跺埢錛屽悓涓涓猼asklet鍙湁涓涓壇鏈湪榪愯錛岃繖鏍峰氨閬垮厤浜嗕嬌鐢╯oftirq鎵瑕佽冭檻鐨勪簰鏂ョ殑闂銆傚啀鑰咃紝tasklet鍦ㄦ墽琛宼asklet->func()鍓嶏紝鍐嶄竴嬈″厑璁竧asklet鍙皟搴︼紙娉ㄥ唽錛夛紝浣嗘槸鍦ㄨtasklet宸叉湁涓涓壇鏈湪鍏朵粬CPU涓婅繍琛岀殑鎯呭喌涓嬶紝瀹冨彧鑳介鍚庢墽琛屻傛諱箣錛屽悓涓涓‖涓柇寮曡搗鐨勪竴涓猼asklet_schedule()鍔ㄤ綔鍙細浣夸竴涓猼asklet琚敞鍐岋紝鑰屼笉鍚屼腑鏂紩璧風殑tasklet鍒欏彲鑳藉湪涓嶅悓鐨勬椂鍒昏娉ㄥ唽鑰屽嬈¤鎵ц銆?br />
tasklet鐨勪簰鏂ャ傜敱浜庡悓涓涓猼asklet涓嶈兘鏈夊涓壇鏈悓鏃惰繍琛岋紝鎵浠ヤ笉闇瑕佸湪澶欳PU涔嬮棿浜掓枼銆傚湪tasklet榪愯鐨勮繃紼嬩腑錛屽畠浼氳紜腑鏂墦鏂紙榪欎篃鏄蔣涓柇鐨勪紭鐐癸級錛屾墍浠ュ鏋渢asklet鍜屽叾浠栦腑鏂箣闂寸殑浜掓枼鏈夊彲鑳藉瓨鍦ㄣ?br />涓柇鏈嶅姟紼嬪簭涓鑸兘鏄湪涓柇璇鋒眰鍏抽棴鐨勬潯浠朵笅鎵ц鐨?浠ラ伩鍏嶅祵濂楄屼嬌涓柇鎺у埗澶嶆潅鍖栥備絾鏄紝涓柇鏄竴涓殢鏈轟簨浠訛紝瀹冮殢鏃朵細鍒版潵錛屽鏋滃叧涓柇鐨勬椂闂村お闀匡紝CPU灝變笉鑳藉強鏃跺搷搴斿叾浠栫殑涓柇璇鋒眰錛屼粠鑰岄犳垚涓柇鐨勪涪澶便傚洜姝わ紝Linux鍐呮牳鐨勭洰鏍囧氨鏄敖鍙兘蹇殑澶勭悊瀹屼腑鏂姹傦紝灝藉叾鎵鑳芥妸鏇村鐨勫鐞嗗悜鍚庢帹榪熴備緥濡傦紝鍋囪涓涓暟鎹潡宸茬粡杈懼埌浜嗙綉綰匡紝褰撲腑鏂帶鍒跺櫒鎺ュ彈鍒拌繖涓腑鏂姹備俊鍙鋒椂錛孡inux鍐呮牳鍙槸綆鍗曞湴鏍囧織鏁版嵁鍒版潵浜嗭紝鐒跺悗璁╁鐞嗗櫒鎭㈠鍒板畠浠ュ墠榪愯鐨勭姸鎬侊紝鍏朵綑鐨勫鐞嗙◢鍚庡啀榪涜錛堝鎶婃暟鎹Щ鍏ヤ竴涓紦鍐插尯錛屾帴鍙楁暟鎹殑榪涚▼灝卞彲浠ュ湪緙撳啿鍖烘壘鍒版暟鎹級銆傚洜姝わ紝鍐呮牳鎶婁腑鏂鐞嗗垎涓轟袱閮ㄥ垎錛氫笂鍗婇儴錛坱ophalf錛夊拰涓嬪崐閮紙bottomhalf錛夛紝涓婂崐閮紙灝辨槸涓柇鏈嶅姟紼嬪簭錛夊唴鏍哥珛鍗蟲墽琛岋紝鑰屼笅鍗婇儴錛堝氨鏄竴浜涘唴鏍稿嚱鏁幫級鐣欑潃紼嶅悗澶勭悊錛?br />
棣栧厛錛屼竴涓揩閫熺殑“涓婂崐閮?#8221;鏉ュ鐞嗙‖浠跺彂鍑虹殑璇鋒眰錛屽畠蹇呴』鍦ㄤ竴涓柊鐨勪腑鏂駭鐢熶箣鍓嶇粓姝€傞氬父錛岄櫎浜嗗湪璁懼鍜屼竴浜涘唴瀛樼紦鍐插尯錛堝鏋滀綘鐨勮澶囩敤鍒頒簡DMA錛屽氨涓嶆榪欎簺錛変箣闂寸Щ鍔ㄦ垨浼犻佹暟鎹紝紜畾紜歡鏄惁澶勪簬鍋ュ叏鐨勭姸鎬佷箣澶栵紝榪欎竴閮ㄥ垎鍋氱殑宸ヤ綔寰堝皯銆?br />
涓嬪崐閮ㄨ繍琛屾椂鏄厑璁鎬腑鏂姹傜殑錛岃屼笂鍗婇儴榪愯鏃舵槸鍏充腑鏂殑錛岃繖鏄簩鑰呬箣闂寸殑涓昏鍖哄埆銆?br />
浣嗘槸錛屽唴鏍稿埌搴曚粈鏃跺欐墽琛屼笅鍗婇儴錛屼互浣曠鏂瑰紡緇勭粐涓嬪崐閮紵榪欏氨鏄垜浠璁ㄨ鐨勪笅鍗婇儴瀹炵幇鏈哄埗錛岃繖縐嶆満鍒跺湪鍐呮牳鐨勬紨鍙樿繃紼嬩腑涓嶆柇寰楀埌鏀硅繘錛屽湪浠ュ墠鐨勫唴鏍鎬腑錛岃繖涓満鍒跺彨鍋歜ottomhalf(綆縐癰h)錛屽湪2.4浠ュ悗鐨勭増鏈腑鏈変簡鏂扮殑鍙戝睍鍜屾敼榪涳紝鏀硅繘鐨勭洰鏍囦嬌涓嬪崐閮ㄥ彲浠ュ湪澶氬鐞嗘満涓婂茍琛屾墽琛岋紝騫舵湁鍔╀簬椹卞姩紼嬪簭鐨勫紑鍙戣呰繘琛岄┍鍔ㄧ▼搴忕殑寮鍙戙備笅闈富瑕佷粙緇嶅父鐢ㄧ殑灝忎換鍔?Tasklet)鏈哄埗鍙?.6鍐呮牳涓殑宸ヤ綔闃熷垪鏈哄埗銆?br />
榪欓噷鐨勫皬浠誨姟鏄寚瀵硅鎺ㄨ繜鎵ц鐨勫嚱鏁拌繘琛岀粍緇囩殑涓縐嶆満鍒躲傚叾鏁版嵁緇撴瀯涓簍asklet_struct錛屾瘡涓粨鏋勪唬琛ㄤ竴涓嫭绔嬬殑灝忎換鍔★紝鍏跺畾涔夊涓嬶細
structtasklet_struct {
structtasklet_struct *next; /*鎸囧悜閾捐〃涓殑涓嬩竴涓粨鏋?/span>*/
unsignedlong state; /* 灝忎換鍔$殑鐘舵?/span>*/
atomic_t count; /* 寮曠敤璁℃暟鍣?/span>*/
void(*func) (unsigned long); /* 瑕佽皟鐢ㄧ殑鍑芥暟*/
unsignedlong data; /* 浼犻掔粰鍑芥暟鐨勫弬鏁?/span>*/
}錛?br />緇撴瀯涓殑func鍩熷氨鏄笅鍗婇儴涓鎺ㄨ繜鎵ц鐨勫嚱鏁幫紝data鏄畠鍞竴鐨勫弬鏁般?br />state鍩熺殑鍙栧間負TASKLET_STATE_SCHED鎴朤ASKLET_STATE_RUN銆俆ASKLET_STATE_SCHED琛ㄧず灝忎換鍔″凡琚皟搴︼紝姝e噯澶囨姇鍏ヨ繍琛岋紝TASKLET_STATE_RUN琛ㄧず灝忎換鍔℃鍦ㄨ繍琛屻俆ASKLET_STATE_RUN鍙湁鍦ㄥ澶勭悊鍣ㄧ郴緇熶笂鎵嶄嬌鐢紝鍗曞鐞嗗櫒緋葷粺浠涔堟椂鍊欓兘娓呮涓涓皬浠誨姟鏄笉鏄鍦ㄨ繍琛岋紙瀹冭涔堝氨鏄綋鍓嶆鍦ㄦ墽琛岀殑浠g爜錛岃涔堜笉鏄級銆?br />count 鍩熸槸灝忎換鍔$殑寮曠敤璁℃暟鍣ㄣ傚鏋滃畠涓嶄負0錛屽垯灝忎換鍔¤紱佹錛屼笉鍏佽鎵ц錛涘彧鏈夊綋瀹冧負闆訛紝灝忎換鍔℃墠琚縺媧伙紝騫朵笖鍦ㄨ璁劇疆涓烘寕璧鋒椂錛屽皬浠誨姟鎵嶈兘澶熸墽琛屻?br />1. 澹版槑鍜屼嬌鐢ㄥ皬浠誨姟澶у鏁版儏鍐典笅錛屼負浜嗘帶鍒朵竴涓甯哥殑紜歡璁懼錛屽皬浠誨姟鏈哄埗鏄疄鐜頒笅鍗婇儴鐨勬渶浣抽夋嫨銆傚皬浠誨姟鍙互鍔ㄦ佸垱寤猴紝浣跨敤鏂逛究錛屾墽琛岃搗鏉ヤ篃姣旇緝蹇?br />鎴戜滑鏃㈠彲浠ラ潤鎬佸湴鍒涘緩灝忎換鍔★紝涔熷彲浠ュ姩鎬佸湴鍒涘緩瀹冦傞夋嫨閭g鏂瑰紡鍙栧喅浜庡埌搴曟槸鎯寵瀵瑰皬浠誨姟榪涜鐩存帴寮曠敤榪樻槸涓涓棿鎺ュ紩鐢ㄣ傚鏋滃噯澶囬潤鎬佸湴鍒涘緩涓涓皬浠誨姟錛堜篃灝辨槸瀵瑰畠鐩存帴寮曠敤錛夛紝浣跨敤涓嬮潰涓や釜瀹忎腑鐨勪竴涓細
DECLARE_TASKLET(name,func, data)
DECLARE_TASKLET_DISABLED(name,func, data)
榪欎袱涓畯閮借兘鏍規嵁緇欏畾鐨勫悕瀛楅潤鎬佸湴鍒涘緩涓涓猼asklet_struct緇撴瀯銆傚綋璇ュ皬浠誨姟琚皟搴︿互鍚庯紝緇欏畾鐨勫嚱鏁癴unc浼氳鎵ц錛屽畠鐨勫弬鏁扮敱data緇欏嚭銆傝繖涓や釜瀹忎箣闂寸殑鍖哄埆鍦ㄤ簬寮曠敤璁℃暟鍣ㄧ殑鍒濆鍊艱緗笉鍚屻傜涓涓畯鎶婂垱寤虹殑灝忎換鍔$殑寮曠敤璁℃暟鍣ㄨ緗負0錛屽洜姝わ紝璇ュ皬浠誨姟澶勪簬嬋媧葷姸鎬併傚彟涓涓妸寮曠敤璁℃暟鍣ㄨ緗負1錛屾墍浠ヨ灝忎換鍔″浜庣姝㈢姸鎬併備緥濡傦細
DECLARE_TASKLET(my_tasklet,my_tasklet_handler, dev);
榪欒浠g爜鍏跺疄絳変環浜?br />struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),tasklet_handler,dev};
榪欐牱灝卞垱寤轟簡涓涓悕涓簃y_tasklet鐨勫皬浠誨姟錛屽叾澶勭悊紼嬪簭涓簍asklet_handler錛屽茍涓斿凡琚縺媧匯傚綋澶勭悊紼嬪簭琚皟鐢ㄧ殑鏃跺欙紝dev灝變細琚紶閫掔粰瀹冦?br />2. 緙栧啓鑷繁鐨勫皬浠誨姟澶勭悊紼嬪簭灝忎換鍔″鐞嗙▼搴忓繀欏葷鍚堝涓嬬殑鍑芥暟綾誨瀷錛?br />void tasklet_handler(unsigned long data)
鐢變簬灝忎換鍔′笉鑳界潯鐪狅紝鍥犳涓嶈兘鍦ㄥ皬浠誨姟涓嬌鐢ㄤ俊鍙烽噺鎴栬呭叾瀹冧駭鐢熼樆濉炵殑鍑芥暟銆備絾鏄皬浠誨姟榪愯鏃跺彲浠ュ搷搴斾腑鏂?br />3. 璋冨害鑷繁鐨勫皬浠誨姟閫氳繃璋冪敤tasklet_schedule()鍑芥暟騫朵紶閫掔粰瀹冪浉搴旂殑tasklt_struct鎸囬拡錛岃灝忎換鍔″氨浼氳璋冨害浠ヤ究閫傚綋鐨勬椂鍊欐墽琛岋細
tasklet_schedule(&my_tasklet); /*鎶妋y_tasklet鏍囪涓烘寕璧?nbsp;*/
鍦ㄥ皬浠誨姟琚皟搴︿互鍚庯紝鍙鏈夋満浼氬畠灝變細灝藉彲鑳芥棭鐨勮繍琛屻傚湪瀹冭繕娌℃湁寰楀埌榪愯鏈轟細涔嬪墠錛屽鏋滀竴涓浉鍚岀殑灝忎換鍔″張琚皟搴︿簡錛岄偅涔堝畠浠嶇劧鍙細榪愯涓嬈°?br />鍙互璋冪敤tasklet_disable()鍑芥暟鏉ョ姝㈡煇涓寚瀹氱殑灝忎換鍔°傚鏋滆灝忎換鍔″綋鍓嶆鍦ㄦ墽琛岋紝榪欎釜鍑芥暟浼氱瓑鍒板畠鎵ц瀹屾瘯鍐嶈繑鍥炪傝皟鐢╰asklet_enable()鍑芥暟鍙互嬋媧諱竴涓皬浠誨姟錛屽鏋滃笇鏈涙妸浠ECLARE_TASKLET_DISABLED錛堬級鍒涘緩鐨勫皬浠誨姟嬋媧伙紝涔熷緱璋冪敤榪欎釜鍑芥暟錛屽錛?br />tasklet_disable(&my_tasklet); /*灝忎換鍔$幇鍦ㄨ紱佹,榪欎釜灝忎換鍔′笉鑳借繍琛?/span>*/
tasklet_enable(&my_tasklet); /* 灝忎換鍔$幇鍦ㄨ嬋媧?/span>*/
涔熷彲浠ヨ皟鐢╰asklet_kill()鍑芥暟浠庢寕璧風殑闃熷垪涓幓鎺変竴涓皬浠誨姟銆傝鍑芥暟鐨勫弬鏁版槸涓涓寚鍚戞煇涓皬浠誨姟鐨則asklet_struct鐨勯暱鎸囬拡銆傚湪灝忎換鍔¢噸鏂拌皟搴﹀畠鑷韓鐨勬椂鍊欙紝浠庢寕璧風殑闃熷垪涓Щ鍘誨凡璋冨害鐨勫皬浠誨姟浼氬緢鏈夌敤銆傝繖涓嚱鏁伴鍏堢瓑寰呰灝忎換鍔℃墽琛屽畬姣曪紝鐒跺悗鍐嶅皢瀹冪Щ鍘匯?br />4.tasklet鐨勭畝鍗曠敤娉?br />涓嬮潰鏄痶asklet鐨勪竴涓畝鍗曞簲鐢?浠ユā鍧楃殑褰㈡垚鍔犺澆銆?br />
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
static struct tasklet_struct my_tasklet;
static void tasklet_handler (unsigned long d ata)
{
printk("tasklet_handler is running.\n");
}
static int __init test_init(void)
{
tasklet_init(&my_tasklet,tasklet_handler,0);
tasklet_schedule(&my_tasklet);
return0;
}
static void __exit test_exit(void)
{
tasklet_kill(&tasklet);
printk("test_exit is running.\n");
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);
浠庤繖涓緥瀛愬彲浠ョ湅鍑猴紝鎵璋撶殑灝忎換鍔℃満鍒舵槸涓轟笅鍗婇儴鍑芥暟鐨勬墽琛屾彁渚涗簡涓縐嶆墽琛屾満鍒訛紝涔熷氨鏄錛屾帹榪熷鐞嗙殑浜嬫儏鏄敱tasklet_handler瀹炵幇錛屼綍鏃舵墽琛岋紝緇忕敱灝忎換鍔℃満鍒跺皝瑁呭悗浜ょ粰鍐呮牳鍘誨鐞嗐?/div>
]]>
鏌ョ湅涓柇:
cat /proc/interrupts
鏌ョ湅涓柇緇熻:
cat /proc/stat
1銆佸ご鏂囦歡
#include <linux/interrupt.h>
#include <asm/arch/irqs.h>
2銆佺敵鏄庝腑鏂鐞嗙▼搴?nbsp;
static spinlock_t wiegand_lock; // 浣跨敤涔嬪墠蹇呴』鍒濆鍖?spin_lock_init(&wiegand_lock);
static irqreturn_t wiegand_minus1_interrupt(int irq, void *dev_id)
{
spin_lock(&wiegand_lock);
//do something
//wiegand_minus_interrupt();
spin_unlock(&wiegand_lock);
return IRQ_HANDLED;
}
3.娉ㄥ唽涓柇 request_irq()
2.6 鍐呮牳 鍑芥暟鍘熷瀷濡備笅錛?br />extern int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id);
絎?涓弬鏁?涓柇鍙?鏄鐢寵鐨勪腑鏂彿
絎?涓弬鏁?涓柇澶勭悊鍑芥暟
絎?涓弬鏁?涓柇瑙﹀彂鏍囧織
IRQF_DISABLED 蹇腑鏂?紱佹鍏朵粬涓柇)
IRQF_TRIGGER_RISING 璁懼鍦ㄤ腑鏂嚎涓婁駭鐢熶竴涓笂鍗囨部鏃?鍙戝嚭涓柇.(璇存槑鍦ㄤ腑鏂箣鍓?璁懼涓鐩村皢涓柇綰夸繚鎸佸湪涓涓數騫充笂)
IRQF_TRIGGER_FALLING 涓嬮檷娌胯Е鍙?br /> IRQF_TRIGGER_HIGH 楂樼數騫寵Е鍙戜腑鏂?br /> IRQF_TRIGGER_LOW 浣庣數騫寵Е鍙戜腑鏂?br /> IRQF_TRIGGER_RANDOM 涓虹郴緇熼殢鏈哄彂鐢熷櫒鎻愪緵鏀寔
IRQF_TRIGGER_SHARED (琛ㄧず鍏變韓鐩稿悓鐨勪腑鏂彿,澶氫釜璁懼鍏變韓)
/*
* linux/interrupt.h
* These correspond to the IORESOURCE_IRQ_* defines in
* linux/ioport.h to select the interrupt line behaviour. When
* requesting an interrupt without specifying a IRQF_TRIGGER, the
* setting should be assumed to be "as already configured", which
* may be as per machine or firmware initialisation.
*/
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE 0x00000010
typedef irqreturn_t (*irq_handler_t)(int, void *);
絎?涓弬鏁?涓柇鐨勬爣璇?涓柇鐨勬爣璇嗕笌/proc/interrupts瀵瑰簲
絎?涓弬鏁?浼犲叆涓柇澶勭悊紼嬪簭鐨勫弬鏁幫紝鍙互涓篘ULL錛屽湪娉ㄥ唽鍏變韓涓柇鏃訛紝姝ゅ弬鏁頒笉鑳戒負NULL錛屼綔涓哄叡浜腑鏂椂鐨勪腑鏂尯鍒弬鏁般?br />
榪斿洖鍊?濡傛灉涓柇澶勭悊鎴愬姛,榪斿洖IREQ_HANDLED,鍚﹀垯,榪斿洖IRQ_NONE
/* irqreturn.h */
typedef int irqreturn_t;
#define IRQ_NONE (0)
#define IRQ_HANDLED (1)
#define IRQ_RETVAL(x) ((x) != 0)
涓柇涓婁笅鏂?br />
涓柇涓婁笅鏂囨敞鎰忎簨欏?
1)涓柇涓婁笅鏂囦唬鐮佺粷涓嶅彲浠ュ仠姝㈣繍琛屻備笉鑳藉仛浠諱綍鍙兘鍙戠敓浼戠湢鐨勬搷浣?鍦ㄤ粠涓柇澶勭悊鍑芥暟涓皟鐢ㄤ竴涓唴鏍窤PI涔嬪墠,搴旇浠旂粏鍒嗘墜瀹?浠ョ‘淇濆叾鍐呴儴涓嶄細瑙﹀彂闃誨絳夊緟!
2)涓轟簡鍦ㄤ腑鏂鐞嗗嚱鏁頒腑淇濇姢涓寸晫鍖?涓嶈兘浣跨敤浜掓枼浣?鍥犱負瀹冧滑涔熻瀵艱嚧鐫$湢,搴旇浣跨敤鑷棆閿佷唬鏇夸簰鏂ヤ綋.
3)涓柇澶勭悊鍑芥暟涓嶈兘涓庣敤鎴風┖闂寸洿鎺ヤ氦浜掓暟鎹?
璋冨害鍣ㄥ伐浣滀簬榪涚▼涔嬮棿,濡傛灉涓柇澶勭悊鍑芥暟鐫$湢騫惰璋冨害鍑哄幓.鏃犳硶璋冨害鍥炴潵!
4)涓柇澶勭悊鍑芥暟涓鏂歸潰闇瑕佸揩閫熷湴涓哄叾浠栬繘紼嬭鍑哄鐞嗗櫒,鍙︿竴鏂歸潰鍙堥渶瑕佸畬鎴愬畠鐨勫伐浣?涓轟簡瑙勯伩榪欑鍐茬獊,涓柇澶勭悊鍑芥暟閫氬父灝嗗伐浣滃垎鎴愪袱涓儴鍒?欏跺崐閮ㄨ涓涓爣蹇椾互瀹gО瀹冨凡緇忔湇鍔′簡璇ヤ腑鏂?鑰岄噸澶х殑宸ヤ綔璐熻澆閮借涓㈢粰浜嗗簳鍗婇儴,搴曞崐閮ㄧ殑鎵ц琚歡鍚?鍦ㄥ叾鎵ц鐜涓?鎵鏈夌殑涓柇閮芥槸浣胯兘鐨?
4.閲婃斁涓柇
extern void free_irq(int irq,void *dev_id)
5銆佸惎鍔ㄧ敤紱佺敤涓柇
extern void disable_irq_nosync(unsigned int irq);
extern void disable_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);
]]>
鍐呮牳絎﹀彿鍒楄〃:
cat /proc/kallsyms
cat /proc/iomem
瀵煎嚭鍐呮牳絎﹀彿:
EXPORT_SYMBOL(sym)
1銆佺己鐪佹儏鍐典笅錛孡inux2.6鍐呮牳涓粯璁や笉瀵煎嚭鎵鏈夌殑絎﹀彿,鍗沖湪2.6鐨勫唴鏍鎬腑娌℃湁榪欎釜瀹廍XPORT_NO_SYMBOLS
2銆佸鏋滄兂瑕佽嚜宸辨寚瀹氬鍑哄摢浜涘彉閲忔垨鍑芥暟錛屽厛鍦∕akefile涓嬌鐢?/span>-DEXPORT_SYMTAB錛岀劧鍚庡湪婧愭枃浠朵腑浣跨敤EXPORT_SYMBOL(xxx);瀵煎嚭涔?br />
echo 8 > /proc/sys/kernel/printk
鏌ョ湅涓柇:
cat /proc/interrupts
涓嬪崐閮ㄦ満鍒?br />1.tasklet
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
2. 宸ヤ綔闃熷垪
struct work_struct my_work; //瀹氫箟涓涓伐浣滈槦鍒?/span>
void my_work_func(unsigned long); //瀹氫箟涓涓鐞嗗嚱鏁?/span>
鍦ㄤ腑鏂鐞嗗嚱鏁?tasklet鍜屽唴鏍稿畾鏃跺櫒絳夐潪榪涚▼涓婁笅鏂囦笉鑳介樆濉?
]]>
]]>
M涓嶆槸涓涓紪璇戦夐」錛岃屾槸涓涓彉閲忥紝浠庨《灞俶akefile鏂囦歡閲屽彲浠ユ壘鍒板畠鐨勫畾涔?
鏂囦歡鍦?/span>
/usr/src/linux-headers-2.6.32-5-common/Makefile
69 ifeq ("$(origin M)", "command line")
70 KBUILD_EXTMOD := $(M)
71 endif
-C 鐢ㄤ簬鎸囧畾鍐呮牳婧愪唬鐮佺殑鐩綍
-M 鐢ㄤ簬module鎵鍦ㄧ殑鐩綍
