📄 icap.c
字号:
// Virtex-II Pro ICAP driver for Linux 2.4.26 on Xilinx XUP// Copyright (C) 2007 by Neil Steiner// Provided by the Virginia Tech Configurable Computing Lab (http://www.ccm.ece.vt.edu)// // 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., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA.#ifndef MODULE#define MODULE#endif#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/devfs_fs_kernel.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/errno.h>#include <asm/system.h>#include <asm/uaccess.h>#include <xparameters.h>#include "xhwicap.h"#include "xhwicap_i.h"MODULE_AUTHOR("Neil Steiner <neil.steiner@vt.edu>");MODULE_DESCRIPTION("Virtex-II Pro ICAP driver");MODULE_LICENSE("GPL");#define HWICAP_PHYS_ADDRESS XPAR_OPB_HWICAP_0_BASEADDR#define HWICAP_PHYS_LENGTH (XPAR_OPB_HWICAP_0_HIGHADDR+1-XPAR_OPB_HWICAP_0_BASEADDR)#define true (-1)#define false (0)#define FSM_WRITE_STATE_NULL 0#define FSM_WRITE_STATE_START 1#define FSM_WRITE_STATE_MAGIC 2#define FSM_WRITE_STATE_ZERO_ONE 3#define FSM_WRITE_STATE_A 4#define FSM_WRITE_STATE_DESIGN_LENGTH 5#define FSM_WRITE_STATE_DESIGN 6#define FSM_WRITE_STATE_B 7#define FSM_WRITE_STATE_DEVICE_LENGTH 8#define FSM_WRITE_STATE_DEVICE 9#define FSM_WRITE_STATE_C 10#define FSM_WRITE_STATE_DATE_LENGTH 11#define FSM_WRITE_STATE_DATE 12#define FSM_WRITE_STATE_D 13#define FSM_WRITE_STATE_TIME_LENGTH 14#define FSM_WRITE_STATE_TIME 15#define FSM_WRITE_STATE_E 16#define FSM_WRITE_STATE_LENGTH 17#define FSM_WRITE_STATE_FULL_HEADER 18#define FSM_WRITE_STATE_STREAM 19#define FSM_WRITE_STATE_COLLECT -1// struct declarationstypedef struct Header { Xuint16 file_magic_length; char* file_magic_bytes; Xuint16 zero_one; Xuint16 design_name_length; char* design_name_bytes; Xuint16 device_name_length; char* device_name_bytes; Xuint16 date_string_length; char* date_string_bytes; Xuint16 time_string_length; char* time_string_bytes; Xuint32 bitstream_length;} Header;// function prototypesstatic int hwicap_init(void);static void hwicap_exit(void);int hwicap_open(struct inode *inode_ptr, struct file *file_ptr);int hwicap_release(struct inode *inode_ptr, struct file *file_ptr);//int hwicap_ioctl(struct inode *inode_ptr, struct file *file_ptr, unsigned int d, unsigned long request);ssize_t hwicap_read(struct file *file_ptr, char *a, size_t b, loff_t *c);ssize_t hwicap_write(struct file *file_ptr, const char *a, size_t b, loff_t *c);ssize_t run_write_state_machine(void);int XHwIcap_init_remap_baseaddress(XHwIcap *xhwicap);XStatus XHwIcap_SetConfiguration_Fixed(XHwIcap *InstancePtr, Xuint32 *Data, Xuint32 Size);// HWICAP base virtual addressvoid* hwicap_virt_ptr = NULL;// global variablesconst char hwicap_driver_name[] = "icap";int hwicap_major_number = 0;int hwicap_minor_number = 0;XHwIcap xhwicap;char* device_name = NULL;devfs_handle_t hwicap_directory = NULL;devfs_handle_t hwicap_device = NULL;Xuint32 word_buffer[XHI_MAX_BUFFER_BYTES >> 2];char local_buffer[1024];char* local_buffer_start;char* local_buffer_pos;char* local_buffer_end;char* local_buffer_wall;loff_t expected_pos = 0;int write_state = FSM_WRITE_STATE_NULL;int next_write_state = FSM_WRITE_STATE_NULL;Header header;int word_count = 0;int total_word_count = 0;// file access function structurestruct file_operations hwicap_ops = { open: hwicap_open, release: hwicap_release, read: hwicap_read, write: hwicap_write};// declare the module init and exit functionsmodule_init(hwicap_init);module_exit(hwicap_exit);// load the module into the kernelstatic int hwicap_init(void) { // memory-map the HWICAP hwicap_virt_ptr = ioremap_nocache(HWICAP_PHYS_ADDRESS,HWICAP_PHYS_LENGTH); // if the memory region was not virtually mapped, consider initialization a complete failure if(!hwicap_virt_ptr) { // return failure printk("<1>\t%s: cannot map HWICAP device into memory space\n",hwicap_driver_name); return -EIO; } // initialize the XHwIcap structure XStatus status = XHwIcap_Initialize(&xhwicap,XPAR_OPB_HWICAP_0_DEVICE_ID, XHI_READ_DEVICEID_FROM_ICAP); if(status != XST_SUCCESS) { // return failure printk("<1>\t%s: cannot initialize HWICAP device %d: %d\n",hwicap_driver_name, XPAR_OPB_HWICAP_0_DEVICE_ID,(int) status); return -EIO; } // determine the device name switch(xhwicap.DeviceIdCode) { case 0x01008093UL: device_name = "XC2V40"; break; case 0x01010093UL: device_name = "XC2V80"; break; case 0x01018093UL: device_name = "XC2V250"; break; case 0x01020093UL: device_name = "XC2V500"; break; case 0x01028093UL: device_name = "XC2V1000"; break; case 0x01030093UL: device_name = "XC2V1500"; break; case 0x01038093UL: device_name = "XC2V2000"; break; case 0x01040093UL: device_name = "XC2V3000"; break; case 0x01050093UL: device_name = "XC2V4000"; break; case 0x01060093UL: device_name = "XC2V6000"; break; case 0x01070093UL: device_name = "XC2V8000"; break; case 0x01226093UL: device_name = "XC2VP2"; break; case 0x0123E093UL: device_name = "XC2VP4"; break; case 0x0124A093UL: device_name = "XC2VP7"; break; case 0x01266093UL: device_name = "XC2VP20"; break; case 0x0127E093UL: device_name = "XC2VP30"; break; case 0x01292093UL: device_name = "XC2VP40"; break; case 0x0129E093UL: device_name = "XC2VP50"; break; case 0x012BA093UL: device_name = "XC2VP70"; break; case 0x012D6093UL: device_name = "XC2VP100"; break; case 0x012F2093UL: device_name = "XC2VP125"; break; default: device_name = "[unknown]"; break; } // allocate a major device number hwicap_major_number = devfs_alloc_major(DEVFS_SPECIAL_CHR); printk("<1>%s: allocated major device number %d\n",hwicap_driver_name,hwicap_major_number); // register the hwicap device hwicap_device = devfs_register(NULL,hwicap_driver_name,DEVFS_FL_DEFAULT, hwicap_major_number,hwicap_minor_number,0777|S_IFCHR,&hwicap_ops,NULL); if(hwicap_device == NULL) { printk("<1>\t%s: unable to register %s device\n",hwicap_driver_name,hwicap_driver_name); return -EIO; } //printk("<1>\t%s: devfs_register for %s returned %8.8X\n",hwicap_driver_name,hwicap_led4_name,(int) devfs_file); // return success and display the available devices printk("<1>%s: driver inserted, device %s\n",hwicap_driver_name,device_name); printk("<1>\t%s: physical address %8.8X mapped to virtual address %8.8X\n",hwicap_driver_name, HWICAP_PHYS_ADDRESS,(unsigned int) hwicap_virt_ptr);#if 0 // if we're still here, the XHwIcap driver should have determined the device settings printk("<2>\t%s: BaseAddress: 0x%8.8X\n",hwicap_driver_name,(unsigned int) xhwicap.BaseAddress); printk("<2>\t%s: IsReady: 0x%8.8X\n",hwicap_driver_name,(unsigned int) xhwicap.IsReady); printk("<2>\t%s: DeviceIdCode: 0x%8.8X\n",hwicap_driver_name,(unsigned int) xhwicap.DeviceIdCode); printk("<2>\t%s: DeviceId: 0x%8.8X\n",hwicap_driver_name,xhwicap.DeviceId); printk("<2>\t%s: Rows: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.Rows); printk("<2>\t%s: Cols: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.Cols); printk("<2>\t%s: BramCols: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.BramCols); printk("<2>\t%s: BytesPerFrame: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.BytesPerFrame); printk("<2>\t%s: WordsPerFrame: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.WordsPerFrame); printk("<2>\t%s: ClbBlockFrames: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.ClbBlockFrames); printk("<2>\t%s: BramBlockFrames: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.BramBlockFrames); printk("<2>\t%s: BramIntBlockFrames: %4d\n",hwicap_driver_name,(unsigned int) xhwicap.BramIntBlockFrames);#endif return 0;}// unload the module from the kernelstatic void hwicap_exit(void) { // release the icap device if(hwicap_device) devfs_unregister(hwicap_device); // release the major number that we've been using devfs_dealloc_major(DEVFS_SPECIAL_CHR,hwicap_major_number); // unmap all of the XUP HWICAP if(hwicap_virt_ptr) { iounmap(hwicap_virt_ptr); hwicap_virt_ptr = NULL; } // say goodbye printk("<1>%s: driver removed\n",hwicap_driver_name);}// open the hwicap deviceint hwicap_open(struct inode *inode_ptr, struct file *file_ptr) { printk("<1>\t%s: opening %s\n",hwicap_driver_name,file_ptr->f_dentry->d_name.name);// printk("<1>\t%s: %d, %d\n",hwicap_driver_name,major(inode_ptr->i_rdev),minor(inode_ptr->i_rdev)); // prepare variables expected_pos = 0; write_state = FSM_WRITE_STATE_START; next_write_state = FSM_WRITE_STATE_NULL; // prepare the local buffer iterators local_buffer_start = local_buffer_pos = local_buffer; local_buffer_wall = local_buffer_end = local_buffer_start + sizeof(local_buffer); word_count = 0; total_word_count = 0; // ensure that all header string pointers appear unallocated header.file_magic_bytes = NULL; header.design_name_bytes = NULL; header.device_name_bytes = NULL; header.date_string_bytes = NULL; header.time_string_bytes = NULL; // return success return 0;}// release the hwicap deviceint hwicap_release(struct inode *inode_ptr, struct file *file_ptr) { printk("<1>\t%s: releasing %s\n",hwicap_driver_name,file_ptr->f_dentry->d_name.name); // if the word count fell short of what we expected, let the user know if((total_word_count << 2) < header.bitstream_length) { printk("<1>\t%s: received only %8.8X of %8.8X expected words\n",hwicap_driver_name, total_word_count,(int) header.bitstream_length >> 2); } // release any memory allocated for header strings if(header.file_magic_bytes) kfree(header.file_magic_bytes); header.file_magic_bytes = NULL; if(header.design_name_bytes) kfree(header.design_name_bytes); header.design_name_bytes = NULL; if(header.device_name_bytes) kfree(header.device_name_bytes); header.device_name_bytes = NULL; if(header.date_string_bytes) kfree(header.date_string_bytes); header.date_string_bytes = NULL; if(header.time_string_bytes) kfree(header.time_string_bytes); header.time_string_bytes = NULL; // return success return 0;}// read from the hwicap devicessize_t hwicap_read(struct file *file_ptr, char *buffer, size_t count, loff_t *f_pos) {// printk("<1>\t%s: reading %s\n",hwicap_driver_name,file_ptr->f_dentry->d_name.name); return 0;}// write to the hwicap devicessize_t hwicap_write(struct file *file_ptr, const char *buffer, size_t count, loff_t *f_pos) { printk("<1>\t%s: writing %s: %8.8X bytes from %8.8llX\n",hwicap_driver_name,file_ptr->f_dentry->d_name.name,count,*f_pos); // declare variables const char* user_buffer_start = buffer; const char* user_buffer_pos = buffer; const char* user_buffer_end = buffer + count; // ensure that the user writes are sequential if(*f_pos != expected_pos) return -ESPIPE; // ensure that we don't flip out and hang up the machine int max_iterations = 0; // transfer all the data from the user space through our local buffer while(user_buffer_pos < user_buffer_end) { // calculate the amount of data remaining in the user buffer size_t local_buffer_copy_length = local_buffer_wall - local_buffer_pos; size_t user_buffer_copy_length = user_buffer_end - user_buffer_pos;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -