v0.1 board believed to be reading Vbat, Pressure, and X/Y/Z correctly now,
[fw/openalt] / usbmass / mscblock.c
1 /*****************************************************************************\
2 *              efs - General purpose Embedded Filesystem library              *
3 *          --------------------- -----------------------------------          *
4 *                                                                             *
5 * Filename : sd.c                                                             *
6 * Revision : Initial developement                                             *
7 * Description : This file contains the functions needed to use efs for        *
8 *               accessing files on an SD-card.                                *
9 *                                                                             *
10 * This library is free software; you can redistribute it and/or               *
11 * modify it under the terms of the GNU Lesser General Public                  *
12 * License as published by the Free Software Foundation; either                *
13 * version 2.1 of the License, or (at your option) any later version.          *
14 *                                                                             *
15 * This library is distributed in the hope that it will be useful,             *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           *
18 * Lesser General Public License for more details.                             *
19 *                                                                             *
20 *                                                    (c)2005 Michael De Nil   *
21 *                                                    (c)2005 Lennart Yseboodt *
22 \*****************************************************************************/
23
24 /*
25   2006, Bertrik Sikken, modified for LPCUSB
26 */
27
28 #include "FreeRTOS.h"
29
30 #include <stdio.h>
31
32 #include "../fatfs/diskio.h"
33 #include "../fatfs/ff.h"
34 #include "../fatfs/mmc.h"
35 #include "../fatfs/spi.h"
36 #include "mscdebug.h"
37 #include "mscblock.h"
38 #include "mscspi.h"
39
40 //
41 //
42 //
43 #define CMD_GOIDLESTATE      0
44 #define CMD_SENDOPCOND       1
45 #define CMD_READCSD          9
46 #define CMD_READCID         10
47 #define CMD_SENDSTATUS      13
48 #define CMD_READSINGLEBLOCK 17
49 #define CMD_WRITE           24
50 #define CMD_WRITE_MULTIPLE  25
51
52 //
53 //
54 //
55 static void mscblockCommand (U8 cmd, U32 param)
56 {
57   U8  abCmd [8];
58
59   abCmd [0] = 0xff;
60   abCmd [1] = 0x40 | cmd;
61   abCmd [2] = (U8)(param >> 24);
62   abCmd [3] = (U8)(param >> 16);
63   abCmd [4] = (U8)(param >> 8);
64   abCmd [5] = (U8)(param);
65   abCmd [6] = 0x95;     /* Checksum (should be only valid for first command (0) */
66   abCmd [7] = 0xff;     /* eat empty command - response */
67
68   mscspiSendBlock (abCmd, 8);
69 }
70
71 //
72 //
73 //
74 static U8 mscblockResp8b (void)
75 {
76   U8 i;
77   U8 resp;
78
79   /* Respone will come after 1 - 8 pings */
80   for (i = 0; i < 8; i++)
81     if ((resp = mscspiTransferByte (0xff)) != 0xff)
82       return resp;
83
84   return resp;
85 }
86
87 //
88 //
89 //
90 static void mscblockResp8bError (U8 value)
91 {
92   switch (value) 
93   {
94     case 0x40 : DBG ("Argument out of bounds.\n");                break;
95     case 0x20 : DBG ("Address out of bounds.\n");                 break;
96     case 0x10 : DBG ("Error during erase sequence.\n");           break;
97     case 0x08 : DBG ("CRC failed.\n");                            break;
98     case 0x04 : DBG ("Illegal command.\n");                       break;
99     case 0x02 : DBG ("Erase reset (see SanDisk docs p5-13).\n");  break;
100     case 0x01 : DBG ("Card is initialising.\n");                  break;
101     default   : DBG ("Unknown error 0x%x (see SanDisk docs p5-13).\n", value); break;
102   }
103 }
104
105 //
106 //  Calculates size of card from CSD 
107 //    (extension by Martin Thomas, inspired by code from Holger Klabunde)
108 //
109 int mscblockGetSize (U32 *pdwDriveSize)
110 {
111   U8 cardresp, i, by;
112   U8 iob [16];
113   U16 c_size, c_size_mult, read_bl_len;
114
115   mscblockCommand (CMD_READCSD, 0);
116
117   do {
118     cardresp = mscblockResp8b ();
119   } 
120   while (cardresp != 0xfe);
121
122   DBG ("CSD:");
123
124   for (i = 0; i < 16; i++) 
125   {
126     iob [i] = mscspiTransferByte (0xff);
127     DBG (" %02x", iob [i]);
128   }
129
130   DBG("\n");
131
132   mscspiTransferByte (0xff);
133   mscspiTransferByte (0xff);
134
135   c_size = iob [6] & 0x03;
136   c_size <<= 10;
137   c_size += (U16) iob [7] << 2;
138   c_size += iob [8] >> 6;
139
140   by = iob [5] & 0x0f;
141   read_bl_len = 1 << by;
142
143   by = iob [9] & 0x03;
144   by <<= 1;
145   by += iob [10] >> 7;
146
147   c_size_mult = 1 << (2 + by);
148
149   *pdwDriveSize = (U32) (c_size + 1) * (U32) c_size_mult * (U32) read_bl_len;
150
151   return 0;
152 }
153
154 //
155 //
156 //
157 static U16 mscblockResp16b (void)
158 {
159   U16 resp;
160
161   resp = (mscblockResp8b() << 8) & 0xff00;
162   resp |= mscspiTransferByte(0xff);
163
164   return resp;
165 }
166
167 //
168 //
169 //
170 static int mscblockState (void)
171 {
172   U16 value;
173
174   mscblockCommand (CMD_SENDSTATUS, 0);
175   value = mscblockResp16b ();
176
177   switch (value) 
178   {
179     case 0x0000 : return 1;
180     case 0x0001 : DBG ("Card is Locked.\n");                                                 break;
181     case 0x0002 : DBG ("WP Erase Skip, Lock/Unlock Cmd Failed.\n");                          break;
182     case 0x0004 : DBG ("General / Unknown error -- card broken?.\n");                        break;
183     case 0x0008 : DBG ("Internal card controller error.\n");                                 break;
184     case 0x0010 : DBG ("Card internal ECC was applied, but failed to correct the data.\n");  break;
185     case 0x0020 : DBG ("Write protect violation.\n");                                        break;
186     case 0x0040 : DBG ("An invalid selection, sectors for erase.\n");                        break;
187     case 0x0080 : DBG ("Out of Range, CSD_Overwrite.\n");                                    break;
188     default     : if (value > 0x00ff)
189                     mscblockResp8bError ((U8) (value >> 8));
190                   else
191                     DBG ("Unknown error: 0x%x (see SanDisk docs p5-14).\n", value);
192                   break;
193   }
194
195   return -1;
196 }
197
198 //
199 //
200 //
201 int mscblockInit (void)
202 {
203   FRESULT f;
204
205   //
206   //  We'll see the error because it means we *must* be using a serial
207   //  console, since we can't use USB for MSC and VCOM at the same time.
208   //
209   mscspiInit (); 
210
211 #if 1
212   if ((f = diskInitialize (0)) != FR_OK)
213     f_printerror (f);
214 #endif
215
216 #if 0
217   U8 resp;
218   int i;
219
220   // 
221   //  Try to send reset command up to 100 times 
222   //
223   i = 100;
224
225   do 
226   {
227     mscblockCommand (CMD_GOIDLESTATE, 0);
228     resp = mscblockResp8b ();
229   } 
230   while (resp != 1 && i--);
231
232   if (resp != 1) 
233   {
234     if (resp == 0xff) 
235     {
236       DBG ("resp=0xff\n");
237       return -1;
238     }
239     else 
240     {
241       mscblockResp8bError (resp);
242       DBG ("resp!=0xff\n");
243       return -2;
244     }
245   }
246
247   //
248   //  Wait till card is ready initialising (returns 0 on CMD_1)
249   //  Try up to 32000 times. */
250   //
251   i = 32000;
252
253   do 
254   {
255     mscblockCommand (CMD_SENDOPCOND, 0);
256
257     if ((resp = mscblockResp8b ()) != 0)
258       mscblockResp8bError (resp);
259   } 
260   while (resp == 1 && i--);
261
262   if (resp != 0) 
263   {
264     mscblockResp8bError (resp);
265     return -3;
266   }
267
268   //
269   //  Increase speed after init 
270   //
271   // mscspiSetSpeed (SPI_PRESCALE_MIN);
272 #endif
273
274   if (mscblockState () < 0) 
275   {
276     DBG ("Card didn't return the ready state, breaking up...\n");
277     return -2;
278   }
279
280   DBG ("Init done...\n");
281
282   return 0;
283 }
284
285 //
286 // WAIT ?? -- FIXME
287 // CMD_WRITE
288 // WAIT
289 // CARD RESP
290 // WAIT
291 // DATA BLOCK OUT
292 //      START BLOCK
293 //      DATA
294 //      CHKS (2B)
295 // BUSY...
296 //
297 int mscblockWrite (U32 dwAddress, U8 * pbBuf)
298 {
299   U32 place;
300   U16 t = 0;
301
302   place = 512 * dwAddress;
303   mscblockCommand (CMD_WRITE, place);
304
305   mscblockResp8b ();       /* Card response */
306
307   mscspiTransferByte (0xfe);      /* Start block */
308   mscspiSendBlock (pbBuf, 512);
309   mscspiTransferByte (0xff);      /* Checksum part 1 */
310   mscspiTransferByte (0xff);      /* Checksum part 2 */
311
312   mscspiTransferByte (0xff);
313
314   while (spiTransferByte (0xff) != 0xff)
315     t++;
316
317   return 0;
318 }
319
320 //
321 // WAIT ?? -- FIXME
322 // CMD_CMD_
323 // WAIT
324 // CARD RESP
325 // WAIT
326 // DATA BLOCK IN
327 //    START BLOCK
328 //    DATA
329 //    CHKS (2B)
330 //
331 int mscblockRead (U32 dwAddress, U8 * pbBuf)
332 {
333   U8 cardresp;
334   U8 firstblock;
335   U16 fb_timeout = 0xffff;
336   U32 place;
337
338   place = 512 * dwAddress;
339   mscblockCommand (CMD_READSINGLEBLOCK, place);
340
341   cardresp = mscblockResp8b ();
342
343   //
344   //  Wait for startblock
345   //
346   do 
347   {
348     firstblock = mscblockResp8b();
349   } 
350   while (firstblock == 0xff && fb_timeout--);
351
352   if (cardresp != 0x00 || firstblock != 0xfe) 
353   {
354     mscblockResp8bError (firstblock);
355     return -1;
356   }
357
358   mscspiReceiveBlock (pbBuf, 512);
359
360   //
361   //  Checksum (2 byte) - ignore for now 
362   //
363   mscspiTransferByte (0xff);
364   mscspiTransferByte (0xff);
365
366   return 0;
367 }