Indentation fix, cleanup.
[AROS.git] / arch / all-hosted / devs / hostdisk / hostdisk_device.c
blob3437bf76a49fb9db85779d234ffffc0978d019d4
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /****************************************************************************************/
8 #define DEBUG 0
9 #define DCMD(x)
10 #define DOPEN(x)
11 #define DREAD(x)
12 #define DWRITE(x)
13 /* #define DUMP_DATA */
15 #include <aros/debug.h>
16 #include <aros/symbolsets.h>
17 #include <devices/trackdisk.h>
18 #include <devices/newstyle.h>
19 #include <exec/errors.h>
20 #include <exec/rawfmt.h>
21 #include <proto/dos.h>
22 #include <proto/exec.h>
23 #include <proto/hostlib.h>
25 #include LC_LIBDEFS_FILE
27 /****************************************************************************************/
29 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR hdskBase)
31 HostLibBase = OpenResource("hostlib.resource");
32 D(bug("hostdisk: HostLibBase: 0x%p\n", HostLibBase));
33 if (!HostLibBase)
34 return FALSE;
36 InitSemaphore(&hdskBase->sigsem);
37 NEWLIST(&hdskBase->units);
39 D(bug("hostdisk: in libinit func. Returning %x (success) :-)\n", hdskBase));
40 return TRUE;
43 static int HostDisk_Cleanup(struct HostDiskBase *hdskBase)
45 D(bug("hostdisk: Expunge(0x%p)\n", hdskBase));
47 if (!HostLibBase)
48 return TRUE;
50 if (hdskBase->iface)
51 HostLib_DropInterface((APTR *)hdskBase->iface);
53 if (hdskBase->KernelHandle)
54 HostLib_Close(hdskBase->KernelHandle, NULL);
56 return TRUE;
59 /****************************************************************************************/
61 static void unitentry(struct IOExtTD *iotd);
63 static void freeUnit(struct unit *unit)
65 if (unit->flags & UNIT_FREENAME)
66 FreeVec(unit->n.ln_Name);
68 FreeMem(unit, sizeof(struct unit));
71 /****************************************************************************************/
73 extern const char GM_UNIQUENAME(LibName)[];
75 static int GM_UNIQUENAME(Open)(LIBBASETYPEPTR hdskBase, struct IOExtTD *iotd, IPTR unitnum, ULONG flags)
77 STRPTR unitname;
78 struct unit *unit;
79 UBYTE unitflags = 0;
81 if (unitnum < 1024)
83 ULONG len = strlen(hdskBase->DiskDevice) + 5;
85 unitname = AllocVec(len, MEMF_ANY);
86 if (!unitname)
87 return FALSE;
89 unitflags = UNIT_FREENAME;
90 NewRawDoFmt(hdskBase->DiskDevice, (VOID_FUNC)RAWFMTFUNC_STRING, unitname, unitnum + hdskBase->unitBase);
92 else
93 unitname = (STRPTR)unitnum;
95 D(bug("hostdisk: open unit %s\n", unitname));
97 ObtainSemaphore(&hdskBase->sigsem);
99 unit = (struct unit *)FindName(&hdskBase->units, unitname);
101 if (unit)
103 unit->usecount++;
104 ReleaseSemaphore(&hdskBase->sigsem);
106 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
107 iotd->iotd_Req.io_Error = 0;
108 iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
110 DOPEN(bug("hostdisk: in libopen func. Yep. Unit is already open\n"));
111 return TRUE;
114 DOPEN(bug("hostdisk: in libopen func. No, it is not. So creating new unit ...\n"));
116 unit = (struct unit *)AllocMem(sizeof(struct unit), MEMF_PUBLIC | MEMF_CLEAR);
118 if (unit != NULL)
120 ULONG p = strlen(GM_UNIQUENAME(LibName));
121 char taskName[p + strlen(unitname) + 2];
122 struct Task *unitTask;
124 DOPEN(bug("hostdisk: in libopen func. Allocation of unit memory okay. Setting up unit and calling CreateNewProc ...\n"));
126 CopyMem(GM_UNIQUENAME(LibName), taskName, p);
127 taskName[p] = ' ';
128 strcpy(&taskName[p + 1], unitname);
130 unit->n.ln_Name = unitname;
131 unit->usecount = 1;
132 unit->hdskBase = hdskBase;
133 unit->flags = unitflags;
134 NEWLIST((struct List *)&unit->changeints);
136 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
137 SetSignal(0, SIGF_SINGLE);
138 unitTask = NewCreateTask(TASKTAG_PC , unitentry,
139 TASKTAG_NAME, taskName,
140 TASKTAG_ARG1, iotd,
141 TAG_DONE);
143 DOPEN(bug("hostdisk: in libopen func. NewCreateTask() called. Task = 0x%p\n", unitTask));
145 if (unitTask)
147 DOPEN(bug("hostdisk: in libopen func. Waiting for signal from unit task...\n"));
148 Wait(SIGF_SINGLE);
150 DOPEN(bug("hostdisk: in libopen func. Unit error %u, flags 0x%02X\n", iotd->iotd_Req.io_Error, unit->flags));
151 if (!iotd->iotd_Req.io_Error)
153 AddTail((struct List *)&hdskBase->units, &unit->n);
154 ReleaseSemaphore(&hdskBase->sigsem);
155 return TRUE;
158 else
159 iotd->iotd_Req.io_Error = TDERR_NoMem;
161 freeUnit(unit);
163 else
164 iotd->iotd_Req.io_Error = TDERR_NoMem;
166 ReleaseSemaphore(&hdskBase->sigsem);
168 return FALSE;
171 /****************************************************************************************/
173 static int GM_UNIQUENAME(Close)(LIBBASETYPEPTR hdskBase, struct IOExtTD *iotd)
175 struct unit *unit = (struct unit *)iotd->iotd_Req.io_Unit;
177 D(bug("hostdisk: close unit %s\n", unit->n.ln_Name));
179 ObtainSemaphore(&hdskBase->sigsem);
181 if (!--unit->usecount)
183 Remove(&unit->n);
185 /* The task will free its unit structure itself */
186 Signal(unit->port->mp_SigTask, SIGBREAKF_CTRL_C);
189 ReleaseSemaphore(&hdskBase->sigsem);
191 return TRUE;
194 /****************************************************************************************/
196 ADD2INITLIB(GM_UNIQUENAME(Init), -5)
197 ADD2EXPUNGELIB(HostDisk_Cleanup, -5);
198 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
199 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
201 /****************************************************************************************/
203 static const UWORD NSDSupported[] = {
204 // CMD_RESET,
205 CMD_READ,
206 CMD_WRITE,
207 CMD_UPDATE,
208 CMD_CLEAR,
209 // CMD_STOP,
210 // CMD_START,
211 CMD_FLUSH,
212 TD_MOTOR,
213 TD_SEEK,
214 TD_FORMAT,
215 // TD_REMOVE,
216 TD_CHANGENUM,
217 TD_CHANGESTATE,
218 TD_PROTSTATUS,
219 // TD_GETNUMTRACKS,
220 TD_ADDCHANGEINT,
221 TD_REMCHANGEINT,
222 TD_GETGEOMETRY,
223 // TD_EJECT,
224 TD_READ64,
225 TD_WRITE64,
226 TD_SEEK64,
227 TD_FORMAT64,
228 TD_GETDRIVETYPE,
229 NSCMD_DEVICEQUERY,
230 NSCMD_TD_READ64,
231 NSCMD_TD_WRITE64,
232 NSCMD_TD_SEEK64,
233 NSCMD_TD_FORMAT64,
237 AROS_LH1(void, beginio,
238 AROS_LHA(struct IOExtTD *, iotd, A1),
239 struct HostDiskBase *, hdskBase, 5, Hostdisk)
241 AROS_LIBFUNC_INIT
243 struct NSDeviceQueryResult *nsdq;
245 DCMD(bug("hostdisk: command %u\n", iotd->iotd_Req.io_Command));
246 switch(iotd->iotd_Req.io_Command)
248 case CMD_UPDATE:
249 case CMD_CLEAR:
250 case CMD_FLUSH:
251 case TD_MOTOR:
252 /* Ignore but don't fail */
253 iotd->iotd_Req.io_Error = 0;
254 break;
256 case CMD_READ:
257 case CMD_WRITE:
258 case TD_SEEK:
259 case TD_FORMAT:
260 case TD_READ64:
261 case TD_WRITE64:
262 case TD_FORMAT64:
263 case TD_SEEK64:
264 case NSCMD_TD_READ64:
265 case NSCMD_TD_WRITE64:
266 case NSCMD_TD_FORMAT64:
267 case NSCMD_TD_SEEK64:
268 case TD_CHANGENUM:
269 case TD_CHANGESTATE:
270 case TD_ADDCHANGEINT:
271 case TD_REMCHANGEINT:
272 case TD_GETGEOMETRY:
273 case TD_EJECT:
274 case TD_PROTSTATUS:
275 /* Forward to unit thread */
276 PutMsg(((struct unit *)iotd->iotd_Req.io_Unit)->port, &iotd->iotd_Req.io_Message);
277 /* Not done quick */
278 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
279 return;
282 New Style Devices query. Introduce self as trackdisk and provide list of
283 commands supported
285 case NSCMD_DEVICEQUERY:
286 nsdq = iotd->iotd_Req.io_Data;
288 nsdq->DevQueryFormat = 0;
289 nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult);
290 nsdq->DeviceType = NSDEVTYPE_TRACKDISK;
291 nsdq->DeviceSubType = 0;
292 nsdq->SupportedCommands = (UWORD *)NSDSupported;
294 iotd->iotd_Req.io_Actual = sizeof(struct NSDeviceQueryResult);
295 iotd->iotd_Req.io_Error = 0;
296 break;
299 New Style Devices report here the 'NSTY' - only if such value is
300 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
301 report error.
303 case TD_GETDRIVETYPE:
304 iotd->iotd_Req.io_Actual = DRIVE_NEWSTYLE;
305 iotd->iotd_Req.io_Error = 0;
306 break;
308 default:
309 /* Not supported */
310 DCMD(bug("hostdisk: command not supported\n"));
311 iotd->iotd_Req.io_Error = IOERR_NOCMD;
312 break;
314 } /* switch(iotd->iotd_Req.io_Command) */
316 /* WaitIO will look into this */
317 iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
319 /* Finish message */
320 if(!(iotd->iotd_Req.io_Flags&IOF_QUICK))
321 ReplyMsg(&iotd->iotd_Req.io_Message);
323 AROS_LIBFUNC_EXIT
326 /****************************************************************************************/
328 AROS_LH1(LONG, abortio,
329 AROS_LHA(struct IOExtTD *, iotd, A1),
330 struct HostDiskBase *, hdskBase, 6, Hostdisk)
332 AROS_LIBFUNC_INIT
333 return IOERR_NOCMD;
334 AROS_LIBFUNC_EXIT
337 /****************************************************************************************/
339 static LONG read(struct unit *unit, struct IOExtTD *iotd)
341 STRPTR buf;
342 LONG size, subsize;
343 ULONG ioerr;
345 buf = iotd->iotd_Req.io_Data;
346 size = iotd->iotd_Req.io_Length;
348 iotd->iotd_Req.io_Actual = 0;
349 while (size)
351 subsize = Host_Read(unit, buf, size, &ioerr);
352 if (!subsize)
354 DREAD(bug("hostdisk.device/read: Host_Read() returned 0. Returning IOERR_BADLENGTH\n"));
355 return IOERR_BADLENGTH;
357 if (subsize == -1)
359 DREAD(bug("hostdisk.device/read: Host_Read() returned -1. Returning error number %d\n", ioerr));
360 return ioerr;
363 iotd->iotd_Req.io_Actual += subsize;
364 buf += subsize;
365 size -= subsize;
368 #ifdef DUMP_DATA
369 buf = iotd->iotd_Req.io_Data;
370 bug("hostdisk/read: returning 0. First 4 buffer bytes = [%c%c%c%c]\n", buf[0], buf[1], buf[2], buf[3]);
371 #endif
373 return 0;
376 /****************************************************************************************/
378 static LONG write(struct unit *unit, struct IOExtTD *iotd)
380 STRPTR buf;
381 LONG size, subsize;
382 ULONG ioerr;
384 if (unit->flags & UNIT_READONLY)
385 return TDERR_WriteProt;
387 buf = iotd->iotd_Req.io_Data;
388 size = iotd->iotd_Req.io_Length;
390 iotd->iotd_Req.io_Actual = 0;
391 while(size)
393 subsize = Host_Write(unit, buf, size, &ioerr);
394 if(subsize == -1)
396 return ioerr;
398 iotd->iotd_Req.io_Actual += subsize;
399 buf += subsize;
400 size -= subsize;
403 return 0;
406 /**************************************************************************/
408 static void addchangeint(struct unit *unit, struct IOExtTD *iotd)
410 Forbid();
411 AddTail((struct List *)&unit->changeints, (struct Node *)iotd);
412 Permit();
415 /**************************************************************************/
417 static void remchangeint(struct unit *unit, struct IOExtTD *iotd)
419 Forbid();
420 Remove((struct Node *)iotd);
421 Permit();
424 /**************************************************************************/
426 static ULONG getgeometry(struct unit *Unit, struct DriveGeometry *dg)
429 * First set some common defaults.
430 * We can work with image file, which is LBA-oriented by nature.
431 * LBA addressing can be represented by flattened geometry, where Heads == TrackSectors == 1,
432 * i. e. one cylinder == one block (sector).
433 * Sector size is assumed to be 512 bytes (a common size for hard disk drives)
434 * Host-specific code can override this if possible.
436 * This gives us a limitation: we can's handle disks longer than 2TB.
437 * It's general AmigaOS limitation, currently inherited by all Amiga family
438 * of operating systems, this is determined by maximum block number that can
439 * fit into ULONG. In order to overcome this we need 64-bit block number.
440 * Perhaps we should completely go LBA in such a case.
442 dg->dg_SectorSize = 512;
443 dg->dg_Heads = 1;
444 dg->dg_TrackSectors = 1;
445 dg->dg_CylSectors = 1; /* Heads * TrackSectors */
446 dg->dg_BufMemType = MEMF_PUBLIC;
447 dg->dg_DeviceType = DG_DIRECT_ACCESS;
448 dg->dg_Flags = 0;
450 /* Call host-specific processing */
451 return Host_GetGeometry(Unit, dg);
454 /**************************************************************************/
456 void eject(struct unit *unit, BOOL eject)
458 struct IOExtTD *iotd;
459 ULONG err;
461 if (eject)
463 Host_Close(unit);
464 unit->file = INVALID_HANDLE_VALUE;
466 else
468 err = Host_Open(unit);
469 if (err)
470 return;
473 unit->changecount++;
475 ForeachNode(&unit->changeints, iotd)
477 Cause((struct Interrupt *)iotd->iotd_Req.io_Data);
481 /****************************************************************************************/
483 static void unitentry(struct IOExtTD *iotd)
485 LONG err = 0;
486 struct Task *me = FindTask(NULL);
487 struct Task *parent = me->tc_UnionETask.tc_ETask->et_Parent;
488 struct unit *unit = (struct unit *)iotd->iotd_Req.io_Unit;
490 D(bug("%s: just started\n", me->tc_Node.ln_Name));
492 unit->port = CreateMsgPort();
493 if (!unit->port)
495 Signal(parent, SIGF_SINGLE);
496 return;
499 D(bug("%s: Trying to open \"%s\" ...\n", me->tc_Node.ln_Name, unit->n.ln_Name));
501 err = Host_Open(unit);
502 if (err)
504 D(bug("%s: open failed :-(\n", me->tc_Node.ln_Name));
506 iotd->iotd_Req.io_Error = err;
508 Signal(parent, SIGF_SINGLE);
509 return;
512 D(bug("%s: open okay :-)\n", me->tc_Node.ln_Name));
514 iotd->iotd_Req.io_Error = 0;
515 Signal(parent, SIGF_SINGLE);
517 D(bug("%s: Now entering main loop\n", me->tc_Node.ln_Name));
519 for(;;)
521 ULONG portsig = 1 << unit->port->mp_SigBit;
522 ULONG sigs = Wait(portsig | SIGBREAKF_CTRL_C);
524 if (sigs & portsig)
526 while((iotd = (struct IOExtTD *)GetMsg(unit->port)) != NULL)
528 switch(iotd->iotd_Req.io_Command)
531 * In fact these two commands make a little sense, but they exist,
532 * so we honestly process them.
534 case TD_SEEK:
535 DCMD(bug("%s: received CMD_SEEK.\n", me->tc_Node.ln_Name));
536 err = Host_Seek(unit, iotd->iotd_Req.io_Offset);
537 break;
539 case TD_SEEK64:
540 case NSCMD_TD_SEEK64:
541 DCMD(bug("%s: received CMD_SEEK64.\n", me->tc_Node.ln_Name));
542 err = Host_Seek64(unit, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Actual);
543 break;
545 case CMD_READ:
546 DCMD(bug("%s: received CMD_READ.\n", me->tc_Node.ln_Name));
547 DREAD(bug("hostdisk/CMD_READ: offset = %u (0x%08X) size = %d\n", iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length));
549 err = Host_Seek(unit, iotd->iotd_Req.io_Offset);
550 if (!err)
551 err = read(unit, iotd);
552 DREAD(else bug("CMD_READ: Seek failed\n");)
553 break;
555 case TD_READ64:
556 case NSCMD_TD_READ64:
557 DREAD(bug("hostdisk/TD_READ64: offset = 0x%08X%08X size = %d\n",
558 iotd->iotd_Req.io_Actual, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length));
560 err = Host_Seek64(unit, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Actual);
561 if (!err)
562 err = read(unit, iotd);
563 DREAD(else bug("CMD_READ64: Seek failed\n");)
564 break;
566 case CMD_WRITE:
567 case TD_FORMAT:
568 DCMD(bug("%s: received %s\n", me->tc_Node.ln_Name, (iotd->iotd_Req.io_Command == CMD_WRITE) ? "CMD_WRITE" : "TD_FORMAT"));
569 DWRITE(bug("hostdisk/CMD_WRITE: offset = %u (0x%08X) size = %d\n", iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length));
571 err = Host_Seek(unit, iotd->iotd_Req.io_Offset);
572 if (!err)
573 err = write(unit, iotd);
574 break;
576 case TD_WRITE64:
577 case TD_FORMAT64:
578 case NSCMD_TD_WRITE64:
579 case NSCMD_TD_FORMAT64:
580 DCMD(bug("%s: received TD_WRITE64\n", me->tc_Node.ln_Name));
581 DWRITE(bug("hostdisk/TD_WRITE64: offset = 0x%08X%08X size = %d\n",
582 iotd->iotd_Req.io_Actual, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length));
584 err = Host_Seek64(unit, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Actual);
585 if (!err)
586 err = write(unit, iotd);
587 break;
589 case TD_CHANGENUM:
590 err = 0;
591 iotd->iotd_Req.io_Actual = unit->changecount;
592 break;
594 case TD_CHANGESTATE:
595 err = 0;
596 iotd->iotd_Req.io_Actual = (unit->file == INVALID_HANDLE_VALUE);
597 break;
599 case TD_ADDCHANGEINT:
600 addchangeint(unit, iotd);
601 err = 0;
602 break;
604 case TD_REMCHANGEINT:
605 remchangeint(unit, iotd);
606 err = 0;
607 break;
609 case TD_GETGEOMETRY:
610 DCMD(bug("%s: received TD_GETGEOMETRY\n", me->tc_Node.ln_Name));
612 err = getgeometry(unit, (struct DriveGeometry *)iotd->iotd_Req.io_Data);
613 break;
615 case TD_EJECT:
616 eject(unit, iotd->iotd_Req.io_Length);
617 err = 0;
618 break;
620 case TD_PROTSTATUS:
621 iotd->iotd_Req.io_Actual = (unit->flags & UNIT_READONLY) ? TRUE : FALSE;
622 err = 0;
623 break;
625 } /* switch(iotd->iotd_Req.io_Command) */
627 iotd->iotd_Req.io_Error = err;
628 ReplyMsg(&iotd->iotd_Req.io_Message);
630 } /* while((iotd = (struct IOExtTD *)GetMsg(&unit->port)) != NULL) */
634 /* Process quit signal after our MsgPort is empty */
635 if (sigs & SIGBREAKF_CTRL_C)
637 D(bug("%s: Received EXIT signal.\n", me->tc_Node.ln_Name));
639 Host_Close(unit);
641 freeUnit(unit);
642 return;
645 } /* for(;;) */
648 /****************************************************************************************/