diff options
| -rw-r--r-- | drivers/mtd/devices/docg3.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 65d22a0439c6..3dbbfa58251d 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c | |||
| @@ -227,7 +227,7 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, | |||
| 227 | u8 data8, *dst8; | 227 | u8 data8, *dst8; |
| 228 | 228 | ||
| 229 | doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); | 229 | doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); |
| 230 | cdr = len & 0x3; | 230 | cdr = len & 0x1; |
| 231 | len4 = len - cdr; | 231 | len4 = len - cdr; |
| 232 | 232 | ||
| 233 | if (first) | 233 | if (first) |
| @@ -732,12 +732,24 @@ err: | |||
| 732 | * @len: the number of bytes to be read (must be a multiple of 4) | 732 | * @len: the number of bytes to be read (must be a multiple of 4) |
| 733 | * @buf: the buffer to be filled in (or NULL is forget bytes) | 733 | * @buf: the buffer to be filled in (or NULL is forget bytes) |
| 734 | * @first: 1 if first time read, DOC_READADDRESS should be set | 734 | * @first: 1 if first time read, DOC_READADDRESS should be set |
| 735 | * @last_odd: 1 if last read ended up on an odd byte | ||
| 736 | * | ||
| 737 | * Reads bytes from a prepared page. There is a trickery here : if the last read | ||
| 738 | * ended up on an odd offset in the 1024 bytes double page, ie. between the 2 | ||
| 739 | * planes, the first byte must be read apart. If a word (16bit) read was used, | ||
| 740 | * the read would return the byte of plane 2 as low *and* high endian, which | ||
| 741 | * will mess the read. | ||
| 735 | * | 742 | * |
| 736 | */ | 743 | */ |
| 737 | static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, | 744 | static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, |
| 738 | int first) | 745 | int first, int last_odd) |
| 739 | { | 746 | { |
| 740 | doc_read_data_area(docg3, buf, len, first); | 747 | if (last_odd && len > 0) { |
| 748 | doc_read_data_area(docg3, buf, 1, first); | ||
| 749 | doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0); | ||
| 750 | } else { | ||
| 751 | doc_read_data_area(docg3, buf, len, first); | ||
| 752 | } | ||
| 741 | doc_delay(docg3, 2); | 753 | doc_delay(docg3, 2); |
| 742 | return len; | 754 | return len; |
| 743 | } | 755 | } |
| @@ -888,20 +900,20 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 888 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); | 900 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); |
| 889 | if (ret < 0) | 901 | if (ret < 0) |
| 890 | goto err_in_read; | 902 | goto err_in_read; |
| 891 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1); | 903 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0); |
| 892 | if (ret < skip) | 904 | if (ret < skip) |
| 893 | goto err_in_read; | 905 | goto err_in_read; |
| 894 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); | 906 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2); |
| 895 | if (ret < nbdata) | 907 | if (ret < nbdata) |
| 896 | goto err_in_read; | 908 | goto err_in_read; |
| 897 | doc_read_page_getbytes(docg3, | 909 | doc_read_page_getbytes(docg3, |
| 898 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, | 910 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, |
| 899 | NULL, 0); | 911 | NULL, 0, (skip + nbdata) % 2); |
| 900 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); | 912 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0); |
| 901 | if (ret < nboob) | 913 | if (ret < nboob) |
| 902 | goto err_in_read; | 914 | goto err_in_read; |
| 903 | doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, | 915 | doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, |
| 904 | NULL, 0); | 916 | NULL, 0, nboob % 2); |
| 905 | 917 | ||
| 906 | doc_get_bch_hw_ecc(docg3, hwecc); | 918 | doc_get_bch_hw_ecc(docg3, hwecc); |
| 907 | eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); | 919 | eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); |
| @@ -1006,7 +1018,7 @@ static int doc_reload_bbt(struct docg3 *docg3) | |||
| 1006 | DOC_LAYOUT_PAGE_SIZE); | 1018 | DOC_LAYOUT_PAGE_SIZE); |
| 1007 | if (!ret) | 1019 | if (!ret) |
| 1008 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, | 1020 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, |
| 1009 | buf, 1); | 1021 | buf, 1, 0); |
| 1010 | buf += DOC_LAYOUT_PAGE_SIZE; | 1022 | buf += DOC_LAYOUT_PAGE_SIZE; |
| 1011 | } | 1023 | } |
| 1012 | doc_read_page_finish(docg3); | 1024 | doc_read_page_finish(docg3); |
| @@ -1066,10 +1078,10 @@ static int doc_get_erase_count(struct docg3 *docg3, loff_t from) | |||
| 1066 | ret = doc_reset_seq(docg3); | 1078 | ret = doc_reset_seq(docg3); |
| 1067 | if (!ret) | 1079 | if (!ret) |
| 1068 | ret = doc_read_page_prepare(docg3, block0, block1, page, | 1080 | ret = doc_read_page_prepare(docg3, block0, block1, page, |
| 1069 | ofs + DOC_LAYOUT_WEAR_OFFSET); | 1081 | ofs + DOC_LAYOUT_WEAR_OFFSET, 0); |
| 1070 | if (!ret) | 1082 | if (!ret) |
| 1071 | ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, | 1083 | ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, |
| 1072 | buf, 1); | 1084 | buf, 1, 0); |
| 1073 | doc_read_page_finish(docg3); | 1085 | doc_read_page_finish(docg3); |
| 1074 | 1086 | ||
| 1075 | if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) | 1087 | if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) |
