Added incomplete PrinterHost demo application.
[pub/USBasp.git] / Demos / Device / ClassDriver / MassStorage / Lib / DataflashManager.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * Functions to manage the physical dataflash media, including reading and writing of
34 * blocks of data. These functions are called by the SCSI layer when data must be stored
35 * or retrieved to/from the physical storage media. If a different media is used (such
36 * as a SD card or EEPROM), functions similar to these will need to be generated.
37 */
38
39 #define INCLUDE_FROM_DATAFLASHMANAGER_C
40 #include "DataflashManager.h"
41
42 /** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
43 * the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes
44 * them to the dataflash in Dataflash page sized blocks.
45 *
46 * \param[in] BlockAddress Data block starting address for the write sequence
47 * \param[in] TotalBlocks Number of blocks of data to write
48 */
49 void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
50 {
51 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
52 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
53 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
54 bool UsingSecondBuffer = false;
55
56 /* Select the correct starting Dataflash IC for the block requested */
57 Dataflash_SelectChipFromPage(CurrDFPage);
58
59 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
60 /* Copy selected dataflash's current page contents to the dataflash buffer */
61 Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
62 Dataflash_SendAddressBytes(CurrDFPage, 0);
63 Dataflash_WaitWhileBusy();
64 #endif
65
66 /* Send the dataflash buffer write command */
67 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
68 Dataflash_SendAddressBytes(0, CurrDFPageByte);
69
70 /* Wait until endpoint is ready before continuing */
71 while (!(Endpoint_IsReadWriteAllowed()));
72
73 while (TotalBlocks)
74 {
75 uint8_t BytesInBlockDiv16 = 0;
76
77 /* Write an endpoint packet sized data block to the dataflash */
78 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
79 {
80 /* Check if the endpoint is currently empty */
81 if (!(Endpoint_IsReadWriteAllowed()))
82 {
83 /* Clear the current endpoint bank */
84 Endpoint_ClearOUT();
85
86 /* Wait until the host has sent another packet */
87 while (!(Endpoint_IsReadWriteAllowed()));
88 }
89
90 /* Check if end of dataflash page reached */
91 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
92 {
93 /* Write the dataflash buffer contents back to the dataflash page */
94 Dataflash_WaitWhileBusy();
95 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
96 Dataflash_SendAddressBytes(CurrDFPage, 0);
97
98 /* Reset the dataflash buffer counter, increment the page counter */
99 CurrDFPageByteDiv16 = 0;
100 CurrDFPage++;
101
102 /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
103 if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
104 UsingSecondBuffer = !(UsingSecondBuffer);
105
106 /* Select the next dataflash chip based on the new dataflash page index */
107 Dataflash_SelectChipFromPage(CurrDFPage);
108
109 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
110 /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
111 if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
112 {
113 /* Copy selected dataflash's current page contents to the dataflash buffer */
114 Dataflash_WaitWhileBusy();
115 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
116 Dataflash_SendAddressBytes(CurrDFPage, 0);
117 Dataflash_WaitWhileBusy();
118 }
119 #endif
120
121 /* Send the dataflash buffer write command */
122 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
123 Dataflash_SendAddressBytes(0, 0);
124 }
125
126 /* Write one 16-byte chunk of data to the dataflash */
127 Dataflash_SendByte(Endpoint_Read_Byte());
128 Dataflash_SendByte(Endpoint_Read_Byte());
129 Dataflash_SendByte(Endpoint_Read_Byte());
130 Dataflash_SendByte(Endpoint_Read_Byte());
131 Dataflash_SendByte(Endpoint_Read_Byte());
132 Dataflash_SendByte(Endpoint_Read_Byte());
133 Dataflash_SendByte(Endpoint_Read_Byte());
134 Dataflash_SendByte(Endpoint_Read_Byte());
135 Dataflash_SendByte(Endpoint_Read_Byte());
136 Dataflash_SendByte(Endpoint_Read_Byte());
137 Dataflash_SendByte(Endpoint_Read_Byte());
138 Dataflash_SendByte(Endpoint_Read_Byte());
139 Dataflash_SendByte(Endpoint_Read_Byte());
140 Dataflash_SendByte(Endpoint_Read_Byte());
141 Dataflash_SendByte(Endpoint_Read_Byte());
142 Dataflash_SendByte(Endpoint_Read_Byte());
143
144 /* Increment the dataflash page 16 byte block counter */
145 CurrDFPageByteDiv16++;
146
147 /* Increment the block 16 byte block counter */
148 BytesInBlockDiv16++;
149
150 /* Check if the current command is being aborted by the host */
151 if (MSInterfaceInfo->State.IsMassStoreReset)
152 return;
153 }
154
155 /* Decrement the blocks remaining counter and reset the sub block counter */
156 TotalBlocks--;
157 }
158
159 /* Write the dataflash buffer contents back to the dataflash page */
160 Dataflash_WaitWhileBusy();
161 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
162 Dataflash_SendAddressBytes(CurrDFPage, 0x00);
163 Dataflash_WaitWhileBusy();
164
165 /* If the endpoint is empty, clear it ready for the next packet from the host */
166 if (!(Endpoint_IsReadWriteAllowed()))
167 Endpoint_ClearOUT();
168
169 /* Deselect all dataflash chips */
170 Dataflash_DeselectChip();
171 }
172
173 /** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
174 * the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash
175 * and writes them in OS sized blocks to the endpoint.
176 *
177 * \param[in] BlockAddress Data block starting address for the read sequence
178 * \param[in] TotalBlocks Number of blocks of data to read
179 */
180 void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
181 {
182 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
183 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
184 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
185
186 /* Select the correct starting Dataflash IC for the block requested */
187 Dataflash_SelectChipFromPage(CurrDFPage);
188
189 /* Send the dataflash main memory page read command */
190 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
191 Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
192 Dataflash_SendByte(0x00);
193 Dataflash_SendByte(0x00);
194 Dataflash_SendByte(0x00);
195 Dataflash_SendByte(0x00);
196
197 /* Wait until endpoint is ready before continuing */
198 while (!(Endpoint_IsReadWriteAllowed()));
199
200 while (TotalBlocks)
201 {
202 uint8_t BytesInBlockDiv16 = 0;
203
204 /* Write an endpoint packet sized data block to the dataflash */
205 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
206 {
207 /* Check if the endpoint is currently full */
208 if (!(Endpoint_IsReadWriteAllowed()))
209 {
210 /* Clear the endpoint bank to send its contents to the host */
211 Endpoint_ClearIN();
212
213 /* Wait until the endpoint is ready for more data */
214 while (!(Endpoint_IsReadWriteAllowed()));
215 }
216
217 /* Check if end of dataflash page reached */
218 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
219 {
220 /* Reset the dataflash buffer counter, increment the page counter */
221 CurrDFPageByteDiv16 = 0;
222 CurrDFPage++;
223
224 /* Select the next dataflash chip based on the new dataflash page index */
225 Dataflash_SelectChipFromPage(CurrDFPage);
226
227 /* Send the dataflash main memory page read command */
228 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
229 Dataflash_SendAddressBytes(CurrDFPage, 0);
230 Dataflash_SendByte(0x00);
231 Dataflash_SendByte(0x00);
232 Dataflash_SendByte(0x00);
233 Dataflash_SendByte(0x00);
234 }
235
236 /* Read one 16-byte chunk of data from the dataflash */
237 Endpoint_Write_Byte(Dataflash_ReceiveByte());
238 Endpoint_Write_Byte(Dataflash_ReceiveByte());
239 Endpoint_Write_Byte(Dataflash_ReceiveByte());
240 Endpoint_Write_Byte(Dataflash_ReceiveByte());
241 Endpoint_Write_Byte(Dataflash_ReceiveByte());
242 Endpoint_Write_Byte(Dataflash_ReceiveByte());
243 Endpoint_Write_Byte(Dataflash_ReceiveByte());
244 Endpoint_Write_Byte(Dataflash_ReceiveByte());
245 Endpoint_Write_Byte(Dataflash_ReceiveByte());
246 Endpoint_Write_Byte(Dataflash_ReceiveByte());
247 Endpoint_Write_Byte(Dataflash_ReceiveByte());
248 Endpoint_Write_Byte(Dataflash_ReceiveByte());
249 Endpoint_Write_Byte(Dataflash_ReceiveByte());
250 Endpoint_Write_Byte(Dataflash_ReceiveByte());
251 Endpoint_Write_Byte(Dataflash_ReceiveByte());
252 Endpoint_Write_Byte(Dataflash_ReceiveByte());
253
254 /* Increment the dataflash page 16 byte block counter */
255 CurrDFPageByteDiv16++;
256
257 /* Increment the block 16 byte block counter */
258 BytesInBlockDiv16++;
259
260 /* Check if the current command is being aborted by the host */
261 if (MSInterfaceInfo->State.IsMassStoreReset)
262 return;
263 }
264
265 /* Decrement the blocks remaining counter */
266 TotalBlocks--;
267 }
268
269 /* If the endpoint is full, send its contents to the host */
270 if (!(Endpoint_IsReadWriteAllowed()))
271 Endpoint_ClearIN();
272
273 /* Deselect all dataflash chips */
274 Dataflash_DeselectChip();
275 }
276
277 /** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
278 * the a given RAM buffer. This routine reads in OS sized blocks from the buffer and writes them to the
279 * dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the
280 * dataflash.
281 *
282 * \param[in] BlockAddress Data block starting address for the write sequence
283 * \param[in] TotalBlocks Number of blocks of data to write
284 * \param[in] BufferPtr Pointer to the data source RAM buffer
285 */
286 void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
287 {
288 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
289 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
290 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
291 bool UsingSecondBuffer = false;
292
293 /* Select the correct starting Dataflash IC for the block requested */
294 Dataflash_SelectChipFromPage(CurrDFPage);
295
296 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
297 /* Copy selected dataflash's current page contents to the dataflash buffer */
298 Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
299 Dataflash_SendAddressBytes(CurrDFPage, 0);
300 Dataflash_WaitWhileBusy();
301 #endif
302
303 /* Send the dataflash buffer write command */
304 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
305 Dataflash_SendAddressBytes(0, CurrDFPageByte);
306
307 while (TotalBlocks)
308 {
309 uint8_t BytesInBlockDiv16 = 0;
310
311 /* Write an endpoint packet sized data block to the dataflash */
312 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
313 {
314 /* Check if end of dataflash page reached */
315 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
316 {
317 /* Write the dataflash buffer contents back to the dataflash page */
318 Dataflash_WaitWhileBusy();
319 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
320 Dataflash_SendAddressBytes(CurrDFPage, 0);
321
322 /* Reset the dataflash buffer counter, increment the page counter */
323 CurrDFPageByteDiv16 = 0;
324 CurrDFPage++;
325
326 /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
327 if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
328 UsingSecondBuffer = !(UsingSecondBuffer);
329
330 /* Select the next dataflash chip based on the new dataflash page index */
331 Dataflash_SelectChipFromPage(CurrDFPage);
332
333 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
334 /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
335 if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
336 {
337 /* Copy selected dataflash's current page contents to the dataflash buffer */
338 Dataflash_WaitWhileBusy();
339 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
340 Dataflash_SendAddressBytes(CurrDFPage, 0);
341 Dataflash_WaitWhileBusy();
342 }
343 #endif
344
345 /* Send the dataflash buffer write command */
346 Dataflash_ToggleSelectedChipCS();
347 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
348 Dataflash_SendAddressBytes(0, 0);
349 }
350
351 /* Write one 16-byte chunk of data to the dataflash */
352 for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
353 Dataflash_SendByte(*(BufferPtr++));
354
355 /* Increment the dataflash page 16 byte block counter */
356 CurrDFPageByteDiv16++;
357
358 /* Increment the block 16 byte block counter */
359 BytesInBlockDiv16++;
360 }
361
362 /* Decrement the blocks remaining counter and reset the sub block counter */
363 TotalBlocks--;
364 }
365
366 /* Write the dataflash buffer contents back to the dataflash page */
367 Dataflash_WaitWhileBusy();
368 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
369 Dataflash_SendAddressBytes(CurrDFPage, 0x00);
370 Dataflash_WaitWhileBusy();
371
372 /* Deselect all dataflash chips */
373 Dataflash_DeselectChip();
374 }
375
376 /** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
377 * the a preallocated RAM buffer. This routine reads in Dataflash page sized blocks from the Dataflash
378 * and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read
379 * the files stored on the dataflash.
380 *
381 * \param[in] BlockAddress Data block starting address for the read sequence
382 * \param[in] TotalBlocks Number of blocks of data to read
383 * \param[out] BufferPtr Pointer to the data destination RAM buffer
384 */
385 void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
386 {
387 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
388 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
389 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
390
391 /* Select the correct starting Dataflash IC for the block requested */
392 Dataflash_SelectChipFromPage(CurrDFPage);
393
394 /* Send the dataflash main memory page read command */
395 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
396 Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
397 Dataflash_SendByte(0x00);
398 Dataflash_SendByte(0x00);
399 Dataflash_SendByte(0x00);
400 Dataflash_SendByte(0x00);
401
402 while (TotalBlocks)
403 {
404 uint8_t BytesInBlockDiv16 = 0;
405
406 /* Write an endpoint packet sized data block to the dataflash */
407 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
408 {
409 /* Check if end of dataflash page reached */
410 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
411 {
412 /* Reset the dataflash buffer counter, increment the page counter */
413 CurrDFPageByteDiv16 = 0;
414 CurrDFPage++;
415
416 /* Select the next dataflash chip based on the new dataflash page index */
417 Dataflash_SelectChipFromPage(CurrDFPage);
418
419 /* Send the dataflash main memory page read command */
420 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
421 Dataflash_SendAddressBytes(CurrDFPage, 0);
422 Dataflash_SendByte(0x00);
423 Dataflash_SendByte(0x00);
424 Dataflash_SendByte(0x00);
425 Dataflash_SendByte(0x00);
426 }
427
428 /* Read one 16-byte chunk of data from the dataflash */
429 for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
430 *(BufferPtr++) = Dataflash_ReceiveByte();
431
432 /* Increment the dataflash page 16 byte block counter */
433 CurrDFPageByteDiv16++;
434
435 /* Increment the block 16 byte block counter */
436 BytesInBlockDiv16++;
437 }
438
439 /* Decrement the blocks remaining counter */
440 TotalBlocks--;
441 }
442
443 /* Deselect all dataflash chips */
444 Dataflash_DeselectChip();
445 }
446
447 /** Disables the dataflash memory write protection bits on the board Dataflash ICs, if enabled. */
448 void DataflashManager_ResetDataflashProtections(void)
449 {
450 /* Select first dataflash chip, send the read status register command */
451 Dataflash_SelectChip(DATAFLASH_CHIP1);
452 Dataflash_SendByte(DF_CMD_GETSTATUS);
453
454 /* Check if sector protection is enabled */
455 if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
456 {
457 Dataflash_ToggleSelectedChipCS();
458
459 /* Send the commands to disable sector protection */
460 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
461 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
462 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
463 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
464 }
465
466 /* Select second dataflash chip (if present on selected board), send read status register command */
467 #if (DATAFLASH_TOTALCHIPS == 2)
468 Dataflash_SelectChip(DATAFLASH_CHIP2);
469 Dataflash_SendByte(DF_CMD_GETSTATUS);
470
471 /* Check if sector protection is enabled */
472 if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
473 {
474 Dataflash_ToggleSelectedChipCS();
475
476 /* Send the commands to disable sector protection */
477 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
478 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
479 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
480 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
481 }
482 #endif
483
484 /* Deselect current dataflash chip */
485 Dataflash_DeselectChip();
486 }