EQuestionAnswers.com Computer/Electronics Questions and Answers
C, C++, VC++, COM/DCOM, DLL and more
#Login #Sign up  Facebook Twitter TGoogle+
 

#Previous Topic #Index #Next Topic

This is the driver part of the device. We implemented a character driver for our device. We are proramming GPIO and CLKOUT0 registers during open() and mapping physical address of the MMIO using ioremap() to map the address in kernel virtual address space. We are handing read(), write() and same read/write via ioctl(). These read/write/ioctl are blocking and will block in wait queue till device sends an interrupt and wait queue is woke up. We have installed interrupt handler for handing EINT3 for this.

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
10  #include <linux/init.h>
11  #include <linux/mm.h>
12  #include <linux/fs.h>
13  #include <linux/types.h>
14  #include <linux/delay.h>
15  #include <linux/moduleparam.h>
16  #include <linux/slab.h>
17  #include <linux/errno.h>
18  #include <linux/ioctl.h>
19  #include <linux/cdev.h>
20  #include <linux/string.h>
21  #include <linux/list.h>
22  #include <linux/pci.h>
23  #include <linux/gpio.h>
24  #include <asm/uaccess.h>
25  #include <asm/atomic.h>
26  #include <asm/unistd.h>
27  #include <linux/sched.h>
28  #include <linux/wait.h>
29 
30  #define DEVICE_NAME "myled"
31  #define GPACON  0x56000000 
32  #define GPA13   (<< 13)
33  #define MISCCR 0x56000080 
34  #define GPHCON 0x56000070
35  #define LEDBASE 0x10000000
36  #define IO_READ 0
37  #define IO_WRITE 1
38  #define IO_NONE (-1)
39 
40  wait_queue_head_t my_write_wait;
41  wait_queue_head_t my_read_wait;
42  spinlock_t myled_lock = SPIN_LOCK_UNLOCKED;
43 
44  static unsigned char __iomem *base_ledaddr = NULL;
45  static int dev_req[2] = { IO_NONE, IO_NONE };
46  void Clk0_Enable(int clock_sel)  
47  {
48    /* 0:MPLLin, 1:UPLL, 2:FCLK, 3:HCLK, 4:PCLK, 5:DCLK0 */
49    unsigned int __iomem *rMISCCR, *rGPHCON;
50    rMISCCR = ioremap(MISCCR, 0x100);
51    if (rMISCCR) {
52      *rMISCCR = (*rMISCCR & (~(7<<4))) | (clock_sel<<4);
53      iounmap(rMISCCR);
54    }
55    rGPHCON = ioremap(GPHCON, 0x100);
56    if (rMISCCR) {
57      *rGPHCON = (*rGPHCON & (~(3<<18))) | (2<<18);
58      iounmap(rGPHCON);
59    }
60    
61  }
62  static irqreturn_t myled_interrupt(int irq, void *dev_id)
63  {
64    int *req = (int*)dev_id;
65    printk("Entered %s\n", "myled_interrupt");
66    
67    if (req[0] == IO_READ) {
68      printk("wakeup read\n");
69      wake_up_interruptible(&my_read_wait);
70      dev_req[0] = IO_NONE;
71    } else if(req[1] == IO_WRITE) {
72      printk("wakeup write\n");
73      wake_up_interruptible(&my_write_wait);
74      dev_req[1] = IO_NONE;
75    }
76    
77    return IRQ_RETVAL(IRQ_HANDLED);
78  }
79  static int myled_open (struct inode *inodep,
80                         struct file *filep)
81  {
82    int err = 0;
83    unsigned int __iomem *base_addr;
84    unsigned long flags;
85    if(base_ledaddr != NULL) return -1;
86    printk("Entered %s\n", "myled_open");
87    base_addr = ioremap(GPACON, 0x100);
88    if(base_addr) {
89      *base_addr = *base_addr  | GPA13;
90    }
91    iounmap(base_addr);
92    Clk0_Enable(4);
93    init_waitqueue_head (&my_read_wait);
94    init_waitqueue_head (&my_write_wait);
95    base_ledaddr = ioremap(LEDBASE, 0x100);
96    if(base_ledaddr == NULL) {
97      return -1;
98    }
99    spin_lock_irqsave(&myled_lock, flags);
100    dev_req[0] = IO_NONE;
101    dev_req[1] = IO_NONE;
102    spin_unlock_irqrestore(&myled_lock, flags);
103      err = request_irq(IRQ_EINT3,
104                        myled_interrupt,
105                        IRQ_TYPE_LEVEL_LOW, 
106                        DEVICE_NAME,
107                        (void *)dev_req);
108    return err;
109    
110  }
111  static int myled_release (struct inode *inodep,
112                            struct file *filep)
113  {
114    unsigned long flags;
115    printk("Entered %s\n", "myled_release");
116    if(base_ledaddr){
117      iounmap(base_ledaddr);
118      base_ledaddr = NULL;
119    }
120    free_irq(IRQ_EINT3, (void *)&dev_req);
121    spin_lock_irqsave(&myled_lock, flags);
122    dev_req[0] = IO_NONE;
123    dev_req[1] = IO_NONE;
124    spin_unlock_irqrestore(&myled_lock, flags);
125     return 0;
126    
127  }
128  static ssize_t myled_read (struct file *filep,
129                             char __user * val,
130                             size_t sizen,
131                             loff_t * off)
132  {
133    
134    unsigned char k_val;
135    unsigned long flags;
136    printk("Entered %s\n", "myled_read");
137    spin_lock_irqsave(&myled_lock, flags);
138    dev_req[0] = IO_READ;
139    k_val = *base_ledaddr;
140    spin_unlock_irqrestore(&myled_lock, flags);
141    wait_event_interruptible(my_read_wait,
142                               (dev_req[0] == IO_NONE));
143    copy_to_user(val, &k_val, 1);
144    return 1;
145  }
146  static ssize_t myled_write(struct file *filep,
147                             const char __user *val,
148                             size_t sizen,
149                             loff_t * off)
150  {
151 
152    unsigned char k_val;
153    unsigned long flags;
154    printk("Entered %s\n", "myled_write");
155    copy_from_user(&k_val, val, 1);
156    spin_lock_irqsave(&myled_lock, flags);
157    dev_req[1] = IO_WRITE;
158    *base_ledaddr = k_val;
159    spin_unlock_irqrestore(myled_lock, flags);
160    wait_event_interruptible(my_write_wait,
161                               (dev_req[1] == IO_NONE));
162    return 1;
163  }
164  static int myled_ioctl(
165    struct inode *inode, 
166    struct file *file, 
167    unsigned int cmd, 
168    unsigned long val)
169  {
170    unsigned char k_val;
171    unsigned long flags;
172    printk("Entered %s request %s\n",
173              "myled_ioctl", (cmd == IO_READ) ? "READ" : "WRITE");
174    switch(cmd) {
175      case IO_READ:
176        spin_lock_irqsave(&myled_lock, flags);
177        dev_req[0] = IO_READ;
178        k_val = *base_ledaddr;
179        spin_unlock_irqrestore(&myled_lock, flags);
180        wait_event_interruptible(my_read_wait,
181                                 (dev_req[0] == IO_NONE));
182        copy_to_user((unsigned char *)val, &k_val, 1);
183        return 0;
184      case IO_WRITE:
185        copy_from_user(&k_val, (unsigned char *)val, 1);
186        spin_lock_irqsave(&myled_lock, flags);
187        dev_req[1] = IO_WRITE;
188        *base_ledaddr = k_val;
189        spin_unlock_irqrestore(&myled_lock, flags);
190        wait_event_interruptible(my_write_wait,
191                                 (dev_req[1] == IO_NONE));
192      return 0;
193    default:
194      return -EINVAL;
195    }
196  }
197 
198  static struct file_operations dev_fops = {
199    .owner  =  THIS_MODULE,
200    .ioctl  =  myled_ioctl,
201    .open   =  myled_open,
202    .release   =  myled_release,
203    .read    = myled_read,
204    .write   = myled_write,
205  };
206 
207  static struct miscdevice misc = {
208    .minor = MISC_DYNAMIC_MINOR,
209    .name = DEVICE_NAME,
210    .fops = &dev_fops,
211  };
212 
213  static int __init leddev_init(void)
214  {
215    int ret;
216    printk("Entered %s\n", "leddev_init");
217    ret = misc_register(&misc);
218 
219    printk (DEVICE_NAME"\tinitialized\n");
220 
221    return ret;
222  }
223 
224  static void __exit leddev_exit(void)
225  {
226    printk("Entered %s\n", "leddev_exit");
227    misc_deregister(&misc);
228  }
229 
230  module_init(leddev_init);
231  module_exit(leddev_exit);
232  MODULE_LICENSE("GPL");
233  MODULE_AUTHOR("EQuestionAnswers.com Inc.");
234 

You have viewed 1 page out of 14. Your learning is 0.00% complete. Login to check your learning progress.

 Vote 0

Similar topics related to this section

Altera FPGA interfacing ARM, ARM CPU internals, ARM CPU, Cache Memory and MMU, ARM bus hierarchy, ARM data, address and control lines, ARM MMIO read, ARM MMIO write, FPGA interfacing with system bus, VHDL/Verilog program, ADS C Code, Linux Direct MMIO App, Linux Device Driver, Linux Application code, Final Demo,

* #1 webmaster Tue 15 Apr/2014 04:50:28(GMT)  Like 0 Unlike 0

Dear Users,

We are pleased to inform you that a forum/blog has been incorporated with www.equestionanswers.com. You are welcomed to add your comments, requests, codes, solutions and feedback to it. Please login(if already a member) or signup(for free) to avail to this facility.

Regards,
Webmaster

Your message goes here:

Name:Guest
Email:anonymous@unknown.com
My Post:*
Secutiry Code: ******  *
Preview this compose before posting this in discussion forum.
 
Note:
  1. Use [Sxx] code to show smiles. Example [S02]
  2. Use [URL ], example [URL http://www.google.com/]
  3. To display code or un formatted text use [CODE] [/CODE]. Example: [CODE] printf("Hello world"); [/CODE]
 [S01]   [S02]   [S03]   [S04]   [S05]   [S06]   [S07]   [S08] 
 [S09]   [S10]   [S11]   [S12]   [S13]   [S14]   [S15]   [S16] 
 [S17]   [S18]   [S19]   [S20]   [S21]   [S22]   [S23]   [S24] 

Note: Only members are allowed, * fields are mandatory.