diff options
author | David Vrabel <david.vrabel@csr.com> | 2007-08-08 09:24:21 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 15:21:32 -0400 |
commit | eb6594689226663968ef0a9fd71ec5e1e4e04f9c (patch) | |
tree | d523962b81a2b5f4a55543d4342daaaebc5d5162 /drivers/mmc/core/sdio_ops.c | |
parent | 9a08f82b3cc522f727ace580a2aaee5402435bc8 (diff) |
sdio: extend sdio_readsb() and friends to handle any length of buffer
Extend sdio_readsb(), sdio_writesb(), sdio_memcpy_fromio(), and
sdio_memcpy_toio() to handle any length of buffer by splitting the transfer
into several IO_RW_EXTENDED commands. Typically, a transfer would be split
into a single block mode transfer followed by a byte mode transfer for the
remainder but we also handle lack of block mode support and the block size
being greater than 512 (the maximum byte mode transfer size).
host->max_seg_size <= host->max_req_size so there's no need to check both
when determining the maximum data size for a single command.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/sdio_ops.c')
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 4f2c77139477..98e20532452a 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c | |||
@@ -88,7 +88,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
88 | } | 88 | } |
89 | 89 | ||
90 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | 90 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, |
91 | unsigned addr, int bang, u8 *buf, unsigned size) | 91 | unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) |
92 | { | 92 | { |
93 | struct mmc_request mrq; | 93 | struct mmc_request mrq; |
94 | struct mmc_command cmd; | 94 | struct mmc_command cmd; |
@@ -97,7 +97,9 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
97 | 97 | ||
98 | BUG_ON(!card); | 98 | BUG_ON(!card); |
99 | BUG_ON(fn > 7); | 99 | BUG_ON(fn > 7); |
100 | BUG_ON(size > 512); | 100 | BUG_ON(blocks == 1 && blksz > 512); |
101 | WARN_ON(blocks == 0); | ||
102 | WARN_ON(blksz == 0); | ||
101 | 103 | ||
102 | memset(&mrq, 0, sizeof(struct mmc_request)); | 104 | memset(&mrq, 0, sizeof(struct mmc_request)); |
103 | memset(&cmd, 0, sizeof(struct mmc_command)); | 105 | memset(&cmd, 0, sizeof(struct mmc_command)); |
@@ -109,18 +111,21 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
109 | cmd.opcode = SD_IO_RW_EXTENDED; | 111 | cmd.opcode = SD_IO_RW_EXTENDED; |
110 | cmd.arg = write ? 0x80000000 : 0x00000000; | 112 | cmd.arg = write ? 0x80000000 : 0x00000000; |
111 | cmd.arg |= fn << 28; | 113 | cmd.arg |= fn << 28; |
112 | cmd.arg |= bang ? 0x00000000 : 0x04000000; | 114 | cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; |
113 | cmd.arg |= addr << 9; | 115 | cmd.arg |= addr << 9; |
114 | cmd.arg |= (size == 512) ? 0 : size; | 116 | if (blocks == 1 && blksz <= 512) |
117 | cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ | ||
118 | else | ||
119 | cmd.arg |= 0x08000000 | blocks; /* block mode */ | ||
115 | cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; | 120 | cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; |
116 | 121 | ||
117 | data.blksz = size; | 122 | data.blksz = blksz; |
118 | data.blocks = 1; | 123 | data.blocks = blocks; |
119 | data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; | 124 | data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; |
120 | data.sg = &sg; | 125 | data.sg = &sg; |
121 | data.sg_len = 1; | 126 | data.sg_len = 1; |
122 | 127 | ||
123 | sg_init_one(&sg, buf, size); | 128 | sg_init_one(&sg, buf, blksz * blocks); |
124 | 129 | ||
125 | mmc_set_data_timeout(&data, card); | 130 | mmc_set_data_timeout(&data, card); |
126 | 131 | ||