📄 mmc_main.c
字号:
/* * 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 + -