Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Committer:
Pawel Zarembski
Date:
Tue Apr 07 12:55:42 2020 +0200
Revision:
0:01f31e923fe2
hani: DAPLink with reset workaround

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Pawel Zarembski 0:01f31e923fe2 1 #
Pawel Zarembski 0:01f31e923fe2 2 # DAPLink Interface Firmware
Pawel Zarembski 0:01f31e923fe2 3 # Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
Pawel Zarembski 0:01f31e923fe2 4 # SPDX-License-Identifier: Apache-2.0
Pawel Zarembski 0:01f31e923fe2 5 #
Pawel Zarembski 0:01f31e923fe2 6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
Pawel Zarembski 0:01f31e923fe2 7 # not use this file except in compliance with the License.
Pawel Zarembski 0:01f31e923fe2 8 # You may obtain a copy of the License at
Pawel Zarembski 0:01f31e923fe2 9 #
Pawel Zarembski 0:01f31e923fe2 10 # http://www.apache.org/licenses/LICENSE-2.0
Pawel Zarembski 0:01f31e923fe2 11 #
Pawel Zarembski 0:01f31e923fe2 12 # Unless required by applicable law or agreed to in writing, software
Pawel Zarembski 0:01f31e923fe2 13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
Pawel Zarembski 0:01f31e923fe2 14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Pawel Zarembski 0:01f31e923fe2 15 # See the License for the specific language governing permissions and
Pawel Zarembski 0:01f31e923fe2 16 # limitations under the License.
Pawel Zarembski 0:01f31e923fe2 17 #
Pawel Zarembski 0:01f31e923fe2 18
Pawel Zarembski 0:01f31e923fe2 19 import os
Pawel Zarembski 0:01f31e923fe2 20 import struct
Pawel Zarembski 0:01f31e923fe2 21 import numbers
Pawel Zarembski 0:01f31e923fe2 22 import time
Pawel Zarembski 0:01f31e923fe2 23 import usb.util
Pawel Zarembski 0:01f31e923fe2 24
Pawel Zarembski 0:01f31e923fe2 25
Pawel Zarembski 0:01f31e923fe2 26 class USBMsd(object):
Pawel Zarembski 0:01f31e923fe2 27 """Wrapper class for a MSD usb device"""
Pawel Zarembski 0:01f31e923fe2 28
Pawel Zarembski 0:01f31e923fe2 29 # Bulk only transport documented in
Pawel Zarembski 0:01f31e923fe2 30 # "Universal Serial Bus Mass Storage Class"
Pawel Zarembski 0:01f31e923fe2 31 # SCSI commands documented in "SCSI Commands Reference Manual" by Seagate
Pawel Zarembski 0:01f31e923fe2 32
Pawel Zarembski 0:01f31e923fe2 33 CLASS_MSD = 0x8
Pawel Zarembski 0:01f31e923fe2 34 # Write 10
Pawel Zarembski 0:01f31e923fe2 35 # Read 10
Pawel Zarembski 0:01f31e923fe2 36 # Test unit ready
Pawel Zarembski 0:01f31e923fe2 37 # Request Sense
Pawel Zarembski 0:01f31e923fe2 38
Pawel Zarembski 0:01f31e923fe2 39 # dCBWSignature
Pawel Zarembski 0:01f31e923fe2 40 # dCBWTag
Pawel Zarembski 0:01f31e923fe2 41 # dCBWDataTransferLength
Pawel Zarembski 0:01f31e923fe2 42 # bmCBWFlags
Pawel Zarembski 0:01f31e923fe2 43 # bCBWLUN
Pawel Zarembski 0:01f31e923fe2 44 # bCBWCBLength
Pawel Zarembski 0:01f31e923fe2 45 FMT_CBW = "<IIIBBB"
Pawel Zarembski 0:01f31e923fe2 46
Pawel Zarembski 0:01f31e923fe2 47 # dCSWSignature
Pawel Zarembski 0:01f31e923fe2 48 # dCSWTag
Pawel Zarembski 0:01f31e923fe2 49 # dCSWDataResidue
Pawel Zarembski 0:01f31e923fe2 50 # bCSWStatus
Pawel Zarembski 0:01f31e923fe2 51 FMT_CSW = "<IIIB"
Pawel Zarembski 0:01f31e923fe2 52
Pawel Zarembski 0:01f31e923fe2 53 CSW_STATUS_PASSED = 0
Pawel Zarembski 0:01f31e923fe2 54 CSW_STATUS_FAILED = 1
Pawel Zarembski 0:01f31e923fe2 55 CSW_STATUS_PHASE_ERROR = 2
Pawel Zarembski 0:01f31e923fe2 56
Pawel Zarembski 0:01f31e923fe2 57 class SCSIError(Exception):
Pawel Zarembski 0:01f31e923fe2 58
Pawel Zarembski 0:01f31e923fe2 59 def __init__(self, error):
Pawel Zarembski 0:01f31e923fe2 60 Exception.__init__(self)
Pawel Zarembski 0:01f31e923fe2 61 self.value = error
Pawel Zarembski 0:01f31e923fe2 62
Pawel Zarembski 0:01f31e923fe2 63 # Some SCSI commands
Pawel Zarembski 0:01f31e923fe2 64 # Value Keil middleware define Seagate name
Pawel Zarembski 0:01f31e923fe2 65 # 0x12 SCSI_INQUIRY INQUIRY
Pawel Zarembski 0:01f31e923fe2 66 # 0x23 SCSI_READ_FORMAT_CAPACITIES Missing
Pawel Zarembski 0:01f31e923fe2 67 # 0x25 SCSI_READ_CAPACITY READ CAPACITY (10)
Pawel Zarembski 0:01f31e923fe2 68 # 0x28 SCSI_READ10 READ (10)
Pawel Zarembski 0:01f31e923fe2 69 # 0x1A SCSI_MODE_SENSE6 MODE SENSE (6)
Pawel Zarembski 0:01f31e923fe2 70 # 0x00 SCSI_TEST_UNIT_READY TEST UNIT READY
Pawel Zarembski 0:01f31e923fe2 71 # 0x2A SCSI_WRITE10 WRITE (10)
Pawel Zarembski 0:01f31e923fe2 72 # 0x03 SCSI_REQUEST_SENSE REQUEST SENSE
Pawel Zarembski 0:01f31e923fe2 73 # 0x1E SCSI_MEDIA_REMOVAL Missing
Pawel Zarembski 0:01f31e923fe2 74
Pawel Zarembski 0:01f31e923fe2 75 def __init__(self, device):
Pawel Zarembski 0:01f31e923fe2 76 self._dev = device
Pawel Zarembski 0:01f31e923fe2 77 self._if = None
Pawel Zarembski 0:01f31e923fe2 78 self.ep_in = None
Pawel Zarembski 0:01f31e923fe2 79 self.ep_out = None
Pawel Zarembski 0:01f31e923fe2 80 self._locked = False
Pawel Zarembski 0:01f31e923fe2 81 self._cbw_tag = 0
Pawel Zarembski 0:01f31e923fe2 82 self.timeout = 60 * 1000
Pawel Zarembski 0:01f31e923fe2 83 # delays are for testing only
Pawel Zarembski 0:01f31e923fe2 84 self.delay_cbw_to_data = 0
Pawel Zarembski 0:01f31e923fe2 85 self.delay_data_to_csw = 0
Pawel Zarembski 0:01f31e923fe2 86
Pawel Zarembski 0:01f31e923fe2 87 # Find interface
Pawel Zarembski 0:01f31e923fe2 88 for interface in device.get_active_configuration():
Pawel Zarembski 0:01f31e923fe2 89 if interface.bInterfaceClass == USBMsd.CLASS_MSD:
Pawel Zarembski 0:01f31e923fe2 90 assert self._if is None
Pawel Zarembski 0:01f31e923fe2 91 self._if = interface
Pawel Zarembski 0:01f31e923fe2 92 assert self._if is not None
Pawel Zarembski 0:01f31e923fe2 93
Pawel Zarembski 0:01f31e923fe2 94 # Find endpoints
Pawel Zarembski 0:01f31e923fe2 95 for endpoint in self._if:
Pawel Zarembski 0:01f31e923fe2 96 if endpoint.bEndpointAddress & 0x80:
Pawel Zarembski 0:01f31e923fe2 97 assert self.ep_in is None
Pawel Zarembski 0:01f31e923fe2 98 self.ep_in = endpoint
Pawel Zarembski 0:01f31e923fe2 99 else:
Pawel Zarembski 0:01f31e923fe2 100 assert self.ep_out is None
Pawel Zarembski 0:01f31e923fe2 101 self.ep_out = endpoint
Pawel Zarembski 0:01f31e923fe2 102 assert self.ep_in is not None
Pawel Zarembski 0:01f31e923fe2 103 assert self.ep_out is not None
Pawel Zarembski 0:01f31e923fe2 104
Pawel Zarembski 0:01f31e923fe2 105 def lock(self):
Pawel Zarembski 0:01f31e923fe2 106 """Acquire exclisive access to MSD"""
Pawel Zarembski 0:01f31e923fe2 107 assert not self._locked
Pawel Zarembski 0:01f31e923fe2 108
Pawel Zarembski 0:01f31e923fe2 109 num = self._if.bInterfaceNumber
Pawel Zarembski 0:01f31e923fe2 110 try:
Pawel Zarembski 0:01f31e923fe2 111 if self._dev.is_kernel_driver_active(num):
Pawel Zarembski 0:01f31e923fe2 112 self._dev.detach_kernel_driver(num)
Pawel Zarembski 0:01f31e923fe2 113 except NotImplementedError:
Pawel Zarembski 0:01f31e923fe2 114 pass
Pawel Zarembski 0:01f31e923fe2 115 except usb.core.USBError:
Pawel Zarembski 0:01f31e923fe2 116 pass
Pawel Zarembski 0:01f31e923fe2 117 usb.util.claim_interface(self._dev, num)
Pawel Zarembski 0:01f31e923fe2 118 self._locked = True
Pawel Zarembski 0:01f31e923fe2 119
Pawel Zarembski 0:01f31e923fe2 120 def unlock(self):
Pawel Zarembski 0:01f31e923fe2 121 """Release exclusive access to MSD"""
Pawel Zarembski 0:01f31e923fe2 122 assert self._locked
Pawel Zarembski 0:01f31e923fe2 123
Pawel Zarembski 0:01f31e923fe2 124 num = self._if.bInterfaceNumber
Pawel Zarembski 0:01f31e923fe2 125 usb.util.release_interface(self._dev, num)
Pawel Zarembski 0:01f31e923fe2 126 try:
Pawel Zarembski 0:01f31e923fe2 127 self._dev.attach_kernel_driver(num)
Pawel Zarembski 0:01f31e923fe2 128 except NotImplementedError:
Pawel Zarembski 0:01f31e923fe2 129 pass
Pawel Zarembski 0:01f31e923fe2 130 except usb.core.USBError:
Pawel Zarembski 0:01f31e923fe2 131 pass
Pawel Zarembski 0:01f31e923fe2 132 self._locked = False
Pawel Zarembski 0:01f31e923fe2 133
Pawel Zarembski 0:01f31e923fe2 134 def scsi_read10(self, lba, block_count):
Pawel Zarembski 0:01f31e923fe2 135 """Send the SCSI read 10 command and return the data read"""
Pawel Zarembski 0:01f31e923fe2 136 block_size = 512
Pawel Zarembski 0:01f31e923fe2 137
Pawel Zarembski 0:01f31e923fe2 138 cbwcb = bytearray(10)
Pawel Zarembski 0:01f31e923fe2 139 cbwcb[0] = 0x28
Pawel Zarembski 0:01f31e923fe2 140 cbwcb[2] = (lba >> (8 * 3)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 141 cbwcb[3] = (lba >> (8 * 2)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 142 cbwcb[4] = (lba >> (8 * 1)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 143 cbwcb[5] = (lba >> (8 * 0)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 144 cbwcb[7] = (block_count >> (8 * 1)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 145 cbwcb[8] = (block_count >> (8 * 0)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 146 ret, data = self._msd_transfer(cbwcb, 0, block_count * block_size)
Pawel Zarembski 0:01f31e923fe2 147 if ret != self.CSW_STATUS_PASSED:
Pawel Zarembski 0:01f31e923fe2 148 raise self.SCSIError(ret)
Pawel Zarembski 0:01f31e923fe2 149 return data
Pawel Zarembski 0:01f31e923fe2 150
Pawel Zarembski 0:01f31e923fe2 151 def scsi_write10(self, lba, data):
Pawel Zarembski 0:01f31e923fe2 152 """Send the SCSI write 10 command"""
Pawel Zarembski 0:01f31e923fe2 153 block_size = 512
Pawel Zarembski 0:01f31e923fe2 154
Pawel Zarembski 0:01f31e923fe2 155 assert len(data) % block_size == 0
Pawel Zarembski 0:01f31e923fe2 156 block_count = (len(data) + (block_size - 1)) // block_size
Pawel Zarembski 0:01f31e923fe2 157
Pawel Zarembski 0:01f31e923fe2 158 cbwcb = bytearray(10)
Pawel Zarembski 0:01f31e923fe2 159 cbwcb[0] = 0x2A
Pawel Zarembski 0:01f31e923fe2 160 cbwcb[2] = (lba >> (8 * 3)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 161 cbwcb[3] = (lba >> (8 * 2)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 162 cbwcb[4] = (lba >> (8 * 1)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 163 cbwcb[5] = (lba >> (8 * 0)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 164 cbwcb[7] = (block_count >> (8 * 1)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 165 cbwcb[8] = (block_count >> (8 * 0)) & 0xFF
Pawel Zarembski 0:01f31e923fe2 166 ret, _ = self._msd_transfer(cbwcb, 0, data)
Pawel Zarembski 0:01f31e923fe2 167 if ret != self.CSW_STATUS_PASSED:
Pawel Zarembski 0:01f31e923fe2 168 raise self.SCSIError(ret)
Pawel Zarembski 0:01f31e923fe2 169
Pawel Zarembski 0:01f31e923fe2 170 def scsi_test_unit_ready(self):
Pawel Zarembski 0:01f31e923fe2 171 """Send the SCSI test unit ready command and return status"""
Pawel Zarembski 0:01f31e923fe2 172 cbwcb = bytearray(10)
Pawel Zarembski 0:01f31e923fe2 173 cbwcb[0] = 0
Pawel Zarembski 0:01f31e923fe2 174 ret, _ = self._msd_transfer(cbwcb, 0)
Pawel Zarembski 0:01f31e923fe2 175 return ret
Pawel Zarembski 0:01f31e923fe2 176
Pawel Zarembski 0:01f31e923fe2 177 def _msd_transfer(self, cbwcb, lun, size_or_data=None):
Pawel Zarembski 0:01f31e923fe2 178 """Perform a bulk only transfer"""
Pawel Zarembski 0:01f31e923fe2 179 assert self._locked
Pawel Zarembski 0:01f31e923fe2 180 assert 1 <= len(cbwcb) <= 16
Pawel Zarembski 0:01f31e923fe2 181
Pawel Zarembski 0:01f31e923fe2 182 # Increment packet tag
Pawel Zarembski 0:01f31e923fe2 183 transfer_tag = self._cbw_tag
Pawel Zarembski 0:01f31e923fe2 184 self._cbw_tag = (self._cbw_tag + 1) & 0xFFFFFFFF
Pawel Zarembski 0:01f31e923fe2 185
Pawel Zarembski 0:01f31e923fe2 186 # None means data size of zero
Pawel Zarembski 0:01f31e923fe2 187 if size_or_data is None:
Pawel Zarembski 0:01f31e923fe2 188 size_or_data = 0
Pawel Zarembski 0:01f31e923fe2 189
Pawel Zarembski 0:01f31e923fe2 190 in_transfer = isinstance(size_or_data, numbers.Number)
Pawel Zarembski 0:01f31e923fe2 191 transfer_size = (size_or_data if in_transfer else len(size_or_data))
Pawel Zarembski 0:01f31e923fe2 192 assert in_transfer or len(size_or_data) > 0
Pawel Zarembski 0:01f31e923fe2 193
Pawel Zarembski 0:01f31e923fe2 194 # Phase - Command transport
Pawel Zarembski 0:01f31e923fe2 195 cbw_signature = 0x43425355
Pawel Zarembski 0:01f31e923fe2 196 cbw_tag = transfer_tag
Pawel Zarembski 0:01f31e923fe2 197 cbw_data_transfer_length = transfer_size
Pawel Zarembski 0:01f31e923fe2 198 cbw_flags = (1 << 7) if in_transfer else 0
Pawel Zarembski 0:01f31e923fe2 199 cbw_lun = lun
Pawel Zarembski 0:01f31e923fe2 200 cbw_length = len(cbwcb)
Pawel Zarembski 0:01f31e923fe2 201 params = [cbw_signature, cbw_tag, cbw_data_transfer_length,
Pawel Zarembski 0:01f31e923fe2 202 cbw_flags, cbw_lun, cbw_length]
Pawel Zarembski 0:01f31e923fe2 203 cbw = struct.pack(self.FMT_CBW, *params)
Pawel Zarembski 0:01f31e923fe2 204 pad_size = 16 - len(cbwcb)
Pawel Zarembski 0:01f31e923fe2 205 payload = cbw + cbwcb + bytearray(pad_size)
Pawel Zarembski 0:01f31e923fe2 206 self.ep_out.write(payload)
Pawel Zarembski 0:01f31e923fe2 207
Pawel Zarembski 0:01f31e923fe2 208 if self.delay_cbw_to_data != 0:
Pawel Zarembski 0:01f31e923fe2 209 time.sleep(self.delay_cbw_to_data)
Pawel Zarembski 0:01f31e923fe2 210
Pawel Zarembski 0:01f31e923fe2 211 # Phase - Data Out or Data In (Optional)
Pawel Zarembski 0:01f31e923fe2 212 data = None
Pawel Zarembski 0:01f31e923fe2 213 if transfer_size > 0:
Pawel Zarembski 0:01f31e923fe2 214 endpoint = self.ep_in if in_transfer else self.ep_out
Pawel Zarembski 0:01f31e923fe2 215 try:
Pawel Zarembski 0:01f31e923fe2 216 if in_transfer:
Pawel Zarembski 0:01f31e923fe2 217 data = self.ep_in.read(transfer_size, self.timeout)
Pawel Zarembski 0:01f31e923fe2 218 else:
Pawel Zarembski 0:01f31e923fe2 219 self.ep_out.write(size_or_data, self.timeout)
Pawel Zarembski 0:01f31e923fe2 220 except usb.core.USBError:
Pawel Zarembski 0:01f31e923fe2 221 endpoint.clear_halt()
Pawel Zarembski 0:01f31e923fe2 222
Pawel Zarembski 0:01f31e923fe2 223 if self.delay_data_to_csw != 0:
Pawel Zarembski 0:01f31e923fe2 224 time.sleep(self.delay_data_to_csw)
Pawel Zarembski 0:01f31e923fe2 225
Pawel Zarembski 0:01f31e923fe2 226 # Phase - Status Transport
Pawel Zarembski 0:01f31e923fe2 227 csw = self.ep_in.read(13, self.timeout)
Pawel Zarembski 0:01f31e923fe2 228 csw_signature, csw_tag, csw_data_residue, csw_status = \
Pawel Zarembski 0:01f31e923fe2 229 struct.unpack(self.FMT_CSW, csw)
Pawel Zarembski 0:01f31e923fe2 230 assert csw_signature == 0x53425355
Pawel Zarembski 0:01f31e923fe2 231 assert csw_tag == transfer_tag
Pawel Zarembski 0:01f31e923fe2 232 #TODO - check residue
Pawel Zarembski 0:01f31e923fe2 233 return (csw_status, data)
Pawel Zarembski 0:01f31e923fe2 234
Pawel Zarembski 0:01f31e923fe2 235
Pawel Zarembski 0:01f31e923fe2 236 class Struct(object):
Pawel Zarembski 0:01f31e923fe2 237 """Base class for a C structure"""
Pawel Zarembski 0:01f31e923fe2 238
Pawel Zarembski 0:01f31e923fe2 239 def __init__(self, name, structure, data):
Pawel Zarembski 0:01f31e923fe2 240 field_list = [field[0] for field in structure]
Pawel Zarembski 0:01f31e923fe2 241 fmt_list = [field[1] for field in structure]
Pawel Zarembski 0:01f31e923fe2 242 format_str = "<" + "".join(fmt_list)
Pawel Zarembski 0:01f31e923fe2 243 struct_size = struct.calcsize(format_str)
Pawel Zarembski 0:01f31e923fe2 244 value_list = struct.unpack(format_str, data[:struct_size])
Pawel Zarembski 0:01f31e923fe2 245 value_dict = {}
Pawel Zarembski 0:01f31e923fe2 246 for name, value in zip(field_list, value_list):
Pawel Zarembski 0:01f31e923fe2 247 value_dict[name] = value
Pawel Zarembski 0:01f31e923fe2 248 self.name = name
Pawel Zarembski 0:01f31e923fe2 249 self.format_str = format_str
Pawel Zarembski 0:01f31e923fe2 250 self.field_list = field_list
Pawel Zarembski 0:01f31e923fe2 251 self.value_dict = value_dict
Pawel Zarembski 0:01f31e923fe2 252 self.size = struct_size
Pawel Zarembski 0:01f31e923fe2 253
Pawel Zarembski 0:01f31e923fe2 254 def __getitem__(self, key):
Pawel Zarembski 0:01f31e923fe2 255 return self.value_dict[key]
Pawel Zarembski 0:01f31e923fe2 256
Pawel Zarembski 0:01f31e923fe2 257 def __setitem__(self, key, value):
Pawel Zarembski 0:01f31e923fe2 258 self.value_dict[key] = value
Pawel Zarembski 0:01f31e923fe2 259
Pawel Zarembski 0:01f31e923fe2 260 def __str__(self):
Pawel Zarembski 0:01f31e923fe2 261 desc = ""
Pawel Zarembski 0:01f31e923fe2 262 desc += self.name + ":" + os.linesep
Pawel Zarembski 0:01f31e923fe2 263 for field in self.field_list:
Pawel Zarembski 0:01f31e923fe2 264 value = self.value_dict[field]
Pawel Zarembski 0:01f31e923fe2 265 if isinstance(value, bytes):
Pawel Zarembski 0:01f31e923fe2 266 value = list(bytearray(value))
Pawel Zarembski 0:01f31e923fe2 267 desc += (" %s=%s" + os.linesep) % (field, value)
Pawel Zarembski 0:01f31e923fe2 268 return desc
Pawel Zarembski 0:01f31e923fe2 269
Pawel Zarembski 0:01f31e923fe2 270 def pack(self):
Pawel Zarembski 0:01f31e923fe2 271 """Return a byte representation of this structure"""
Pawel Zarembski 0:01f31e923fe2 272 value_list = []
Pawel Zarembski 0:01f31e923fe2 273 for field in self.field_list:
Pawel Zarembski 0:01f31e923fe2 274 value_list.append(self.value_dict[field])
Pawel Zarembski 0:01f31e923fe2 275 return struct.pack(self.format_str, *value_list)
Pawel Zarembski 0:01f31e923fe2 276
Pawel Zarembski 0:01f31e923fe2 277
Pawel Zarembski 0:01f31e923fe2 278 class MBR(Struct):
Pawel Zarembski 0:01f31e923fe2 279 """Wrapper class for a FAT MBR"""
Pawel Zarembski 0:01f31e923fe2 280
Pawel Zarembski 0:01f31e923fe2 281 STRUCTURE = (
Pawel Zarembski 0:01f31e923fe2 282 ("BS_jmpBoot", "3s"),
Pawel Zarembski 0:01f31e923fe2 283 ("BS_OEMName", "8s"),
Pawel Zarembski 0:01f31e923fe2 284 ("BPB_BytsPerSec", "H"),
Pawel Zarembski 0:01f31e923fe2 285 ("BPB_SecPerClus", "B"),
Pawel Zarembski 0:01f31e923fe2 286 ("BPB_RsvdSecCnt", "H"),
Pawel Zarembski 0:01f31e923fe2 287 ("BPB_NumFATs", "B"),
Pawel Zarembski 0:01f31e923fe2 288 ("BPB_RootEntCnt", "H"),
Pawel Zarembski 0:01f31e923fe2 289 ("BPB_TotSec16", "H"),
Pawel Zarembski 0:01f31e923fe2 290 ("BPB_Media", "B"),
Pawel Zarembski 0:01f31e923fe2 291 ("BPB_FATSz16", "H"),
Pawel Zarembski 0:01f31e923fe2 292 ("BPB_SecPerTrk", "H"),
Pawel Zarembski 0:01f31e923fe2 293 ("BPB_NumHeads", "H"),
Pawel Zarembski 0:01f31e923fe2 294 ("BPB_HiddSec", "L"),
Pawel Zarembski 0:01f31e923fe2 295 ("BPB_TotSec32", "L"),
Pawel Zarembski 0:01f31e923fe2 296 )
Pawel Zarembski 0:01f31e923fe2 297
Pawel Zarembski 0:01f31e923fe2 298 def __init__(self, data, sector=None):
Pawel Zarembski 0:01f31e923fe2 299 Struct.__init__(self, "MBR", self.STRUCTURE, data)
Pawel Zarembski 0:01f31e923fe2 300 self.sector = sector
Pawel Zarembski 0:01f31e923fe2 301
Pawel Zarembski 0:01f31e923fe2 302
Pawel Zarembski 0:01f31e923fe2 303 class DirectoryEntry(Struct):
Pawel Zarembski 0:01f31e923fe2 304 """Wrapper class for a FAT DirectoryEntry"""
Pawel Zarembski 0:01f31e923fe2 305
Pawel Zarembski 0:01f31e923fe2 306 STRUCTURE = (
Pawel Zarembski 0:01f31e923fe2 307 ("DIR_Name", "11s"),
Pawel Zarembski 0:01f31e923fe2 308 ("DIR_Attr", "B"),
Pawel Zarembski 0:01f31e923fe2 309 ("DIR_NTRes", "B"),
Pawel Zarembski 0:01f31e923fe2 310 ("DIR_CrtTimeTenth", "B"),
Pawel Zarembski 0:01f31e923fe2 311 ("DIR_CrtTime", "H"),
Pawel Zarembski 0:01f31e923fe2 312 ("DIR_CrtDate", "H"),
Pawel Zarembski 0:01f31e923fe2 313 ("DIR_LstAccDate", "H"),
Pawel Zarembski 0:01f31e923fe2 314 ("DIR_FstClusHI", "H"),
Pawel Zarembski 0:01f31e923fe2 315 ("DIR_WrtTime", "H"),
Pawel Zarembski 0:01f31e923fe2 316 ("DIR_WrtDate", "H"),
Pawel Zarembski 0:01f31e923fe2 317 ("DIR_FstClusLO", "H"),
Pawel Zarembski 0:01f31e923fe2 318 ("DIR_FileSize", "L"),
Pawel Zarembski 0:01f31e923fe2 319 )
Pawel Zarembski 0:01f31e923fe2 320
Pawel Zarembski 0:01f31e923fe2 321 def __init__(self, data):
Pawel Zarembski 0:01f31e923fe2 322 Struct.__init__(self, "DirectoryEntry", self.STRUCTURE, data)
Pawel Zarembski 0:01f31e923fe2 323
Pawel Zarembski 0:01f31e923fe2 324
Pawel Zarembski 0:01f31e923fe2 325 class Directory(object):
Pawel Zarembski 0:01f31e923fe2 326 """Wrapper class for a FAT Directory"""
Pawel Zarembski 0:01f31e923fe2 327
Pawel Zarembski 0:01f31e923fe2 328 ENTRY_SIZE = 32
Pawel Zarembski 0:01f31e923fe2 329
Pawel Zarembski 0:01f31e923fe2 330 def __init__(self, entry_count, data, sector=None):
Pawel Zarembski 0:01f31e923fe2 331 directory_list = []
Pawel Zarembski 0:01f31e923fe2 332 for i in range(entry_count):
Pawel Zarembski 0:01f31e923fe2 333 start = i * self.ENTRY_SIZE
Pawel Zarembski 0:01f31e923fe2 334 dir_data = data[start:start + self.ENTRY_SIZE]
Pawel Zarembski 0:01f31e923fe2 335 entry = DirectoryEntry(dir_data)
Pawel Zarembski 0:01f31e923fe2 336 directory_list.append(entry)
Pawel Zarembski 0:01f31e923fe2 337 self.directory_list = directory_list
Pawel Zarembski 0:01f31e923fe2 338 self.sector = sector
Pawel Zarembski 0:01f31e923fe2 339
Pawel Zarembski 0:01f31e923fe2 340 def __iter__(self):
Pawel Zarembski 0:01f31e923fe2 341 return iter(self.directory_list)
Pawel Zarembski 0:01f31e923fe2 342
Pawel Zarembski 0:01f31e923fe2 343 def __getitem__(self, key):
Pawel Zarembski 0:01f31e923fe2 344 return self.directory_list[key]
Pawel Zarembski 0:01f31e923fe2 345
Pawel Zarembski 0:01f31e923fe2 346 def find_free_entry_index(self):
Pawel Zarembski 0:01f31e923fe2 347 """Find a free index in this Directory or return None"""
Pawel Zarembski 0:01f31e923fe2 348 for idx, directory in enumerate(self.directory_list):
Pawel Zarembski 0:01f31e923fe2 349 name_data = bytearray(directory["DIR_Name"])
Pawel Zarembski 0:01f31e923fe2 350 if name_data[0] in (0x00, 0xE5):
Pawel Zarembski 0:01f31e923fe2 351 return idx
Pawel Zarembski 0:01f31e923fe2 352 return None
Pawel Zarembski 0:01f31e923fe2 353
Pawel Zarembski 0:01f31e923fe2 354 def pack(self):
Pawel Zarembski 0:01f31e923fe2 355 """Return a byte a Directory"""
Pawel Zarembski 0:01f31e923fe2 356 data = bytearray()
Pawel Zarembski 0:01f31e923fe2 357 for directory in self.directory_list:
Pawel Zarembski 0:01f31e923fe2 358 data.extend(directory.pack())
Pawel Zarembski 0:01f31e923fe2 359 return data
Pawel Zarembski 0:01f31e923fe2 360
Pawel Zarembski 0:01f31e923fe2 361
Pawel Zarembski 0:01f31e923fe2 362 class Fat(object):
Pawel Zarembski 0:01f31e923fe2 363 """Wrapper class for a FAT filesystem on a SCSI device"""
Pawel Zarembski 0:01f31e923fe2 364
Pawel Zarembski 0:01f31e923fe2 365 SECTOR_SIZE = 512
Pawel Zarembski 0:01f31e923fe2 366 CLUSTER_SIZE = 4 * 1024
Pawel Zarembski 0:01f31e923fe2 367
Pawel Zarembski 0:01f31e923fe2 368 def __init__(self, msd):
Pawel Zarembski 0:01f31e923fe2 369 self.msd = msd
Pawel Zarembski 0:01f31e923fe2 370 self.reload()
Pawel Zarembski 0:01f31e923fe2 371
Pawel Zarembski 0:01f31e923fe2 372 def reload(self):
Pawel Zarembski 0:01f31e923fe2 373 """Reload all internal data of this Fat filesystem"""
Pawel Zarembski 0:01f31e923fe2 374
Pawel Zarembski 0:01f31e923fe2 375 # Read MBR
Pawel Zarembski 0:01f31e923fe2 376 mbr_data = self.msd.scsi_read10(0, 1)
Pawel Zarembski 0:01f31e923fe2 377 mbr = MBR(mbr_data, 0)
Pawel Zarembski 0:01f31e923fe2 378
Pawel Zarembski 0:01f31e923fe2 379 # Read in the root directory
Pawel Zarembski 0:01f31e923fe2 380 root_dir_sec = (mbr["BPB_RsvdSecCnt"] +
Pawel Zarembski 0:01f31e923fe2 381 (mbr["BPB_NumFATs"] * mbr["BPB_FATSz16"]))
Pawel Zarembski 0:01f31e923fe2 382 sec_count = (mbr["BPB_RootEntCnt"] * 32 + 512 - 1) // 512
Pawel Zarembski 0:01f31e923fe2 383 root_dir_data = self.msd.scsi_read10(root_dir_sec, sec_count)
Pawel Zarembski 0:01f31e923fe2 384 root_dir = Directory(mbr["BPB_RootEntCnt"], root_dir_data,
Pawel Zarembski 0:01f31e923fe2 385 root_dir_sec)
Pawel Zarembski 0:01f31e923fe2 386 self.mbr = mbr
Pawel Zarembski 0:01f31e923fe2 387 self.root_dir = root_dir