disable debug
[AROS.git] / rom / devs / trackdisk / trackdisk_device.c
blobd53508ac5d523924688dd5ea9fab0d4627d56921
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Amiga-style device for trackdisk
6 Lang: English
7 */
9 #include <devices/trackdisk.h>
10 #include <exec/resident.h>
11 #include <exec/errors.h>
12 #include <exec/memory.h>
13 #include <exec/lists.h>
14 #include <exec/alerts.h>
15 #include <exec/tasks.h>
16 #include <libraries/expansion.h>
17 #include <libraries/expansionbase.h>
18 #include <libraries/configvars.h>
19 #include <dos/filehandler.h>
20 #include <dos/dosextens.h>
21 #include <dos/dostags.h>
22 #include <clib/alib_protos.h>
23 #include <aros/symbolsets.h>
24 #include <aros/bootloader.h>
25 #include <oop/oop.h>
27 #include <proto/oop.h>
28 #include <proto/exec.h>
29 #include <proto/expansion.h>
30 #include <proto/utility.h>
31 #include <proto/bootloader.h>
32 #include <proto/dos.h>
33 #include <asm/io.h>
35 #include <SDI/SDI_interrupt.h>
37 #include "trackdisk_device.h"
38 #include "trackdisk_hw.h"
40 #include LC_LIBDEFS_FILE
42 #define DEBUG 0
43 #include <aros/debug.h>
45 #undef kprintf
47 int td_getbyte(unsigned char *, struct TrackDiskBase *);
48 int td_sendbyte(unsigned char, struct TrackDiskBase *);
49 ULONG TD_InitTask(struct TrackDiskBase *);
50 static void TD_DevTask();
51 BOOL TD_PerformIO( struct IOExtTD *, struct TrackDiskBase *);
53 struct TDU *TD_InitUnit(ULONG num, struct TrackDiskBase *tdb)
55 struct TDU *unit;
56 struct ExpansionBase *ExpansionBase = NULL;
57 struct DeviceNode *devnode;
58 IPTR *pp;
59 TEXT dosdevname[4] = "DF0", *handler = "FastFileSystem";
60 UWORD len;
62 /* Try to get memory for structure */
63 unit = AllocMem(sizeof(struct TDU), MEMF_PUBLIC | MEMF_CLEAR);
65 if (!tdb->td_nomount)
66 ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",40);
67 if (unit)
69 unit->tdu_DiskIn = TDU_NODISK; /* Assume there is no floppy in there */
70 unit->pub.tdu_StepDelay = 4; /* Standard values here */
71 unit->pub.tdu_SettleDelay = 16;
72 unit->pub.tdu_RetryCnt = 3;
73 unit->pub.tdu_CalibrateDelay = 4;
74 unit->tdu_UnitNum=num;
75 unit->tdu_lastcyl = -1;
76 unit->tdu_lasthd = -1;
77 NEWLIST(&unit->tdu_Listeners);
79 /* Alloc memory for track buffering */
80 unit->td_DMABuffer = AllocMem(DP_SECTORS * 512, MEMF_CLEAR | MEMF_24BITDMA);
82 if (!unit->td_DMABuffer)
84 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_NoMemory);
87 /* If buffer doesn't fit into DMA page realloc it */
88 /* FIXME: we should ensure that the buffer is suitable the first time,
89 either by using an aligned memory allocation function or by
90 allocating twice as much as needed and manually aligning */
91 if (( (((ULONG)(IPTR)unit->td_DMABuffer + DP_SECTORS*512) & 0xffff0000) -
92 ((ULONG)(IPTR)unit->td_DMABuffer&0xffff0000) ) != 0)
94 APTR buffer;
96 buffer = AllocMem(DP_SECTORS * 512, MEMF_CLEAR | MEMF_24BITDMA);
97 if (!buffer)
99 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_NoMemory);
102 FreeMem(unit->td_DMABuffer, DP_SECTORS*512);
103 unit->td_DMABuffer = buffer;
105 /* Store the unit in TDBase */
106 tdb->td_Units[num] = unit;
108 if (ExpansionBase)
110 D(bug("TD: Adding bootnode\n"));
111 pp = (IPTR *)AllocMem(sizeof(struct DosEnvec)+sizeof(IPTR)*4,MEMF_PUBLIC|MEMF_CLEAR);
113 if (pp)
115 dosdevname[2] += num;
116 pp[0] = (IPTR)dosdevname;
117 pp[1] = (IPTR)MOD_NAME_STRING;
118 pp[2] = num;
119 pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS;
120 pp[DE_SIZEBLOCK + 4] = 128;
121 pp[DE_NUMHEADS + 4] = 2;
122 pp[DE_SECSPERBLOCK + 4] = 1;
123 pp[DE_BLKSPERTRACK + 4] = 18;
124 pp[DE_RESERVEDBLKS + 4] = 2;
125 pp[DE_LOWCYL + 4] = 0;
126 pp[DE_HIGHCYL + 4] = 79;
127 pp[DE_NUMBUFFERS + 4] = 10;
128 pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC | MEMF_24BITDMA;
129 pp[DE_MAXTRANSFER + 4] = 0x00200000;
130 pp[DE_MASK + 4] = 0x7FFFFFFE;
131 pp[DE_BOOTPRI + 4] = 5;
132 pp[DE_DOSTYPE + 4] = 0;
133 pp[DE_BOOTBLOCKS + 4] = 2;
134 devnode = MakeDosNode(pp);
136 if (devnode)
138 len = strlen(handler);
139 devnode->dn_Handler = MKBADDR(AllocMem(
140 AROS_BSTR_MEMSIZE4LEN(len), MEMF_PUBLIC | MEMF_CLEAR)
143 if (devnode->dn_Handler != BNULL)
145 CopyMem(handler, AROS_BSTR_ADDR(devnode->dn_Handler),
146 len);
147 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
148 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, NULL);
154 if (ExpansionBase)
156 CloseLibrary((struct Library *)ExpansionBase);
158 return (unit);
161 static AROS_INTH1(td_floppytimer, struct TrackDiskBase *, TDBase)
163 AROS_INTFUNC_INIT
165 // Does anyone wait for io?
166 if (TDBase->td_inttmo)
168 // Decrease timeout
169 TDBase->td_inttmo--;
170 // timeout?
171 if (!TDBase->td_inttmo)
173 Signal(&TDBase->td_TaskData->td_Task,(1L << TDBase->td_TmoBit));
177 return FALSE;
179 AROS_INTFUNC_EXIT
182 static AROS_INTH1(td_floppyint, struct TrackDiskBase *, TDBase)
184 AROS_INTFUNC_INIT
186 Signal(&TDBase->td_TaskData->td_Task,(1L << TDBase->td_IntBit));
188 return FALSE;
190 AROS_INTFUNC_EXIT
193 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR TDBase)
195 struct BootLoaderBase *BootLoaderBase;
196 ULONG i;
197 UBYTE drives;
198 struct Interrupt *irq;
200 D(bug("TD: Init\n"));
202 /* First thing, are we disabled from the bootloader? */
203 if ((BootLoaderBase = OpenResource("bootloader.resource")))
205 struct List *list;
206 struct Node *node;
208 list = (struct List *)GetBootInfo(BL_Args);
209 if (list)
211 ForeachNode(list,node)
213 if (0 == strncmp(node->ln_Name,"floppy=",5))
215 if (strstr(&node->ln_Name[7], "disabled"))
217 D(bug("[Floppy] Disabled with bootloader argument\n"));
218 return FALSE;
220 TDBase->td_nomount = (strstr(&node->ln_Name[7], "nomount") != NULL);
226 /* First we check if there are any floppy drives configured in BIOS */
227 /* We do this by reading CMOS byte 0x10 */
228 /* It should really reside in battclock.resource */
229 outb(0x10,0x70);
230 drives = inb(0x71);
232 if (drives == 0)
234 /* No drives here. abort */
235 D(bug("TD: No drives defined in BIOS\n"));
236 return FALSE;
239 for (i=0; i<TD_NUMUNITS; i++)
240 TDBase->td_Units[i] = NULL;
242 irq = &TDBase->td_FloppyInt;
243 irq->is_Node.ln_Type = NT_INTERRUPT;
244 irq->is_Node.ln_Pri=127; /* Set the highest pri */
245 irq->is_Node.ln_Name = (STRPTR)MOD_NAME_STRING;
246 irq->is_Code = (VOID_FUNC)td_floppyint;
247 irq->is_Data = (APTR)TDBase;
249 AddIntServer(INTB_KERNEL + 6, irq);
251 irq = &TDBase->td_TimerInt;
252 irq->is_Node.ln_Type = NT_INTERRUPT;
253 irq->is_Node.ln_Pri=10; /* Set the highest pri */
254 irq->is_Node.ln_Name = (STRPTR)MOD_NAME_STRING;
255 irq->is_Code = (VOID_FUNC)td_floppytimer;
256 irq->is_Data = (APTR)TDBase;
258 AddIntServer(INTB_KERNEL + 0, irq);
260 /* Swap drivebits around */
261 drives = ( (drives&0xf0)>>4 | (drives&0x0f)<<4 );
263 for (i=0;i<TD_NUMUNITS;i++)
265 /* We only want 3.5" 1.44MB drives */
266 if (((drives >> (4*i))&0x0f) == 4)
268 kprintf("[Floppy] Unit %d is a 1.44MB drive\n",i);
269 TD_InitUnit(i,TDBase);
273 /* Create the message processor task */
274 TD_InitTask(TDBase);
276 return TRUE;
279 static int GM_UNIQUENAME(Open)
281 LIBBASETYPEPTR TDBase,
282 struct IOExtTD *iotd,
283 ULONG unitnum,
284 ULONG flags
287 D(bug("TD: Open\n"));
288 iotd->iotd_Req.io_Error = IOERR_OPENFAIL;
290 /* Is the requested unitNumber valid? */
291 if (unitnum < TD_NUMUNITS)
293 struct TDU *unit;
295 iotd->iotd_Req.io_Device = (struct Device *)TDBase;
297 /* Get TDU structure */
298 unit = TDBase->td_Units[unitnum];
299 if (unit && (unit->tdu_Present)) {
300 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
301 ((struct Unit *)unit)->unit_OpenCnt++;
302 iotd->iotd_Req.io_Error = 0;
306 return iotd->iotd_Req.io_Error == 0;
310 static int GM_UNIQUENAME(Close)
312 LIBBASETYPEPTR TDBase,
313 struct IOExtTD *iotd
316 iotd->iotd_Req.io_Unit->unit_OpenCnt --;
318 return TRUE;
321 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
322 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
323 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
325 AROS_LH1(void, beginio,
326 AROS_LHA(struct IOExtTD *, iotd, A1),
327 struct TrackDiskBase *, TDBase, 5, TrackDisk)
329 AROS_LIBFUNC_INIT
330 struct TDU *tdu;
332 if (iotd->iotd_Req.io_Flags & IOF_QUICK)
334 switch(iotd->iotd_Req.io_Command)
336 case TD_CHANGESTATE:
337 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
338 if ((!(tdu->pub.tdu_PubFlags & TDPF_NOCLICK)) || (tdu->tdu_DiskIn == TDU_DISK))
339 break;
340 case CMD_READ:
341 case CMD_UPDATE:
342 case CMD_WRITE:
343 case TD_FORMAT:
344 case TD_MOTOR:
345 case TD_SEEK:
346 case ETD_READ:
347 case ETD_UPDATE:
348 case ETD_WRITE:
349 case ETD_FORMAT:
350 case ETD_MOTOR:
351 case ETD_SEEK:
352 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
353 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
354 return;
356 TD_PerformIO(iotd,TDBase);
357 return;
359 else
361 /* Forward to devicetask */
362 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
363 /* Not done quick */
364 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
365 return;
367 AROS_LIBFUNC_EXIT
370 AROS_LH1(LONG, abortio,
371 AROS_LHA(struct IOExtTD *, iotd, A1),
372 struct TrackDiskBase *, TDBase, 6, TrackDisk)
374 AROS_LIBFUNC_INIT
375 D(bug("TD: AbortIO\n"));
376 return IOERR_NOCMD;
377 AROS_LIBFUNC_EXIT
380 void TestInsert(struct TrackDiskBase *tdb, struct TDU *tdu)
382 UBYTE dir;
383 struct IOExtTD *iotd;
385 td_rseek(tdu->tdu_UnitNum,tdu->tdu_stepdir,1,tdb);
386 tdu->tdu_stepdir = !tdu->tdu_stepdir;
387 dir = (inb(FDC_DIR)>>7);
388 if (dir == 0)
390 D(bug("[Floppy] Insertion detected\n"));
391 td_recalibrate(tdu->tdu_UnitNum,1,0,tdb);
392 tdu->tdu_DiskIn = TDU_DISK;
393 tdu->pub.tdu_Counter++;
394 tdu->tdu_ProtStatus = td_getprotstatus(tdu->tdu_UnitNum,tdb);
395 Forbid();
396 ForeachNode(&tdu->tdu_Listeners,iotd)
398 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
400 Permit();
404 BOOL TD_PerformIO( struct IOExtTD *iotd, struct TrackDiskBase *tdb)
406 struct TDU *tdu;
407 struct DriveGeometry *geo;
408 UBYTE temp;
409 BOOL reply;
411 reply = TRUE;
412 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
413 switch(iotd->iotd_Req.io_Command)
415 case ETD_CLEAR:
416 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
417 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
418 break;
420 case CMD_CLEAR:
421 tdu->tdu_flags = 0;
422 tdu->tdu_lastcyl = -1;
423 tdu->tdu_lasthd = -1;
424 iotd->iotd_Req.io_Error = 0;
425 break;
426 case ETD_READ:
427 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
428 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
429 break;
431 case CMD_READ:
432 tdu->tdu_Busy = TRUE;
433 iotd->iotd_Req.io_Error = td_read(iotd, tdb);
434 tdu->tdu_Busy = FALSE;
435 break;
436 case ETD_UPDATE:
437 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
438 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
439 break;
441 case CMD_UPDATE:
442 tdu->tdu_Busy = TRUE;
443 iotd->iotd_Req.io_Error = td_update(tdu, tdb);
444 tdu->tdu_Busy = FALSE;
445 break;
446 case ETD_WRITE:
447 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
448 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
449 break;
451 case CMD_WRITE:
452 tdu->tdu_Busy = TRUE;
453 iotd->iotd_Req.io_Error = td_write(iotd, tdb);
454 tdu->tdu_Busy = FALSE;
455 break;
456 case TD_ADDCHANGEINT:
457 Forbid();
458 AddTail(&tdu->tdu_Listeners,(struct Node *)iotd);
459 Permit();
460 reply = FALSE;
461 break;
462 case TD_CHANGENUM:
463 iotd->iotd_Req.io_Actual = tdu->pub.tdu_Counter;
464 iotd->iotd_Req.io_Error=0;
465 break;
466 case TD_CHANGESTATE:
467 if ((tdu->pub.tdu_PubFlags & TDPF_NOCLICK) && (tdu->tdu_DiskIn == TDU_NODISK)) {
468 TestInsert(tdb, tdu);
469 if (!tdu->tdu_MotorOn)
470 td_motoroff(tdu->tdu_UnitNum, tdb);
472 if (tdu->tdu_DiskIn == TDU_DISK)
474 /* test if disk is still in there */
475 temp = td_getDiskChange();
476 iotd->iotd_Req.io_Actual = temp;
477 tdu->tdu_DiskIn = temp ^ 1;
479 else
481 /* No disk in drive */
482 iotd->iotd_Req.io_Actual = 1;
484 iotd->iotd_Req.io_Error=0;
485 break;
486 case ETD_FORMAT:
487 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
488 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
489 break;
491 case TD_FORMAT:
492 tdu->tdu_Busy = TRUE;
493 iotd->iotd_Req.io_Error = td_format(iotd,tdb);
494 tdu->tdu_Busy = FALSE;
495 break;
496 case ETD_MOTOR:
497 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
498 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
499 break;
501 case TD_MOTOR:
502 iotd->iotd_Req.io_Error=0;
503 switch (iotd->iotd_Req.io_Length)
505 case 0:
506 tdu->tdu_MotorOn = 0;
507 td_motoroff(tdu->tdu_UnitNum,tdb);
508 break;
509 case 1:
510 tdu->tdu_MotorOn = 1;
511 td_motoron(tdu->tdu_UnitNum,tdb,TRUE);
512 break;
513 default:
514 iotd->iotd_Req.io_Error = TDERR_NotSpecified;
515 break;
517 break;
518 case TD_PROTSTATUS:
519 iotd->iotd_Req.io_Actual = tdu->tdu_ProtStatus;
520 iotd->iotd_Req.io_Error=0;
521 break;
522 case TD_REMCHANGEINT:
523 Forbid();
524 Remove((struct Node *)iotd);
525 Permit();
526 break;
527 case TD_GETGEOMETRY:
528 geo = (struct DriveGeometry *)iotd->iotd_Req.io_Data;
529 geo->dg_SectorSize = 512;
530 geo->dg_TotalSectors = DP_STOTAL;
531 geo->dg_Cylinders = DP_TRACKS;
532 geo->dg_CylSectors = DP_SECTORS*2;
533 geo->dg_Heads = 2;
534 geo->dg_TrackSectors = DP_SECTORS;
535 geo->dg_BufMemType = MEMF_PUBLIC;
536 geo->dg_DeviceType = DG_DIRECT_ACCESS;
537 geo->dg_Flags = DGF_REMOVABLE;
538 iotd->iotd_Req.io_Error=0;
539 break;
540 case TD_GETDRIVETYPE:
541 iotd->iotd_Req.io_Actual = DRIVE3_5;
542 iotd->iotd_Req.io_Error=0;
543 break;
544 case TD_GETNUMTRACKS:
545 iotd->iotd_Req.io_Actual = DP_TRACKS*2;
546 iotd->iotd_Req.io_Error=0;
547 break;
548 case ETD_SEEK:
549 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
550 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
551 break;
553 case TD_SEEK:
554 temp = (iotd->iotd_Req.io_Offset >> 10) / DP_SECTORS;
555 tdu->tdu_MotorOn = 1;
556 iotd->iotd_Req.io_Error = td_recalibrate(tdu->tdu_UnitNum, 0, temp, tdb);
557 break;
558 default:
559 /* Not supported */
560 D(bug("TD: Unknown command received\n"));
561 iotd->iotd_Req.io_Error = IOERR_NOCMD;
562 break;
563 } /* switch(iotd->iotd_Req.io_Command) */
564 return (reply);
567 ULONG TD_InitTask(struct TrackDiskBase *tdb)
569 struct TaskData *t;
570 struct MemList *ml;
571 struct Task *me;
573 /* Allocate Task Data structure */
574 t = AllocMem(sizeof(struct TaskData), MEMF_PUBLIC|MEMF_CLEAR);
575 /* Allocate Stack space */
576 if ((t) && ((t->td_Stack = AllocMem(STACK_SIZE, MEMF_PUBLIC|MEMF_CLEAR)) == NULL))
578 FreeMem(t, sizeof(struct TaskData));
579 t = NULL;
581 /* Allocate MemEntry for this task */
582 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
584 /* Find the current task */
585 me = FindTask(NULL);
587 if (t && ml)
589 D(bug("TD: Creating devicetask..."));
590 /* Save stack info into task structure */
591 t->td_Task.tc_SPLower = t->td_Stack;
592 t->td_Task.tc_SPUpper = (BYTE *)t->td_Stack + STACK_SIZE;
593 t->td_Task.tc_SPReg = (BYTE *)t->td_Task.tc_SPUpper - SP_OFFSET - sizeof(APTR);
595 /* Init MsgPort */
596 NEWLIST(&t->td_Port.mp_MsgList);
597 t->td_Port.mp_Node.ln_Type = NT_MSGPORT;
598 t->td_Port.mp_Flags = PA_SIGNAL;
599 t->td_Port.mp_SigBit = SIGBREAKB_CTRL_F;
600 t->td_Port.mp_SigTask = &t->td_Task;
601 t->td_Port.mp_Node.ln_Name = "trackdisk.device";
603 /* Init MemList */
604 ml->ml_NumEntries = 1;
605 ml->ml_ME[0].me_Addr = t;
606 ml->ml_ME[0].me_Length = sizeof(struct TaskData);
607 NEWLIST(&t->td_Task.tc_MemEntry);
608 AddHead(&t->td_Task.tc_MemEntry, &ml->ml_Node);
610 /* Init Task structure */
611 t->td_Task.tc_Node.ln_Name = "trackdisk.task";
612 t->td_Task.tc_Node.ln_Type = NT_TASK;
613 t->td_Task.tc_Node.ln_Pri = 5;
614 t->td_Task.tc_UserData = me;
616 tdb->td_TaskData = t;
618 struct TagItem task_Tags[] = {
619 { TASKTAG_ARG1, (IPTR)tdb },
620 { TAG_DONE, 0 },
622 /* Add task to system task list */
623 NewAddTask(&t->td_Task, &TD_DevTask, NULL, task_Tags );
625 /* Wait until started */
626 Wait(SIGBREAKF_CTRL_F);
628 D(bug(" OK\n"));
630 return 1;
632 else
634 if (t)
636 if (t->td_Stack) FreeMem(t->td_Stack, STACK_SIZE);
637 FreeMem(t, sizeof(struct TaskData));
639 if (ml) FreeMem(ml, sizeof(struct MemList));
642 return 0;
645 static void TD_DevTask(struct TrackDiskBase *tdb)
647 struct TaskData *td;
648 struct IOExtTD *iotd;
649 struct TDU *tdu;
650 ULONG tasig,tisig,sigs,i;
651 UBYTE dir;
653 D(bug("[TDTask] TD_DevTask(tdb=%p)\n", tdb));
655 td = tdb->td_TaskData;
657 D(bug("[TDTask] TD_DevTask: struct TaskData @ %p\n", td));
659 tdb->td_IntBit = AllocSignal(-1);
660 tdb->td_TmoBit = AllocSignal(-1);
661 tdb->td_TimerMP = CreateMsgPort();
662 tdb->td_TimerIO = (struct timerequest *) CreateIORequest(tdb->td_TimerMP, sizeof(struct timerequest));
663 OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tdb->td_TimerIO, 0);
665 /* Initialize FDC */
666 td_dinit(tdb);
668 /* Initial check for floppies */
669 for (i=0;i<TD_NUMUNITS;i++)
671 if(tdb->td_Units[i])
673 td_rseek(i, 0, 1, tdb);
674 tdb->td_Units[i]->tdu_Present = !td_recalibrate(tdb->td_Units[i]->tdu_UnitNum,1,0,tdb);
675 tdb->td_Units[i]->pub.tdu_CurrTrk = 0;
676 tdb->td_Units[i]->tdu_DiskIn = (td_getDiskChange() ^ 1);
677 tdb->td_Units[i]->tdu_ProtStatus = td_getprotstatus(i,tdb);
678 tdb->td_Units[i]->tdu_Busy = FALSE;
679 tdb->td_Units[i]->tdu_stepdir = 0;
680 if (((tdb->td_Units[i]->pub.tdu_PubFlags & TDPF_NOCLICK) && (tdb->td_Units[i]->tdu_DiskIn == TDU_NODISK))
681 || (!tdb->td_Units[i]->tdu_Present))
682 td_motoroff(i, tdb);
683 D(bug("Drive %d presence: %ld\n", i, tdb->td_Units[i]->tdu_Present));
687 tasig = 1L << td->td_Port.mp_SigBit;
688 tisig = 1L << tdb->td_TimerMP->mp_SigBit;
690 /* Reply to startup message */
691 Signal(td->td_Task.tc_UserData,SIGBREAKF_CTRL_F);
693 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
694 tdb->td_TimerIO->tr_time.tv_secs = 2;
695 tdb->td_TimerIO->tr_time.tv_micro = 500000;
696 SendIO((struct IORequest *)tdb->td_TimerIO);
698 /* Endless task loop */
699 for(;;)
701 sigs = 0L;
702 sigs = Wait(tasig | tisig); /* Wait for a message */
703 /* If unit was not active process message */
704 if (sigs & tasig)
706 /* We received a message. Deal with it */
707 while((iotd = (struct IOExtTD *)GetMsg(&td->td_Port)) != NULL)
709 /* Execute command */
710 if (TD_PerformIO( iotd, tdb))
712 /* Finish message */
713 ReplyMsg((struct Message *)iotd);
717 if (sigs & tisig)
719 /* We were woken up by the timer. */
720 WaitIO((struct IORequest *)tdb->td_TimerIO);
721 for(i=0;i<TD_NUMUNITS;i++)
723 /* If there is no floppy in drive, scan for changes */
724 if (tdb->td_Units[i])
726 tdu = tdb->td_Units[i];
727 switch (tdu->tdu_DiskIn)
729 case TDU_NODISK:
731 Unfortunately "NoClick" technology which works on Amiga will not
732 work on PC because i82077 does not send step pulse when told to
733 seek to "-1" track and the drive can't recognize disk insertion.
734 Many thanks to Intel! :-(((
736 Here we use another technique: in NoClick mode we just do nothing
737 if the disk is not in drive. We can perform this test only once
738 inside TD_CHANGESTATE command which is invoked by DISKCHANGE
739 CLI command. This means that we'll have to issue DISKCHANGE command
740 manually after we insert the disk, but this is probably better
741 than those clicks.
743 if (tdu->pub.tdu_PubFlags & TDPF_NOCLICK) {
744 if (!tdu->tdu_MotorOn)
745 td_motoroff(tdu->tdu_UnitNum, tdb);
746 } else
747 TestInsert(tdb, tdu);
748 break;
749 case TDU_DISK:
751 Fortunately this part is completely silent so we don't have to
752 do any extra mess here
754 if (!tdu->tdu_Busy)
756 if (!tdu->tdu_MotorOn)
757 td_motoron(tdu->tdu_UnitNum,tdb,FALSE);
758 dir = (inb(FDC_DIR)>>7);
759 if (!tdu->tdu_MotorOn)
760 td_motoroff(tdu->tdu_UnitNum,tdb);
761 if (dir == 1)
763 D(bug("[Floppy] Removal detected\n"));
764 /* Go to cylinder 0 */
765 td_recalibrate(tdu->tdu_UnitNum,1,0,tdb);
766 tdu->tdu_DiskIn = TDU_NODISK;
767 tdu->pub.tdu_Counter++;
768 Forbid();
769 ForeachNode(&tdu->tdu_Listeners,iotd)
771 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
773 Permit();
774 tdu->tdu_stepdir = 0;
777 break;
782 /* Reload the timer again */
783 GetMsg(tdb->td_TimerMP);
784 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
785 tdb->td_TimerIO->tr_time.tv_secs = 2;
786 tdb->td_TimerIO->tr_time.tv_micro = 500000;
787 SendIO((struct IORequest *)tdb->td_TimerIO);