⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hal_mem.c

📁 这是motorola公司的powerpc芯片上的嵌入式linux上的驱动程序和测试程序
💻 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 + -