Contiki-Inga 3.x
diskio.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Institute of Operating Systems and Computer Networks (TU Braunschweig).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Author: Christoph Peltz <peltz@ibr.cs.tu-bs.de>
30  */
31 
32 /**
33  * \addtogroup cfs
34  * @{
35  *
36  * \addtogroup diskio_layer
37  * @{
38  */
39 
40 /**
41  * \file
42  * DiskIO Abstraction Layer Implementation
43  * \author
44  * Christoph Peltz <peltz@ibr.cs.tu-bs.de>
45  */
46 
47 #include "diskio.h"
48 #include "mbr.h"
49 #include <string.h>
50 #include "diskio-arch.h"
51 
52 #ifndef DISKIO_DEBUG
53 #define DISKIO_DEBUG 0
54 #endif
55 #if DISKIO_DEBUG
56 #include <stdio.h>
57 #define PRINTF(...) printf(__VA_ARGS__)
58 #else
59 #define PRINTF(...)
60 #endif
61 
62 /* Number of read/write retries */
63 #define DISKIO_RW_RETRIES 150
64 /* Delay between retries. */
65 #define DISKIO_RW_DELAY_MS 10
66 
67 static struct diskio_device_info *default_device = 0;
68 static struct diskio_device_info devices[DISKIO_MAX_DEVICES];
69 
70 static int diskio_rw_op(struct diskio_device_info *dev, uint32_t block_start_address, uint32_t num_blocks, uint8_t *buffer, uint8_t op);
71 /*----------------------------------------------------------------------------*/
72 void
74 {
75  printf("DiskIO Device Info\n");
76 
77  printf("\ttype = ");
78  switch (dev->type & 0x7F) {
79  case DISKIO_DEVICE_TYPE_SD_CARD:
80  printf("SD_CARD");
81  break;
82  case DISKIO_DEVICE_TYPE_GENERIC_FLASH:
83  printf("Generic_Flash");
84  break;
85  default:
86  printf("Unknown: %d", dev->type & 0x7F);
87  break;
88  }
89 
90  if (dev->type & DISKIO_DEVICE_TYPE_PARTITION) {
91  printf(" (Partition)");
92  }
93 
94  printf("\n");
95  printf("\tnumber = %d\n", dev->number);
96  printf("\tpartition = %d\n", dev->partition);
97  printf("\tnum_sectors = %ld\n", dev->num_sectors);
98  printf("\tsector_size = %d\n", dev->sector_size);
99  printf("\tfirst_sector = %ld\n", dev->first_sector);
100 }
101 /*----------------------------------------------------------------------------*/
102 int
103 diskio_read_block(struct diskio_device_info *dev, uint32_t block_address, uint8_t *buffer)
104 {
105  return diskio_rw_op(dev, block_address, 1, buffer, DISKIO_OP_READ_BLOCK);
106 }
107 /*----------------------------------------------------------------------------*/
108 int
109 diskio_read_blocks(struct diskio_device_info *dev, uint32_t block_start_address, uint32_t num_blocks, uint8_t *buffer)
110 {
111  return diskio_rw_op(dev, block_start_address, num_blocks, buffer, DISKIO_OP_READ_BLOCKS);
112 }
113 /*----------------------------------------------------------------------------*/
114 int
115 diskio_write_block(struct diskio_device_info *dev, uint32_t block_address, uint8_t *buffer)
116 {
117  return diskio_rw_op(dev, block_address, 1, buffer, DISKIO_OP_WRITE_BLOCK);
118 }
119 /*----------------------------------------------------------------------------*/
120 int
121 diskio_write_blocks_start(struct diskio_device_info *dev, uint32_t block_start_address, uint32_t num_blocks)
122 {
123  return diskio_rw_op(dev, block_start_address, num_blocks, NULL, DISKIO_OP_WRITE_BLOCKS_START);
124 }
125 /*----------------------------------------------------------------------------*/
126 int
127 diskio_write_blocks_next(struct diskio_device_info *dev, uint8_t *buffer)
128 {
129  return diskio_rw_op(dev, 0, 1, buffer, DISKIO_OP_WRITE_BLOCKS_NEXT);
130 }
131 /*----------------------------------------------------------------------------*/
132 int
134 {
135  return diskio_rw_op(dev, 0, 0, NULL, DISKIO_OP_WRITE_BLOCKS_DONE);
136 }
137 /*----------------------------------------------------------------------------*/
138 static int
139 diskio_rw_op(struct diskio_device_info *dev, uint32_t block_start_address, uint32_t num_blocks, uint8_t *buffer, uint8_t op)
140 {
141  static uint32_t multi_block_nr = 0;
142 
143  if (dev == NULL) {
144  if (default_device == 0) {
145  PRINTF("\nNo default device");
146  return DISKIO_ERROR_NO_DEVICE_SELECTED;
147  }
148  dev = default_device;
149  }
150 
151  block_start_address += dev->first_sector;
152 
153  uint8_t ret_code = 0;
154  uint8_t tries = 0, reinit = 0;
155  switch (dev->type & DISKIO_DEVICE_TYPE_MASK) {
156 
157 #ifdef SD_INIT
158  case DISKIO_DEVICE_TYPE_SD_CARD:
159  switch (op) {
160  case DISKIO_OP_READ_BLOCK:
161 #ifndef DISKIO_OLD_STYLE
162  for (tries = 0; tries < DISKIO_RW_RETRIES; tries++) {
163  ret_code = SD_READ_BLOCK(block_start_address, buffer);
164  if (ret_code == 0) {
165  return DISKIO_SUCCESS;
166  } else {
167  //PRINTF("\nret_code: %u", ret_code);
168  }
169 
170 #ifdef FAT_COOPERATIVE
171  if (!coop_step_allowed) {
172  next_step_type = READ;
173  coop_switch_sp();
174  } else {
175  coop_step_allowed = 0;
176  }
177 #else /* FAT_COOPERATIVE */
178  _delay_ms(DISKIO_RW_DELAY_MS);
179 #endif /* FAT_COOPERATIVE */
180 
181  /* Try once to reinit sd card if access failed. */
182  if ((reinit == 0) && (tries == DISKIO_RW_RETRIES - 1)) {
183  PRINTF("\nReinit");
184  tries = 0;
185  reinit = 1;
186  SD_INIT();
187  }
188  }
189  PRINTF("\ndiskion_rw_op(): Unrecoverable Read Error!");
190  return DISKIO_ERROR_INTERNAL_ERROR;
191 #else /* !DISKIO_OLD_STYLE */
192  if (SD_READ_BLOCK(block_start_address, buffer) == 0) {
193  return DISKIO_SUCCESS;
194  }
195  return DISKIO_ERROR_TRY_AGAIN;
196 #endif /* !DISKIO_OLD_STYLE */
197  break;
198 
199  case DISKIO_OP_READ_BLOCKS:
200  return DISKIO_ERROR_TO_BE_IMPLEMENTED;
201  break;
202 
203  case DISKIO_OP_WRITE_BLOCK:
204 #ifndef DISKIO_OLD_STYLE
205  for (tries = 0; tries < DISKIO_RW_RETRIES; tries++) {
206  ret_code = SD_WRITE_BLOCK(block_start_address, buffer);
207  if (ret_code == 0) {
208  return DISKIO_SUCCESS;
209  }
210 
211 #ifdef FAT_COOPERATIVE
212  if (!coop_step_allowed) {
213  next_step_type = WRITE;
214  coop_switch_sp();
215  } else {
216  coop_step_allowed = 0;
217  }
218 #else /* FAT_COOPERATIVE */
219  _delay_ms(DISKIO_RW_DELAY_MS);
220 #endif /* FAT_COOPERATIVE */
221  if ((reinit == 0) && (tries == DISKIO_RW_RETRIES - 1)) {
222  PRINTF("\nReinit");
223  tries = 0;
224  reinit = 1;
225  SD_INIT();
226  }
227  }
228  PRINTF("\ndiskion_rw_op(): Unrecoverable Write Error!");
229  return DISKIO_ERROR_INTERNAL_ERROR;
230 #else /* !DISKIO_OLD_STYLE */
231  if (SD_WRITE_BLOCK(block_start_address, buffer) == 0) {
232  return DISKIO_SUCCESS;
233  }
234  return DISKIO_ERROR_TRY_AGAIN;
235 #endif /* !DISKIO_OLD_STYLE */
236  break;
237 
238  case DISKIO_OP_WRITE_BLOCKS_START:
239  ret_code = SD_WRITE_BLOCKS_START(block_start_address, num_blocks);
240  if (ret_code == 0) {
241  return DISKIO_SUCCESS;
242  } else {
243  return DISKIO_ERROR_INTERNAL_ERROR;
244  }
245  break;
246 
247  case DISKIO_OP_WRITE_BLOCKS_NEXT:
248  ret_code = SD_WRITE_BLOCKS_NEXT(buffer);
249  if (ret_code == 0) {
250  return DISKIO_SUCCESS;
251  } else {
252  return DISKIO_ERROR_INTERNAL_ERROR;
253  }
254  break;
255 
256  case DISKIO_OP_WRITE_BLOCKS_DONE:
257  ret_code = SD_WRITE_BLOCKS_DONE();
258  if (ret_code == 0) {
259  return DISKIO_SUCCESS;
260  } else {
261  return DISKIO_ERROR_INTERNAL_ERROR;
262  }
263  break;
264 
265  default:
266  return DISKIO_ERROR_OPERATION_NOT_SUPPORTED;
267  break;
268  }
269  break;
270 #endif /* SD_INIT */
271 
272 #ifdef FLASH_INIT
273  case DISKIO_DEVICE_TYPE_GENERIC_FLASH:
274  switch (op) {
275  case DISKIO_OP_READ_BLOCK:
276  FLASH_READ_BLOCK(block_start_address, 0, buffer, 512);
277  return DISKIO_SUCCESS;
278  break;
279  case DISKIO_OP_READ_BLOCKS:
280  return DISKIO_ERROR_TO_BE_IMPLEMENTED;
281  break;
282  case DISKIO_OP_WRITE_BLOCK:
283  FLASH_WRITE_BLOCK(block_start_address, 0, buffer, 512);
284  return DISKIO_SUCCESS;
285  break;
286  // fake multi block write
287  case DISKIO_OP_WRITE_BLOCKS_START:
288  if (multi_block_nr != 0) {
289  return DISKIO_ERROR_INTERNAL_ERROR;
290  }
291  multi_block_nr = block_start_address;
292  return DISKIO_SUCCESS;
293  break;
294  case DISKIO_OP_WRITE_BLOCKS_NEXT:
295  FLASH_WRITE_BLOCK(multi_block_nr, 0, buffer, 512);
296  multi_block_nr++;
297  return DISKIO_SUCCESS;
298  case DISKIO_OP_WRITE_BLOCKS_DONE:
299  multi_block_nr = 0;
300  return DISKIO_SUCCESS;
301  break;
302  default:
303  return DISKIO_ERROR_OPERATION_NOT_SUPPORTED;
304  break;
305  }
306  break;
307 #endif /* FLASH_INIT */
308 
310  default:
311  return DISKIO_ERROR_NO_DEVICE_SELECTED;
312  }
313  return DISKIO_SUCCESS;
314 }
315 /*----------------------------------------------------------------------------*/
316 void
318 {
319  default_device = dev;
320 }
321 /*----------------------------------------------------------------------------*/
322 struct diskio_device_info *
324 {
325  return devices;
326 }
327 /*----------------------------------------------------------------------------*/
328 int
330 {
331  struct mbr mbr;
332  int dev_num = 0;
333  int i = 0, index = 0;
334 
335  memset(devices, 0, DISKIO_MAX_DEVICES * sizeof (struct diskio_device_info));
336 
337 /** @todo Place definitions at proper position */
338 #ifndef FLASH_ARCH_NUM_SECTORS
339  /* This Flash has 4096 Pages */
340 #define FLASH_ARCH_NUM_SECTORS 4096
341 #endif
342 #ifndef FLASH_ARCH_SECTOR_SIZE
343  /* A Page is 528 Bytes long, but for easier access we use only 512 Byte*/
344 #define FLASH_ARCH_SECTOR_SIZE 512
345 #endif
346 
347 #ifdef FLASH_INIT
348  if (FLASH_INIT() == 0) {
349  devices[index].type = DISKIO_DEVICE_TYPE_GENERIC_FLASH;
350  devices[index].number = dev_num;
351  devices[index].num_sectors = FLASH_ARCH_NUM_SECTORS;
352  devices[index].sector_size = FLASH_ARCH_SECTOR_SIZE;
353  devices[index].first_sector = 0;
354  index += 1;
355  }
356 #endif /* FLASH_INIT */
357 
358 #ifdef SD_INIT
359  if (SD_INIT() == 0) {
360  devices[index].type = DISKIO_DEVICE_TYPE_SD_CARD;
361  devices[index].number = dev_num;
362  devices[index].num_sectors = SD_GET_BLOCK_NUM();
363  devices[index].sector_size = SD_GET_BLOCK_SIZE();
364  devices[index].first_sector = 0;
365  if (devices[index].sector_size > DISKIO_MAX_SECTOR_SIZE) {
366  goto end_of_function;
367  }
368 
369  mbr_init(&mbr);
370  mbr_read(&devices[index], &mbr);
371  index += 1;
372  // test for max 5 partitions
373  for (i = 0; i < 4; ++i) {
374  if (mbr_hasPartition(&mbr, i + 1) != 0) {
375  devices[index].type = DISKIO_DEVICE_TYPE_SD_CARD | DISKIO_DEVICE_TYPE_PARTITION;
376  devices[index].number = dev_num;
377  devices[index].partition = i + 1;
378  devices[index].num_sectors = mbr.partition[i].lba_num_sectors;
379  devices[index].sector_size = devices[dev_num].sector_size;
380  devices[index].first_sector = mbr.partition[i].lba_first_sector;
381  index += 1;
382  }
383  }
384 
385  dev_num += 1;
386  index += 1;
387  }
388 #endif /* SD_INIT */
389 
390 end_of_function:
391 
392  if (index == 0) {
393  return DISKIO_FAILURE;
394  }
395 
396  return DISKIO_SUCCESS;
397 }