📄 tffsdrv1.c
字号:
#include "flcustom.h"#include "tffsdrv.h"#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,7,0))#include "flsystem.h"#include "tffs2lnx.h"#include <linux/blkdev.h>#include <linux/hdreg.h> /* HDIO_GETGEO */#include <linux/sockios.h> /* for SIOCDEVPRIVATE *//* module parameters */#ifdef MODULEMODULE_AUTHOR("yurid@msys.com");MODULE_DESCRIPTION("TrueFFS driver");MODULE_LICENSE("Proprietary");MODULE_SUPPORTED_DEVICE(TFFS_SUPPORTED_DEVICE);#endifstatic int /*__initdata*/ major=TFFS_MAJOR;#ifdef MODULEMODULE_PARM(major,"i"); /* set to zero to get dynamic major */MODULE_PARM_DESC(major, "Major device number to use.");#endif#if 0static int __initdata rahead=0;#ifdef MODULEMODULE_PARM(rahead,"i");MODULE_PARM_DESC(rahead,"Set readahead flag for driver.");#endifstatic int __initdata blksize=0;#ifdef MODULEMODULE_PARM(blksize,"i");MODULE_PARM_DESC(blksize,"The size of the block for all devices, in bytes.");#endif#endifstatic int __initdata hardsect=0;#ifdef MODULEMODULE_PARM(hardsect,"i");MODULE_PARM_DESC(hardsect,"The size of the hardware sector for all devices, in bytes.");#endif#ifndef DO_NOT_YIELD_CPUstatic int __initdata prio=-20; /* max -20 */# ifdef MODULEMODULE_PARM(prio,"i");MODULE_PARM_DESC(prio,"Kernel thread priority.");# endif#endifstatic void InitFree(unsigned char bStep);static int Open(struct inode*inode,struct file*filp);static void Request(request_queue_t*q);int Ioctl(struct inode*inode,struct file*filp,unsigned int cmd,unsigned long arg);static void TransferRequests(request_queue_t*q);#ifndef DO_NOT_YIELD_CPUstatic int IoKernelThread(void*device);#endifstatic TheDiskInfo diskInfo;static struct block_device_operations blockDeviceOper={ .owner=THIS_MODULE, .ioctl=Ioctl, .open=Open,};/* Initialize the driver, register major and link into gendisk_list. */int tffs_init(void){ int result; unsigned char bDevice; PrintkInfo("TrueFFS driver %d.%d",TFFS_SVER/100,TFFS_DRV_VER); PrintkDebug("\"%s\" (pid %i)",current->comm,current->pid); /* init TFFS */ TffsInit(&diskInfo); if(diskInfo.noOfDevices==0) { PrintkError("Cannot find any TrueFFS devices"); InitFree(1); return -EBUSY; } /* get major number */ diskInfo.major=major; if((result=register_blkdev(diskInfo.major,TFFS_DEVICE_NAME)) < 0) { PrintkError("Can't get major %d",diskInfo.major); InitFree(1); return result; } if (diskInfo.major==0) { diskInfo.major=result; /* dynamic */ } PrintkInfo("Registered module at major %d",diskInfo.major); /* device loop */ for(bDevice=0;bDevice<diskInfo.noOfDevices;bDevice++) { DeviceInfo*pDevice=diskInfo.pDevices+bDevice; if(pDevice->fValid /* find next valid device */#ifdef TFFS_ALLOW_UNFORMATTED || (pDevice->pSocket->fDummy && ((pDevice->handle&0xf0)==0)) /* allow 1 dummy device per socket */#endif ) { spin_lock_init(&pDevice->queueLock);#ifndef DO_NOT_YIELD_CPU /* Init thread */ sema_init(&pDevice->threadSemaphore,0); /* init down */ init_waitqueue_head(&pDevice->waitQueueHead); pDevice->threadInit=1; kernel_thread(IoKernelThread,(void*)pDevice,0); down_interruptible(&pDevice->threadSemaphore); /* wait to thread */ PrintkDebug("tffs_init: after kernel_thread");#endif /* init queue */ pDevice->requestQueue=blk_init_queue(Request,&pDevice->queueLock); if(pDevice->requestQueue==NULL) { InitFree(3); return -ENOMEM; } PrintkDebug("blk_init_queue(%d) OK",bDevice);#ifndef DO_NOT_YIELD_CPU pDevice->requestQueue->queuedata=pDevice;#endif blk_queue_hardsect_size(pDevice->requestQueue,(hardsect==0)?pDevice->pSocket->maxSectorSize:hardsect); PrintkDebug("tffs_init:blk_queue_hardsect_size(%d,%d)",bDevice,pDevice->pSocket->maxSectorSize); pDevice->usage=0; spin_lock_init(&pDevice->o_c_lock); /* init gendisk */ pDevice->genDisk=alloc_disk(TFFS_NO_OF_PARTS_PER_DEVICE); if(pDevice->genDisk==NULL) { InitFree(3); return -ENOMEM; } PrintkDebug("alloc_disk(%d) OK",bDevice); pDevice->genDisk->major=diskInfo.major; pDevice->genDisk->first_minor=bDevice*(1<<DEV2PART_SHIFT); /* don't use TFFS_NO_OF_PARTS_PER_DEVICE here */ pDevice->genDisk->fops=&blockDeviceOper; pDevice->genDisk->private_data=pDevice; sprintf(pDevice->genDisk->disk_name,"%s%c",TFFS_DEVICE_NAME,'a'+bDevice); set_capacity(pDevice->genDisk,pDevice->size>>9); pDevice->genDisk->queue=pDevice->requestQueue; add_disk(pDevice->genDisk); } } return 0;}module_init(tffs_init);static void InitFree(unsigned char bStep){ unsigned char bDevice,bSocket; PrintkDebug("InitFree"); switch(bStep) { case 0: case 3:#ifndef DO_NOT_YIELD_CPU for(bSocket=0;bSocket<diskInfo.noOfSockets;bSocket++) { }#endif for(bDevice=0;bDevice<diskInfo.noOfDevices;bDevice++) { DeviceInfo*pDevice=diskInfo.pDevices+bDevice; if(pDevice->threadInit==1) { /* flush devices */ /* TODO */ /* stop IO thread */ pDevice->threadInit=0; wake_up(&pDevice->waitQueueHead); PrintkDebug("cleanup_module: queue waked, device %d",bDevice); down_interruptible(&pDevice->threadSemaphore); /* wait for last request end */ PrintkDebug("cleanup_module: semaphore down, device %d",bDevice); } if(pDevice->genDisk!=NULL) { del_gendisk(pDevice->genDisk); pDevice->genDisk=NULL; blk_cleanup_queue(pDevice->requestQueue); pDevice->requestQueue=NULL; } } case 2: unregister_blkdev(diskInfo.major,TFFS_DEVICE_NAME); case 1: TffsCleanup(&diskInfo); }}#ifdef MODULEvoid tffs_exit(void){ InitFree(0);}module_exit(tffs_exit);#endif /* MODULE */static int Open(struct inode*inode,struct file*filp){ DeviceInfo*pDevice=inode->i_bdev->bd_disk->private_data; PrintkDebug("Open 0x%x",pDevice->handle);#ifdef TFFS_ALLOW_UNFORMATTED if(pDevice->pSocket->fDummy) { PrintkDebug("Open 0x%x: not valid",pDevice->handle); return 0; }#endif#ifdef HW_PROTECTION if(TffsIsWriteProtected(pDevice)) /* write protected */ { if(filp->f_mode&0x02) { PrintkDebug("Open: device write protected"); return -EROFS; } }#endif spin_lock(&pDevice->o_c_lock); if(!pDevice->usage) { if(!TffsOpen(pDevice)) { PrintkError("Open: can't access device %d",iminor(inode)); return -ENODEV; } } pDevice->usage++; spin_unlock(&pDevice->o_c_lock); PrintkDebug("Open 0x%x OK",pDevice->handle); return 0; /* success */}int Release(struct inode*inode,struct file*filp){ DeviceInfo*pDevice=inode->i_bdev->bd_disk->private_data; PrintkDebug("Release 0x%x",(unsigned short)iminor(inode));#ifdef TFFS_ALLOW_UNFORMATTED if(pDevice->pSocket->fDummy) return 0;#endif /* lock and dec usage count */ spin_lock(&pDevice->o_c_lock); pDevice->usage--; if(!pDevice->usage) { if(!TffsRelease(pDevice)) { PrintkError("Release: can't access device %d",iminor(inode)); return -ENODEV; } } spin_unlock(&pDevice->o_c_lock); return 0;}int Ioctl(struct inode*inode,struct file*filp,unsigned int cmd,unsigned long arg){#if defined(IOCTL_INTERFACE) || !defined(DO_NOT_YIELD_CPU) DeviceInfo*pDevice=inode->i_bdev->bd_disk->private_data;#endif int res=0; PrintkDebug("Ioctl: cmd 0x%x",cmd);#ifdef IOCTL_INTERFACE if(cmd>=SIOCDEVPRIVATE) { PrintkDebug("Ioctl: TffsIoctl(0x%lx) = 0x%lx -0x%lx",(unsigned long)(cmd-SIOCDEVPRIVATE),(unsigned long)cmd,(unsigned long)SIOCDEVPRIVATE); res=TffsIoctl(pDevice,cmd-SIOCDEVPRIVATE,arg); switch(res) { case 0: /* OK */ return 0; case 1: /* not tffs ioctl - continue */ break; default: /* error */ PrintkError("Ioctl: cmd 0x%x error",cmd); return res; } }#endif /* IOCTL_INTERFACE */ switch(cmd) { case HDIO_GETGEO: { struct hd_geometry geometry; PrintkDebug("Ioctl: HDIO_GETGEO"); /* check arg */ if((void*)arg==NULL) { res=-EINVAL; break; } if(!access_ok(VERIFY_WRITE,(void*)arg,sizeof(struct hd_geometry))) { res=-EFAULT; break; } TffsGetDriveGeometry(pDevice->size/pDevice->pSocket->maxSectorSize,1024/(pDevice->pSocket->maxSectorSize>>9),&geometry.heads,&geometry.sectors,(unsigned int*)(&geometry.cylinders)); geometry.start=get_start_sect(inode->i_bdev); PrintkDebug("Ioctl: heads 0x%x cylinders 0x%x sectors 0x%x start_sect 0x%lx",geometry.heads,geometry.cylinders,geometry.sectors,geometry.start); if(copy_to_user((void*)arg,&geometry,sizeof(struct hd_geometry))) return -EFAULT; break; } default: /* unknown command */ res=-ENOTTY; } if(res) PrintkError("Ioctl: cmd 0x%x error",cmd); return res;}static void Request(request_queue_t*q){/* PrintkDebug("Request"); */#ifdef DO_NOT_YIELD_CPU TransferRequests(q);#else /* DO_NOT_YIELD_CPU */ wake_up_interruptible(&((DeviceInfo*)q->queuedata)->waitQueueHead);#endif /* DO_NOT_YIELD_CPU *//* PrintkDebug("Request: exit"); */}static void TransferRequests(request_queue_t*q){ struct request*pRequest;#ifdef CONFIG_PREEMPT BOOL fNeedYetCheck=FALSE;yet_check:#endif/* PrintkDebug("TransferRequests: queue begin"); */ while((pRequest=elv_next_request(q))!= NULL) /* ask for first request */ { DeviceInfo*pDevice=pRequest->rq_disk->private_data; BOOL fStat=0;#ifdef CONFIG_PREEMPT fNeedYetCheck=TRUE;#endif/* PrintkDebug("TransferRequests: request begin"); */#ifdef TFFS_ALLOW_UNFORMATTED if(pDevice->pSocket->fDummy) { end_request(pRequest,0); /* return error */ continue; }#endif if(!blk_fs_request(pRequest)) /* check the request */ { end_request(pRequest,0); /* return error */ continue; }#ifdef DRIVER_DEBUG /* check sectors are in range */ if((pRequest->sector+pRequest->current_nr_sectors) > (pDevice->size>>9)) { PrintkError("TransferRequests: request not in range: %lx+%lx >= %lx",(DWORD)pRequest->sector,(DWORD)pRequest->current_nr_sectors,(DWORD)pDevice->size>>9); end_request(pRequest,0); continue; }#endif if(pRequest->flags&1) { spin_unlock_irq(q->queue_lock);/* PrintkDebug("TransferRequest: WRITE start_sect 0x%lx current_nr_sectors 0x%lx",(DWORD)pRequest->sector,(DWORD)pRequest->current_nr_sectors); */ fStat=TffsWrite(pDevice,pRequest->buffer,pRequest->sector,pRequest->current_nr_sectors); } else { spin_unlock_irq(q->queue_lock);/* PrintkDebug("TransferRequest: READ start_sect 0x%lx current_nr_sectors 0x%lx",(DWORD)pRequest->sector,(DWORD)pRequest->current_nr_sectors); */ fStat=TffsRead(pDevice,pRequest->buffer,pRequest->sector,pRequest->current_nr_sectors); }/* PrintkDebug("TransferRequests:request end"); */ spin_lock_irq(q->queue_lock); end_request(pRequest,fStat); }#ifdef CONFIG_PREEMPT /* It's special stupid patch for preemptive kernels. The Request() adds next request to queue immediatly after previous end_request() called and queue_lock unlocked. */ if(fNeedYetCheck) { spin_unlock_irq(q->queue_lock); fNeedYetCheck=FALSE; spin_lock_irq(q->queue_lock); goto yet_check; }#endif/* PrintkDebug("TransferRequests:queue end"); */}#ifndef DO_NOT_YIELD_CPUstatic int IoKernelThread(void*device) { DeviceInfo*pDevice=(DeviceInfo*)device; PrintkDebug("IoKernelThread"); current->flags|=PF_MEMALLOC; daemonize("tffs%c",'a'+(pDevice-diskInfo.pDevices)); spin_lock_irq(¤t->sighand->siglock); sigfillset(¤t->blocked); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); set_user_nice(current,prio); up(&pDevice->threadSemaphore); PrintkDebug("IoKernelThread: threadSemaphore released"); spin_lock_irq(&pDevice->queueLock); while(pDevice->threadInit) {#if defined(DRIVER_DEBUG) && defined(CONFIG_PREEMPT) unsigned long timeot;#endif/* PrintkDebug("IoKernelThread: going sleep"); */ spin_unlock_irq(&pDevice->queueLock);#ifdef CONFIG_PREEMPT /* my own preemptive paranoia */# ifdef DRIVER_DEBUG timeot=interruptible_sleep_on_timeout(&pDevice->waitQueueHead,HZ*20); if(timeot==0) PrintkDebug("EXIT ON TIMEOUT");# else interruptible_sleep_on_timeout(&pDevice->waitQueueHead,HZ);# endif/* PrintkDebug("IoKernelThread: awaked"); */#else /* CONFIG_PREEMPT */ interruptible_sleep_on(&pDevice->waitQueueHead);#endif /* CONFIG_PREEMPT */ spin_lock_irq(&pDevice->queueLock); TransferRequests(pDevice->requestQueue); } spin_unlock_irq(&pDevice->queueLock); /* Let the process terminating us know we are done. */ up(&pDevice->threadSemaphore); PrintkDebug("IoKernelThread: exit from thread"); return 0;}void LnxSleep(unsigned long milliseconds,unsigned char bSocket){ wait_queue_head_t qw;#if FL_SKIP_SLEEPS static unsigned short wSkipSleep=0; if(++wSkipSleep<=FL_SKIP_SLEEPS) { return; } wSkipSleep=0;#endif/* PrintkDebug("LnxSleep: enter"); *//* sleep_on_timeout(&diskInfo.pSockets[bSocket].waitQueueHead,(HZ*milliseconds)>>10); */ init_waitqueue_head(&qw); sleep_on_timeout(&qw,(HZ*milliseconds)>>10);/* PrintkDebug("LnxSleep: exit"); */}#endif /* DO_NOT_YIELD_CPU */#endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,7,0)) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -