📄 hal_mem.c
字号:
/*********************************************************************** * * (C) Copyright 2002,12 * * Qi zhaoling * All rights left. * * * a memory map API Device Driver for UT850GE * * Can be loaded as module * * $Id: hal_mem.c,v 1.1 2000/02/15 16:38:01 wd Exp $ * ***********************************************************************//* * Standard in kernel modules */#include <linux/kernel.h> /* We're doing kernel work */#include <linux/module.h> /* Specifically, a module */#include <asm/uaccess.h> /* for put_user */#include <asm/init.h> /* for __initfunc */#include <linux/mm.h>#include <linux/ioport.h>#include <asm/io.h>#include <asm/8xx_immap.h>#include <asm/mpc8xx.h>#undef DEBUG#ifdef DEBUG# define debugk(fmt,args...) printk(fmt ,##args)#else# define debugk(fmt,args...)#endif/* * Deal with CONFIG_MODVERSIONS */#if CONFIG_MODVERSIONS==1/* # define MODVERSIONS */# include <linux/modversions.h>#endif/* * For character devices */#include <linux/fs.h> /* character device definitions */#include <linux/wrapper.h> /* wrapper for compatibility with future versions */#ifndef KERNEL_VERSION# define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))#endif#define DEBUG 1#define SUCCESS 0#define UT_MEM_MAJOR 43 /* free for demo/sample use *//* * Device Declarations *//* * The name for our device, as it will appear in /proc/devices */#define DEVICE_NAME "mem_api"/* * prevent concurent access of the same device */static int Device_Open = 0;/* * Prototypes */int hal_mem_init (void );static int device_open(struct inode *, struct file *);static int device_release(struct inode *, struct file *);static ssize_t device_read(struct file *, char *, size_t, loff_t *);static ssize_t device_write(struct file *, const char *, size_t, loff_t *);static loff_t device_seek (struct file *, loff_t , int );int init_module(void);void cleanup_module(void);struct file_operations ut_mem_ops ={ llseek: device_seek, read: device_read, write: device_write, open: device_open, release: device_release, };static int Major;unsigned long Bm8024RegBase = 0x80000000;unsigned long virt_addr;void init_mem_br(){ unsigned long immr; volatile memctl8xx_t *memctrl_p = 0; asm( "mfspr %0,638": "=r"(immr) : ); immr &= 0xFFFF0000; memctrl_p = (memctl8xx_t *) &((volatile immap_t *)immr)->im_memctl; /*init br0 & or0*/ memctrl_p->memc_br0 = 0x02800801; memctrl_p->memc_or0 = 0xFF800940; /*init br1 & or1*/ memctrl_p->memc_or1 = 0xFFFF8124; memctrl_p->memc_br1 = 0x80050401; /*init br2 & or2*/ memctrl_p->memc_or2 = 0xFE000800; memctrl_p->memc_br2 = 0x00000081; /*init br3 & or 3*/ memctrl_p->memc_or3 = 0xFFFF0984; memctrl_p->memc_br3 = 0x80000001;}/* * Initialize the driver - Register the character device */int hal_mem_init (void) { init_mem_br(); virt_addr = 0; virt_addr = (unsigned long) ioremap(Bm8024RegBase, 0x1ff); printk("<1>virt_addr = 0x%x \n", virt_addr); /* * Register the character device */ if ( check_mem_region(0x80000000, 0x1ff) ) { printk("<1> %s: memory already in use\n",DEVICE_NAME); return -EBUSY; } request_mem_region(0x80000000, 0x1ff, DEVICE_NAME); Major = register_chrdev (UT_MEM_MAJOR, DEVICE_NAME, &ut_mem_ops); /* Negative values signify an error */ if (Major < 0) { iounmap((void*)virt_addr); printk ("UT_MEM init_module: failed with %d\n", Major); return Major; } Major = UT_MEM_MAJOR; debugk ("UT_MEM registred: major = %d\n", Major); return 0;}/* * called whenever a process attempts to open the device */static int device_open (struct inode *inode, struct file *file){ debugk ("device_open(%p,%p)\n", inode, file); /* * Get major / minor numbers when needed */ debugk ("Device: %d.%d\n", inode->i_rdev >> 8, inode->i_rdev & 0xFF); /* * exclusive open only */ if (Device_Open) { return -EBUSY; } /* * Be careful here on SMP kernels! */ Device_Open++; /* * Make sure that the module isn't removed while * the file is open by incrementing the usage count */ MOD_INC_USE_COUNT; return SUCCESS;}/* * Called when a process closes the device. * Doesn't have a return value in version 2.0.x because it can't fail, * but in version 2.2.x it is allowed to fail */static int device_release (struct inode *inode, struct file *file){ debugk ("device_release(%p,%p)\n", inode, file); /* We're now ready for our next caller */ Device_Open--; MOD_DEC_USE_COUNT; /*hal_unmap((void*)virt_addr);*/ iounmap((void*)virt_addr); release_mem_region(0x80000000, 0x1ff); return 0;}/* * read entry point: */static ssize_t device_read (struct file *file, char *buffer, /* The buffer to fill with data */ size_t length, /* The length of the buffer */ loff_t * offset) /* Our offset in the file */{ volatile unsigned int intx; unsigned long addr; char val[4]; unsigned long len; len = 0; if(length < 4 ) { printk("<1> device_read: offset must larger than 4 \n"); return -1; } while(length) { addr = virt_addr + (unsigned long)(*offset) - Bm8024RegBase; debugk("<1> addr = 0x%x \n",addr); intx = readl(addr); /* val[0] = (char) intx >> 24 & 0xFF; val[1] = (char) intx >> 16 & 0xFF; val[2] = (char) intx >> 8 & 0xFF; val[4] = (char) intx & 0xFF; if( copy_to_user (buffer, val, 4)) { return -1; } */ if( copy_to_user(buffer,(char*) &intx, 4)) return -1; buffer = buffer + 4; length = length - 4; *offset = *offset + 4; len = len + 4; printk("<1> 0x%x = 0x%x \n", (unsigned int) *offset, intx); } return (len); /* read() always returns exactly two byte */}/* * write entry point: dummy here */static ssize_t device_write (struct file *file, const char *buffer, /* buffer */ size_t length, /* length of buffer */ loff_t * offset) /* offset in the file */{ volatile unsigned int intx; unsigned long len, addr; if(length < 4) return -1; len = 0; while(length) { addr = virt_addr + (unsigned long)(*offset) - Bm8024RegBase; debugk("<1> addr = 0x%x \n",addr); if( copy_from_user((void*) &intx, buffer, 4) ) return -1; writel((u32 *) &intx, (void *)addr); *offset = *offset + 4; length = length - 4; buffer = buffer + 4; len = len + 4; } return (len);}static loff_t device_seek (struct file *filp, loff_t off, int whence){ loff_t newpos; debugk("<1> off=%u , whence = %u \n", off, whence); switch(whence) { case 0: /* SEEK_SET */ { newpos = off; debugk("<1> SEEK_SET: %u ,whence = %u \n", off, whence); } break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break; case 2: /* SEEK_END */ return -EINVAL; break; default: /* */ return -EINVAL; } debugk("<1> newpos=%u \n",newpos); if ((unsigned long)newpos < 0) return -EINVAL; filp->f_pos = newpos; debugk("<1> newpos = %u \n",newpos); return newpos; }/****************************** **** Module Declarations ***** **************************** */#ifdef MODULE/* * Initialize the module */int init_module (void){ return hal_mem_init();}/* * Cleanup - unregister the appropriate file from /proc */void cleanup_module (void){ int ret; /* * Unregister the device */ ret = unregister_chrdev (Major, DEVICE_NAME); /* * If there's an error, report it */ if (ret < 0) { printk ("unregister_chrdev: error %d\n", ret); }}void *hal_remap(unsigned long phys_addr, unsigned long len){ /* The code comes mainly from arch/any/mm/ioremap.c */ unsigned long offset, last_addr, size; last_addr = phys_addr + len - 1; offset = phys_addr & ~PAGE_MASK; /* Adjust the begin and end to remap a full page */ phys_addr &= PAGE_MASK; size = PAGE_ALIGN(last_addr) - phys_addr; return ioremap(phys_addr, size) + offset;}/* Unmap a region obtained with short_remap */void hal_unmap(void *virt_add){ iounmap((void *)((unsigned long)virt_add & PAGE_MASK));}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -