📄 tffsdrv26.c
字号:
/****************************************************************************** * * * Project: DOC Driver for Linux 2.6 Block device driver for mDOC H3 family * * of devices under Linux kernel 2.6. * * * * Version: 1.0 * * Email questions to: oemsupport@sandisk.com * * Copyright (C) SanDisk IL Ltd. 1995 - 2007 * * SanDisk IL Ltd., 7 Atir Yeda Street, Kfar Saba 44425, Israel * * * ****************************************************************************** * * * 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 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, which is set forth in the readme.txt file. * * 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 * * * * This License does not grant you any right to use the trademarks, service * * marks or logos of SanDisk IL Ltd. or SanDisk Corporation. * * Subject to the foregoing, SanDisk IL Ltd., for itself and on behalf of its * * licensors, hereby reserves all intellectual property rights in the program,* * except for the rights expressly granted in this License. * * * ******************************************************************************//* * $Log$ */#include "tffsdrv.h"#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))#include "tffs2lnx.h"#include "flbase.h"MODULE_AUTHOR("M-Systems");MODULE_DESCRIPTION("TrueFFS driver");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE(TFFS_SUPPORTED_DEVICE);/* * module parameters *//* major device # to use */int tffs_major = 100;module_param(tffs_major, int, S_IRUGO);MODULE_PARM_DESC(tffs_major, "major device number, zero to use dynamic.");/* priority of driver's I/O threads */static int tffs_prio = 0; /* max -20, min 19 */module_param(tffs_prio, int, (S_IRUGO | S_IWUSR));MODULE_PARM_DESC(tffs_prio,"priority of DiskOnChip I/O thread.");/* interrupt line that DiskOnChip's IREQ is connected to */int tffs_irq = TFFS_IRQ;module_param(tffs_irq, int, S_IRUGO);MODULE_PARM_DESC(tffs_irq, "Interrupt line DiskOnChip's IREQ is connected to.");/* DMA mode. Allowed modes are: * 0 (don't use DMA) * 1 (use s/w DMA in read operations only; uses intermediate DMA buffer) * 2 (use s/w DMA in write operations only; uses intermediate DMA buffer) * 3 (combined 1 and 2) * 5 (use s/w DMA for direct transfers from user source buffers) * 6 (use s/w DMA for direct transfers to user dest. buffers) * 7 (combined 5 and 6) * Default is don't use DMA. */int tffs_dma_mode = 0;module_param(tffs_dma_mode, int, S_IRUGO);MODULE_PARM_DESC(tffs_dma_mode, "DMA mode (0, 1, 2, 3, 5, 6 or 7).");/* Automatic Deep PowerDown mode. Allowed modes are 0 (default; disabled), * or 1 (enabled). When enabled, Automatic Deep PowerDown mode will cause * DiskOnChip driver to power down DiskOnChip after completion of every * read/write operation, and power it up again before starting the next one. */int tffs_auto_dpd = FL_OFF;module_param(tffs_auto_dpd, int, S_IRUGO);MODULE_PARM_DESC(tffs_auto_dpd, "Powerdown DiskOnChip after every operation (1), or don't (0).");/* Upon completion of every read/write access, DiskOnChip H3 devices * immediately switch from the normal mode into the idle mode, and stay * in the idle mode for 'DOCH_DPD_DEFAULT_DPD_TIMEOUT' milliseconds before * switching into deep-power-down mode. */int tffs_dpd_timeout = 1;module_param(tffs_dpd_timeout, int, S_IRUGO);MODULE_PARM_DESC(tffs_dpd_timeout, "Time (in milliseconds) before DiskOnChip automatically powers itself down.");/* Read data from DiskOnChip into scatter/gather buffer, then scatter it to * destination buffers. Allowed values are TRUE (scatter data) or FALSE (don't). */int tffs_sg_read = TRUE;module_param(tffs_sg_read, int, S_IRUGO);MODULE_PARM_DESC(tffs_sg_read, "Use scatter/gather during read operations.");/* Gather data from source buffers into scatter/gather buffer before writing * it to DiskOnChip. Allowed values are TRUE (gather data) or FALSE (don't). */int tffs_sg_write = TRUE;module_param(tffs_sg_write, int, S_IRUGO);MODULE_PARM_DESC(tffs_sg_write, "Use scatter/gather during write operations.");/* size of scatter/gather buffer in bytes; must be multiple of PAGE_SIZE */int tffs_sg_bufsize = (16 * PAGE_SIZE);module_param(tffs_sg_bufsize, int, S_IRUGO);MODULE_PARM_DESC(tffs_sg_bufsize, "Size of scatter/gather buffer, in bytes.");/* * macros */#ifndef _MIN# define _MIN(a,b) ((a) < (b) ? (a) : (b))#endif/* * types */struct scatter_t /* scatter buffer for READ requests */{ char * buf; /* starting address */ char * pcurrent; unsigned int size; /* size of buffer in bytes */ unsigned int remaining_bytes; sector_t start_sector; /* starting disk sector # */ unsigned int sectors; /* remaining sectors in this request */};struct gather_t /* gather buffer for WRITE requests */{ char * buf; /* starting address */ char * free; /* free part fo the buffer */ unsigned int size; /* size of buffer in bytes */ unsigned int free_bytes; /* remaining free space in bytes */ sector_t start_sector; /* starting disk sector # */};/* * global vars */int write_requests = 0;/* * static routines */static int /* __init */ __tffs_module_init (void);static void /* __init */ init_socket (SocketInfo *psoc);static void /* __init */ init_disk (DeviceInfo *pdisk);static void /* __exit */ release_socket (SocketInfo *psoc);static void /* __exit */ release_disk (DeviceInfo * pdisk);static void cleanup (int STEP);static void disk_request_queue_handler (request_queue_t *q);static int socket_io_thread (void *arg);static int requests_to_do (SocketInfo *psoc);static void do_requests_list (SocketInfo *psoc);static int do_write_request (struct request *r);static int do_read_request (struct request *r);static int rw_bio_no_sg (struct bio *bio, DeviceInfo *pdisk, int rw);static int write_bio (struct bio *bio, struct gather_t *gather, DeviceInfo *pdisk);static int read_bio (struct bio *bio, struct scatter_t *scatter, DeviceInfo *pdisk);static int disk_open (struct inode *inode, struct file *filp);static int disk_close (struct inode *inode, struct file *filp);static int disk_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);static irqreturn_t interrupt_handler (int irq, void *psoc, struct pt_regs *regs);#ifdef CONFIG_PROC_FS static int /* __init */ procfs_register (DeviceInfo *pdisk); static int /* __exit */ procfs_unregister (DeviceInfo *pdisk); static int procfs_write (struct file* file, const char* buffer, unsigned long count, void* data); static int procfs_read (char* buffer, char** start, off_t offset, int length, int* eof, void* data);#endif/* * static vars */static struct semaphore open_close_mutex; /* used to serialize disk open/close calls */static char tffs_str[] = TFFS_DEVICE_NAME;static struct block_device_operations tffs_bdev_ops ={ .open = disk_open, .release = disk_close, .ioctl = disk_ioctl, .owner = THIS_MODULE};/* for tracking enabled/disabled state of IRQ that DiskOnChip is connected to */static spinlock_t __irq_lock = SPIN_LOCK_UNLOCKED;#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_MACH_MAINSTONE) static int __irq_enabled = TRUE;#else static int __irq_enabled = FALSE;#endif/******************************************************************************* * * * t f f s _ m o d u l e _ i n i t * * * * Module initialization routine. * * * * Parameters: none * * * * Returns: zero if success, otherwise standard negative error code * * * *******************************************************************************/int /* __init */ tffs_module_init (void){# ifdef TRACE32 /* needed for section relocation in TRACE32 */ extern int trace32_data; extern int trace32_bss; extern const int trace32_rodata; printk ("\n\nTRACE32 section relocation: .data=0x%lx .bss=0x%lx .rodata=0x%lx\n\n", (long)(&trace32_data), (long)(&trace32_bss), (long)(&trace32_rodata));# endif return __tffs_module_init();}module_init(tffs_module_init);/******************************************************************************* * * * t f f s _ m o d u l e _ e x i t * * * * Module cleanup and routine; called when module is unloaded. * * * * Parameters: none * * * *******************************************************************************/void /* __exit */ tffs_module_exit (void){ cleanup (100);}module_exit(tffs_module_exit);/******************************************************************************* * * * _ _ t f f s _ m o d u l e _ i n i t * * * * Initialize DiskOnChip driver. * * * * Parameters: none * * * * Returns: zero if success, otherwise standard negative error code * * * *******************************************************************************/staticint /* __init */ __tffs_module_init (void){ int STEP, iSoc, tmp; STEP = 0; PrintkInfo ("mDOC driver %s.%d", TrueFFSVersion, TFFS_DRV_VER); memset (tffsInfo.sockets, 0, sizeof(tffsInfo.sockets)); for (iSoc = 0; iSoc < FL_SOCKETS; iSoc++) { sema_init (&tffsInfo.sockets[iSoc].sleep_sem, 0); init_waitqueue_head (&tffsInfo.sockets[iSoc].waitQueueHead); } STEP++; /* 1 */ /* if requested, install handler for DiskOnChip interrupts */ if (tffs_irq >= 0) { if( request_irq(tffs_irq, interrupt_handler, 0 /* SA_INTERRUPT */, tffs_str, &tffsInfo.sockets[0]) == 0 ) { tffs_irq_disable (TRUE); PrintkInfo ("use IRQ %d", tffs_irq); } else /* can't install interrupt handler, won't use IRQ */ { PrintkWarning ("failed to get IRQ %d", tffs_irq); tffs_irq = -1; } } else { PrintkInfo ("will not use IRQ"); } STEP++; /* 2 */ /* Find all DiskOnChip sockets, find out how many disks are on * each socket, and abs.mount each disk. */ if( TffsInit() <= 0 ) { PrintkError ("No DiskOnChips found"); return -ENODEV; } STEP++; /* 3 */ if (tffs_irq >= 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -