Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1298845
  • 博文数量: 548
  • 博客积分: 7597
  • 博客等级: 少将
  • 技术积分: 4224
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-15 13:21
个人简介

嵌入式软件工程师&&太极拳

文章分类

全部博文(548)

文章存档

2014年(10)

2013年(76)

2012年(175)

2011年(287)

分类: 嵌入式

2012-05-15 18:19:57


 

点击(此处)折叠或打开

  1. AT91SAM9G20驱动程序设计
  2. 开发环境:Vmware + ubuntu10.04
  3. 硬件平台:AT91SAM9G20
  4. Linux版本:linux2.6.27
  5. 一:led驱动
  6. 说明:因为设计的开发板上没有led灯,便通过PC0来演示,通过示波器来观察引脚端的电平变化。
  7. 1.驱动程序:my_led.c
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/module.h>
  11. #include <linux/fs.h>
  12. #include <linux/cdev.h>
  13. #include <linux/types.h>
  14. #include <asm/gpio.h>

  15. #define MY_LED_MAJOR    250        //定义主设备号
  16. #define LED_ON         0
  17. #define LED_OFF         1
  18. struct global_dev{
  19.     struct cdev cdev;
  20. };    //定义设备结构体
  21. struct global_dev *global_devp;    //定义一个指向设备结构体的指针
  22. static int my_led_open(struct inode *inode, struct file *filp)
  23. {
  24.     filp->private_data = global_devp;
  25.     return 0;
  26. }
  27. static int my_led_release(struct inode *inode, struct file *file)
  28. {
  29.     return 0;
  30. }
  31. static int my_led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
  32. {    
  33.     switch(cmd)
  34.     {
  35.         case LED_ON:
  36.             at91_set_gpio_value(AT91_PIN_PC0, 0);    //将PC0引脚置低
  37.             break;
  38.         case LED_OFF:
  39.             at91_set_gpio_value(AT91_PIN_PC0, 1);    //将PC1引脚置高
  40.             break;
  41.         default:
  42.             printk("no valid cmd input!\n");
  43.             break;
  44.     }
  45.     return 0;
  46. }
  47. struct file_operations my_led_ctl_ops ={
  48.     .owner = THIS_MODULE,
  49.     .open = my_led_open,
  50.     .release = my_led_release,
  51.     .ioctl = my_led_ioctl,
  52. };
  53. /*初始化设备结构体*/
  54. static void my_led_setup(struct global_dev *dev, int index)
  55. {
  56.     int err;
  57.     int devno = MKDEV(MY_LED_MAJOR, index);
  58.     cdev_init(&dev->cdev, &my_led_ctl_ops);
  59.     dev->cdev.owner = THIS_MODULE;
  60.     dev->cdev.ops = &my_led_ctl_ops;
  61.     err = cdev_add(&dev->cdev, devno, 1);
  62.     if(err)
  63.         printk("add my led setup failed!\n");
  64. }
  65. static int my_led_init(void)
  66. {
  67.     int ret;
  68.     dev_t devno = MKDEV(MY_LED_MAJOR, 0);    //创建设备号
  69.     printk("my first driver--led!\n");
  70.     at91_set_GPIO_periph(AT91_PIN_PC0, 1);
  71.     at91_set_gpio_output(AT91_PIN_PC0, 1);    //对PC0引脚的初始化
  72.     ret = register_chrdev_region(devno, 1, "my_led");    //申请设备号
  73.     if( ret < 0) {
  74.         printk("my_led init_module failed with %d\n", ret);
  75.         return ret;
  76.     }
  77.     else
  78.         printk("my_led init_module success!\n");
  79.     global_devp = kmalloc(sizeof(struct global_dev), GFP_KERNEL);    //申请设备内存
  80.     memset(global_devp, 0, sizeof(struct global_dev));
  81.     my_led_setup(global_devp, 0);
  82.     return ret;
  83. }
  84. static void my_led_cleanup(void)
  85. {
  86.     cdev_del(&global_devp->cdev);    //删除设备
  87.     kfree(global_devp);        //释放内存
  88.     unregister_chrdev_region(MKDEV(MY_LED_MAJOR, 0), 1);    //释放设备号
  89. }
  90. MODULE_LICENSE("MYGPL");
  91. MODULE_AUTHOR("FANY");
  92. module_init(my_led_init);    //注册设备
  93. module_exit(my_led_cleanup);    //卸载设备
  94. 2:如何将驱动驱动程序编译成模块
  95. ①在drivers目录下新建led目录,并在该目录下添加Kconfig,Makefile文件。
  96. Kconfig:
  97. Menu "My driver support"
  98. Config
  99. Trisate "led driver!"
  100. Help
  101. Led driver
  102. Endmenu:
  103. Makefile:
  104. Obj-$(CONFIG_MY_LED)    += my_led.o
  105. ②修改linux/drivers目录下的Kconfig,Makefile文件
  106. Kconfig:
  107. Source "drivers/led/Kconfig"
  108. Makefile:
  109. Obj-y     += my_led/
  110. ③修改体系结构目录arch/arm目录下的Kconfig文件,否则在配置菜单中将无法看到led的配置选项。(如果是在drivers目录下新建一文件夹,并在其中添加驱动程序,必须相应的体系结构目录下添加配置选项)。
  111. Kconfig:
  112. Source "driver/led/Kconfig"
  113. 3.测试程序:my_led_test.c
  114. #include <stdio.h>
  115. #include <string.h>
  116. #include <stdlib.h>
  117. #include <fcntl.h>
  118. #include <unistd.h>

  119. #define DEVICE_NAME "/dev/my_led"
  120. #define LED_ON    0
  121. #define LED_OFF     1

  122. int main(void)
  123. {
  124.     int fd;
  125.     int ret;
  126.     int i;
  127.     printf("my_led_driver test!\n");

  128.     fd = open(DEVICE_NAME, O_RDONLY);
  129.     if(fd == -1)
  130.         printf("open device %s error!\n", DEVICE_NAME);
  131.     for(i = 0; i < 50; i++)
  132.     {
  133.         ioctl(fd, LED_OFF);
  134.         sleep(1);
  135.         ioctl(fd, LED_ON);
  136.         sleep(1);
  137.     }
  138.     ret = close(fd);
  139.     printf("ret = %d\n", ret);
  140.     printf("close my_led_driver!\n");
  141.     return 0;
  142. }

  143. 将测试程序编译成目标平台的可执行文件,并下载到开发板
  144. GCC=/home/zzq/9G20/arm-2007q1/bin/arm-none-linux-gnueabi-gcc #交叉编译器的路径
  145. My_led_test:my_led_test.c
  146.     $(GCC) -o my_led_test my_led_test.c
  147. clean:
  148.     rm -f my_led_test
  149. 学习总结:熟悉驱动程序的架构,如何将驱动程序添加到内核即如何写测试程序。
  150. 二:按键驱动设计
  151. 1.硬件部分:PC4接按键。
  152. 2.驱动程序:
  153. #include <linux/module.h>
  154. #include <linux/cdev.h>
  155. #include <linux/init.h>
  156. #include <linux/fs.h>
  157. #include <linux/interrupt.h>
  158. #include <linux/irq.h>
  159. #include <linux/sched.h>
  160. #include <linux/pm.h>
  161. #include <linux/sysctl.h>
  162. #include <linux/proc_fs.h>
  163. #include <linux/delay.h>
  164. #include <linux/input.h>
  165. #include <linux/gpio_keys.h>

  166. #include <asm/gpio.h>
  167. #include <asm/uaccess.h>
  168. #include <asm/io.h>
  169. #include <asm/irq.h>
  170. #include <mach/gpio.h>

  171. #define BUTTON_MAJOR    245
  172. #define DEVICE_NAME     "/dev/button"

  173. static volatile int ev_press = 0;
  174. static struct cdev button_cdev;

  175. static void button_do_tasklet(unsigned long n);
  176. DECLARE_TASKLET(button_tasklet, button_do_tasklet, 0);//定义tasklet并与处理函数关联起来

  177. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//静态的初始化一个等待队列

  178. struct button_irq_desc {
  179.     int irq;
  180.     int irq_type;
  181.     int pin;
  182.     int number;
  183.     char *name;
  184. };

  185. static struct button_irq_desc button_irq[1] = { {AT91_PIN_PB22, AT91_AIC_SRCTYPE_LOW, AT91_PIN_PB22, 0, "KEY0"} };

  186. static int key_values[1]={0};
  187. //中断处理底半部
  188. static void button_do_tasklet(unsigned long n)
  189. {
  190.     wake_up_interruptible(&button_waitq);    //唤醒队列
  191.     printk("button press!\n");    
  192. }
  193. //中断处理顶半部
  194. static irqreturn_t button_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  195. {
  196.     int up;
  197.      static int press_down;
  198.     up = gpio_get_value(button_irq[0].pin);
  199.     printk("irq\n");
  200.     /*按键消抖*/
  201.     if(up)    press_down = 1;    //当按键没有按下,置标志位为1.
  202.     if(!up && (press_down == 1)) {            
  203.         press_down = 0; //当按键按下,置标志位为0.    
  204.         ev_press = 1;
  205.         at91_set_gpio_value(button_irq[0].pin, 1);                        
  206.         key_values[button_irq[0].number] = !up;
  207. tasklet_schedule(&button_tasklet);    
  208.     }
  209.     return IRQ_RETVAL(IRQ_HANDLED);
  210. }
  211. static int button_open(struct inode *inode, struct file *filp)
  212. {
  213.     return 0;
  214. }
  215. static int button_release(struct inode *inode, struct file *filp)
  216. {
  217.     return 0;
  218. }
  219. static int button_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
  220. {
  221.     int ret;
  222.     if(!ev_press) {    //当按键没有按下时,读进程挂起,知道按键按下。    
  223.         wait_event_interruptible(button_waitq, ev_press);
  224.     }
  225.     ev_press = 0;
  226.     ret = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
  227.     memset((void __user *)key_values, 0, sizeof(key_values));
  228.     return ret ? -EFAULT:min(sizeof(key_values), count);
  229. }

  230. static struct file_operations button_fops = {
  231.     .owner = THIS_MODULE,
  232.     .open = button_open,
  233.     .release = button_release,
  234.     .read = button_read,
  235. };

  236. static int irq_init(void)
  237. {
  238.     int err;
  239.     at91_set_gpio_input(button_irq[0].pin, 1);
  240.     at91_set_deglitch(button_irq[0].pin, 1);//将PC0设置为中断功能
  241.     set_irq_type(button_irq[0].irq, button_irq[0].irq_type);//设置中断类型
  242.     at91_set_gpio_value(button_irq[0].pin, 1);

  243.     err = request_irq( button_irq[0].irq, button_interrupt, IRQF_DISABLED, \
  244.             button_irq[0].name, (void *)&button_irq[0]);//申请中断
  245.     if ( err ) {
  246.         disable_irq(button_irq[0].irq);
  247.         free_irq(button_irq[0].irq, (void *)&button_irq[0]);
  248.         return -EBUSY;
  249.     }    

  250.     return 0;
  251. }

  252. static int __init button_init(void)
  253. {
  254.     int ret, err;
  255.     ret = register_chrdev_region(MKDEV(BUTTON_MAJOR, 0), 1, DEVICE_NAME);
  256.     if(ret < 0) {
  257.         printk("button init failed with %d\n", ret);
  258.         return ret;
  259.     }
  260.     cdev_init(&button_cdev, &button_fops);
  261.     button_cdev.owner = THIS_MODULE;
  262.     button_cdev.ops = &button_fops;
  263.     err = cdev_add(&button_cdev, MKDEV(BUTTON_MAJOR, 0), 1);
  264.     if( err<0 ) {
  265.         printk("key add failed\n");
  266.         return err;
  267.     }
  268.     irq_init();
  269.     printk("key driver add success!\n");
  270.     return 0;
  271. }
  272. static void __exit button_exit(void)
  273. {
  274.     cdev_del(&button_cdev);
  275.     unregister_chrdev_region(MKDEV(BUTTON_MAJOR, 0), 1);
  276.     disable_irq(button_irq[0].irq);
  277.     free_irq(button_irq[0].irq, (void *)&button_irq[0]);
  278.     printk("unregister key driver!\n");
  279. }
  280. module_init(button_init);
  281. module_exit(button_exit);
  282. MODULE_AUTHOR("fany");
  283. MODULE_DESCRIPTION("Atmel9g20 key Driver");
  284. MODULE_LICENSE("GPL");
  285. 3.测试程序:
  286. #include <stdio.h>
  287. #include <string.h>
  288. #include <stdlib.h>
  289. #include <fcntl.h>
  290. #include <unistd.h>
  291. #include <errno.h>

  292. #define DEVICE_NAME "/dev/button"

  293. int main(void)
  294. {
  295.     int fd,i;
  296.     int ret;
  297.     int key_value[1];
  298.     printf("key test!\n");
  299.     fd = open(DEVICE_NAME, O_RDWR);
  300.     if(fd < 0)
  301.         printf("open device %s error!\n", DEVICE_NAME);
  302.     else
  303.         printf("open device success!\n");
  304.     while(1) {
  305.         ret = read(fd, key_value, 1);
  306.         if( !ret ) {
  307.             printf("button not press!\n");
  308.         }
  309.         else
  310.             printf("button press!\n");    
  311.         printf("key_value %d\n", key_value);
  312.     }
  313.     close(fd);
  314.     printf("close key driver!\n");
  315.     return 0;
  316. }
  317. 4.学习总结:
  318. 在linux设备驱动程序中,中断处理程序通常分为两部分:上半部和下半部。上半部处理比较紧急的的硬件操作,比如简单的读取寄存器中的状态并清除中断标志后,进行登记中断的工作。剩下的工作就由下半部来实现。
  319. 对阻塞与非阻塞进程的理解,阻塞:在执行设备操作时,若不能获取设备资源则挂起,直到满足可操作的条件后再进行操作。非阻塞操作:在执行设备操作时,若不能获取设备资源则立即返回。
  320. 三:总线驱动
  321. AT91SAM9G20存储器映射图(截取部分),片选4接外设,利用总线对外设进行访问。

  322. 但是在linux驱动,不能对物理地址进行操作,可通过内存访问的机制实现对物理地址的访问。将一段物理地址空间映射到虚拟地址空间中,然后对虚拟地址的操作即是对物理地址的操作。

  323. 3.1:总线驱动
  324. #include <linux/module.h>
  325. #include <linux/errno.h>
  326. #include <linux/types.h>
  327. #include <linux/device.h>
  328. #include <linux/fs.h>
  329. #include <linux/platform_device.h>
  330. #include <linux/init.h>
  331. #include <linux/cdev.h>

  332. #include <asm/io.h>
  333. #include <asm/uaccess.h>
  334. #include <mach/gpio.h>
  335. #include <mach/at91sam9_smc.h>
  336. #include <mach/at91sam9260_matrix.h>
  337. #include <mach/at91sam9260.h>
  338. #include <mach/at91_pmc.h>
  339. #include "atmel9g20_liu.h"

  340. struct gr_liu_info {
  341.     void __iomem    *virtbase;
  342.     void __iomem    *regbase;
  343.     struct resource *res;
  344.     u32    flags;
  345. };

  346. static struct gr_liu_info liu_info;
  347. static struct cdev atmel9g20_liu_cdev;

  348. unsigned short liu_read(unsigned addr)
  349. {    
  350.     addr &= ATMEL9G20_LIU_MASK;
  351.     addr = addr << 1;
  352.     addr += (unsigned long)liu_info.regbase;
  353.     printk("read the virtual addr is 0x%x\n", addr);
  354.     return readw(addr) & 0xff;    //读IO内存。
  355. }
  356. EXPORT_SYMBOL(liu_read);

  357. int liu_write(unsigned addr, unsigned val)
  358. {
  359.     addr &= ATMEL9G20_LIU_MASK;
  360.     addr = addr << 1;
  361.     addr += (unsigned long)liu_info.regbase;
  362.     printk("write the virtual addr is 0x%x\n", addr);
  363.     writew(val&0xff, addr);    //写IO内存
  364.     return 0;
  365. }
  366. EXPORT_SYMBOL(liu_write);

  367. static int atmel9g20_liu_open(struct inode *inode, struct file *filp)
  368. {    
  369.     return 0;
  370. }

  371. static int atmel9g20_liu_release(struct inode *inode, struct file *filp)
  372. {
  373.     return 0;
  374. }

  375. static int atmel9g20_liu_ioctl(struct inode *inode, struct file *filp, unsigned cmd, unsigned long arg)
  376. {
  377.     int ret;
  378.     liu_ctlf_t ctlf;
  379.     
  380.     switch (cmd) {
  381.         case LIU_IOCSET:
  382.             ret = copy_from_user(&ctlf, (liu_ctlf_t __user *)arg, sizeof(liu_ctlf_t));
  383.                 if (ret)
  384.                 return ret;
  385.                 printk("input addr is 0x%x,input val is 0x%x\n",ctlf.addr, ctlf.val);
  386.             liu_write(ctlf.addr, ctlf.val);
  387.             return ret;

  388.         case LIU_IOCGET:
  389.             ret = copy_from_user(&ctlf, (liu_ctlf_t __user *)arg, sizeof(liu_ctlf_t));
  390.             if (ret)
  391.                 return ret;
  392.             ctlf.val = liu_read(ctlf.addr);            
  393.             if (copy_to_user((void __user *)arg, &ctlf, sizeof(liu_ctlf_t)))
  394.                 return -EFAULT;
  395.             return ret;
  396.     }
  397.     return -ENOTTY;
  398. }

  399. static const struct file_operations atmel9g20_liu_fops = {
  400.     .owner    =     THIS_MODULE,
  401.     .open        =    atmel9g20_liu_open,
  402.     .ioctl        =    atmel9g20_liu_ioctl,
  403.     .release    =    atmel9g20_liu_release,
  404. };
  405. static int __devinit liu_probe(struct platform_device *pdev)
  406. {
  407.     int ret = 0;    
  408.     if (pdev->num_resources != 1) {
  409.         ret = -ENODEV;
  410.         goto err1;
  411.     }
  412. //IO内存的申请
  413.     liu_info.res = request_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1, "9g20-liu");

  414.     if (!liu_info.res) {
  415.         printk("liu: can't get request mem region");
  416.         ret = -ENOMEM;
  417.         goto err1;
  418.     }
  419. //IO内存的映射
  420.     liu_info.regbase = ioremap(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1);
  421.     printk("request virtual addr liu_info.regbase=0x%x\n",(unsigned int)liu_info.regbase);
  422.     if (liu_info.regbase == NULL) {
  423.         printk("liu: can't get ioremap mem\n");
  424.         ret = -ENOMEM;
  425.         goto err2;
  426.     }
  427.     dev_set_drvdata(&pdev->dev, &liu_info);
  428.     printk("LIU probe done!\n");    
  429.     return 0;    
  430. err2:
  431.     release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1);
  432. err1:
  433.     return ret;
  434. }

  435. static int liu_remove(struct platform_device *pdev)
  436. {
  437.     struct gr_liu_info *fi;
  438.     fi = pdev->dev.driver_data;
  439.     iounmap(fi->regbase);//解除映射,
  440.     release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1);//释放内存
  441.     fi->flags = 0x0;
  442.     return 0;
  443. }

  444. static struct platform_driver liu_driver = {
  445.     .probe = liu_probe,
  446.     .remove = liu_remove,
  447.     .driver = {
  448.         .name = "9g20-liu",
  449.         .owner = THIS_MODULE,
  450.     },
  451. };
  452. //设置SMC寄存器
  453. static void cs4_init(void)
  454. {
  455.     at91_sys_write(AT91_MATRIX_EBICSA,at91_sys_read(AT91_MATRIX_EBICSA) | AT91_MATRIX_CS4A_SMC);
  456.     
  457.     /* Configure SMC CS4 */
  458.     at91_sys_write(AT91_SMC_SETUP(4),
  459.          AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(2) |
  460.          AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(2));
  461.     at91_sys_write(AT91_SMC_PULSE(4),
  462.          AT91_SMC_NWEPULSE_(12) | AT91_SMC_NCS_WRPULSE_(10) |
  463.          AT91_SMC_NRDPULSE_(12) | AT91_SMC_NCS_RDPULSE_(10));
  464.     at91_sys_write(AT91_SMC_CYCLE(4),
  465.          AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
  466.     at91_sys_write(AT91_SMC_MODE(4),
  467.          AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_DBW_16 |
  468.          AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(3));

  469.     at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_PIOC);

  470.     /* Enable CS4 */
  471.         at91_set_A_periph(AT91_PIN_PC8, 1);

  472.         printk("*************at91sam9g20ek_ebibus_cs4_init*******\n");    
  473. }

  474. static int __init atmel9g20_liu_init(void)
  475. {
  476.     int ret,err;
  477.     ret = register_chrdev_region(MKDEV(LIU_MAJOR, 0), 1, "/dev/liu");

  478.     if( ret < 0) {
  479.         printk("LIU init_module failed with %d\n", ret);
  480.         return ret;
  481.     }    

  482.     cdev_init(&atmel9g20_liu_cdev, &atmel9g20_liu_fops);
  483.     atmel9g20_liu_cdev.owner = THIS_MODULE;
  484.     atmel9g20_liu_cdev.ops = &atmel9g20_liu_fops;
  485.     err = cdev_add(&atmel9g20_liu_cdev, MKDEV(LIU_MAJOR, 0), 1);
  486.     
  487.     if( err<0 ) {
  488.         printk("liu add failed\n");
  489.         return err;
  490.     }
  491.     cs4_init();    
  492.     return platform_driver_register(&liu_driver);    //注册平台设备。
  493. }
  494. static void __exit atmel9g20_liu_cleanup(void)
  495. {
  496.     printk("atmel 9g20 liu exit\n");

  497.     cdev_del(&atmel9g20_liu_cdev);
  498.     unregister_chrdev_region(MKDEV(LIU_MAJOR, 0), 1);
  499.     platform_driver_unregister(&liu_driver);
  500. }

  501. module_init(atmel9g20_liu_init);
  502. module_exit(atmel9g20_liu_cleanup);
  503. MODULE_AUTHOR("fany");
  504. MODULE_DESCRIPTION("Atmel9g20 liu Driver");
  505. MODULE_LICENSE("GPL");
  506. 并在/arch/arm/mach-at91/board-sam9g20ek.c中初始化
  507. #define GR_LIU_BASE 0x50000000
  508. #define GR_LIU_SIZE 0x1000
  509. static struct resource gr_liu_resource[] = {
  510.     {        
  511.         .start        = GR_LIU_BASE,
  512.         .end        = GR_LIU_BASE + GR_LIU_SIZE - 1,
  513.         .flags        = IORESOURCE_MEM,
  514.     }
  515. };

  516. static struct platform_device grd_liu = {
  517.     .name    = "9g20-liu",
  518.     .id        = -1,
  519.     .dev        = {
  520.                 .platform_data    = NULL,
  521.             },
  522.     .resource    = gr_liu_resource,
  523.     .num_resources    = 1,
  524. };

  525. static void __init at91_add_device_liu(void) {    
  526.     platform_device_register(&grd_liu);
  527.      printk("*************at91_add_device_liu*******\n");
  528. }
  529. static void __init ek_board_init(void)
  530. {
  531. ........
  532. at91_add_device_liu();
  533. }
  534. 3.2:总线驱动测试程序:
  535. #include <sys/types.h>
  536. #include <sys/fcntl.h>
  537. #include <sys/ioctl.h>
  538. #include <stdio.h>
  539. #include <stdlib.h>
  540. #include <string.h>
  541. #include <math.h>

  542. #define DRIVER_LIU_FILE         "/dev/liu"
  543. #define LIU_IOCSET _IOW('i',30,liu_ctlf_t)
  544. #define LIU_IOCGET _IOWR('i',31,liu_ctlf_t)

  545. typedef struct liu_ctlf{
  546.     unsigned addr;
  547.     unsigned val;
  548. }liu_ctlf_t;
  549. //写IO内存
  550. unsigned int LiuWrite(unsigned addr, unsigned data)
  551. {
  552.     int liu_fd;
  553.     liu_ctlf_t ctlf;

  554.     liu_fd = open(DRIVER_LIU_FILE, O_RDWR, 0666);
  555.     if (liu_fd<0)
  556.     {
  557.       printf("open liu file error!\n");
  558.      return -1;
  559.     }
  560.     ctlf.addr = addr;
  561.     ctlf.val = data&0xffff;
  562.     ioctl(liu_fd, LIU_IOCSET, &ctlf);
  563.     close(liu_fd);
  564.     return (0);
  565. }
  566. //读IO内存
  567. unsigned int LiuRead(unsigned addr)
  568. {
  569.     int liu_fd;
  570.     liu_ctlf_t ctlf;

  571.     liu_fd = open(DRIVER_LIU_FILE, O_RDONLY, 0666);
  572.         if (liu_fd<0)
  573.         {
  574.              printf("open liu file error!\n");
  575.          return -1;
  576.         }
  577.     ctlf.addr=addr;
  578.     ctlf.val = 0;
  579.         ioctl(liu_fd,LIU_IOCGET, &ctlf);
  580.     close(liu_fd);
  581.         return ((ctlf.val)&0xffff);
  582. }

  583. int main(int argc, const char * * argv)
  584. {
  585.     unsigned int LiuAddr, value, readBack;
  586.     if (argc < 3) {
  587.         printf("writeFpgaReg addr value\n");
  588.         return -1;
  589.     }
  590.     sscanf(argv[1],"%x", &LiuAddr);
  591.     sscanf(argv[2],"%x", &value);
  592.     LiuWrite(LiuAddr, value);
  593.     readBack = LiuRead(LiuAddr);
  594.     printf("readback: 0x%0x=0x%x\n",LiuAddr, readBack);

  595.     return 0;
  596. }
  597. 输入命令的格式为:./test addr val
  598. 片选4的物理地址为0x50000000,申请一段从0x50000000开始的一段内存空间,其大小为0xffff,并将这段地址空间做映射,在上层对物理地址的操作既是对这一段虚拟地址空间的操作。
  599. 4:信号量
  600. 当多个执行单元,同时并行执行,在获取共享资源时,可能发生冲突,如何利用信号量来保护临界区代码,解决冲突。
  601. #include <linux/module.h>
  602. #include <linux/init.h>
  603. #include <linux/fs.h>
  604. #include <linux/types.h>
  605. #include <linux/errno.h>
  606. #include <linux/mm.h>
  607. #include <linux/slab.h>
  608. #include <linux/kernel.h>
  609. #include <linux/sched.h>
  610. #include <linux/cdev.h>

  611. #include <asm/io.h>
  612. #include <asm/system.h>
  613. #include <asm/uaccess.h>

  614. #define MEMDEV_MAJOR 200

  615. #define MEM_SIZE 100

  616. struct mem_dev {
  617.     struct cdev cdev;
  618.     unsigned char mem[MEM_SIZE];
  619.     struct semaphore sem;    //定义信号量
  620. };

  621. struct mem_dev *mem_devp;

  622. int memdev_open(struct inode *inode, struct file *filp) {
  623.     filp->private_data = mem_devp;
  624.     return 0;
  625. }

  626. int memdev_release(struct inode *inode, struct file *filp) {
  627.     return 0;
  628. }

  629. static ssize_t memdev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
  630. {
  631.     unsigned long p = *ppos;
  632.     unsigned int count = size;
  633.     int ret = 0;
  634.     
  635.     struct mem_dev *dev = filp->private_data;

  636.     if(p > MEM_SIZE)
  637.         return count;
  638.     if(count > MEM_SIZE - p)
  639.         count = MEM_SIZE - p;
  640.     
  641.     if(down_interruptible(&dev->sem)){    //获取信号量
  642.         return -ERESTARTSYS;
  643.     }

  644.     if(copy_to_user(buf, (void *)(dev->mem + p), count)) {
  645.         return - EFAULT;
  646.     }
  647.     else {
  648.         *ppos += count;
  649.         ret = count;
  650.         printk("read %d bytes from %d\n", count, (unsigned int)p);
  651.     }
  652.     up(&dev->sem);    //释放信号量
  653.     return ret;
  654. }

  655. static ssize_t memdev_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
  656. {
  657.     unsigned long p = *ppos;
  658.     unsigned count = size;
  659.     int ret = 0;

  660.     struct mem_dev *dev = filp->private_data;

  661.     if(p > MEM_SIZE)
  662.         return count;
  663.     if(count > MEM_SIZE - p)
  664.         count = MEM_SIZE - p;

  665.     if(copy_from_user(dev->mem + p, buf, count))
  666.         return -EFAULT;
  667.     else {
  668.         *ppos += count;
  669.         ret = count;
  670.         printk("write %d bytes from %d\n", count, (unsigned int)p);
  671.     }
  672.     
  673.     return ret;
  674. }

  675. static loff_t memdev_llseek(struct file *filp, loff_t offset, int orig)
  676. {
  677.     switch(orig) {
  678.         case SEEK_SET:
  679.             if((offset < 0) || (offset > MEM_SIZE))
  680.                 return -EINVAL;
  681.             filp->f_pos = (unsigned int)offset;
  682.             break;
  683.         case SEEK_CUR:
  684.             if(((filp->f_pos + offset) > MEM_SIZE) || ((filp->f_pos + offset)< 0))
  685.                 return -EINVAL;
  686.             filp->f_pos = filp->f_pos + offset;
  687.             break;
  688.         default:
  689.             return -EINVAL;
  690.             break;
  691.     }
  692.     return filp->f_pos;
  693. }

  694. static const struct file_operations mem_fops = {
  695.     .owner = THIS_MODULE,
  696.     .open = memdev_open,
  697.     .release = memdev_release,
  698.     .read = memdev_read,
  699.     .write = memdev_write,
  700.     .llseek = memdev_llseek,
  701. };

  702. static void memdev_setup_cdev(struct mem_dev *dev, int index)
  703. {
  704.     int err;
  705.     dev_t devno = MKDEV(MEMDEV_MAJOR, index);
  706.     cdev_init(&dev->cdev, &mem_fops);
  707.     dev->cdev.owner = THIS_MODULE;
  708.     dev->cdev.ops = &mem_fops;
  709.     err = cdev_add(&dev->cdev, devno, 1);
  710.     if(err < 0) {
  711.         printk("add memdev failed!\n");
  712.     }
  713. }
  714. static int memdev_init(void)
  715. {
  716.     int ret;
  717.     dev_t devno = MKDEV(MEMDEV_MAJOR, 0);
  718.     ret = register_chrdev_region(devno, 1, "/dev/memdev");
  719.     if (ret < 0)
  720.     {
  721.         printk("register memdev failed\n");
  722.         return ret;
  723.     }

  724.     mem_devp = kmalloc(sizeof(struct mem_dev), GFP_KERNEL);
  725.     if(!mem_devp)
  726.     {
  727.         printk("kmalloc failed!\n");
  728.     }
  729.     memset(mem_devp, 0, sizeof(struct mem_dev));

  730.     memdev_setup_cdev(mem_devp, 0);

  731.     init_MUTEX(&mem_devp->sem);    //初始化信号量
  732.     
  733.     printk("memdev init!\n");
  734.     return 0;
  735. }

  736. static void memdev_exit(void)
  737. {
  738.     cdev_del(&mem_devp->cdev);
  739.     kfree(mem_devp);
  740.     unregister_chrdev_region(MKDEV(MEMDEV_MAJOR, 0), 1);
  741.     printk("memdev exit!\n");
  742. }

  743. MODULE_LICENSE("GPL");
  744. MODULE_DESCRIPTION("MEM DRIVERS");
  745. MODULE_AUTHOR("FANY");

  746. module_init(memdev_init);
  747. module_exit(memdev_exit);


 

阅读(1316) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~