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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* TODO:
  2.    (C) 2002, Mizi Research Inc.
  3.    Author: Hwang, Chideok <hwang@mizi.co.kr>
  4. */
  5. #include <linux/config.h>
  6. #include <linux/types.h>
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/mtd/mtd.h>
  10. #include <linux/mtd/partitions.h>
  11. #include <linux/mtd/nand_ecc.h>
  12. #include <asm/errno.h>
  13. #define BON_MAJOR 97
  14. #define MAJOR_NR BON_MAJOR
  15. #define DEVICE_NAME "bon"
  16. #define DEVICE_REQUEST do_bon_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. #include <linux/devfs_fs_kernel.h>
  23. static int PARTITION_OFFSET  = (~0);
  24. #define MAX_RETRY 5
  25. #define MAX_MTD_PART 2
  26. #define MAX_PART 5
  27. typedef struct {
  28.     unsigned long offset;
  29.     unsigned long size;
  30.     unsigned long flag;
  31.     devfs_handle_t devfs_rw_handle;
  32.     unsigned short *bad_blocks;
  33. } partition_t;
  34. static struct {
  35.     struct mtd_info *mtd;
  36.     struct mtd_info *shadow_mtd[MAX_MTD_PART];
  37.     int num_part;
  38. int num_mtd_part;
  39.     devfs_handle_t devfs_dir_handle;
  40.     partition_t parts[MAX_PART];
  41. struct mtd_partition mtd_parts[MAX_MTD_PART];
  42. } bon;
  43. static const char BON_MAGIC[8] = {'M', 0, 0, 'I', 0, 'Z', 'I', 0};
  44. static int bon_sizes[MAX_PART];
  45. static int bon_blksizes[MAX_PART];
  46. #ifdef CONFIG_PROC_FS
  47. #include <linux/proc_fs.h>
  48. static struct proc_dir_entry *proc_bon;
  49. static inline 
  50. int bon_proc_info (char *buf, int i)
  51. {
  52. partition_t *this = (partition_t *)&bon.parts[i];
  53. if (!this)
  54. return 0;
  55. return sprintf(buf, "bon%d: %8.8lx-%8.8lx (%8.8lx) %8.8lxn", i, 
  56. this->offset, this->offset + this->size, this->size, this->flag);
  57. }
  58. static int 
  59. bon_read_proc ( char *page, char **start, off_t off,int count 
  60. ,int *eof, void *data_unused)
  61. {
  62. int len, l, i;
  63. off_t   begin = 0;
  64. len = sprintf(page, "      position          size       flagn");
  65. for (i=0; i< bon.num_part; i++) { 
  66. l = bon_proc_info(page + len, i);
  67. len += l;
  68. if (len+begin > off+count)
  69. goto done;
  70. if (len+begin < off) {
  71. begin += len;
  72. len = 0;
  73. }
  74. }
  75. *eof = 1;
  76. done:
  77. if (off >= len+begin)
  78. return 0;
  79. *start = page + (off-begin);
  80. return ((count < begin+len-off) ? count : begin+len-off);
  81. }
  82. #endif // CONFIG_PROC_FS
  83. static int
  84. bon_open(struct inode *inode, struct file *file)
  85. {
  86.     int minor = MINOR(inode->i_rdev);
  87.     partition_t *part = &bon.parts[minor];
  88.     if (minor >= bon.num_part || !part->size) return -ENODEV;
  89.     get_mtd_device(bon.mtd, -1);
  90.     return 0;
  91. }
  92. static int
  93. bon_close(struct inode *inode, struct file *file)
  94. {
  95. //    int minor = MINOR(inode->i_rdev);
  96.     struct mtd_info *mtd;
  97. //    partition_t *part = &bon.parts[minor];
  98.     mtd = bon.mtd;
  99. #if LINUX_VERSION_CODE != KERNEL_VERSION(2,4,18)
  100.     invalidate_device(inode->i_rdev, 1);
  101. #endif
  102.     if (mtd->sync) mtd->sync(mtd);
  103.     put_mtd_device(mtd);
  104.     return 0;
  105. }
  106. static int
  107. bon_ioctl(struct inode *inode, struct file *file,
  108.     u_int cmd, u_long arg)
  109. {
  110.     int minor = MINOR(inode->i_rdev);
  111.     partition_t *part = &bon.parts[minor];
  112.     switch(cmd) {
  113. case BLKGETSIZE:
  114.     return put_user((part->size>>9), (long *)arg);
  115. #ifdef BLKGETSIZE64
  116. case BLKGETSIZE64:
  117.     return put_user((u64)(part->size>>9), (long *)arg);
  118. #endif
  119. case BLKFLSBUF:
  120.     if (!capable(CAP_SYS_ADMIN)) return -EACCES;
  121.     fsync_dev(inode->i_rdev);
  122.     invalidate_buffers(inode->i_rdev);
  123.     if (bon.mtd->sync) bon.mtd->sync(bon.mtd);
  124.     return 0;
  125. default:
  126.     return -ENOTTY;
  127.     }
  128. }
  129. static struct block_device_operations bon_blk_fops = {
  130.     owner: THIS_MODULE,
  131.     open: bon_open,
  132.     release: bon_close,
  133.     ioctl: bon_ioctl
  134. };
  135. static int
  136. do_read(partition_t *part, char *buf, unsigned long pos, size_t size)
  137. {
  138.     int ret, retlen;
  139.     int i;
  140.     while(size > 0) {
  141. unsigned long block = pos / bon.mtd->erasesize;
  142. unsigned long start, start_in_block;
  143. size_t this_size;
  144. if (part->bad_blocks) {
  145.     unsigned short *bad = part->bad_blocks;
  146.     while(*bad++ <= block) {
  147. block++;
  148.     }
  149. }
  150. start_in_block = pos % bon.mtd->erasesize;
  151. start = block * bon.mtd->erasesize + start_in_block;
  152. this_size = bon.mtd->erasesize - start_in_block;
  153. if (this_size > size) this_size = size;
  154. ret = MTD_READ(bon.mtd, part->offset + start, this_size, &retlen, buf);
  155. if (ret) return ret;
  156. if (this_size != retlen) return -EIO;
  157. /* ecc */
  158. for(i=0;i<this_size;i++) {
  159.     unsigned char oobbuf[16];
  160.     unsigned char *ecc1 = oobbuf + 8, *ecc2 = ecc1 + 3;
  161.     unsigned char calc_ecc[3];
  162.     size_t retlen;
  163.     int ecc_result;
  164.     MTD_READOOB(bon.mtd, part->offset + start + i, 16, &retlen, oobbuf);
  165.     nand_calculate_ecc(buf,  calc_ecc);
  166.     ecc_result = nand_correct_data(buf, ecc1, calc_ecc);
  167.     if (ecc_result == -1) {
  168. printk("bon: ecc error, page = 0x%08lxn", (part->offset + start + i) >> 9);
  169. return -EIO;
  170.     }
  171.     nand_calculate_ecc(buf + 256,  calc_ecc);
  172.     ecc_result = nand_correct_data(buf + 256, ecc2, calc_ecc);
  173.     if (ecc_result == -1) {
  174. printk("bon: ecc error, page = 0x%08lxn", (part->offset + start + i) >> 9);
  175. return -EIO;
  176.     }
  177.     i += 512;
  178. }
  179. size -= this_size;
  180. buf += this_size;
  181. pos += this_size;
  182.     }
  183.     return 0;
  184. }
  185. static void
  186. do_bon_request(request_queue_t *q)
  187. {
  188.     struct request *req;
  189. //    struct mtd_info *mtd = bon.mtd;
  190.     partition_t *part;
  191.     int res;
  192.     while (1) {
  193. INIT_REQUEST;
  194. req = CURRENT;
  195. spin_unlock_irq(&io_request_lock);
  196. res = 0;
  197. if (MINOR(req->rq_dev) >= bon.num_part) {
  198.     printk("bon: Unsupported devicesn");
  199.     goto end_req;
  200. }
  201. part = &bon.parts[MINOR(req->rq_dev)];
  202. if (req->current_nr_sectors << 9 > part->size) {
  203.     printk("bon: attempt to read past end of device!n");
  204.     goto end_req;
  205. }
  206. switch(req->cmd) {
  207.     int err;
  208.     case READ:
  209. err = do_read(part, req->buffer, 
  210.     req->sector << 9, req->current_nr_sectors << 9);
  211. if (!err) res = 1;
  212. break;
  213.     case WRITE:
  214. break;
  215. }
  216. end_req:
  217. spin_lock_irq(&io_request_lock);
  218. end_request(res);
  219.     }
  220. }
  221. static int
  222. read_partition_info(struct mtd_info *mtd)
  223. {
  224.     unsigned long offset = PARTITION_OFFSET;
  225.     int i;
  226.     char buf[512];
  227.     unsigned char oobbuf[16];
  228.     unsigned int *s;
  229.     int retlen, k;
  230.     int retry_count = MAX_RETRY;
  231.     if (offset > mtd->size - mtd->erasesize) 
  232. offset = mtd->size - mtd->erasesize;
  233.     while(retry_count-- > 0) {
  234. if (MTD_READOOB(mtd, offset, 8, &retlen, oobbuf) < 0) {
  235.     goto next_block;
  236. }
  237. if (oobbuf[5] != 0xff) {
  238.     goto next_block;
  239. }
  240. if (MTD_READ(mtd, offset, 512, &retlen, buf) < 0) {
  241.     goto next_block;
  242. }
  243. if (strncmp(buf, BON_MAGIC, 8) == 0) break;
  244. printk("bon:cannot find partition tablen");
  245. return -1;
  246. next_block:
  247.         offset -= mtd->erasesize;
  248.     }
  249.     if (retry_count <= 0) {
  250. printk("bon:cannot find partition tablen");
  251. return -1;
  252.     }
  253.     s = (unsigned int *)(buf + 8);
  254.     bon.num_part = min_t(unsigned long, *s++, MAX_PART);
  255. bon.num_mtd_part = 0;
  256.     bon.mtd = mtd;
  257.     bon.devfs_dir_handle = devfs_mk_dir(NULL, "bon", NULL);
  258.     // for each partition, make 
  259.     for(i=0;i < bon.num_part; i++) {
  260. char name[8];
  261. // int num_block;
  262. bon.parts[i].offset = *s++;
  263. bon.parts[i].size = *s++;
  264. bon.parts[i].flag = *s++;
  265. printk("bon%d: %8.8lx-%8.8lx (%8.8lx) %8.8lxn", i, 
  266. bon.parts[i].offset, bon.parts[i].offset + bon.parts[i].size, bon.parts[i].size, bon.parts[i].flag);
  267. if (bon.parts[i].flag & 0x01) {
  268. #if 0 // bushi
  269. struct mtd_partition *mtd_part;
  270. if (bon.num_mtd_part >= MAX_MTD_PART)
  271. continue;
  272.     mtd_part = &(bon.mtd_parts[bon.num_mtd_part]);
  273.     mtd_part->mask_flags = 0;
  274.     mtd_part->size = bon.parts[i].size;
  275.     mtd_part->name = "nandflash  (bon  )";
  276. sprintf(mtd_part->name, "nandflash%d (bon%d)", bon.num_mtd_part, i);
  277.     mtd_part->offset = bon.parts[i].offset;
  278. mtd_part->mtdp = &bon.shadow_mtd[bon.num_mtd_part];
  279.     bon.num_mtd_part++;
  280. #endif
  281. } else {
  282.     sprintf(name, "%d", i);
  283.     bon.parts[i].devfs_rw_handle = devfs_register(bon.devfs_dir_handle,
  284. name, DEVFS_FL_DEFAULT, BON_MAJOR, i, 
  285. S_IFBLK | S_IRUGO, // | S_IWUGO, /* forbid writing */
  286. &bon_blk_fops, NULL);
  287. }
  288.     }
  289.     for(i=0;i<bon.num_part;i++) {
  290. unsigned int num_bad_block = *s++;
  291. if (num_bad_block == 0) continue;
  292. bon.parts[i].bad_blocks = kmalloc((1+num_bad_block) * sizeof(unsigned short), GFP_KERNEL);
  293. for(k=0;k<num_bad_block;k++) {
  294.     bon.parts[i].bad_blocks[k] = *s++;
  295. }
  296. bon.parts[i].bad_blocks[k] = ~0;
  297.     }
  298. #if 0 // bushi
  299. printk("add mtd part! - startn");
  300. if (bon.num_mtd_part) {
  301. add_mtd_partitions(mtd, &bon.mtd_parts[0], bon.num_mtd_part);
  302. }
  303. printk("add mtd part! - endn");
  304. #endif
  305.     return 0;
  306. }
  307. static void
  308. bon_notify_add(struct mtd_info *mtd)
  309. {
  310. //    partition_t *part;
  311. //    int dev;
  312.     int i;
  313.     if (!mtd->read_oob) return; 
  314.     if (bon.num_part) return;
  315.     if (read_partition_info(mtd)) return;
  316.     for(i=0;i<bon.num_part;i++) {
  317. bon_sizes[i] = bon.parts[i].size/1024;
  318. bon_blksizes[i] = mtd->erasesize;
  319. if (bon_blksizes[i] > PAGE_SIZE) bon_blksizes[i] = PAGE_SIZE;
  320.     }
  321. }
  322. static void
  323. bon_notify_remove(struct mtd_info *mtd)
  324. {
  325.     int i;
  326.     if (!bon.num_part || bon.mtd != mtd) return;
  327.     devfs_unregister(bon.devfs_dir_handle);
  328.     for(i=0;i<bon.num_part;i++) {
  329. devfs_unregister(bon.parts[i].devfs_rw_handle);
  330.     }
  331.     memset(&bon, 0, sizeof(bon));
  332. }
  333. static struct mtd_notifier bon_notifier = {
  334.     add: bon_notify_add,
  335.     remove: bon_notify_remove
  336. };
  337. static int
  338. init_bon(void)
  339. {
  340.     int i;
  341.     memset(&bon, 0, sizeof(bon));
  342.     if (devfs_register_blkdev(BON_MAJOR, "bon", &bon_blk_fops)) {
  343. printk(KERN_WARNING "bon: unable to allocate major device numn");
  344. return -EAGAIN;
  345.     }
  346.     for(i=0;i<MAX_PART;i++) {
  347.         bon_blksizes[i] = 1024;
  348. bon_sizes[i] = 0;
  349.     }
  350.     blksize_size[BON_MAJOR] = bon_blksizes;
  351.     blk_size[BON_MAJOR] = bon_sizes;
  352.     blk_init_queue(BLK_DEFAULT_QUEUE(BON_MAJOR), &do_bon_request);
  353.     register_mtd_user(&bon_notifier);
  354. #ifdef CONFIG_PROC_FS
  355. if ((proc_bon = create_proc_entry( "bon", 0, 0 )))
  356. proc_bon->read_proc = bon_read_proc;
  357. #endif
  358.     return 0;
  359. }
  360. static void __exit cleanup_bon(void)
  361. {
  362.     unregister_mtd_user(&bon_notifier);
  363.     devfs_unregister_blkdev(BON_MAJOR, "bon");
  364.     blk_cleanup_queue(BLK_DEFAULT_QUEUE(BON_MAJOR));
  365.     blksize_size[BON_MAJOR] = NULL;
  366. #ifdef CONFIG_PROC_FS
  367. if (proc_bon)
  368. remove_proc_entry( "bon", 0);
  369. #endif
  370. }
  371. #ifdef MODULE
  372. MODULE_PARM(PARTITION_OFFSET, "i");
  373. #else
  374. int __init part_setup(char *options)
  375. {
  376.     if (!options || !*options) return 0;
  377.     PARTITION_OFFSET = simple_strtoul(options, &options, 0);
  378.     if (*options == 'k' || *options == 'K') {
  379. PARTITION_OFFSET *= 1024;
  380.     } else if (*options == 'm' || *options == 'M') {
  381. PARTITION_OFFSET *= 1024;
  382.     }
  383.     return 0;
  384. }
  385. __setup("nand_part_offset=", part_setup);
  386. #endif
  387. void get_bon_data_area(unsigned long *address, unsigned long *size)
  388. {
  389. *address = bon.parts[2].offset;
  390. *size    = bon.parts[2].size;
  391. }
  392. module_init(init_bon);
  393. module_exit(cleanup_bon);
  394. MODULE_LICENSE("GPL");
  395. MODULE_AUTHOR("Hwang, Chideok <hwang@mizi.co.kr>");
  396. MODULE_DESCRIPTION("Simple Block Device for Nand Flash");