summaryrefslogtreecommitdiff
path: root/sys/arch/amiga/stand/device-streams/getdevices.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/amiga/stand/device-streams/getdevices.c')
-rw-r--r--sys/arch/amiga/stand/device-streams/getdevices.c326
1 files changed, 326 insertions, 0 deletions
diff --git a/sys/arch/amiga/stand/device-streams/getdevices.c b/sys/arch/amiga/stand/device-streams/getdevices.c
new file mode 100644
index 00000000000..0a56d0d078d
--- /dev/null
+++ b/sys/arch/amiga/stand/device-streams/getdevices.c
@@ -0,0 +1,326 @@
+/* --------------------------------------------------
+ | NAME
+ | getdevices
+ | PURPOSE
+ | build a drive list from RDB from exec.device's
+ | found on the Dos list.
+ | NOTES
+ | This code relies on peoples hard drive controllers
+ | working properly. I used similar code in some
+ | cross dos configuration code and it seemed to
+ | lock some amiga controllers up when it polled
+ | each unit. I don't wish to do all the checks
+ | I did then, so if your controller is one of these
+ | types (you'll find out I guess) sorry.
+ |
+ | known working types:
+ | ----------------------
+ | scsi.device.
+ | gvpscsi.device.
+ |
+ | COPYRIGHT
+ | Copyright (C) 1993 Christian E. Hopps
+ |
+ | This program is free software; you can redistribute it and/or modify
+ | it under the terms of the GNU General Public License as published by
+ | the Free Software Foundation; either version 2 of the License, or
+ | (at your option) any later version.
+ |
+ | This program is distributed in the hope that it will be useful,
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ | GNU General Public License for more details.
+ |
+ | You should have received a copy of the GNU General Public License
+ | along with this program; if not, write to the Free Software
+ | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ |
+ | HISTORY
+ | chopps - Oct 9, 1993: Created.
+ +--------------------------------------------------- */
+
+#include <dos/dos.h>
+#include <dos/dosextens.h>
+#include <dos/filehandler.h>
+#include <devices/hardblocks.h>
+#include <string.h>
+#include "util.h"
+#include "getdevices.h"
+
+struct List *
+get_drive_list (void)
+{
+ struct DosList *dl;
+ struct device *dev;
+
+ struct List *drive_list = zmalloc (sizeof (*drive_list));
+ if (drive_list == NULL) {
+ return (NULL);
+ }
+ NewList (drive_list);
+
+ D (debug_message ("Walking (LDF_READ|LDF_DEVICES) dos list."));
+ /* walk the dos list and fetch our device names. */
+ dl = LockDosList (LDF_DEVICES|LDF_READ); {
+ while (dl = NextDosEntry (dl,LDF_DEVICES)) {
+ char * name;
+
+ name = get_hard_drive_device_name (dl);
+ if (name) { /* if the drive has a device */
+ /* name. */
+ add_name_to_drive_list (drive_list, name);
+ }
+ }
+ } UnLockDosList (LDF_DEVICES);
+ D (debug_message ("done walking (LDF_READ|LDF_DEVICES) dos list."));
+
+ /* now get the units. */
+ dev = ptrfrom (struct device, node, drive_list->lh_Head);
+ while (dev->node.ln_Succ) {
+ ulong i;
+ for (i = 0; i < 7; i++) {
+ struct device_data *dd = alloc_device (dev->name, i, 0, sizeof (struct IOStdReq));
+ if (dd) {
+ /* we have a unit. */
+ do_unit (dev, dd);
+ free_device (dd);
+ }
+ }
+ dev = ptrfrom (struct device, node, dev->node.ln_Succ);
+ }
+ return (drive_list);
+}
+
+void
+free_drive_list (struct List *l)
+{
+ struct device *d = ptrfrom (struct device, node, l->lh_Head);
+ while (d->node.ln_Succ) {
+ struct Node *n;
+ struct device *next = ptrfrom (struct device, node, d->node.ln_Succ);
+ D (verbose_debug_message ("zfree()'ing \"%s\"", d->name));
+ while (n = RemHead (&d->units)) {
+ struct unit *u = ptrfrom (struct unit, node, n);
+ free_unit (u);
+ }
+ zfree (d->name); /* free name. */
+ zfree (d); /* free node. */
+ d = next;
+ }
+}
+
+/* this function returns an error or 0 for success. */
+/* -1 for NO MEM. */
+/* 1 for already on list */
+int
+add_name_to_drive_list (struct List *l, char *dev_name)
+{
+ if (!find_name (l,dev_name)) { /* not on list. */
+ struct device *d;
+
+ verbose_message ("found new device \"%s\"", dev_name);
+ d = zmalloc (sizeof (*d));
+ if (d) {
+ d->node.ln_Name = d->name = copy_string (dev_name);
+ NewList (&d->units);
+ if (d->name) {
+ AddTail (l, &d->node);
+ return (0);
+ }
+ zfree (d);
+ }
+ warn_message ("cannot allocate, unable to process \"%s\"",dev_name);
+ return (-1);
+ } else {
+ return (1);
+ }
+}
+
+
+char *
+get_hard_drive_device_name (struct DosList *dl)
+{
+ struct DeviceNode *dn = (struct DeviceNode *)dl;
+ if (dn->dn_Type == DLT_DEVICE) {
+ struct FileSysStartupMsg *m = BADDR (dn->dn_Startup);
+ D (debug_message ("checking dos device \"%b\" for info.", dl->dol_Name));
+ if (m && valid_mem (m)) {
+ ULONG *envec = BADDR (m->fssm_Environ);
+ char *name = BADDR (m->fssm_Device); /* null term bstring. */
+ name++; /* inc for bstring adj. */
+
+ if (valid_mem (envec) && valid_mem (name)) {
+ if (envec[DE_TABLESIZE] > DE_UPPERCYL) {
+ ulong dev_size = envec[DE_UPPERCYL] - envec[DE_LOWCYL] + 1;
+ dev_size *= envec[DE_NUMHEADS] * envec[DE_BLKSPERTRACK];
+ dev_size *= envec[DE_SIZEBLOCK] << 2;
+ if (dev_size > (1024*1024*2)) {
+ return (name); /* if larger than 2M */
+ }
+ }
+ } else {
+ D (verbose_debug_message ("\"%b\"'s startup message is non-standard.", dl->dol_Name));
+ }
+ } else {
+ D (verbose_debug_message ("\"%b\" has no startup message.", dl->dol_Name));
+ }
+ }
+ return (NULL);
+}
+
+ulong checksum (ulong sl, ulong *buf)
+{
+ ulong ck = 0;
+ while (sl--) {
+ ck += *buf++;
+ }
+ return (ck);
+}
+
+void
+do_unit (struct device *dev, struct device_data *dd)
+{
+ struct unit *u = zmalloc (sizeof (*u));
+ if (u) {
+ int i;
+ u->name = dev->name;
+ NewList (&u->parts);
+ u->unit = dd->unit;
+ u->flags = dd->flags;
+ u->rdb_at = (ulong)-1L;
+ u->rdb = zmalloc (512);
+ if (NULL == u->rdb) {
+ free_unit (u);
+ return;
+ }
+ /* scans the first 200 blocks for the RDB root. */
+ for (i = 0; i<200; i++) {
+ if (512 != device_read (dd, 512*i, 512, u->rdb)) {
+ verbose_message ("warn: unable to read \"%s\" unit: %ld flags 0x%lx",
+ dd->name, dd->unit, dd->flags);
+ free_unit (u);
+ return;
+ }
+ if (u->rdb->rdb_ID == IDNAME_RIGIDDISK) {
+ if (!checksum (u->rdb->rdb_SummedLongs, (ulong *)u->rdb)) {
+ u->rdb_at = i;
+ u->cylinders = u->rdb->rdb_Cylinders;
+ u->heads = u->rdb->rdb_Heads;
+ u->blocks_per_track = u->rdb->rdb_Sectors;
+ u->bytes_per_block = u->rdb->rdb_BlockBytes;
+ u->total_blocks = u->cylinders*u->heads*u->blocks_per_track;
+ verbose_message ("found drive %.8s %.16s %.4s [capacity:%ldM]"
+ "\n at unit %ld on device \"%s\"" ,
+ u->rdb->rdb_DiskVendor,
+ u->rdb->rdb_DiskProduct,
+ u->rdb->rdb_DiskRevision,
+ (u->total_blocks*u->bytes_per_block)/(1024*1024),
+ u->unit, u->name);
+ if (u->rdb->rdb_PartitionList != (ulong)~0) {
+ get_partitions (dd, u);
+ }
+ AddTail (&dev->units, &u->node);
+ break;
+ } else {
+ warn_message ("found RDB at %ld on unit %ld of \"%s\", failed checksum", i, u->unit, u->name);
+ break;
+ }
+ }
+ }
+ if (u->rdb_at == (ulong)-1L) {
+ verbose_message ("\"%s\" at unit: %ld has no RDB.", u->name, u->unit);
+ free_unit (u);
+ return;
+ }
+ }
+}
+
+void
+free_unit (struct unit *u)
+{
+ if (u) {
+ struct Node *n;
+ while (n = RemHead (&u->parts)) {
+ struct partition *p = ptrfrom (struct partition, node, n);
+ free_partition (p);
+ }
+ zfree (u->rdb);
+ zfree (u);
+ }
+}
+
+
+void
+get_partitions (struct device_data *dd, struct unit *u)
+{
+ ulong bpb = u->bytes_per_block;
+ struct PartitionBlock *pb = zmalloc (bpb);
+ if (pb) {
+ ulong partblock = u->rdb->rdb_PartitionList;
+ while (partblock != (ulong)~0) {
+ ulong nextpartblock = (ulong)~0;
+
+ if (bpb != device_read (dd, bpb*partblock, bpb, pb)) {
+ verbose_message ("warn: unable to read block: %ld from \"%s\" unit: %ld flags 0x%lx",
+ partblock, dd->name, dd->unit, dd->flags);
+ break;
+ }
+ if (pb->pb_ID == IDNAME_PARTITION) {
+ if (!checksum (pb->pb_SummedLongs, (ulong *)pb)) {
+ if (pb->pb_Environment[DE_TABLESIZE] > DE_UPPERCYL) {
+ struct partition *p = zmalloc (sizeof (struct partition));
+ if (p) {
+ ulong *e;
+ CopyMem (pb, &p->pb, sizeof (struct PartitionBlock));
+ e = p->pb.pb_Environment;
+ p->name = p->pb.pb_DriveName;
+ p->name[p->name[0]+1] = 0;
+ p->name++; /* adjust for size */
+ /* byte. */
+ p->node.ln_Name = p->name;
+ p->unit = u;
+ p->start_block = e[DE_LOWCYL]*e[DE_NUMHEADS]*e[DE_BLKSPERTRACK];
+ p->end_block = (e[DE_UPPERCYL]+1)*e[DE_NUMHEADS]*e[DE_BLKSPERTRACK] - 1;
+ p->total_blocks = p->end_block - p->start_block + 1;
+ p->block_size = e[DE_SIZEBLOCK] << 2;
+
+ /* the size stuff is convoluted to avoid overflow. */
+ verbose_message ("| partition: \"%s\" sb: %ld eb: %ld totb: %ld",
+ p->name, p->start_block,
+ p->end_block, p->total_blocks);
+ verbose_message ("| Block Size: %ld Capacity: %ld.%ldM",
+ p->block_size,
+ (p->block_size*p->total_blocks)/(1024*1024),
+ (10*((p->block_size*p->total_blocks)/(1024) % 1024))/1024);
+
+ nextpartblock = pb->pb_Next;
+ p->unit = u;
+ AddTail (&u->parts, &p->node);
+ } else {
+ warn_message ("failed to allocate memory for partition");
+ }
+ } else {
+ warn_message ("found PART at %ld on unit %ld of\"%s\",\n tablesize to small",
+ partblock, u->unit, u->name);
+ break;
+ }
+
+ } else {
+ warn_message ("found PART at %ld on unit %ld of \"%s\", failed checksum",
+ partblock, u->unit, u->name);
+ break;
+ }
+ }
+ partblock = nextpartblock;
+ }
+ zfree (pb);
+ }
+}
+
+void
+free_partition (struct partition *p)
+{
+ zfree (p);
+}
+
+