mtdblock_ro.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $
  3.  *
  4.  * Read-only version of the mtdblock device, without the 
  5.  * read/erase/modify/writeback stuff
  6.  */
  7. #ifdef MTDBLOCK_DEBUG
  8. #define DEBUGLVL debug
  9. #endif        
  10. #include <linux/module.h>
  11. #include <linux/types.h>
  12. #include <linux/mtd/mtd.h>
  13. #include <linux/mtd/compatmac.h>
  14. #define MAJOR_NR MTD_BLOCK_MAJOR
  15. #define DEVICE_NAME "mtdblock"
  16. #define DEVICE_REQUEST mtdblock_request
  17. #define DEVICE_NR(device) (device)
  18. #define DEVICE_ON(device)
  19. #define DEVICE_OFF(device)
  20. #define DEVICE_NO_RANDOM
  21. #include <linux/blk.h>
  22. #if LINUX_VERSION_CODE < 0x20300
  23. #define RQFUNC_ARG void
  24. #define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
  25. #else
  26. #define RQFUNC_ARG request_queue_t *q
  27. #endif
  28. #ifdef MTDBLOCK_DEBUG
  29. static int debug = MTDBLOCK_DEBUG;
  30. MODULE_PARM(debug, "i");
  31. #endif
  32. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
  33. #define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
  34. #define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
  35. #else
  36. #define BLK_INC_USE_COUNT do {} while(0)
  37. #define BLK_DEC_USE_COUNT do {} while(0)
  38. #endif
  39. static int mtd_sizes[MAX_MTD_DEVICES];
  40. static int mtdblock_open(struct inode *inode, struct file *file)
  41. {
  42. struct mtd_info *mtd = NULL;
  43. int dev;
  44. DEBUG(1,"mtdblock_openn");
  45. if (inode == 0)
  46. return -EINVAL;
  47. dev = MINOR(inode->i_rdev);
  48. mtd = get_mtd_device(NULL, dev);
  49. if (!mtd)
  50. return -EINVAL;
  51. if (MTD_ABSENT == mtd->type) {
  52. put_mtd_device(mtd);
  53. return -EINVAL;
  54. }
  55. BLK_INC_USE_COUNT;
  56. mtd_sizes[dev] = mtd->size>>9;
  57. DEBUG(1, "okn");
  58. return 0;
  59. }
  60. static release_t mtdblock_release(struct inode *inode, struct file *file)
  61. {
  62. int dev;
  63. struct mtd_info *mtd;
  64.     DEBUG(1, "mtdblock_releasen");
  65. if (inode == NULL)
  66. release_return(-ENODEV);
  67.    
  68. dev = MINOR(inode->i_rdev);
  69. mtd = __get_mtd_device(NULL, dev);
  70. if (!mtd) {
  71. printk(KERN_WARNING "MTD device is absent on mtd_release!n");
  72. BLK_DEC_USE_COUNT;
  73. release_return(-ENODEV);
  74. }
  75. if (mtd->sync)
  76. mtd->sync(mtd);
  77. put_mtd_device(mtd);
  78. DEBUG(1, "okn");
  79. BLK_DEC_USE_COUNT;
  80. release_return(0);
  81. }  
  82. static void mtdblock_request(RQFUNC_ARG)
  83. {
  84.    struct request *current_request;
  85.    unsigned int res = 0;
  86.    struct mtd_info *mtd;
  87.    while (1)
  88.    {
  89.       /* Grab the Request and unlink it from the request list, INIT_REQUEST
  90.          will execute a return if we are done. */
  91.       INIT_REQUEST;
  92.       current_request = CURRENT;
  93.    
  94.       if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
  95.       {
  96.  printk("mtd: Unsupported device!n");
  97.  end_request(0);
  98.  continue;
  99.       }
  100.       
  101.       // Grab our MTD structure
  102.       mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
  103.       if (!mtd) {
  104.       printk("MTD device %d doesn't appear to exist any moren", CURRENT_DEV);
  105.       end_request(0);
  106.       }
  107.       if (current_request->sector << 9 > mtd->size ||
  108.   (current_request->sector + current_request->nr_sectors) << 9 > mtd->size)
  109.       {
  110.  printk("mtd: Attempt to read past end of device!n");
  111.  printk("size: %x, sector: %lx, nr_sectors %lxn", mtd->size, current_request->sector, current_request->nr_sectors);
  112.  end_request(0);
  113.  continue;
  114.       }
  115.       
  116.       /* Remove the request we are handling from the request list so nobody messes
  117.          with it */
  118. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
  119.       /* Now drop the lock that the ll_rw_blk functions grabbed for us
  120.          and process the request. This is necessary due to the extreme time
  121.          we spend processing it. */
  122.       spin_unlock_irq(&io_request_lock);
  123. #endif
  124.       // Handle the request
  125.       switch (current_request->cmd)
  126.       {
  127.          size_t retlen;
  128.  case READ:
  129.  if (MTD_READ(mtd,current_request->sector<<9, 
  130.       current_request->nr_sectors << 9, 
  131.       &retlen, current_request->buffer) == 0)
  132.     res = 1;
  133.  else
  134.     res = 0;
  135.  break;
  136.  
  137.  case WRITE:
  138.  /* printk("mtdblock_request WRITE sector=%d(%d)n",current_request->sector,
  139. current_request->nr_sectors);
  140.  */
  141.  // Read only device
  142.  if ((mtd->flags & MTD_CAP_RAM) == 0)
  143.  {
  144.     res = 0;
  145.     break;
  146.  }
  147.  // Do the write
  148.  if (MTD_WRITE(mtd,current_request->sector<<9, 
  149.        current_request->nr_sectors << 9, 
  150.        &retlen, current_request->buffer) == 0)
  151.     res = 1;
  152.  else
  153.     res = 0;
  154.  break;
  155.  
  156.  // Shouldn't happen
  157.  default:
  158.  printk("mtd: unknown requestn");
  159.  break;
  160.       }
  161.       // Grab the lock and re-thread the item onto the linked list
  162. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
  163. spin_lock_irq(&io_request_lock);
  164. #endif
  165. end_request(res);
  166.    }
  167. }
  168. static int mtdblock_ioctl(struct inode * inode, struct file * file,
  169.       unsigned int cmd, unsigned long arg)
  170. {
  171. struct mtd_info *mtd;
  172. mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
  173. if (!mtd) return -EINVAL;
  174. switch (cmd) {
  175. case BLKGETSIZE:   /* Return device size */
  176. return put_user((mtd->size >> 9), (unsigned long *) arg);
  177. #ifdef BLKGETSIZE64
  178. case BLKGETSIZE64:
  179. return put_user((u64)mtd->size, (u64 *)arg);
  180. #endif
  181. case BLKFLSBUF:
  182. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
  183. if(!capable(CAP_SYS_ADMIN))  return -EACCES;
  184. #endif
  185. fsync_dev(inode->i_rdev);
  186. invalidate_buffers(inode->i_rdev);
  187. if (mtd->sync)
  188. mtd->sync(mtd);
  189. return 0;
  190. default:
  191. return -ENOTTY;
  192. }
  193. }
  194. #if LINUX_VERSION_CODE < 0x20326
  195. static struct file_operations mtd_fops =
  196. {
  197. open: mtdblock_open,
  198. ioctl: mtdblock_ioctl,
  199. release: mtdblock_release,
  200. read: block_read,
  201. write: block_write
  202. };
  203. #else
  204. static struct block_device_operations mtd_fops = 
  205. {
  206. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
  207. owner: THIS_MODULE,
  208. #endif
  209. open: mtdblock_open,
  210. release: mtdblock_release,
  211. ioctl: mtdblock_ioctl
  212. };
  213. #endif
  214. int __init init_mtdblock(void)
  215. {
  216. int i;
  217. if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
  218. printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.n",
  219.        MTD_BLOCK_MAJOR);
  220. return -EAGAIN;
  221. }
  222. /* We fill it in at open() time. */
  223. for (i=0; i< MAX_MTD_DEVICES; i++) {
  224. mtd_sizes[i] = 0;
  225. }
  226. /* Allow the block size to default to BLOCK_SIZE. */
  227. blksize_size[MAJOR_NR] = NULL;
  228. blk_size[MAJOR_NR] = mtd_sizes;
  229. blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
  230. return 0;
  231. }
  232. static void __exit cleanup_mtdblock(void)
  233. {
  234. unregister_blkdev(MAJOR_NR,DEVICE_NAME);
  235. blksize_size[MAJOR_NR] = NULL;
  236. blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
  237. }
  238. module_init(init_mtdblock);
  239. module_exit(cleanup_mtdblock);
  240. MODULE_LICENSE("GPL");
  241. MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
  242. MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices");