Set the magic value
[AROS.git] / workbench / devs / fdsk_device.c
blobf60a5b9ce6d6c1519f83427a4914eecad7aecd58
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /****************************************************************************************/
8 #include <devices/trackdisk.h>
9 #include <devices/newstyle.h>
10 #include <exec/resident.h>
11 #include <exec/errors.h>
12 #include <exec/memory.h>
13 #include <exec/initializers.h>
14 #include <proto/exec.h>
15 #include <dos/dosextens.h>
16 #include <dos/dostags.h>
17 #include <proto/dos.h>
18 #include <aros/asmcall.h>
19 #include <aros/libcall.h>
20 #include <aros/symbolsets.h>
21 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
22 #include "fdsk_device_gcc.h"
23 #endif
25 #define DEBUG 0
26 #include <aros/debug.h>
28 #include LC_LIBDEFS_FILE
30 #define NEWSTYLE_DEVICE 1
32 #if NEWSTYLE_DEVICE
33 static const UWORD SupportedCommands[] =
35 CMD_UPDATE,
36 CMD_CLEAR,
37 TD_MOTOR,
38 CMD_READ,
39 CMD_WRITE,
40 TD_FORMAT,
41 TD_CHANGENUM,
42 TD_CHANGESTATE,
43 TD_ADDCHANGEINT,
44 TD_REMCHANGEINT,
45 TD_GETGEOMETRY,
46 TD_EJECT,
47 TD_PROTSTATUS,
48 ETD_READ,
49 ETD_WRITE,
50 ETD_UPDATE,
51 ETD_CLEAR,
52 ETD_MOTOR,
53 ETD_FORMAT,
54 TD_GETDRIVETYPE,
55 NSCMD_DEVICEQUERY,
58 #endif
60 /****************************************************************************************/
62 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR fdskbase)
64 D(bug("[FDSK ] in libinit func\n"));
66 InitSemaphore(&fdskbase->sigsem);
67 NEWLIST((struct List *)&fdskbase->units);
68 fdskbase->port.mp_Node.ln_Type = NT_MSGPORT;
69 fdskbase->port.mp_Flags = PA_SIGNAL;
70 fdskbase->port.mp_SigBit = SIGB_SINGLE;
71 NEWLIST((struct List *)&fdskbase->port.mp_MsgList);
73 D(bug("[FDSK ] in libinit func. Returning %x (success) :-)\n", fdskbase));
74 return TRUE;
77 /****************************************************************************************/
79 AROS_UFP3(LONG, unitentry,
80 AROS_UFPA(STRPTR, argstr, A0),
81 AROS_UFPA(ULONG, arglen, D0),
82 AROS_UFPA(struct ExecBase *, SysBase, A6));
84 /****************************************************************************************/
86 static int GM_UNIQUENAME(Open)
88 LIBBASETYPEPTR fdskbase,
89 struct IOExtTD *iotd,
90 ULONG unitnum,
91 ULONG flags
94 static const struct TagItem tags[] =
96 { NP_Name , (IPTR)"File Disk Unit Process"},
97 { NP_Input , 0 },
98 { NP_Output , 0 },
99 { NP_Error , 0 },
100 { NP_CurrentDir , 0 },
101 { NP_Priority , 0 },
102 { NP_HomeDir , 0 },
103 { NP_CopyVars , 0 },
104 { NP_Entry , (IPTR)unitentry },
105 { TAG_END , 0 }
107 struct unit *unit;
109 D(bug("[FDSK%02ld] in libopen func.\n", unitnum));
111 D(bug("[FDSK%02ld] in libopen func. Looking if unit%ld is already open\n", unitnum, unitnum));
113 ObtainSemaphore(&fdskbase->sigsem);
115 for(unit = (struct unit *)fdskbase->units.mlh_Head;
116 unit->msg.mn_Node.ln_Succ != NULL;
117 unit = (struct unit *)unit->msg.mn_Node.ln_Succ)
118 if(unit->unitnum == unitnum)
120 unit->usecount++;
121 ReleaseSemaphore(&fdskbase->sigsem);
123 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
124 iotd->iotd_Req.io_Error = 0;
125 iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
127 D(bug("[FDSK%02ld] in libopen func. Yep. Unit is already open\n", unitnum));
129 return TRUE;
132 D(bug("[FDSK%02ld] in libopen func. No, it is not. So creating new unit ...\n", unitnum));
134 unit = (struct unit *)AllocMem(sizeof(struct unit),
135 MEMF_PUBLIC | MEMF_CLEAR);
136 if(unit != NULL)
138 D(bug("[FDSK%02ld] in libopen func. Allocation of unit memory okay. Setting up unit and calling CreateNewProc ...\n", unitnum));
140 unit->usecount = 1;
141 unit->fdskbase = fdskbase;
142 unit->unitnum = unitnum;
143 unit->msg.mn_ReplyPort = &fdskbase->port;
144 unit->msg.mn_Length = sizeof(struct unit);
145 unit->port.mp_Node.ln_Type = NT_MSGPORT;
146 unit->port.mp_Flags = PA_IGNORE;
147 unit->port.mp_SigTask = CreateNewProc((struct TagItem *)tags);
148 NEWLIST((struct List *)&unit->changeints);
150 D(bug("[FDSK%02ld] in libopen func. CreateNewProc called. Proc = %x\n", unitnum, unit->port.mp_SigTask));
152 if(unit->port.mp_SigTask != NULL)
154 NEWLIST((struct List *)&unit->port.mp_MsgList);
156 /* setup replyport to point to active task */
157 fdskbase->port.mp_SigTask = FindTask(NULL);
158 SetSignal(0, SIGF_SINGLE);
160 D(bug("[FDSK%02ld] in libopen func. Sending startup msg\n", unitnum));
161 PutMsg(&((struct Process *)unit->port.mp_SigTask)->pr_MsgPort, &unit->msg);
163 D(bug("[FDSK%02ld] in libopen func. Waiting for replymsg\n", unitnum));
164 WaitPort(&fdskbase->port);
165 (void)GetMsg(&fdskbase->port);
166 D(bug("[FDSK%02ld] in libopen func. Received replymsg\n", unitnum));
168 AddTail((struct List *)&fdskbase->units, &unit->msg.mn_Node);
169 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
170 /* Set returncode */
171 iotd->iotd_Req.io_Error = 0;
172 ReleaseSemaphore(&fdskbase->sigsem);
173 return TRUE;
174 }else
175 iotd->iotd_Req.io_Error = TDERR_NoMem;
176 FreeMem(unit, sizeof(struct unit));
177 }else
178 iotd->iotd_Req.io_Error = TDERR_NoMem;
180 ReleaseSemaphore(&fdskbase->sigsem);
182 return FALSE;
185 /****************************************************************************************/
187 static int GM_UNIQUENAME(Close)
189 LIBBASETYPEPTR fdskbase,
190 struct IOExtTD *iotd
193 struct unit *unit;
195 ObtainSemaphore(&fdskbase->sigsem);
196 unit = (struct unit *)iotd->iotd_Req.io_Unit;
197 if(!--unit->usecount)
199 Remove(&unit->msg.mn_Node);
200 fdskbase->port.mp_SigTask = FindTask(NULL);
201 SetSignal(0, SIGF_SINGLE);
202 PutMsg(&unit->port, &unit->msg);
203 WaitPort(&fdskbase->port);
204 (void)GetMsg(&fdskbase->port);
205 FreeMem(unit, sizeof(struct unit));
207 ReleaseSemaphore(&fdskbase->sigsem);
209 return TRUE;
212 /****************************************************************************************/
214 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
215 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
216 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
218 /****************************************************************************************/
220 AROS_LH1(void, beginio,
221 AROS_LHA(struct IOExtTD *, iotd, A1),
222 struct fdskbase *, fdskbase, 5, Fdsk)
224 AROS_LIBFUNC_INIT
226 struct unit *unit = (struct unit *)iotd->iotd_Req.io_Unit;
227 switch(iotd->iotd_Req.io_Command)
229 #if NEWSTYLE_DEVICE
230 case NSCMD_DEVICEQUERY:
231 D(bug("[FDSK ] NSCMD_DEVICEQUERY\n"));
232 if(iotd->iotd_Req.io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
234 iotd->iotd_Req.io_Error = IOERR_BADLENGTH;
236 else
238 struct NSDeviceQueryResult *d;
240 d = (struct NSDeviceQueryResult *)iotd->iotd_Req.io_Data;
242 d->DevQueryFormat = 0;
243 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
244 d->DeviceType = NSDEVTYPE_TRACKDISK;
245 d->DeviceSubType = 0;
246 d->SupportedCommands = (UWORD *)SupportedCommands;
248 iotd->iotd_Req.io_Actual = sizeof(struct NSDeviceQueryResult);
249 iotd->iotd_Req.io_Error = 0;
251 break;
252 case TD_GETDRIVETYPE:
253 iotd->iotd_Req.io_Actual = DRIVE_NEWSTYLE;
254 break;
255 #endif
256 case ETD_UPDATE:
257 case ETD_CLEAR:
258 case ETD_MOTOR:
259 case CMD_UPDATE:
260 case CMD_CLEAR:
261 case TD_MOTOR:
262 /* Ignore but don't fail */
263 iotd->iotd_Req.io_Error = 0;
264 break;
266 case ETD_READ:
267 case ETD_WRITE:
268 case ETD_FORMAT:
269 case CMD_READ:
270 case CMD_WRITE:
271 case TD_FORMAT:
272 case TD_GETGEOMETRY:
273 if (unit->file == BNULL)
275 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
276 break;
278 case TD_CHANGENUM:
279 case TD_CHANGESTATE:
280 case TD_ADDCHANGEINT:
281 case TD_REMCHANGEINT:
282 case TD_EJECT:
283 case TD_PROTSTATUS:
284 /* Forward to unit thread */
285 PutMsg(&unit->port, &iotd->iotd_Req.io_Message);
286 /* Not done quick */
287 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
288 return;
290 default:
291 /* Not supported */
292 iotd->iotd_Req.io_Error = IOERR_NOCMD;
293 break;
295 } /* switch(iotd->iotd_Req.io_Command) */
297 /* WaitIO will look into this */
298 iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
300 /* Finish message */
301 if(!(iotd->iotd_Req.io_Flags&IOF_QUICK))
302 ReplyMsg(&iotd->iotd_Req.io_Message);
304 AROS_LIBFUNC_EXIT
307 /****************************************************************************************/
309 AROS_LH1(LONG, abortio,
310 AROS_LHA(struct IOExtTD *, iotd, A1),
311 struct fdskbase *, fdskbase, 6, Fdsk)
313 AROS_LIBFUNC_INIT
314 return IOERR_NOCMD;
315 AROS_LIBFUNC_EXIT
318 /****************************************************************************************/
320 #define fdskbase unit->fdskbase
322 /****************************************************************************************/
324 static LONG error(LONG error)
326 switch(error)
328 case ERROR_SEEK_ERROR:
329 return TDERR_SeekError;
331 case ERROR_DISK_WRITE_PROTECTED:
332 case ERROR_WRITE_PROTECTED:
333 return TDERR_WriteProt;
335 case ERROR_NO_DISK:
336 return TDERR_DiskChanged;
338 default:
339 return TDERR_NotSpecified;
343 /****************************************************************************************/
345 static LONG read(struct unit *unit, struct IOExtTD *iotd)
347 STRPTR buf;
348 LONG size, subsize;
350 D(bug("[FDSK%02ld] read32: offset = %08x size = %08x\n", unit->unitnum, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length));
352 #if 0
353 if(iotd->iotd_SecLabel)
355 D(bug("[FDSK%02ld] read32: iotd->iotd_SecLabel is != NULL -> returning IOERR_NOCMD\n", unit->unitnum));
356 return IOERR_NOCMD;
358 #endif
360 if(Seek(unit->file, iotd->iotd_Req.io_Offset, OFFSET_BEGINNING) == -1)
362 D(bug("[FDSK%02ld] read32: Seek to offset %d failed. Returning TDERR_SeekError\n", unit->unitnum, iotd->iotd_Req.io_Offset));
363 return TDERR_SeekError;
366 buf = iotd->iotd_Req.io_Data;
367 size = iotd->iotd_Req.io_Length;
368 iotd->iotd_Req.io_Actual = size;
370 while(size)
372 subsize = Read(unit->file, buf, size);
373 if(!subsize)
375 iotd->iotd_Req.io_Actual -= size;
376 D(bug("[FDSK%02ld] read32: Read() returned 0. Returning IOERR_BADLENGTH\n", unit->unitnum));
377 return IOERR_BADLENGTH;
379 if(subsize == -1)
381 iotd->iotd_Req.io_Actual -= size;
382 D(bug("[FDSK%02ld] read32: Read() returned -1. Returning error number %d\n", unit->unitnum, error(IoErr())));
383 return error(IoErr());
385 buf += subsize;
386 size -= subsize;
389 #if DEBUG
390 buf = iotd->iotd_Req.io_Data;
391 D(bug("[FDSK%02ld] read32: returning 0. First 4 buffer bytes = [%c%c%c%c]\n", unit->unitnum, buf[0], buf[1], buf[2], buf[3]));
392 #endif
394 return 0;
397 /****************************************************************************************/
399 static LONG write(struct unit *unit, struct IOExtTD *iotd)
401 STRPTR buf;
402 LONG size, subsize;
404 D(bug("[FDSK%02ld] write32: offset = %08x size = %08x\n", unit->unitnum, iotd->iotd_Req.io_Offset, iotd->iotd_Req.io_Length));
406 if(!unit->writable)
407 return TDERR_WriteProt;
408 #if 0
409 if(iotd->iotd_SecLabel)
410 return IOERR_NOCMD;
411 #endif
412 if(Seek(unit->file, iotd->iotd_Req.io_Offset, OFFSET_BEGINNING) == -1)
413 return TDERR_SeekError;
415 buf = iotd->iotd_Req.io_Data;
416 size = iotd->iotd_Req.io_Length;
417 iotd->iotd_Req.io_Actual = size;
419 while(size)
421 subsize = Write(unit->file, buf, size);
422 if(subsize == -1)
424 iotd->iotd_Req.io_Actual -= size;
425 return error(IoErr());
427 buf += subsize;
428 size -= subsize;
431 return 0;
434 /**************************************************************************/
436 static void addchangeint(struct unit *unit, struct IOExtTD *iotd) {
437 Forbid();
438 AddTail((struct List *)&unit->changeints, (struct Node *)iotd);
439 Permit();
442 /**************************************************************************/
444 static void remchangeint(struct unit *unit, struct IOExtTD *iotd) {
445 Forbid();
446 Remove((struct Node *)iotd);
447 Permit();
450 /**************************************************************************/
452 void getgeometry(struct unit *unit, struct DriveGeometry *dg) {
453 struct FileInfoBlock fib;
455 ExamineFH(unit->file, &fib);
456 dg->dg_SectorSize = 512;
457 dg->dg_Heads = 16;
458 dg->dg_TrackSectors = 63;
459 dg->dg_TotalSectors = fib.fib_Size / dg->dg_SectorSize;
460 /* in case of links or block devices with emul_handler we get the wrong size */
461 if (dg->dg_TotalSectors == 0)
462 dg->dg_TotalSectors = dg->dg_Heads*dg->dg_TrackSectors*5004;
463 dg->dg_Cylinders = dg->dg_TotalSectors / (dg->dg_Heads * dg->dg_TrackSectors);
464 dg->dg_CylSectors = dg->dg_Heads * dg->dg_TrackSectors;
465 dg->dg_BufMemType = MEMF_PUBLIC;
466 dg->dg_DeviceType = DG_DIRECT_ACCESS;
467 dg->dg_Flags = DGF_REMOVABLE;
470 /**************************************************************************/
472 void eject(struct unit *unit, BOOL eject) {
473 struct IOExtTD *iotd;
474 struct FileInfoBlock fib;
476 if((eject && unit->file != BNULL) || (!eject && unit->file == BNULL))
478 if (eject)
480 Close(unit->file);
481 unit->file = (BPTR)NULL;
483 else
485 unit->file = Open(unit->filename, MODE_OLDFILE);
486 if (unit->file == BNULL)
487 return;
488 ExamineFH(unit->file, &fib);
489 unit->writable = !(fib.fib_Protection & FIBF_WRITE);
492 unit->changecount++;
494 ForeachNode(&unit->changeints, iotd)
496 Cause((struct Interrupt *)iotd->iotd_Req.io_Data);
500 return;
503 /**************************************************************************/
505 AROS_UFH2(void, putchr,
506 AROS_UFHA(UBYTE, chr, D0),
507 AROS_UFHA(STRPTR *, p, A3)
510 AROS_USERFUNC_INIT
511 *(*p)++ = chr;
512 AROS_USERFUNC_EXIT
515 /****************************************************************************************/
517 AROS_UFH3(LONG, unitentry,
518 AROS_UFHA(STRPTR, argstr, A0),
519 AROS_UFHA(ULONG, arglen, D0),
520 AROS_UFHA(struct ExecBase *, SysBase, A6))
522 AROS_USERFUNC_INIT
524 UBYTE buf[10 + sizeof(LONG) * 8 * 301 / 1000 + 1];
525 STRPTR ptr = buf;
526 struct Process *me;
527 LONG err = 0L;
528 struct IOExtTD *iotd;
529 struct unit *unit;
530 APTR win;
531 struct FileInfoBlock fib;
533 me = (struct Process *)FindTask(NULL);
535 WaitPort(&me->pr_MsgPort);
536 unit = (struct unit *)GetMsg(&me->pr_MsgPort);
537 unit->port.mp_SigBit = AllocSignal(-1);
538 unit->port.mp_Flags = PA_SIGNAL;
540 /* disable DOS error requesters. save the old pointer so we can put it
541 * back later */
542 win = me->pr_WindowPtr;
543 me->pr_WindowPtr = (APTR) -1;
545 (void)RawDoFmt("FDSK:Unit%ld", &unit->unitnum, (VOID_FUNC)putchr, &ptr);
547 D(bug("[FDSK%02ld] Trying to open \"%s\" ...\n", unit->unitnum, buf));
549 unit->filename = buf;
550 unit->file = Open(buf, MODE_OLDFILE);
552 if(unit->file != BNULL)
554 ExamineFH(unit->file, &fib);
555 unit->writable = !(fib.fib_Protection & FIBF_WRITE);
558 /* enable requesters */
559 me->pr_WindowPtr = win;
561 D(bug("[FDSK%02ld] open okay :-) Replying startup msg.\n", unit->unitnum));
563 ReplyMsg(&unit->msg);
565 D(bug("[FDSK%02ld] now entering main loop.\n", unit->unitnum));
567 for(;;)
569 while((iotd = (struct IOExtTD *)GetMsg(&unit->port)) != NULL)
571 if(&iotd->iotd_Req.io_Message == &unit->msg)
573 D(bug("[FDSK%02ld] received EXIT message.\n", unit->unitnum));
575 Close(unit->file);
576 Forbid();
577 ReplyMsg(&unit->msg);
578 return 0;
580 switch(iotd->iotd_Req.io_Command)
582 case ETD_READ:
583 case CMD_READ:
584 D(bug("[FDSK%02ld] received CMD_READ.\n", unit->unitnum));
585 err = read(unit, iotd);
586 break;
587 case ETD_WRITE:
588 case CMD_WRITE:
589 case TD_FORMAT:
590 case ETD_FORMAT:
591 D(bug("[FDSK%02ld] received %s\n", unit->unitnum, (
592 (iotd->iotd_Req.io_Command == ETD_WRITE) ||
593 (iotd->iotd_Req.io_Command == CMD_WRITE)) ? "CMD_WRITE" : "TD_FORMAT"));
594 err = write(unit, iotd);
595 break;
596 case TD_CHANGENUM:
597 err = 0;
598 iotd->iotd_Req.io_Actual = unit->changecount;
599 break;
600 case TD_CHANGESTATE:
601 err = 0;
602 iotd->iotd_Req.io_Actual = unit->file == (BPTR)NULL;
603 break;
604 case TD_ADDCHANGEINT:
605 addchangeint(unit, iotd);
606 err = 0;
607 break;
608 case TD_REMCHANGEINT:
609 remchangeint(unit, iotd);
610 err = 0;
611 break;
612 case TD_GETGEOMETRY:
613 getgeometry(unit, (struct DriveGeometry *)iotd->iotd_Req.io_Data);
614 err = 0;
615 break;
616 case TD_EJECT:
617 eject(unit, iotd->iotd_Req.io_Length);
618 err = 0;
619 break;
620 case TD_PROTSTATUS:
621 iotd->iotd_Req.io_Actual = !unit->writable;
622 err = 0;
623 break;
625 } /* switch(iotd->iotd_Req.io_Command) */
626 iotd->iotd_Req.io_Error = err;
627 ReplyMsg(&iotd->iotd_Req.io_Message);
628 } /* while((iotd = (struct IOExtTD *)GetMsg(&unit->port)) != NULL) */
629 WaitPort(&unit->port);
630 } /* for(;;) */
631 AROS_USERFUNC_EXIT
634 /****************************************************************************************/