added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / libs / partition / partitionmbr.c
blob6242a1f7507861cf80ac82fb5f52e9db62fb91b8
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 */
7 #include <proto/exec.h>
8 #include <proto/partition.h>
10 #include <exec/memory.h>
11 #include <exec/types.h>
12 #include <libraries/partition.h>
14 #include "partition_support.h"
15 #include "partitionmbr.h"
16 #include "platform.h"
18 #ifndef DEBUG
19 #define DEBUG 1
20 #endif
21 #include "debug.h"
23 struct MBRData {
24 struct PCPartitionTable *entry;
25 UBYTE position;
28 static LONG PartitionMBRCheckPartitionTable
30 struct Library *PartitionBase,
31 struct PartitionHandle *root
34 struct MBR mbr;
36 if (readBlock(PartitionBase, root, 0, &mbr) == 0)
38 if (
39 (AROS_LE2WORD(mbr.magic) == 0xAA55) &&
40 (((mbr.pcpt[0].status & 0x0F)==0) || (mbr.pcpt[0].status & 0x80)) &&
41 (((mbr.pcpt[1].status & 0x0F)==0) || (mbr.pcpt[1].status & 0x80)) &&
42 (((mbr.pcpt[2].status & 0x0F)==0) || (mbr.pcpt[2].status & 0x80)) &&
43 (((mbr.pcpt[3].status & 0x0F)==0) || (mbr.pcpt[3].status & 0x80))
46 if (root->root)
48 return 0;
50 return 1;
53 return 0;
56 static struct PartitionHandle *PartitionMBRNewHandle
58 struct Library *PartitionBase,
59 struct PartitionHandle *root,
60 UBYTE position,
61 struct PCPartitionTable *entry
64 struct PartitionHandle *ph;
65 ULONG cylsecs;
67 if (entry->first_sector != 0)
69 ph = AllocMem(sizeof(struct PartitionHandle), MEMF_PUBLIC | MEMF_CLEAR);
70 if (ph)
72 struct MBRData *data;
74 data = AllocMem(sizeof(struct MBRData), MEMF_PUBLIC);
75 if (data)
77 cylsecs = root->de.de_BlocksPerTrack*root->de.de_Surfaces;
78 data->entry = entry;
79 data->position = position;
80 ph->root = root;
81 ph->bd = root->bd;
82 ph->data = data;
84 /* initialize DosEnvec */
86 /* Check if partition starts and ends on a cylinder boundary */
87 CopyMem(&root->de, &ph->de, sizeof(struct DosEnvec));
88 if (
89 (AROS_LE2LONG(data->entry->first_sector) % cylsecs != 0) ||
90 (AROS_LE2LONG(data->entry->count_sector) % cylsecs != 0)
93 /* Treat each track as a cylinder if possible */
94 ph->de.de_Surfaces = 1;
95 cylsecs = ph->de.de_BlocksPerTrack*ph->de.de_Surfaces;
96 if (
97 (AROS_LE2LONG(data->entry->first_sector) % cylsecs != 0) ||
98 (AROS_LE2LONG(data->entry->count_sector) % cylsecs != 0)
101 /* We can't. We could find the highest common factor of
102 first_sector and count_sector here, but currently we
103 simply use one block per cylinder */
104 ph->de.de_BlocksPerTrack = 1;
105 cylsecs = ph->de.de_BlocksPerTrack*ph->de.de_Surfaces;
108 ph->de.de_LowCyl = AROS_LE2LONG(data->entry->first_sector) / cylsecs;
109 ph->de.de_HighCyl =
110 ph->de.de_LowCyl+
111 (AROS_LE2LONG(data->entry->count_sector)/cylsecs)-1;
112 ph->de.de_TableSize = 10; // only until de_HighCyl
113 ph->ln.ln_Pri = MBR_MAX_PARTITIONS-1-position;
115 /* initialize DriveGeometry */
116 ph->dg.dg_DeviceType = DG_DIRECT_ACCESS;
117 ph->dg.dg_SectorSize = ph->de.de_SizeBlock<<2;
118 ph->dg.dg_Heads = ph->de.de_Surfaces;
119 ph->dg.dg_TrackSectors = ph->de.de_BlocksPerTrack;
120 ph->dg.dg_Cylinders = ph->de.de_HighCyl - ph->de.de_LowCyl + 1;
121 ph->dg.dg_BufMemType = ph->de.de_BufMemType;
122 return ph;
124 FreeMem(ph, sizeof(struct PartitionHandle));
127 return NULL;
130 static LONG PartitionMBROpenPartitionTable
132 struct Library *PartitionBase,
133 struct PartitionHandle *root
136 struct PartitionHandle *ph;
137 struct MBR *mbr;
138 UBYTE i;
140 mbr = AllocMem(root->de.de_SizeBlock<<2, MEMF_PUBLIC);
141 if (mbr)
143 if (readBlock(PartitionBase, root, 0, mbr) == 0)
145 NEWLIST(&root->table->list);
146 root->table->data = mbr;
147 for (i=0;i<4;i++)
149 ph = PartitionMBRNewHandle(PartitionBase, root, i, &mbr->pcpt[i]);
150 if (ph != NULL)
151 Enqueue(&root->table->list, &ph->ln);
153 return 0;
155 FreeMem(mbr, root->de.de_SizeBlock<<2);
157 return 1;
160 static void PartitionMBRFreeHandle
162 struct Library *PartitionBase,
163 struct PartitionHandle *ph
166 ClosePartitionTable(ph);
167 FreeMem(ph->data, sizeof(struct MBRData));
168 FreeMem(ph, sizeof(struct PartitionHandle));
171 static void PartitionMBRClosePartitionTable
173 struct Library *PartitionBase,
174 struct PartitionHandle *root
177 struct PartitionHandle *ph;
179 while ((ph = (struct PartitionHandle *)RemTail(&root->table->list)))
180 PartitionMBRFreeHandle(PartitionBase, ph);
181 FreeMem(root->table->data, root->de.de_SizeBlock<<2);
184 static LONG PartitionMBRWritePartitionTable
186 struct Library *PartitionBase,
187 struct PartitionHandle *root
190 #warning "FIXME: readBlock(0) and synchronize data"
192 /* root->data = mbr is up to date */
193 if (writeBlock(PartitionBase, root, 0, root->table->data))
194 return 1;
195 return 0;
198 static LONG PartitionMBRCreatePartitionTable
200 struct Library *PartitionBase,
201 struct PartitionHandle *ph
204 struct MBR *mbr;
206 mbr = AllocMem(ph->de.de_SizeBlock<<2, MEMF_PUBLIC);
207 if (mbr)
209 if (readBlock(PartitionBase, ph, 0, mbr) == 0)
211 ph->table->data = mbr;
212 fillMem((BYTE *)mbr->pcpt, sizeof(mbr->pcpt), 0);
213 mbr->magic = AROS_WORD2LE(0xAA55);
214 NEWLIST(&ph->table->list);
215 return 0;
217 FreeMem(mbr, ph->de.de_SizeBlock<<2);
219 return 1;
222 void PartitionMBRSetGeometry
224 struct PartitionHandle *root,
225 struct PCPartitionTable *entry,
226 ULONG sector,
227 ULONG count,
228 ULONG relative_sector
231 ULONG track;
232 ULONG cyl;
234 /* Store LBA start block and block count */
236 entry->first_sector = AROS_LONG2LE(sector - relative_sector);
237 entry->count_sector = AROS_LONG2LE(count);
239 /* Store CHS-address of start block. The upper two bits of the cylinder
240 number are stored in the upper two bits of the sector field */
242 track = sector/root->de.de_BlocksPerTrack;
243 cyl = track/root->de.de_Surfaces;
244 if (cyl<1024)
246 entry->start_head = track % root->de.de_Surfaces;
247 entry->start_sector =
248 ((sector % root->de.de_BlocksPerTrack) + 1)
249 | ((cyl & 0x300) >> 2);
250 entry->start_cylinder = (cyl & 0xFF);
252 else
254 entry->start_head = 0xFE;
255 entry->start_sector = 0xFF;
256 entry->start_cylinder = 0xFF;
259 /* Store CHS-address of last block */
261 sector += count - 1;
262 track = sector/root->de.de_BlocksPerTrack;
263 cyl = track/root->de.de_Surfaces;
264 if (cyl<1024)
266 entry->end_head = track % root->de.de_Surfaces;
267 entry->end_sector = ((sector % root->de.de_BlocksPerTrack) + 1)
268 | ((cyl & 0x300)>>2);
269 entry->end_cylinder = (cyl & 0xFF);
271 else
273 entry->end_head = 0xFE;
274 entry->end_sector = 0xFF;
275 entry->end_cylinder = 0xFF;
279 static void PartitionMBRSetDosEnvec
281 struct PartitionHandle *root,
282 struct PCPartitionTable *entry,
283 struct DosEnvec *de
286 ULONG sector, count;
288 sector = de->de_LowCyl * de->de_Surfaces * de->de_BlocksPerTrack;
289 count = (de->de_HighCyl - de->de_LowCyl + 1) *
290 de->de_Surfaces *
291 de->de_BlocksPerTrack;
292 PartitionMBRSetGeometry(root, entry, sector, count, 0);
295 static struct PartitionHandle *PartitionMBRAddPartition
297 struct Library *PartitionBase,
298 struct PartitionHandle *root,
299 struct TagItem *taglist
302 struct TagItem *tag;
304 tag = findTagItem(PT_DOSENVEC, taglist);
305 if (tag)
307 struct PCPartitionTable *entry;
308 struct PartitionHandle *ph;
309 struct DosEnvec *de;
310 WORD pos = -1, i;
312 de = (struct DosEnvec *)tag->ti_Data;
313 tag = findTagItem(PT_POSITION, taglist);
314 if (tag != NULL)
315 pos = tag->ti_Data;
316 else
318 // Find an unused slot
319 for (i = 0; i < MBR_MAX_PARTITIONS && pos == -1; i++)
321 entry = &((struct MBR *)root->table->data)->pcpt[i];
322 if (entry->type == 0)
323 pos = i;
327 if (pos != -1)
329 entry = &((struct MBR *)root->table->data)->pcpt[pos];
330 tag = findTagItem(PT_ACTIVE, taglist);
331 if (tag)
332 entry->status = tag->ti_Data ? 0x80 : 0;
333 else
334 entry->status = 0;
335 tag = findTagItem(PT_TYPE, taglist);
336 if (tag)
338 struct PartitionType *ptype = (struct PartitionType *)tag->ti_Data;
340 entry->type = ptype->id[0];
342 else
343 entry->type = 0;
344 PartitionMBRSetDosEnvec(root, entry, de);
345 ph = PartitionMBRNewHandle(PartitionBase, root, pos, entry);
346 if (ph != NULL)
347 Enqueue(&root->table->list, &ph->ln);
348 else
349 fillMem((BYTE *)entry, sizeof(struct PCPartitionTable), 0);
350 return ph;
353 return NULL;
356 static void PartitionMBRDeletePartition
358 struct Library *PartitionBase,
359 struct PartitionHandle *ph
362 struct MBRData *data;
364 data = (struct MBRData *)ph->data;
365 fillMem((BYTE *)data->entry, sizeof(struct PCPartitionTable), 0);
366 Remove(&ph->ln);
367 PartitionMBRFreeHandle(PartitionBase, ph);
370 static LONG PartitionMBRGetPartitionTableAttrs
372 struct Library *PartitionBase,
373 struct PartitionHandle *root,
374 struct TagItem *taglist
378 while (taglist[0].ti_Tag != TAG_DONE)
381 switch (taglist[0].ti_Tag)
383 case PTT_TYPE:
384 *((LONG *)taglist[0].ti_Data) = root->table->type;
385 break;
386 case PTT_RESERVED:
387 *((LONG *)taglist[0].ti_Data) =
388 root->de.de_BlocksPerTrack; /* One track */
389 break;
390 case PTT_MAX_PARTITIONS:
391 *((LONG *)taglist[0].ti_Data) = MBR_MAX_PARTITIONS;
393 taglist++;
395 return 0;
398 static LONG PartitionMBRSetPartitionTableAttrs
400 struct Library *PartitionBase,
401 struct PartitionHandle *root,
402 struct TagItem *taglist
406 while (taglist[0].ti_Tag != TAG_DONE)
409 switch (taglist[0].ti_Tag)
412 taglist++;
414 return 0;
417 static LONG PartitionMBRGetPartitionAttrs
419 struct Library *PartitionBase,
420 struct PartitionHandle *ph,
421 struct TagItem *taglist
425 while (taglist[0].ti_Tag != TAG_DONE)
427 struct MBRData *data = (struct MBRData *)ph->data;
429 switch (taglist[0].ti_Tag)
431 case PT_GEOMETRY:
433 struct DriveGeometry *dg = (struct DriveGeometry *)taglist[0].ti_Data;
434 CopyMem(&ph->dg, dg, sizeof(struct DriveGeometry));
436 break;
437 case PT_DOSENVEC:
438 CopyMem(&ph->de, (struct DosEnvec *)taglist[0].ti_Data, sizeof(struct DosEnvec));
439 break;
440 case PT_TYPE:
442 struct PartitionType *ptype=(struct PartitionType *)taglist[0].ti_Data;
444 ptype->id[0] = (LONG)data->entry->type;
445 ptype->id_len = 1;
447 break;
448 case PT_POSITION:
449 *((LONG *)taglist[0].ti_Data) = (LONG)data->position;
450 break;
451 case PT_ACTIVE:
452 *((LONG *)taglist[0].ti_Data) = data->entry->status & 0x80 ? 1 : 0;
453 break;
455 taglist++;
457 return 0;
460 static LONG PartitionMBRSetPartitionAttrs
462 struct Library *PartitionBase,
463 struct PartitionHandle *ph,
464 struct TagItem *taglist
468 while (taglist[0].ti_Tag != TAG_DONE)
470 struct MBRData *data = (struct MBRData *)ph->data;
472 switch (taglist[0].ti_Tag)
474 case PT_DOSENVEC:
476 struct DosEnvec *de;
477 de = (struct DosEnvec *)taglist[0].ti_Data;
478 CopyMem(de, &ph->de, sizeof(struct DosEnvec));
479 PartitionMBRSetDosEnvec(ph->root, data->entry, de);
481 break;
482 case PT_TYPE:
484 struct PartitionType *ptype=(struct PartitionType *)taglist[0].ti_Data;
486 data->entry->type = ptype->id[0];
488 break;
489 case PT_POSITION:
490 if (taglist[0].ti_Data != data->position)
492 struct PartitionHandle *node;
493 struct PCPartitionTable *entry;
495 node = (struct PartitionHandle *)ph->root->table->list.lh_Head;
496 while (node->ln.ln_Succ)
498 if (taglist[0].ti_Data == ((struct MBRData *)node->data)->position)
499 goto posbreak;
500 node = (struct PartitionHandle *)node->ln.ln_Succ;
502 data->position = taglist[0].ti_Data;
503 entry = &((struct MBR *)ph->root->table->data)->pcpt[data->position];
504 CopyMem(data->entry, entry, sizeof(struct PCPartitionTable));
505 fillMem((BYTE *)data->entry, sizeof(struct PCPartitionTable), 0);
506 data->entry = entry;
507 ph->ln.ln_Pri = MBR_MAX_PARTITIONS-1-data->position;
508 Remove(&ph->ln);
509 Enqueue(&ph->root->table->list, &ph->ln);
510 posbreak:
513 break;
514 case PT_ACTIVE:
515 if (taglist[0].ti_Data)
516 data->entry->status |= 0x80;
517 else
518 data->entry->status &= ~0x80;
519 break;
521 taglist++;
523 return 0;
526 static struct PartitionAttribute PartitionMBRPartitionTableAttrs[]=
528 {PTTA_TYPE, PLAM_READ},
529 {PTTA_RESERVED, PLAM_READ},
530 {PTTA_MAX_PARTITIONS, PLAM_READ},
531 {PTTA_DONE, 0}
534 static struct PartitionAttribute *PartitionMBRQueryPartitionTableAttrs(struct Library *PartitionBase)
536 return PartitionMBRPartitionTableAttrs;
539 static struct PartitionAttribute PartitionMBRPartitionAttrs[]=
541 {PTA_GEOMETRY, PLAM_READ},
542 {PTA_TYPE, PLAM_READ | PLAM_WRITE},
543 {PTA_POSITION, PLAM_READ | PLAM_WRITE},
544 {PTA_ACTIVE, PLAM_READ | PLAM_WRITE},
545 {PTA_DONE, 0}
548 struct PartitionAttribute *PartitionMBRQueryPartitionAttrs(struct Library *PartitionBase)
550 return PartitionMBRPartitionAttrs;
553 static ULONG PartitionMBRDestroyPartitionTable
555 struct Library *PartitionBase,
556 struct PartitionHandle *root
559 struct MBR *mbr;
561 mbr = root->table->data;
562 fillMem((BYTE *)mbr->pcpt, sizeof(mbr->pcpt), 0);
563 if (writeBlock(PartitionBase, root, 0, root->table->data))
564 return 1;
565 return 0;
568 struct PTFunctionTable PartitionMBR =
570 PHPTT_MBR,
571 "PC-MBR",
572 PartitionMBRCheckPartitionTable,
573 PartitionMBROpenPartitionTable,
574 PartitionMBRClosePartitionTable,
575 PartitionMBRWritePartitionTable,
576 PartitionMBRCreatePartitionTable,
577 PartitionMBRAddPartition,
578 PartitionMBRDeletePartition,
579 PartitionMBRGetPartitionTableAttrs,
580 PartitionMBRSetPartitionTableAttrs,
581 PartitionMBRGetPartitionAttrs,
582 PartitionMBRSetPartitionAttrs,
583 PartitionMBRQueryPartitionTableAttrs,
584 PartitionMBRQueryPartitionAttrs,
585 PartitionMBRDestroyPartitionTable