1 //==========================================================================
5 // High level disk driver
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003 Savin Zlobec
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
43 // Purpose: Top level disk driver
46 //####DESCRIPTIONEND####
48 //==========================================================================
50 #include <pkgconf/io.h>
51 #include <pkgconf/io_disk.h>
53 #include <cyg/io/io.h>
54 #include <cyg/io/devtab.h>
55 #include <cyg/io/disk.h>
56 #include <cyg/infra/cyg_ass.h> // assertion support
57 #include <cyg/infra/diag.h> // diagnostic output
59 // ---------------------------------------------------------------------------
64 # define D(_args_) diag_printf _args_
69 // ---------------------------------------------------------------------------
71 // Master Boot Record defines
72 #define MBR_SIG_ADDR 0x1FE // signature address
73 #define MBR_SIG_BYTE0 0x55 // signature first byte value
74 #define MBR_SIG_BYTE1 0xAA // signature second byte value
75 #define MBR_PART_ADDR 0x1BE // first partition address
76 #define MBR_PART_SIZE 0x10 // partition size
77 #define MBR_PART_NUM 4 // number of partitions
79 // Get cylinders, heads and sectors from data (MBR partition format)
80 #define READ_CHS(_data_, _c_, _h_, _s_) \
82 _h_ = (*((cyg_uint8 *)_data_)); \
83 _s_ = (*(((cyg_uint8 *)_data_)+1) & 0x3F); \
84 _c_ = (*(((cyg_uint8 *)_data_)+1) & ~0x3F) << 2 | \
85 (*(((cyg_uint8 *)_data_)+2)); \
88 // Get double word from data (MBR partition format)
89 #define READ_DWORD(_data_, _val_) \
91 _val_ = *((cyg_uint8 *)_data_) | \
92 *(((cyg_uint8 *)_data_)+1) << 8 | \
93 *(((cyg_uint8 *)_data_)+2) << 16 | \
94 *(((cyg_uint8 *)_data_)+3) << 24; \
97 // Convert cylinders, heads and sectors to LBA sectors
98 #define CHS_TO_LBA(_info_, _c_, _h_, _s_, _lba_) \
99 (_lba_=(((_c_)*(_info_)->heads_num+(_h_))*(_info_)->sectors_num)+(_s_)-1)
101 // ---------------------------------------------------------------------------
103 static Cyg_ErrNo disk_bread(cyg_io_handle_t handle,
108 static Cyg_ErrNo disk_bwrite(cyg_io_handle_t handle,
113 static Cyg_ErrNo disk_select(cyg_io_handle_t handle,
117 static Cyg_ErrNo disk_get_config(cyg_io_handle_t handle,
122 static Cyg_ErrNo disk_set_config(cyg_io_handle_t handle,
127 BLOCK_DEVIO_TABLE(cyg_io_disk_devio,
135 static cyg_bool disk_init(struct cyg_devtab_entry *tab);
137 static Cyg_ErrNo disk_connected(struct cyg_devtab_entry *tab,
138 cyg_disk_identify_t *ident);
140 static Cyg_ErrNo disk_disconnected(struct cyg_devtab_entry *tab);
142 static Cyg_ErrNo disk_lookup(struct cyg_devtab_entry **tab,
143 struct cyg_devtab_entry *sub_tab,
146 DISK_CALLBACKS(cyg_io_disk_callbacks,
153 // ---------------------------------------------------------------------------
156 // Read partition from data
159 read_partition(cyg_uint8 *data,
160 cyg_disk_info_t *info,
161 cyg_disk_partition_t *part)
165 part->type = data[4];
166 part->state = data[0];
168 READ_CHS(&data[1], c, h, s);
169 CHS_TO_LBA(&info->ident, c, h, s, part->start);
171 READ_CHS(&data[5], c, h, s);
172 CHS_TO_LBA(&info->ident, c, h, s, part->end);
174 READ_DWORD(&data[12], part->size);
178 // Read Master Boot Record (partitions)
181 read_mbr(disk_channel *chan)
183 cyg_disk_info_t *info = chan->info;
184 disk_funs *funs = chan->funs;
186 Cyg_ErrNo res = ENOERR;
189 for (i = 0; i < info->partitions_num; i++)
190 info->partitions[i].type = 0x00;
192 res = (funs->read)(chan, (void *)buf, 512, 0);
196 if (MBR_SIG_BYTE0 == buf[MBR_SIG_ADDR+0] && MBR_SIG_BYTE1 == buf[MBR_SIG_ADDR+1])
200 D(("disk MBR found\n"));
202 npart = info->partitions_num < MBR_PART_NUM ?
203 info->partitions_num : MBR_PART_NUM;
205 for (i = 0; i < npart; i++)
207 cyg_disk_partition_t *part = &info->partitions[i];
209 read_partition(&buf[MBR_PART_ADDR+MBR_PART_SIZE*i], info, part);
211 if (0x00 != part->type)
213 D(("\ndisk MBR partition %d:\n", i));
214 D((" type = %02X\n", part->type));
215 D((" state = %02X\n", part->state));
216 D((" start = %d\n", part->start));
217 D((" end = %d\n", part->end));
218 D((" size = %d\n\n", part->size));
227 disk_init(struct cyg_devtab_entry *tab)
229 disk_channel *chan = (disk_channel *) tab->priv;
230 cyg_disk_info_t *info = chan->info;
235 info->connected = false;
237 // clear partition data
238 for (i = 0; i < info->partitions_num; i++)
239 info->partitions[i].type = 0x00;
247 disk_connected(struct cyg_devtab_entry *tab,
248 cyg_disk_identify_t *ident)
250 disk_channel *chan = (disk_channel *) tab->priv;
251 cyg_disk_info_t *info = chan->info;
252 Cyg_ErrNo res = ENOERR;
257 info->ident = *ident;
258 info->block_size = 512;
259 info->blocks_num = ident->lba_sectors_num;
261 D(("disk connected\n"));
262 D((" serial = '%s'\n", ident->serial));
263 D((" firmware rev = '%s'\n", ident->firmware_rev));
264 D((" model num = '%s'\n", ident->model_num));
265 D((" block_size = %d\n", info->block_size));
266 D((" blocks_num = %d\n", info->blocks_num));
268 if (chan->mbr_support)
270 // read disk master boot record
271 res = read_mbr(chan);
276 // now declare that we are connected
277 info->connected = true;
284 disk_disconnected(struct cyg_devtab_entry *tab)
286 disk_channel *chan = (disk_channel *) tab->priv;
287 cyg_disk_info_t *info = chan->info;
293 info->connected = false;
296 // clear partition data and invalidate partition devices
297 for (i = 0; i < info->partitions_num; i++)
299 info->partitions[i].type = 0x00;
300 chan->pdevs_chan[i].valid = false;
304 D(("disk disconnected\n"));
310 disk_lookup(struct cyg_devtab_entry **tab,
311 struct cyg_devtab_entry *sub_tab,
314 disk_channel *chan = (disk_channel *) (*tab)->priv;
315 cyg_disk_info_t *info = chan->info;
316 struct cyg_devtab_entry *new_tab;
317 disk_channel *new_chan;
320 if (!info->connected)
325 while ('\0' != *name)
327 if (*name < '0' || *name > '9')
330 dev_num = 10 * dev_num + (*name - '0');
334 if (dev_num > info->partitions_num)
337 D(("disk lookup dev number = %d\n", dev_num));
341 // 0 is the root device number
344 if (0x00 == info->partitions[dev_num-1].type)
346 D(("disk NO partition for dev\n"));
350 new_tab = &chan->pdevs_dev[dev_num-1];
351 new_chan = &chan->pdevs_chan[dev_num-1];
353 // copy device data from parent
357 new_tab->priv = (void *)new_chan;
360 new_chan->partition = &info->partitions[dev_num-1];
368 // ---------------------------------------------------------------------------
371 disk_bread(cyg_io_handle_t handle,
376 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *) handle;
377 disk_channel *chan = (disk_channel *) t->priv;
378 disk_funs *funs = chan->funs;
379 cyg_disk_info_t *info = chan->info;
380 cyg_uint32 size = *len;
381 cyg_uint8 *bbuf = (cyg_uint8 *)buf;
382 Cyg_ErrNo res = ENOERR;
385 if (!info->connected || !chan->valid)
388 if (NULL != chan->partition)
390 pos += chan->partition->start;
391 last = chan->partition->end;
395 last = info->blocks_num-1;
398 D(("disk read block=%d len=%d buf=%p\n", pos, *len, buf));
408 res = (funs->read)(chan, (void*)bbuf, info->block_size, pos);
412 if (!info->connected)
418 bbuf += info->block_size;
426 // ---------------------------------------------------------------------------
429 disk_bwrite(cyg_io_handle_t handle,
434 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *) handle;
435 disk_channel *chan = (disk_channel *) t->priv;
436 disk_funs *funs = chan->funs;
437 cyg_disk_info_t *info = chan->info;
438 cyg_uint32 size = *len;
439 cyg_uint8 *bbuf = (cyg_uint8 * const) buf;
440 Cyg_ErrNo res = ENOERR;
443 if (!info->connected || !chan->valid)
446 if (NULL != chan->partition)
448 pos += chan->partition->start;
449 last = chan->partition->end;
453 last = info->blocks_num-1;
456 D(("disk write block=%d len=%d buf=%p\n", pos, *len, buf));
466 res = (funs->write)(chan, (void*)bbuf, info->block_size, pos);
470 if (!info->connected)
476 bbuf += info->block_size;
484 // ---------------------------------------------------------------------------
487 disk_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
489 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *) handle;
490 disk_channel *chan = (disk_channel *) t->priv;
491 cyg_disk_info_t *cinfo = chan->info;
493 if (!cinfo->connected || !chan->valid)
499 // ---------------------------------------------------------------------------
502 disk_get_config(cyg_io_handle_t handle,
507 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *) handle;
508 disk_channel *chan = (disk_channel *) t->priv;
509 cyg_disk_info_t *info = chan->info;
510 cyg_disk_info_t *buf = (cyg_disk_info_t *) xbuf;
511 disk_funs *funs = chan->funs;
512 Cyg_ErrNo res = ENOERR;
514 if (!info->connected || !chan->valid)
517 D(("disk get config key=%d\n", key));
520 case CYG_IO_GET_CONFIG_DISK_INFO:
521 if (*len < sizeof(cyg_disk_info_t)) {
525 *len = sizeof(cyg_disk_info_t);
529 // pass down to lower layers
530 res = (funs->get_config)(chan, key, xbuf, len);
536 // ---------------------------------------------------------------------------
539 disk_set_config(cyg_io_handle_t handle,
544 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *) handle;
545 disk_channel *chan = (disk_channel *) t->priv;
546 cyg_disk_info_t *info = chan->info;
547 disk_funs *funs = chan->funs;
549 if (!info->connected || !chan->valid)
552 D(("disk set config key=%d\n", key));
554 // pass down to lower layers
555 return (funs->set_config)(chan, key, xbuf, len);
558 // ---------------------------------------------------------------------------