sm_common.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright © 2009 - Maxim Levitsky
  3. * Common routines & support for xD format
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/mtd/nand.h>
  11. #include "sm_common.h"
  12. static struct nand_ecclayout nand_oob_sm = {
  13. .eccbytes = 6,
  14. .eccpos = {8, 9, 10, 13, 14, 15},
  15. .oobfree = {
  16. {.offset = 0 , .length = 4}, /* reserved */
  17. {.offset = 6 , .length = 2}, /* LBA1 */
  18. {.offset = 11, .length = 2} /* LBA2 */
  19. }
  20. };
  21. /* NOTE: This layout is is not compatabable with SmartMedia, */
  22. /* because the 256 byte devices have page depenent oob layout */
  23. /* However it does preserve the bad block markers */
  24. /* If you use smftl, it will bypass this and work correctly */
  25. /* If you not, then you break SmartMedia compliance anyway */
  26. static struct nand_ecclayout nand_oob_sm_small = {
  27. .eccbytes = 3,
  28. .eccpos = {0, 1, 2},
  29. .oobfree = {
  30. {.offset = 3 , .length = 2}, /* reserved */
  31. {.offset = 6 , .length = 2}, /* LBA1 */
  32. }
  33. };
  34. static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
  35. {
  36. struct mtd_oob_ops ops;
  37. struct sm_oob oob;
  38. int ret, error = 0;
  39. memset(&oob, -1, SM_OOB_SIZE);
  40. oob.block_status = 0x0F;
  41. /* As long as this function is called on erase block boundaries
  42. it will work correctly for 256 byte nand */
  43. ops.mode = MTD_OOB_PLACE;
  44. ops.ooboffs = 0;
  45. ops.ooblen = mtd->oobsize;
  46. ops.oobbuf = (void *)&oob;
  47. ops.datbuf = NULL;
  48. ret = mtd->write_oob(mtd, ofs, &ops);
  49. if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) {
  50. printk(KERN_NOTICE
  51. "sm_common: can't mark sector at %i as bad\n",
  52. (int)ofs);
  53. error = -EIO;
  54. } else
  55. mtd->ecc_stats.badblocks++;
  56. return error;
  57. }
  58. int sm_register_device(struct mtd_info *mtd)
  59. {
  60. struct nand_chip *chip = (struct nand_chip *)mtd->priv;
  61. int ret;
  62. chip->options |= NAND_SKIP_BBTSCAN | NAND_SMARTMEDIA;
  63. /* Scan for card properties */
  64. ret = nand_scan_ident(mtd, 1, NULL);
  65. if (ret)
  66. return ret;
  67. /* Bad block marker postion */
  68. chip->badblockpos = 0x05;
  69. chip->badblockbits = 7;
  70. chip->block_markbad = sm_block_markbad;
  71. /* ECC layout */
  72. if (mtd->writesize == SM_SECTOR_SIZE)
  73. chip->ecc.layout = &nand_oob_sm;
  74. else if (mtd->writesize == SM_SMALL_PAGE)
  75. chip->ecc.layout = &nand_oob_sm_small;
  76. else
  77. return -ENODEV;
  78. ret = nand_scan_tail(mtd);
  79. if (ret)
  80. return ret;
  81. return add_mtd_device(mtd);
  82. }
  83. EXPORT_SYMBOL_GPL(sm_register_device);
  84. MODULE_LICENSE("GPL");
  85. MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
  86. MODULE_DESCRIPTION("Common SmartMedia/xD functions");