Skip to content

Commit a275cb0

Browse files
aykevldpgeorge
authored andcommitted
drivers/sdcard: Avoid allocation on the heap.
This commit fixes two things: 1. Do not allocate on the heap in readblocks() - unless the block size is bigger than 512 bytes. 2. Raise an error instead of returning 1 to indicate an error: the FAT block device layer does not check the return value. And other backends (e.g. esp32 blockdev) also raise an error instead of returning non-zero.
1 parent bb34122 commit a275cb0

1 file changed

Lines changed: 22 additions & 26 deletions

File tree

drivers/sdcard/sdcard.py

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def __init__(self, spi, cs):
4646

4747
self.cmdbuf = bytearray(6)
4848
self.dummybuf = bytearray(512)
49+
self.tokenbuf = bytearray(1)
4950
for i in range(512):
5051
self.dummybuf[i] = 0xff
5152
self.dummybuf_memoryview = memoryview(self.dummybuf)
@@ -134,7 +135,7 @@ def init_card_v2(self):
134135
return
135136
raise OSError("timeout waiting for v2 card")
136137

137-
def cmd(self, cmd, arg, crc, final=0, release=True):
138+
def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
138139
self.cs(0)
139140

140141
# create and send the command
@@ -147,9 +148,13 @@ def cmd(self, cmd, arg, crc, final=0, release=True):
147148
buf[5] = crc
148149
self.spi.write(buf)
149150

151+
if skip1:
152+
self.spi.readinto(self.tokenbuf, 0xff)
153+
150154
# wait for the response (response[7] == 0)
151155
for i in range(_CMD_TIMEOUT):
152-
response = self.spi.read(1, 0xff)[0]
156+
self.spi.readinto(self.tokenbuf, 0xff)
157+
response = self.tokenbuf[0]
153158
if not (response & 0x80):
154159
# this could be a big-endian integer that we are getting here
155160
for j in range(final):
@@ -164,27 +169,19 @@ def cmd(self, cmd, arg, crc, final=0, release=True):
164169
self.spi.write(b'\xff')
165170
return -1
166171

167-
def cmd_nodata(self, cmd):
168-
self.spi.write(cmd)
169-
self.spi.read(1, 0xff) # ignore stuff byte
170-
for _ in range(_CMD_TIMEOUT):
171-
if self.spi.read(1, 0xff)[0] == 0xff:
172-
self.cs(1)
173-
self.spi.write(b'\xff')
174-
return 0 # OK
175-
self.cs(1)
176-
self.spi.write(b'\xff')
177-
return 1 # timeout
178-
179172
def readinto(self, buf):
180173
self.cs(0)
181174

182175
# read until start byte (0xff)
183-
while self.spi.read(1, 0xff)[0] != 0xfe:
184-
pass
176+
while True:
177+
self.spi.readinto(self.tokenbuf, 0xff)
178+
if self.tokenbuf[0] == 0xfe:
179+
break
185180

186181
# read data
187-
mv = self.dummybuf_memoryview[:len(buf)]
182+
mv = self.dummybuf_memoryview
183+
if len(buf) != len(mv):
184+
mv = mv[:len(buf)]
188185
self.spi.write_readinto(mv, buf)
189186

190187
# read checksum
@@ -231,41 +228,41 @@ def count(self):
231228
return self.sectors
232229

233230
def readblocks(self, block_num, buf):
234-
nblocks, err = divmod(len(buf), 512)
235-
assert nblocks and not err, 'Buffer length is invalid'
231+
nblocks = len(buf) // 512
232+
assert nblocks and not len(buf) % 512, 'Buffer length is invalid'
236233
if nblocks == 1:
237234
# CMD17: set read address for single block
238235
if self.cmd(17, block_num * self.cdv, 0) != 0:
239-
return 1
236+
raise OSError(5) # EIO
240237
# receive the data
241238
self.readinto(buf)
242239
else:
243240
# CMD18: set read address for multiple blocks
244241
if self.cmd(18, block_num * self.cdv, 0) != 0:
245-
return 1
242+
raise OSError(5) # EIO
246243
offset = 0
247244
mv = memoryview(buf)
248245
while nblocks:
249246
self.readinto(mv[offset : offset + 512])
250247
offset += 512
251248
nblocks -= 1
252-
return self.cmd_nodata(b'\x0c') # cmd 12
253-
return 0
249+
if self.cmd(12, 0, 0xff, skip1=True):
250+
raise OSError(5) # EIO
254251

255252
def writeblocks(self, block_num, buf):
256253
nblocks, err = divmod(len(buf), 512)
257254
assert nblocks and not err, 'Buffer length is invalid'
258255
if nblocks == 1:
259256
# CMD24: set write address for single block
260257
if self.cmd(24, block_num * self.cdv, 0) != 0:
261-
return 1
258+
raise OSError(5) # EIO
262259

263260
# send the data
264261
self.write(_TOKEN_DATA, buf)
265262
else:
266263
# CMD25: set write address for first block
267264
if self.cmd(25, block_num * self.cdv, 0) != 0:
268-
return 1
265+
raise OSError(5) # EIO
269266
# send the data
270267
offset = 0
271268
mv = memoryview(buf)
@@ -274,4 +271,3 @@ def writeblocks(self, block_num, buf):
274271
offset += 512
275272
nblocks -= 1
276273
self.write_token(_TOKEN_STOP_TRAN)
277-
return 0

0 commit comments

Comments
 (0)