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

📄 mmc_main.c

📁 给予mx21处理器的嵌入式系统的mmc卡驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 * * Copyright (C) 2002 Motorola Semiconductors HK Ltd * *//****************************************************************************** *  * Copyright (C) 2001, Motorola All Rights Reserved *  * File Name:   mmcsd.c *  * Progammers:  Yiwei Zhao  * * Date of Creations:   30  DEC,2001 * * Synopsis: * * Modification History: * 30 DEC, 2001 * 24,Dec,2003 Karen Kang *****************************************************************************/#ifndef __KERNEL__#  define __KERNEL__#endif#ifndef MODULE#  define MODULE#endif#define  TESTING_PAGE (1024*1024*40/512) #define MMCSD_TEST_PAGE_NUM 8 #include <linux/config.h>#include <asm/bitops.h>#include <linux/delay.h>#include <linux/errno.h>  /* error codes */#include <linux/fs.h>     /* everything... */#include <linux/fcntl.h>  /* O_ACCMODE */#include <linux/hdreg.h>  /* HDIO_GETGEO */#include <linux/ioctl.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/kernel.h> /* printk() */#include <linux/kdev_t.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/tqueue.h>#include <linux/types.h>  /* size_t */#include <linux/pm.h>#include <linux/poll.h>#include <linux/ptrace.h>#include <linux/vmalloc.h>#include <linux/version.h>#include <linux/proc_fs.h>//for proc//#include <linux/malloc.h>#include <asm/io.h>#include <linux/wait.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/system.h>   /* cli(), *_flags */#include <asm/dma.h>#include <linux/blkdev.h>#include <linux/devfs_fs_kernel.h>/*These symbols in <linux/blk.h> that must be defined in advance.*/#define DEVICE_NR(device) MINOR(device)		#define DEVICE_NAME "mmc"			/* name for messaging */#define DEVICE_NO_RANDOM			/* no entropy to contribute */#include <linux/blk.h>#ifdef CONFIG_ARCH_MX1ADS#include "dbmx1_dma.h"#endif#include "mmc_def.h"#include "mmc_main.h"        /* local definitions */#ifdef LINUX_20#  error "This module can't run with Linux-2.0"#endif#ifdef CONFIG_PM#define PM_OPT " [pm]"#else#define PM_OPT ""#endif/* * if partition is considered then HAVE_BLKPG_H should be defined. */#include <linux/blkpg.h>  /* blk_ioctl() *//* * variables will be initialized in init function. */MMCSD_Dev 		*g_mmcsd_devices = NULL;u8	 			g_mmcsd_cur_device = 0xff;u8				g_mmcsd_num = 0;u8				g_mmcsd_cmd[2] = {0,0};MMCSD_Lock		g_selected_lock[2];int 			g_mmcsd_major;int				g_mmcsd_presence = 0;volatile u32	g_mmcsd_status =0;static devfs_handle_t devfs_handle = NULL;	//devfs/* Function declarations */static int mmcsd_open(struct inode *inode, struct file *filp);static int mmcsd_release(struct inode *inode, struct file *filp);static int  mmcsd_revalidate(kdev_t dev);static MMCSD_Dev *mmcsd_locate_device(const struct request *req);void mmcsd_request_handler(request_queue_t  * q);static int mmcsd_data_transfer(MMCSD_Dev *device,struct request *req);static int mmcsd_read(	MMCSD_Dev *device, char * buffer, 			u32 sector, u32 nr_sector);static int mmcsd_write(	MMCSD_Dev *device, char * buffer, 			u32 sector, u32 nr_sector);static int mmcsd_sector_erase(MMCSD_Dev *device, MMCSD_Blks *blks);MMCSD_STATUS mmcsd_ReadBlock(MMCSD_Dev *device,u32 start_addr,u16 nsects, u8 *buff);MMCSD_STATUS mmcsd_ReadSingleBlock(MMCSD_Dev *device,u32 addr,u8 * buff);MMCSD_STATUS mmcsd_DMA_ReadSingleBlock(MMCSD_Dev *device,u32 addr,u8 * buff);int mmcsd_DmaStartTransfer(MMCSD_Dev *device,u8 * buff,u32 counter, u8 mode,u8 is_4_bit);void mmcsd_dma_handler(void);//void mmcsd_tasklet(void);static int mmcsd_ioctl(struct inode *inode,struct file *filp,unsigned command,unsigned long argument);static int mmcsd_write_protect(MMCSD_Dev *device,u32 addr, char is_set);static int mmcsd_passwd_cmd(MMCSD_Dev * device, MMCSD_PWD *pwd);	static int mmcsd_is_writeprotection(MMCSD_Dev *device);void mmcsd_irq_handler(int irq,void * data, struct pt_regs * pt);static int mmcsd_getMBR(MMCSD_Dev * device);static int mmcsd_check_status(MMCSD_Dev *device,u32 *pstate);static void mmcsd_dma_isr(void * arg);static void mmcsd_dma_isr_1(void * arg);static void mmcsd_dma_err_isr(int error_type);MMCSD_STATUS mmcsd_write_blks(MMCSD_Dev *device);MMCSD_STATUS mmcsd_dma_write_blks(MMCSD_Dev *device);void mmcsd_free_buffer(MMCSD_Dev *device);void _mmcsd_16_big_2_little(u8 *buf, u32 size);void _mmcsd_cp_16_little_2_big(u8 *src,u8 *target, int size);void mmcsd_delay(u32 delay);static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);/* Set up our tasklets. */static struct block_device_operations mmcsd_bdops = {		open:				mmcsd_open,		release:			mmcsd_release,		ioctl:				mmcsd_ioctl,		revalidate:			mmcsd_revalidate,};#ifndef MODULEextern int errno;#endifextern unsigned char  gSDWriteProtect;#ifdef CONFIG_ARCH_MX2ADSstatic char g_socket1_info;#define SD_SOCKET_NO_CARD		0x01#define SD_SOCKET_CARD			0x02static char gSDumounted;static devfs_handle_t devfs_handle1 = NULL;	//devfsvoid mmcsd_irq_handler_2(int irq,void * data, struct pt_regs * pt);void mmcsd_socket1_irq_handler(int irq, void *dev_id, struct pt_regs * regs){	u32 status,trigger;	status = _reg_GPIO_ISR(GPIOD);	trigger = _reg_GPIO_ICR2(GPIOD);	if((status & 0x02000000)==0x02000000) //get PortB16 int	{		if((trigger & 0x000C0000)==0x00080000)//it is positive level now		{			g_socket1_info = SD_SOCKET_NO_CARD;			_reg_GPIO_ICR2(GPIOD) |= 0x000C0000; //set it to be negative level trigger detect card withdraw			printk("A card is withdrawn from socket1 \n");					}		if((trigger & 0x000C0000)==0x000C0000)//it is negative level now		{	        g_socket1_info = SD_SOCKET_CARD;	        _reg_GPIO_ICR2(GPIOD) &= ~0x00040000;  // config as positive level trigger10 	        _reg_GPIO_ICR2(GPIOD) |= 0x00080000;//set it to be positive level trigger detect card insert			printk("A card is inserted in socket1 \n"); 		}		_mmcsd_socket1_clear_irq();	}}static int mmcsd_proc_output (char *buf){	char *p;	unsigned long flags;	int rostatus;	save_flags(flags);	cli();	p = buf;//Add to proc to indicate which card in which socket	if(g_socket1_info == SD_SOCKET_NO_CARD)	{		p += sprintf(p, "socket1 : nocard \n");	//		p += sprintf(p, "socket2 : nocard \n");		}	else if(g_socket1_info == SD_SOCKET_CARD)	{		p += sprintf(p, "socket1 : card \n");		}	restore_flags(flags);				return p - buf;			 	}static int mmcsd_read_proc(char *page, char **start, off_t off,                         int count, int *eof, void *data){                int len = mmcsd_proc_output(page);        if (len <= (off+count))        	*eof = 1;        *start = page + off;        len -= off;        if (len>count)         	len = count;        if (len<0)         	len = 0;        return len;}#endif/****************************************************************************** * Function Name: mmcsd_init * * Input:		None. * Value Returned:	0:	success; *			others 	failure;	 * * Description: This is the initialization routine for the driver. And this function  *		will be called while the module being installed. * * Modification History: * 	30 DEC,2001, Initial version.  			Yiwei Zhao  *****************************************************************************/#ifdef MODULEint init_module(void)#elseint __init mmcsd_init(void)#endif{	int ret,i;	printk("MMC device driver version 0.2.0\n");	TRACE("\n Begin initialize mmcsd module ");	/***************************************************** 	* Register the block driver. 	*****************************************************/	g_mmcsd_major = MMCSD_MAJOR;	ret = devfs_register_blkdev(g_mmcsd_major, "mmc", &mmcsd_bdops);	if (ret < 0)	{        	FAILED(" can't get major %d\n",MMCSD_MAJOR);        	return ret;    }    if(g_mmcsd_major == 0) 	{		g_mmcsd_major = ret; /* dynamic */	}	devfs_handle=devfs_register(NULL,"mmc",DEVFS_FL_DEFAULT,ret,0, 					S_IFBLK | S_IRUGO | S_IWUGO,&mmcsd_bdops,NULL);	devfs_handle1 = devfs_register(NULL, "mmc1",DEVFS_FL_DEFAULT,ret,1, 					S_IFBLK | S_IRUGO | S_IWUGO,&mmcsd_bdops,NULL);    read_ahead[g_mmcsd_major] = MMCSD_READ_AHEAD;/* in sectors */	/******************************************************* 	* Allocate space for each devices.  	*******************************************************/		g_mmcsd_num = MMCSD_DEVICE_NUM;	g_mmcsd_devices = kmalloc((g_mmcsd_num*sizeof(MMCSD_Dev)), GFP_KERNEL);    	if (!g_mmcsd_devices)	{        	goto fail_init;	}    memset(g_mmcsd_devices,0,(g_mmcsd_num * sizeof(MMCSD_Dev)));    for (i=0; i < g_mmcsd_num; i++)	{		spin_lock_init(&(g_mmcsd_devices[i].lock));		spin_unlock(&(g_mmcsd_devices[i].lock));		init_waitqueue_head(&(g_mmcsd_devices[i].select_wait));		sema_init(&(g_mmcsd_devices[i].sema),1);		g_mmcsd_devices[i].dma_channel = 0xFFFFFFFF;    }	g_selected_lock[0].device = NULL;	g_selected_lock[1].device = NULL;	/******************************************************* 	* Allocate request queue for each device. 	*******************************************************/	/*	for(i = 0;i < g_mmcsd_num; i++)	{		blk_init_queue(&(g_mmcsd_devices[i].queue), mmcsd_request_handler);		blk_queue_headactive(&(g_mmcsd_devices[i].queue),0);	}	*/	blk_init_queue(BLK_DEFAULT_QUEUE(g_mmcsd_major),mmcsd_request_handler);	/****************************************************** 	* Regist Interrupt Service Routine  	******************************************************/	ret = request_irq(MMCSD_IRQ, 			  mmcsd_irq_handler,			  SA_INTERRUPT,			  "mmc",			  "mmc");	if(ret)	{		TRACE("request irq error");		goto fail_init;	}#ifdef 	CONFIG_ARCH_MX2ADS	ret = request_irq(MMCSD2_IRQ, 			  mmcsd_irq_handler_2,			  SA_INTERRUPT,			  "mmc1",			  "mmc1");	if(ret)	{		TRACE("request irq error");		goto fail_init;	}	/*****************************************************	*setting for auto-mount/umount	******************************************************/	g_socket1_info = SD_SOCKET_NO_CARD;	ret = request_irq(MMCSD_SOCKET1_INT,				mmcsd_socket1_irq_handler,				SA_INTERRUPT|SA_SHIRQ,				"mmc",				"mmc");	if(ret)	{		TRACE("request irq error");		goto fail_init;			}				_mmcsd_socket1_irq_set();	create_proc_read_entry ("mmc", 0, 0, mmcsd_read_proc, NULL);#endif		/****************************************************** 	* Regist PM device.  	******************************************************/	pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, handle_pm_event);	/******************************************************	 * Pin Configuration	 *	 *****************************************************/	_MMCSD_64M_MMC_PinConfig();    /******************************************************    	*  LOOP FOR THE MAXIMUM NUMBER OF CARD SLOTS 	******************************************************/    	for ( i = 0 ; i < MMCSD_DEVICE_NUM ; i++ )    	{       		g_mmcsd_devices[i].card_state= MMCSD_NOTREADY;			g_mmcsd_devices[i].card_rca = 1;    	}	return 0;	/****************************************************** 	* Enable SDHC module	 ******************************************************/fail_init:    read_ahead[g_mmcsd_major] = 0;    if (g_mmcsd_devices)     {	    kfree(g_mmcsd_devices);    }    free_irq(MMCSD_IRQ,"mmc");#ifdef 	CONFIG_ARCH_MX2ADS    free_irq(MMCSD2_IRQ,"mmc1");    free_irq(MMCSD_SOCKET1_INT,"mmc");#endif    devfs_unregister_blkdev(g_mmcsd_major, "mmc");    devfs_unregister(devfs_handle);    devfs_unregister(devfs_handle1);    return ret;}/****************************************************************************** * Function Name: mmcsd_cleanup * * Input:		None. * Value Returned:	0:	success; *			others 	failure;	 * * Description:  *	this routine will clean up mmcsd module.	 * * Modification History: * 	30 DEC,2001, Initial version.  			Yiwei Zhao  *****************************************************************************/#ifdef MODULEvoid cleanup_module(void)#elseint __exit mmcsd_cleanup(void)#endif{    pm_unregister_all(handle_pm_event);    read_ahead[g_mmcsd_major] = 0;    if (g_mmcsd_devices)     {	    kfree(g_mmcsd_devices);    }    free_irq(MMCSD_IRQ,"mmc");#ifdef 	CONFIG_ARCH_MX2ADS    free_irq(MMCSD2_IRQ,"mmc1");    free_irq(MMCSD_SOCKET1_INT,"mmc");    remove_proc_entry("mmc", NULL);#endif    devfs_unregister_blkdev(g_mmcsd_major, "mmc");    devfs_unregister(devfs_handle);#ifdef 	CONFIG_ARCH_MX2ADS    devfs_unregister(devfs_handle1);#endif   return ;}/****************************************************************************** * Function Name: mmcsd_revalidate * * Input:		None. * Value Returned:	0:	success; *			others 	failure;	 * * Description: This routine will revalidate device. *	 * Modification History: * 	30 DEC,2001, Initial version.  			Yiwei Zhao  *****************************************************************************/static int  mmcsd_revalidate(kdev_t dev){	return 0;}/****************************************************************************** * Function Name: mmcsd_open * * Input:		None. * Value Returned:	0:	success; *			others 	failure;	 * * Description: This routine will initilialize a device. *	 * Modification History: * 	30 DEC,2001, Initial version.  			Yiwei Zhao  *****************************************************************************/static int mmcsd_open(struct inode *inode, struct file *filp){	MMCSD_Dev *device;	int num,i,ret,major;	int	channel=-1;	TRACE("mmcsd_open is called");	/*********************************************************************	 * Check the device numer 	 *********************************************************************/	num = MINOR(inode->i_rdev);	major = MAJOR(inode->i_rdev);	gSDWriteProtect = 0;	#ifdef CONFIG_ARCH_MX2ADS	if(num == 0)		_reg_CRM_PCCR0 |= 0x0200;//enable sdhc1 clk	else if(num == 1)		_reg_CRM_PCCR0 |= 0x0400;//enable sdhc2 clk

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -