JTAGARM7 is back up and running, folks! Tested Halt/Release, Get/Set Registers,...
[goodfet] / client / goodfet.maxusbmass
1 #!/usr/bin/env python
2
3 #USB Mass Storage Emulator
4 #by Travis Goodspeed
5 #with thanks to Brandon Wilson and his Linky project.
6
7 import sys;
8 import binascii;
9 import array;
10 import time;
11
12 from GoodFETMAXUSB import *;
13
14 def zeros(length):
15     """Returns a list of zeroes of the specified length."""
16     l=range(0,length);
17     for foo in l:
18         l[foo]=0;
19     return l;
20
21 class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
22     """This emulates a USB Mass Storage device."""
23     
24     #Too much data to watch everything.
25     usbverbose=False;
26
27     def getSectorData(self,lba):
28         """Overload this to return data from a given 512-byte sector."""
29         print "You forgot to overload getSectorData().  Returning something neighborly.";
30         sector=[
31             0xE9, 0x86, 0x00, 0x0A, 0x47, 0x6F, 0x6F, 0x64, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x30, 0x2E, 0x30,
32             0x31, 0x0A, 0x0D, 0x62, 0x79, 0x20, 0x54, 0x72, 0x61, 0x76, 0x69, 0x73, 0x20, 0x47, 0x6F, 0x6F,
33             0x64, 0x73, 0x70, 0x65, 0x65, 0x64, 0x0A, 0x0A, 0x0D, 0x00, 0x59, 0x6F, 0x75, 0x20, 0x68, 0x61,
34             0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x65, 0x61, 0x74, 0x65, 0x6E, 0x20, 0x62, 0x79,
35             0x20, 0x61, 0x20, 0x67, 0x72, 0x75, 0x65, 0x2E, 0x20, 0x20, 0x53, 0x6F, 0x72, 0x72, 0x79, 0x2E,
36             0x0A, 0x0D, 0x00, 0x31, 0x29, 0x20, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6B, 0x65,
37             0x72, 0x6E, 0x65, 0x6C, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x0A,
38             0x0D, 0x00, 0x32, 0x29, 0x20, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6B,
39             0x65, 0x72, 0x6E, 0x65, 0x6C, 0x2E, 0x0A, 0x0D, 0x00, 0xBE, 0x03, 0x7C, 0xE8, 0x41, 0x00, 0xE8,
40             0x7B, 0x00, 0x31, 0xC0, 0x30, 0xD2, 0xCD, 0x13, 0x0F, 0x82, 0xE8, 0x00, 0xBE, 0x53, 0x7C, 0xE8,
41             0x2E, 0x00, 0xB8, 0xE0, 0x07, 0x8E, 0xC0, 0x31, 0xDB, 0xB8, 0x10, 0x02, 0xB5, 0x00, 0xB1, 0x02,
42             0xB6, 0x00, 0xB2, 0x00, 0xCD, 0x13, 0x0F, 0x82, 0xCA, 0x00, 0xB8, 0x00, 0x7E, 0x89, 0xC6, 0xE8,
43             0x7C, 0x00, 0xBE, 0x72, 0x7C, 0xE8, 0x08, 0x00, 0xEA, 0x00, 0x00, 0xE0, 0x07, 0xE8, 0xB4, 0x00,
44             0xAC, 0x3C, 0x00, 0x74, 0x06, 0xB4, 0x0E, 0xCD, 0x10, 0xEB, 0xF5, 0xC3, 0x30, 0x78, 0x00, 0x20,
45             0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x20,
46             0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2E, 0x0A, 0x0D, 0x00, 0x53, 0x65, 0x67, 0x6D,
47             0x65, 0x6E, 0x74, 0x73, 0x3A, 0x20, 0x00, 0x2C, 0x20, 0x00, 0x0A, 0x0D, 0x00, 0xBE, 0xDC, 0x7C,
48             0xE8, 0xBD, 0xFF, 0xE8, 0x63, 0x00, 0xE8, 0x07, 0x00, 0xBE, 0xDF, 0x7C, 0xE8, 0xB1, 0xFF, 0xC3,
49             0x89, 0xC3, 0xC1, 0xE8, 0x0C, 0xE8, 0x39, 0x00, 0x89, 0xD8, 0xC1, 0xE8, 0x08, 0xE8, 0x31, 0x00,
50             0x89, 0xD8, 0xC1, 0xE8, 0x04, 0xE8, 0x29, 0x00, 0x89, 0xD8, 0xE8, 0x24, 0x00, 0xC3, 0x31, 0xC9,
51             0xAD, 0xE8, 0xDC, 0xFF, 0xE8, 0x2C, 0x00, 0x83, 0xC1, 0x02, 0x81, 0xF9, 0x00, 0x02, 0x75, 0xF0,
52             0xC3, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45,
53             0x46, 0x50, 0x56, 0x83, 0xE0, 0x0F, 0x05, 0x51, 0x7D, 0x89, 0xC6, 0xAC, 0xB4, 0x0E, 0xCD, 0x10,
54             0x5E, 0x58, 0xC3, 0xB8, 0x20, 0x0E, 0xCD, 0x10, 0xC3, 0x31, 0xC0, 0xCD, 0x12, 0x72, 0x05, 0x85,
55             0xC0, 0x74, 0x01, 0xC3, 0xBE, 0x2A, 0x7C, 0xE8, 0x46, 0xFF, 0xEB, 0xFE, 0xEA, 0x00, 0x00, 0xFF,
56             0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
63             ];
64         return sector;
65     def putSectorData(self,lba,block):
66         """Overload this to write data to a given 512-byte sector."""
67         print "You forgot to overload putSectorData().  Ignoring sector write.";
68         return;
69     
70     def getSectorCount(self):
71         """Returns the number of viable Logical Block Addresses."""
72         print "You forgot to overload getSectorCount().  Guessing 0x200.";
73         return 0x200;
74     
75     def massinit(self):
76         """Initialize a USB Mass Storage device."""
77         self.usb_disconnect();
78         time.sleep(1);
79         self.usb_connect();
80         self.massrun();
81         
82     def massrun(self):
83         """Main loop of the USB Mass Storage emulator."""
84         print "Starting a Mass Storage device.";
85         while 1:
86             sys.stdout.flush();
87             self.service_irqs();
88     def do_SETUP(self):
89         """Handle USB Enumeration"""
90         
91         #Grab the SETUP packet from the buffer.
92         SUD=self.readbytes(rSUDFIFO,8);
93         
94         #Parse the SETUP packet
95         print "Handling a setup packet of %s" % self.setup2str(SUD);
96         setuptype=(ord(SUD[bmRequestType])&0x60);
97         if setuptype==0x00:
98             self.std_request(SUD);
99         elif setuptype==0x20:
100             self.class_request(SUD);
101         elif setuptype==0x40:
102             self.vendor_request(SUD);
103         else:
104             print "Unknown bmRequestType=0x%02x." % ord(SUD[bmRequestType])
105             self.STALL_EP0(SUD);
106     def class_request(self,SUD):
107         """Handle a class request."""
108         requesttype=ord(SUD[bmRequestType]);
109         request=ord(SUD[bRequest]);
110         if requesttype==0xA1 and request==0xFE:
111             print "Reporting 0 as the maximum LUN.";
112             #This is a Get Max LUN request.
113             #Return 1-byte maximum Logical Unit Number
114             self.wreg(rEP0FIFO,0x00); # Just one LUN.
115             self.wregAS(rEP0BC,1); # ARM and fire!
116             return; #Don't stall.
117         if requesttype==0x21 and request==0xff:
118             print "Received BBB reset."
119             self.wregAS(rEP0BC,0); # ARM and fire!
120             return; #Don't stall.
121         print "Stalling an unknown class request: %s" % self.setup2str(SUD);
122         self.STALL_EP0(SUD);
123     def vendor_request(self,SUD):
124         """Handle a vendor request."""
125         request=ord(SUD[bRequest]);
126         print "Why the hell is there a vendor request?";
127         #self.wreg(rEP0FIFO,0);
128         self.wregAS(rEP0BC,0);
129     def std_request(self,SUD):
130         """Handles a standard setup request."""
131         setuptype=ord(SUD[bRequest]);
132         if setuptype==SR_GET_DESCRIPTOR: self.send_descriptor(SUD);
133         #elif setuptype==SR_SET_FEATURE: self.feature(1);
134         elif setuptype==SR_SET_CONFIGURATION: self.set_configuration(SUD);
135         elif setuptype==SR_GET_STATUS: self.get_status(SUD);
136         elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR);
137         elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD);
138         else:
139             #print "Stalling Unknown standard setup request type %02x" % setuptype;
140             #self.STALL_EP0(SUD);
141             print "Accepting unknown standard setup request type %02x" % setuptype;
142             self.wregAS(rEP0BC,0);
143             
144     def get_interface(self,SUD):
145         """Handles a setup request for SR_GET_INTERFACE."""
146         if ord(SUD[wIndexL]==0):
147             self.wreg(rEP0FIFO,0);
148             self.wregAS(rEP0BC,1);
149         else:
150             self.STALL_EP0(SUD);
151     
152
153
154 #Device Descriptor
155     DD=[ 
156         
157     0x12, #length
158     0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
159     0x81, 0x07, #Sandisk 
160     0x50, 0x51, #SDCZ2 Cruzer Mini Flash Drive (thin)
161     0x00, 0x03,
162     0x01, 0x02, 0x03, #Strings
163     0x01
164     
165     ];
166
167 #Configuration Descriptor
168     CD=[
169
170   0x09, #Length
171   0x02, #Type
172   0x20, #Total Length
173   0x00, 0x01, 0x01, 0x00, 0xE0, 0x00, 0x09, 0x04, 0x00, 0x00,
174   0x02, #Num Endpoints
175   0x08, #Mass Storage Bulk Only
176   0x06, #SCSI
177   0x50, 0x00,
178   
179   #OUT EP1
180   0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
181   #IN EP3
182   0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
183
184 ];
185     strDesc=[
186 # STRING descriptor 0--Language string
187 "\x04\x03\x09\x04",
188 # [
189 #         0x04,                 # bLength
190 #       0x03,                   # bDescriptorType = string
191 #       0x09,0x04               # wLANGID(L/H) = English-United Sates
192 # ],
193 # STRING descriptor 1--Manufacturer ID
194 "\x10\x03G\x00o\x00o\x00d\x00F\x00E\x00T\x00",
195 # STRING descriptor 2 - Product ID
196 "\x1C\x03M\x00A\x00S\x00S\x00 \x00E\x00m\x00u\x00l\x00a\x00t\x00o\x00r\x00",
197 # STRING descriptor 3 - Serial Number ID
198 "\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
199 ];
200
201     def get_status(self,SUD):
202         """Get the USB Setup Status."""
203         testbyte=ord(SUD[bmRequestType])
204         
205         #Toward Device
206         if testbyte==0x80:
207             self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered
208             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
209             self.wregAS(rEP0BC,2);    #Load byte count, arm transfer, and ack CTL.
210         #Toward Interface
211         elif testbyte==0x81:
212             self.wreg(rEP0FIFO,0x00);
213             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
214             self.wregAS(rEP0BC,2);
215         #Toward Endpoint
216         elif testbyte==0x82:
217             if(ord(SUD[wIndexL])==0x83):
218                 print "This code almost certainly doesn't work.";
219                 self.wreg(rEP0FIFO,0x01); #Stall EP3
220                 self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
221                 self.wregAS(rEP0BC,2);
222             else:
223                 print "Stalling unknown status.";
224                 self.STALL_EP0(SUD);
225         else:
226             print "Stalling unknown status.";
227             self.STALL_EP0(SUD);
228     
229     def do_IN3(self):
230         """Handle IN3 input event."""
231         # Do nothing here, as it'll be taken care of elsewhere.  The
232         # interrupt just means that the buffer is empty, not that we
233         # are expected to fill it.
234         
235     def do_OUT1(self):
236         """Handle an OUT1 output event."""
237         l=self.rreg(rEP1OUTBC);
238         frame=self.readbytes(rEP1OUTFIFO,l);
239         self.handleCBW(frame);
240         
241     lastCBW="";
242     def handleCBW(self,cbw):
243         """Handles an incoming Command Block Wrapper.  See USB Mass
244         Storage Class for details."""
245         
246         if len(cbw)!=31:
247             print "Invalid CBW length of %i bytes.  Aborting." % len(cbw);
248             return;
249         sig=cbw[0:4];
250         if sig!="USBC":
251             print "Invalid CBW signature: %s.  Should be USBC; aborting." % sig;
252             return;
253         self.lastCBW=cbw;
254         
255         dtlen=ord(cbw[8])+(ord(cbw[9])<<8)+(ord(cbw[10])<<16)+(ord(cbw[11])<<24);
256         flags=ord(cbw[12]);
257         dtdir=flags&0x80; # 0x80 for dev->host, 0x00 for host->dev
258         lun=ord(cbw[13])&0x0F; # Should be zero, as we only reported one LUN.
259         cblen=ord(cbw[14])&0x1F;
260         cb=cbw[15:31];
261         self.handleCB(cb,cblen,dtlen,dtdir);
262         
263     def handleCB(self,cb,cblen,dtlen,dtdir):
264         """Handles a command block, then replies with a CSW."""
265         if self.usbverbose:
266             print "Got command block, type 0x%02x requesting 0x%02x bytes" % (
267                 ord(cb[0]), dtlen);
268         verb=ord(cb[0]);
269         status=00; #good, set to 1 for bad.
270         if verb==0x00: # Test Unit Ready
271             # Send nothing, just the success code.
272             status=0;
273         elif verb==0x03: # Request Sense
274             print "Responding to Request Sense.  Needed for Macs.";
275             response=[0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
276                       0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
277                       0x00, 0x00,
278                       0,0,0,0,0];
279             #status=1;
280             self.writebytes(rEP3INFIFO,
281                             response);
282             self.wreg(rEP3INBC,len(response));
283         elif verb==0x12: #Inquiry
284             #print "Responding to CB inquiry.";
285             response=[
286                 0x00, # 00 for Direct, 1F for "no floppy"
287                 0x80, # make 0x80 for removable media
288                 0x00, # Version
289                 0x01, # Response Data Format
290                 0x1f, #Additional length.
291                 0x00, 0x00, 0x00,
292                 #Manufacturer
293                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
294                 #Device name
295                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
296                 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
297                 ord('0'),ord('.'),ord('0'),ord('1')]
298             #print "Sending %i byte reply to %i byte query." % (
299             #        len(response),dtlen);
300             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
301             #    #Wait for the packet to complete before sending the next.
302             #    print "Waiting to complete inquiry."
303             #    pass;
304             self.writebytes(rEP3INFIFO,
305                             response);
306             self.wregAS(rEP3INBC,
307                         dtlen);
308                         #len(response));
309             #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
310             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
311             #    #Wait for the packet to complete before sending the next.
312             #    print "Waiting to complete inquiry."
313             #    pass;
314         elif verb==0x1e: #Prevent/Allow Removal
315             # Give a good status to pretend we understand.
316             status=0x00;
317         elif verb==0x1A: #Mode Sense (6)
318             # I should probably send six bytes here.
319             print "Mode Sense (6) requesting %i byte Page Code %02x" % (
320                 dtlen,ord(cb[2])&0x3F);
321             #This is completely wrong.
322             response=[0x12,0,0,0, 0,0,0,0x1C];
323             self.fifo_ep3in_tx(response);
324         elif verb==0x5A: #Mode Sense (10)
325             # I should probably send ten bytes here.
326             print "Mode Sense (10) requesting %i byte Page Code %02x" % (
327                 dtlen,ord(cb[2])&0x3F);
328             #This is completely wrong.
329             response=[0x12,0x00,0,0, 0,0,0,0x1C]
330             self.fifo_ep3in_tx(response);
331         elif verb==0x23: #Read Format Capacity
332             response=[
333                 0x00, 0,0x00,0x08, #Capacity list length.
334                 0,0x00,0x10,0x00,   # Number of sectors, implying 10MB.
335                 0x01,0x00,            #reserved/desciptor code.
336                 0x02,0x00             # 512 bytes/sector.  Why is this twice?
337                 ];
338             self.writebytes(rEP3INFIFO,
339                             response);
340             self.wregAS(rEP3INBC,
341                         len(response));
342         elif verb==0x25: #Read Capacity
343             lastlba=self.getSectorCount();
344             response=[
345                 #0x00, 0, 0x0f, 0xFF, # Last LBA
346                 (lastlba>>24)&0xFF, (lastlba>>16)&0xFF, (lastlba>>8)&0xFF, lastlba&0xFF, # Last LBA
347                 0x00,0x00,0x02,0x00   # Block length of 512 bytes.
348                 ];
349             self.writebytes(rEP3INFIFO,
350                             response);
351             self.wregAS(rEP3INBC,
352                         len(response));
353         elif verb==0x28: #READ SECTOR
354             cbw=self.lastCBW;
355             baselba=(
356                 ord(cbw[20]) |
357                 (ord(cbw[19])<<8) |
358                 (ord(cbw[18])<<16) |
359                 (ord(cbw[17])<<24)
360                 );
361             count=dtlen/512;
362             print "Fetching %i blocks starting at  LBA %i." % (count,baselba);
363             if count>32:
364                 count=0;
365                 status=1; #Fail if we're asked to read more than 32 blocks.
366                 #Now we need to stall EP3.  It's not acceptable to just forget to transmit.
367                 self.wreg(rEPSTALLS,0x10);
368             for i in range(0,count):
369                 data=self.getSectorData(baselba+i);
370                 for j in range(0,8):
371                     #print "Sending block fragment %i,%i" % (i,j);
372                     #Transmit each 64-byte block fragment, then wait for next.
373                     while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass;
374                     response=data[j*64:j*64+64];
375                     self.writebytes(rEP3INFIFO,
376                                     response);
377                     self.wregAS(rEP3INBC,
378                                 64);
379             #sys.exit();
380         elif verb==0x2A: #WRITE SECTOR
381             print "Haven't implemented WRITE SECTOR.";
382             #sys.exit();
383         else:
384             print "ERROR: Unknown SCSI command block verb %02x." % verb;
385             status=1; #Command Failed
386             if dtlen>0:
387                 print "Sending %i bytes of dummy data here." % dtlen;
388                 self.fifo_ep3in_tx(zeros(dtlen));
389             #sys.exit(1);
390         cbw=self.lastCBW;
391         
392         #Now we need to send the CSW.
393         csw=[
394             #Standard prefix.
395             ord('U'),ord('S'),ord('B'),ord('S'),
396             #CBW key; must be the same as the one we're replying to.
397             ord(cbw[4]),ord(cbw[5]),ord(cbw[6]),ord(cbw[7]),
398             #CSW Data Residue, probably oughtn't be zeroed.
399             0,0,0,0,
400             #Status byte: 00 for good, 01 for bad.
401             status];
402         self.writebytes(rEP3INFIFO,
403                         csw);
404         self.wregAS(rEP3INBC,len(csw));
405         
406         
407         return;
408
409 class GoodFETMAXUSBMassFile(GoodFETMAXUSBMass):
410     """This emulates a USB Mass Storage Device, providing a file as
411     its image.  Writes are not yet supported, and this is very slow.
412     Performance hacks will come after the code stabilizes."""
413     
414     datafile=None;
415     datafilelen=None;
416     def openImage(self,filename):
417         """Opens an image for use.  Call this *before* massinit()."""
418         self.datafile=open(filename,"rb");
419         print "Opened an image with %i blocks." % self.getSectorCount();
420     def putSectorData(self,lba,block):
421         """Writes a 512-byte sector to the lba address."""
422         print "Writes aren't yet supported.";
423         return;
424     
425     def getSectorData(self,lba):
426         """Returns data from a 512-byte sector."""
427         toret="";
428         
429         #Seek to the appropraite block.
430         #print "Seeking to position %i"% (lba*512)
431         self.datafile.seek(lba*512,0);
432         pos=self.datafile.tell();
433         if pos!=lba*512:
434             print "SEEK ERROR: Seeked to %i (lba=%i), but now I'm at %i (lba=%i)" % (
435                 lba*512,lba,
436                 pos,pos/512);
437             #sys.exit();
438         
439         #Dump the data out, assuming no blocking and filling with nonsense.
440         toret=self.datafile.read(512);
441         if len(toret)<512:
442             print "Holy hell, I only have %i bytes of 512." % len(toret);
443         
444         toretbytes=range(0,len(toret));
445         for b in range(0,len(toret)): toretbytes[b]=ord(toret[b]);
446         return toretbytes;
447         
448     def getSectorCount(self):
449         """Returns the number of viable Logical Block Addresses."""
450         
451         # Python must have a better way to read a file length, but for
452         # now we just read the whole damned thing and then throw it
453         # away.  With present performance, we can't read anything
454         # large enough for this to be a problem.
455         if self.datafilelen==None:
456             self.datafile.seek(0);
457             self.datafilelen=len(self.datafile.read());
458         if self.datafilelen%512!=0:
459             print "ERROR: Image does not have an integer number of blocks!"
460             print "%i \% 512 == %i" % (self.datafilelen,
461                                        self.datafilelen%512);
462             sys.exit();
463         return self.datafilelen/512-1;
464 if(len(sys.argv)==1):
465     print "Usage: %s disk.img\n" % sys.argv[0];
466     sys.exit();
467
468
469 #Initialize FET and set baud rate
470 client=GoodFETMAXUSBMassFile();
471 client.serInit()
472
473 client.openImage(sys.argv[1]);
474
475 client.MAXUSBsetup();
476 client.massinit();
477