mtdblock_ro.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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