📄 de2_buttons.c
字号:
/* Copyright (C) 2007 Philipp Lutz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/////////////////////////////////////////////////////////////////////////////////////////////////////*Description:------------This device driver reads the button-values of the DE2 board using an interrupt. As soon as the driver isloaded into the kernel (module or build-in) the interrupt is registered and everytime a button was pressedthis chracter device driver reads out the button-values and stores it in kernel-space memory.For a more sophisticated device driver with kernel work-processes and nonblocking read-accesslook at "drivers/char/altera_pio_button.c".It uses the major number (BUTTONS_MAJOR) to be able to create a corresponding device file to access the buttons.In uClinux for NIOS2 the automatic creation of device files is found in the script located at"vendors/Altera/nios2nommu/romfs_list".In uClinux it works with the following command:mknod /dev/buttons 666 c 240 0*////////////////////////////////////////////////////////////////////////////////////////////////////// // Debug defines:// --------------//// uncomment following line to use the kernelmodule without// io (inb / outb) functions, needed for debug purposses on host machine.//#define TEST// enables debug-kernel-messages (viewed directly in the shell or via "dmesg" command)//#define DEBUG///////////////////////////////////////////////////////////////////////////////////////////////////#include "de2_includes.h"#define BUTTONS_MAJOR 244#define BUTTONS_MINOR 0#define BUTTONS_BASE na_KEY#define BUTTONS_IRQ na_KEY_irq#define BUTTONS_BUF_SIZE 100char buttons_string[4] = "0\0";char *buttons_ptr = buttons_string;int buttons_is_open = 0;int *devid = (int*) BUTTONS_BASE;/////////////////////////////////////////////////////////////////////////// Interrupt Service Routine for button device driver/////////////////////////////////////////////////////////////////////////static irqreturn_t button_isr(int irq, void *dev_id, struct pt_regs *regs){ int status = 0; np_pio* pio_buttons = (np_pio *)BUTTONS_BASE;#ifdef DEBUG printk("de2_buttons ISR called!\n");#endif if (!pio_buttons) return IRQ_NONE;#ifndef TEST // disable interrupts outl(0, &pio_buttons->np_pioedgecapture); // clear active interrupts outl(0, &pio_buttons->np_piointerruptmask); status = (~inl(&pio_buttons->np_piodata)) & 0xF;#endif itoa(buttons_string,status); buttons_ptr = buttons_string;#ifdef DEBUG printk("button(s) pressed: %i\n",status);#endif#ifndef TEST // activate interrupts on all pins outl(-1, &pio_buttons->np_piointerruptmask);#endif return IRQ_HANDLED;}/////////////////////////////////////////////////////////////////////////// Start function which is executed on init/////////////////////////////////////////////////////////////////////////static int button_start(int *dev_id){ np_pio *pio_buttons = (np_pio *)(BUTTONS_BASE);#ifndef TEST // set pins to input mode outl(0, &pio_buttons->np_piodirection); // clear active interrupts outl(0, &pio_buttons->np_pioedgecapture);#endif // register interrupt if (request_irq(BUTTONS_IRQ, button_isr, SA_INTERRUPT, "de2_buttons", (void *) (dev_id))) { printk("de2_buttons: unable to register interrupt %d\n", BUTTONS_IRQ); return -1; }#ifdef DEBUG printk("button IRQ registered successfully!\n");#endif#ifndef TEST // activate interrupts on all pins outl(-1, &pio_buttons->np_piointerruptmask); itoa(buttons_string,0);#endif return 0;}/////////////////////////////////////////////////////////////////////////// Open handler/////////////////////////////////////////////////////////////////////////static int button_open(struct inode *inode, struct file *filp){#ifdef DEBUG printk("button_open called\n");#endif if (buttons_is_open++) { printk("device busy...\n"); return -EBUSY; } buttons_ptr = buttons_string; // If buttons were not pressed yet, resp. not pressed since the last read if (*buttons_ptr == 0) {#ifdef DEBUG printk("buttons not pressed yet!\n");#endif itoa(buttons_string,0); } try_module_get(THIS_MODULE); return 0;}/////////////////////////////////////////////////////////////////////////// Release/Close handler/////////////////////////////////////////////////////////////////////////static int button_release(struct inode *inode, struct file *filp){#ifdef DEBUG printk("button_release called\n");#endif buttons_is_open--; module_put(THIS_MODULE); return 0;}/////////////////////////////////////////////////////////////////////////// Read handler/////////////////////////////////////////////////////////////////////////static ssize_t button_read(struct file *filp, char *buffer, size_t length, loff_t * ppos){ // Number of bytes actually written to the buffer int bytes_read = 0;#ifdef DEBUG printk("button_read called\n");#endif // If we're at the end of the message, return 0 signifying end of file if (*buttons_ptr == 0) return 0; while (length-- && *buttons_ptr) { /* The buffer is in the user data segment, not the kernel segment so "*" assignment won't work. We have to use put_user which copies data from the kernel data segment to the user data segment. */ put_user(*(buttons_ptr++), buffer++); bytes_read++; }#ifdef DEBUG printk("bytes read: %i\n",bytes_read);#endif // return count of bytes, sent to user return bytes_read;}// Structure which assigns handler functions to hardware operationsstatic struct file_operations fops_buttons = { .read = button_read, .open = button_open, .release= button_release,};/////////////////////////////////////////////////////////////////////////// Init funktion/////////////////////////////////////////////////////////////////////////static int __init button_init(void){ // reserving memory regions for the PIO port if(!request_mem_region((unsigned long)BUTTONS_BASE, sizeof(np_pio), "de2_buttons")) return -1; // registering PIO port as character device to the kernel if(register_chrdev(BUTTONS_MAJOR, "de2_buttons", &fops_buttons)) { printk("register_chrdev of de2_buttons failed!\n"); release_mem_region((unsigned long)BUTTONS_BASE, sizeof(np_pio)); return -EIO; }#ifdef DEBUG printk("de2_buttons device driver successfully loaded!\n");#ifdef TEST printk("TEST mode active, so no I/O interaction is possible!\n");#endif#endif // we need to register IRQ at init (not recommended in most other cases!) button_start(devid); return 0;}/////////////////////////////////////////////////////////////////////////// Exit function (will be spared if build-in device driver selected)/////////////////////////////////////////////////////////////////////////static void __exit button_exit(void){#ifndef TEST np_pio *pio_buttons = (np_pio *)(BUTTONS_BASE); // disable interrupts outl(0, &pio_buttons->np_piointerruptmask);#endif // unregister interrupt in linux free_irq(BUTTONS_IRQ, (void *) (devid)); // unregister character device unregister_chrdev(BUTTONS_MAJOR,"de2_buttons"); // release memory region release_mem_region((unsigned long)BUTTONS_BASE, sizeof(np_pio));}module_init(button_init);module_exit(button_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Philipp Lutz");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -