linux原子化运行一段代码,【正点原子Linux连载】第五十一章Linux中断实验-摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南 (amobbs.com 阿莫电子论坛)...

1   #include

2   #include

3   #include

4   #include

5   #include

6   #include

7   #include

8   #include

9   #include

10  #include

11  #include

12  #include

13  #include

14  #include

15  #include

16  #include

17  #include

18  #include

19  #include

20  #include

21/***************************************************************

22  Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.

23文件名        : imx6uirq.c

24作者        : 左忠凯

25版本        : V1.0

26描述        : Linux中断驱动实验

27其他        : 无

28论坛        : www.openedv.com

29日志        : 初版V1.0 2019/7/26 左忠凯创建

30  ***************************************************************/

31  #define IMX6UIRQ_CNT             1        /* 设备号个数                */

32  #define IMX6UIRQ_NAME          "imx6uirq"        /* 名字                */

33  #define KEY0VALUE               0X01        /* KEY0按键值                */

34  #define INVAKEY                  0XFF        /* 无效的按键值                */

35  #define KEY_NUM                  1        /* 按键数量                */

36

37/* 中断IO描述结构体 */

38struct irq_keydesc {

39int gpio;        /* gpio                         */

40int irqnum;        /* 中断号                */

41unsignedchar value;        /* 按键对应的键值        */

42char name[10];        /* 名字                        */

43      irqreturn_t (*handler)(int,void*);        /* 中断服务函数 */

44};

45

46/* imx6uirq设备结构体 */

47struct imx6uirq_dev{

48      dev_t devid;        /* 设备号                                */

49struct cdev cdev;        /* cdev                                     */

50struct class *class;        /* 类                                        */

51struct device *device;        /* 设备                                        */

52int major;        /* 主设备号                                */

53int minor;        /* 次设备号                                */

54struct device_node  *nd;        /* 设备节点                                        */

55      atomic_t keyvalue;        /* 有效的按键键值                        */

56      atomic_t releasekey;        /* 标记是否完成一次完成的按键*/

57struct timer_list timer;        /* 定义一个定时器*/

58struct irq_keydesc irqkeydesc[KEY_NUM];        /* 按键描述数组 */

59unsignedchar curkeynum;                /* 当前的按键号 */

60};

61

62struct imx6uirq_dev imx6uirq;/* irq设备 */

63

64/* @description           : 中断服务函数,开启定时器,延时10ms,

65   *                           定时器用于按键消抖。

66   * @param - irq             : 中断号

67   * @param - dev_id          : 设备结构。

68   * @return                  : 中断执行结果

69   */

70static irqreturn_t key0_handler(int irq,void*dev_id)

71{

72struct imx6uirq_dev *dev =(struct imx6uirq_dev *)dev_id;

73

74      dev->curkeynum =0;

75      dev->timer.data =(volatilelong)dev_id;

76      mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10));

77return IRQ_RETVAL(IRQ_HANDLED);

78}

79

80/* @description         : 定时器服务函数,用于按键消抖,定时器到了以后

81   *                        再次读取按键值,如果按键还是处于按下状态就表示按键有效。

82   * @param – arg        : 设备结构变量

83   * @return              : 无

84   */

85void timer_function(unsignedlong arg)

86{

87unsignedchar value;

88unsignedchar num;

89struct irq_keydesc *keydesc;

90struct imx6uirq_dev *dev =(struct imx6uirq_dev *)arg;

91

92      num = dev->curkeynum;

93      keydesc =&dev->irqkeydesc[num];

94

95      value = gpio_get_value(keydesc->gpio);        /* 读取IO值        */

96if(value ==0){                /* 按下按键                */

97          atomic_set(&dev->keyvalue, keydesc->value);

98}

99else{                        /* 按键松开                */

100         atomic_set(&dev->keyvalue,0x80| keydesc->value);

101         atomic_set(&dev->releasekey,1);        /* 标记松开按键 */

102}

103}

104

105/*

106  * @description        : 按键IO初始化

107  * @param               : 无

108  * @return              : 无

109  */

110staticint keyio_init(void)

111{

112unsignedchar i =0;

113char name[10];

114int ret =0;

115

116     imx6uirq.nd = of_find_node_by_path("/key");

117if(imx6uirq.nd==NULL){

118         printk("key node not find!\r\n");

119return-EINVAL;

120}

121

122/* 提取GPIO */

123for(i =0; i < KEY_NUM; i++){

124         imx6uirq.irqkeydesc.gpio = of_get_named_gpio(imx6uirq.nd,

"key-gpio", i);

125if(imx6uirq.irqkeydesc.gpio <0){

126             printk("can't get key%d\r\n", i);

127}

128}

129

130/* 初始化key所使用的IO,并且设置成中断模式 */

131for(i =0; i < KEY_NUM; i++){

132         memset(imx6uirq.irqkeydesc.name,0,sizeof(name));

133         sprintf(imx6uirq.irqkeydesc.name,"KEY%d", i);

134         gpio_request(imx6uirq.irqkeydesc.gpio, name);

135         gpio_direction_input(imx6uirq.irqkeydesc.gpio);

136         imx6uirq.irqkeydesc.irqnum = irq_of_parse_and_map(

imx6uirq.nd, i);

137 #if0

138         imx6uirq.irqkeydesc.irqnum = gpio_to_irq(

imx6uirq.irqkeydesc.gpio);

139 #endif

140         printk("key%d:gpio=%d, irqnum=%d\r\n",i,

imx6uirq.irqkeydesc.gpio,

141                                            imx6uirq.irqkeydesc.irqnum);

142}

143/* 申请中断 */

144     imx6uirq.irqkeydesc[0].handler = key0_handler;

145     imx6uirq.irqkeydesc[0].value = KEY0VALUE;

146

147for(i =0; i < KEY_NUM; i++){

148         ret = request_irq(imx6uirq.irqkeydesc.irqnum,

imx6uirq.irqkeydesc.handler,

IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,

imx6uirq.irqkeydesc.name,&imx6uirq);

149if(ret <0){

150             printk("irq %d request failed!\r\n",

imx6uirq.irqkeydesc.irqnum);

151return-EFAULT;

152}

153}

154

155/* 创建定时器 */

156     init_timer(&imx6uirq.timer);

157     imx6uirq.timer.function = timer_function;

158return0;

159}

160

161/*

162  * @description          : 打开设备

163  * @param – inode        : 传递给驱动的inode

164  * @param - filp         : 设备文件,file结构体有个叫做private_data的成员变量

165  *                    一般在open的时候将private_data指向设备结构体。

166  * @return                : 0 成功;其他失败

167  */

168staticint imx6uirq_open(struct inode *inode,struct file *filp)

169{

170     filp->private_data =&imx6uirq;/* 设置私有数据 */

171return0;

172}

173

174/*

175   * @description         : 从设备读取数据

176   * @param – filp        : 要打开的设备文件(文件描述符)

177   * @param – buf        : 返回给用户空间的数据缓冲区

178   * @param - cnt         : 要读取的数据长度

179   * @param – offt        : 相对于文件首地址的偏移

180   * @return               : 读取的字节数,如果为负值,表示读取失败

181   */

182static ssize_t imx6uirq_read(struct file *filp,char __user *buf,

size_t cnt, loff_t *offt)

183{

184int ret =0;

185unsignedchar keyvalue =0;

186unsignedchar releasekey =0;

187struct imx6uirq_dev *dev =(struct imx6uirq_dev *)

filp->private_data;

188

189     keyvalue = atomic_read(&dev->keyvalue);

190     releasekey = atomic_read(&dev->releasekey);

191

192if(releasekey){                                                /* 有按键按下        */

193if(keyvalue &0x80){

194             keyvalue &=~0x80;

195             ret = copy_to_user(buf,&keyvalue,sizeof(keyvalue));

196}else{

197goto data_error;

198}

199         atomic_set(&dev->releasekey,0);        /* 按下标志清零        */

200}else{

201goto data_error;

202}

203return0;

204

205 data_error:

206return-EINVAL;

207}

208

209/* 设备操作函数 */

210staticstruct file_operations imx6uirq_fops ={

211.owner = THIS_MODULE,

212.open = imx6uirq_open,

213.read = imx6uirq_read,

214};

215

216/*

217  * @description        : 驱动入口函数

218  * @param               : 无

219  * @return              : 无

220  */

221staticint __init imx6uirq_init(void)

222{

223/* 1、构建设备号 */

224if(imx6uirq.major){

225         imx6uirq.devid = MKDEV(imx6uirq.major,0);

226         register_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT,

IMX6UIRQ_NAME);

227}else{

228         alloc_chrdev_region(&imx6uirq.devid,0, IMX6UIRQ_CNT,

IMX6UIRQ_NAME);

229         imx6uirq.major = MAJOR(imx6uirq.devid);

230         imx6uirq.minor = MINOR(imx6uirq.devid);

231}

232

233/* 2、注册字符设备        */

234     cdev_init(&imx6uirq.cdev,&imx6uirq_fops);

235     cdev_add(&imx6uirq.cdev, imx6uirq.devid, IMX6UIRQ_CNT);

236

237/* 3、创建类                */

238     imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME);

239if(IS_ERR(imx6uirq.class)){

240return PTR_ERR(imx6uirq.class);

241}

242

243/* 4、创建设备                */

244     imx6uirq.device = device_create(imx6uirq.class,NULL,

imx6uirq.devid,NULL, IMX6UIRQ_NAME);

245if(IS_ERR(imx6uirq.device)){

246return PTR_ERR(imx6uirq.device);

247}

248

249/* 5、始化按键                */

250     atomic_set(&imx6uirq.keyvalue, INVAKEY);

251     atomic_set(&imx6uirq.releasekey,0);

252     keyio_init();

253return0;

254}

255

256/*

257  * @description        : 驱动出口函数

258  * @param               : 无

259  * @return              : 无

260  */

261staticvoid __exit imx6uirq_exit(void)

262{

263unsigned i =0;

264/* 删除定时器 */

265     del_timer_sync(&imx6uirq.timer);

266

267/* 释放中断 */

268for(i =0; i < KEY_NUM; i++){

269         free_irq(imx6uirq.irqkeydesc.irqnum,&imx6uirq);

270}

271     cdev_del(&imx6uirq.cdev);

272     unregister_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT);

273     device_destroy(imx6uirq.class, imx6uirq.devid);

274     class_destroy(imx6uirq.class);

275}

276

277 module_init(imx6uirq_init);

278 module_exit(imx6uirq_exit);

279 MODULE_LICENSE("GPL");

280 MODULE_AUTHOR("zuozhongkai");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值