- Updated handler name.
[AROS.git] / rom / devs / trackdisk / trackdisk_device.c
blob21e21a3b59ebf2fc457fbd3537df9e889dcf172c
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 = "afs-handler";
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_CHIP | 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 if (( (((ULONG)(IPTR)unit->td_DMABuffer + DP_SECTORS*512) & 0xffff0000) -
89 ((ULONG)(IPTR)unit->td_DMABuffer&0xffff0000) ) != 0)
91 APTR buffer;
93 buffer = AllocMem(DP_SECTORS*512, MEMF_CLEAR | MEMF_CHIP | MEMF_24BITDMA);
94 if (!buffer)
96 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_NoMemory);
99 FreeMem(unit->td_DMABuffer, DP_SECTORS*512);
100 unit->td_DMABuffer = buffer;
102 /* Store the unit in TDBase */
103 tdb->td_Units[num] = unit;
105 if (ExpansionBase)
107 D(bug("TD: Adding bootnode\n"));
108 pp = (IPTR *)AllocMem(sizeof(struct DosEnvec)+sizeof(IPTR)*4,MEMF_PUBLIC|MEMF_CLEAR);
110 if (pp)
112 dosdevname[2] += num;
113 pp[0] = (IPTR)dosdevname;
114 pp[1] = (IPTR)MOD_NAME_STRING;
115 pp[2] = num;
116 pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS;
117 pp[DE_SIZEBLOCK + 4] = 128;
118 pp[DE_NUMHEADS + 4] = 2;
119 pp[DE_SECSPERBLOCK + 4] = 1;
120 pp[DE_BLKSPERTRACK + 4] = 18;
121 pp[DE_RESERVEDBLKS + 4] = 2;
122 pp[DE_LOWCYL + 4] = 0;
123 pp[DE_HIGHCYL + 4] = 79;
124 pp[DE_NUMBUFFERS + 4] = 10;
125 pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC | MEMF_CHIP;
126 pp[DE_MAXTRANSFER + 4] = 0x00200000;
127 pp[DE_MASK + 4] = 0x7FFFFFFE;
128 pp[DE_BOOTPRI + 4] = 5;
129 pp[DE_DOSTYPE + 4] = 0;
130 pp[DE_BOOTBLOCKS + 4] = 2;
131 devnode = MakeDosNode(pp);
133 if (devnode)
135 len = strlen(handler);
136 devnode->dn_Handler = MKBADDR(AllocMem(
137 AROS_BSTR_MEMSIZE4LEN(len), MEMF_PUBLIC | MEMF_CLEAR)
140 if (devnode->dn_Handler != BNULL)
142 CopyMem(handler, AROS_BSTR_ADDR(devnode->dn_Handler),
143 len);
144 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
145 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, NULL);
151 if (ExpansionBase)
153 CloseLibrary((struct Library *)ExpansionBase);
155 return (unit);
158 static AROS_INTH1(td_floppytimer, struct TrackDiskBase *, TDBase)
160 AROS_INTFUNC_INIT
162 // Does anyone wait for io?
163 if (TDBase->td_inttmo)
165 // Decrease timeout
166 TDBase->td_inttmo--;
167 // timeout?
168 if (!TDBase->td_inttmo)
170 Signal(&TDBase->td_TaskData->td_Task,(1L << TDBase->td_TmoBit));
174 return FALSE;
176 AROS_INTFUNC_EXIT
179 static AROS_INTH1(td_floppyint, struct TrackDiskBase *, TDBase)
181 AROS_INTFUNC_INIT
183 Signal(&TDBase->td_TaskData->td_Task,(1L << TDBase->td_IntBit));
185 return FALSE;
187 AROS_INTFUNC_EXIT
190 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR TDBase)
192 struct BootLoaderBase *BootLoaderBase;
193 ULONG i;
194 UBYTE drives;
195 struct Interrupt *irq;
197 D(bug("TD: Init\n"));
199 /* First thing, are we disabled from the bootloader? */
200 if ((BootLoaderBase = OpenResource("bootloader.resource")))
202 struct List *list;
203 struct Node *node;
205 list = (struct List *)GetBootInfo(BL_Args);
206 if (list)
208 ForeachNode(list,node)
210 if (0 == strncmp(node->ln_Name,"floppy=",5))
212 if (strstr(&node->ln_Name[7], "disabled"))
214 D(bug("[Floppy] Disabled with bootloader argument\n"));
215 return FALSE;
217 TDBase->td_nomount = (strstr(&node->ln_Name[7], "nomount") != NULL);
223 /* First we check if there are any floppy drives configured in BIOS */
224 /* We do this by reading CMOS byte 0x10 */
225 /* It should really reside in battclock.resource */
226 outb(0x10,0x70);
227 drives = inb(0x71);
229 if (drives == 0)
231 /* No drives here. abort */
232 D(bug("TD: No drives defined in BIOS\n"));
233 return FALSE;
236 for (i=0; i<TD_NUMUNITS; i++)
237 TDBase->td_Units[i] = NULL;
239 irq = &TDBase->td_FloppyInt;
240 irq->is_Node.ln_Type = NT_INTERRUPT;
241 irq->is_Node.ln_Pri=127; /* Set the highest pri */
242 irq->is_Node.ln_Name = (STRPTR)MOD_NAME_STRING;
243 irq->is_Code = (VOID_FUNC)td_floppyint;
244 irq->is_Data = (APTR)TDBase;
246 AddIntServer(INTB_KERNEL + 6, irq);
248 irq = &TDBase->td_TimerInt;
249 irq->is_Node.ln_Type = NT_INTERRUPT;
250 irq->is_Node.ln_Pri=10; /* Set the highest pri */
251 irq->is_Node.ln_Name = (STRPTR)MOD_NAME_STRING;
252 irq->is_Code = (VOID_FUNC)td_floppytimer;
253 irq->is_Data = (APTR)TDBase;
255 AddIntServer(INTB_KERNEL + 0, irq);
257 /* Swap drivebits around */
258 drives = ( (drives&0xf0)>>4 | (drives&0x0f)<<4 );
260 for (i=0;i<TD_NUMUNITS;i++)
262 /* We only want 3.5" 1.44MB drives */
263 if (((drives >> (4*i))&0x0f) == 4)
265 kprintf("[Floppy] Unit %d is a 1.44MB drive\n",i);
266 TD_InitUnit(i,TDBase);
270 /* Create the message processor task */
271 TD_InitTask(TDBase);
273 return TRUE;
276 static int GM_UNIQUENAME(Open)
278 LIBBASETYPEPTR TDBase,
279 struct IOExtTD *iotd,
280 ULONG unitnum,
281 ULONG flags
284 D(bug("TD: Open\n"));
285 iotd->iotd_Req.io_Error = IOERR_OPENFAIL;
287 /* Is the requested unitNumber valid? */
288 if (unitnum < TD_NUMUNITS)
290 struct TDU *unit;
292 iotd->iotd_Req.io_Device = (struct Device *)TDBase;
294 /* Get TDU structure */
295 unit = TDBase->td_Units[unitnum];
296 if (unit && (unit->tdu_Present)) {
297 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
298 ((struct Unit *)unit)->unit_OpenCnt++;
299 iotd->iotd_Req.io_Error = 0;
303 return iotd->iotd_Req.io_Error == 0;
307 static int GM_UNIQUENAME(Close)
309 LIBBASETYPEPTR TDBase,
310 struct IOExtTD *iotd
313 iotd->iotd_Req.io_Unit->unit_OpenCnt --;
315 return TRUE;
318 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
319 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
320 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
322 AROS_LH1(void, beginio,
323 AROS_LHA(struct IOExtTD *, iotd, A1),
324 struct TrackDiskBase *, TDBase, 5, TrackDisk)
326 AROS_LIBFUNC_INIT
327 struct TDU *tdu;
329 if (iotd->iotd_Req.io_Flags & IOF_QUICK)
331 switch(iotd->iotd_Req.io_Command)
333 case TD_CHANGESTATE:
334 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
335 if ((!(tdu->pub.tdu_PubFlags & TDPF_NOCLICK)) || (tdu->tdu_DiskIn == TDU_DISK))
336 break;
337 case CMD_READ:
338 case CMD_UPDATE:
339 case CMD_WRITE:
340 case TD_FORMAT:
341 case TD_MOTOR:
342 case TD_SEEK:
343 case ETD_READ:
344 case ETD_UPDATE:
345 case ETD_WRITE:
346 case ETD_FORMAT:
347 case ETD_MOTOR:
348 case ETD_SEEK:
349 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
350 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
351 return;
353 TD_PerformIO(iotd,TDBase);
354 return;
356 else
358 /* Forward to devicetask */
359 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
360 /* Not done quick */
361 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
362 return;
364 AROS_LIBFUNC_EXIT
367 AROS_LH1(LONG, abortio,
368 AROS_LHA(struct IOExtTD *, iotd, A1),
369 struct TrackDiskBase *, TDBase, 6, TrackDisk)
371 AROS_LIBFUNC_INIT
372 D(bug("TD: AbortIO\n"));
373 return IOERR_NOCMD;
374 AROS_LIBFUNC_EXIT
377 void TestInsert(struct TrackDiskBase *tdb, struct TDU *tdu)
379 UBYTE dir;
380 struct IOExtTD *iotd;
382 td_rseek(tdu->tdu_UnitNum,tdu->tdu_stepdir,1,tdb);
383 tdu->tdu_stepdir = !tdu->tdu_stepdir;
384 dir = (inb(FDC_DIR)>>7);
385 if (dir == 0)
387 D(bug("[Floppy] Insertion detected\n"));
388 td_recalibrate(tdu->tdu_UnitNum,1,0,tdb);
389 tdu->tdu_DiskIn = TDU_DISK;
390 tdu->pub.tdu_Counter++;
391 tdu->tdu_ProtStatus = td_getprotstatus(tdu->tdu_UnitNum,tdb);
392 Forbid();
393 ForeachNode(&tdu->tdu_Listeners,iotd)
395 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
397 Permit();
401 BOOL TD_PerformIO( struct IOExtTD *iotd, struct TrackDiskBase *tdb)
403 struct TDU *tdu;
404 struct DriveGeometry *geo;
405 UBYTE temp;
406 BOOL reply;
408 reply = TRUE;
409 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
410 switch(iotd->iotd_Req.io_Command)
412 case ETD_CLEAR:
413 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
414 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
415 break;
417 case CMD_CLEAR:
418 tdu->tdu_flags = 0;
419 tdu->tdu_lastcyl = -1;
420 tdu->tdu_lasthd = -1;
421 iotd->iotd_Req.io_Error = 0;
422 break;
423 case ETD_READ:
424 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
425 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
426 break;
428 case CMD_READ:
429 tdu->tdu_Busy = TRUE;
430 iotd->iotd_Req.io_Error = td_read(iotd, tdb);
431 tdu->tdu_Busy = FALSE;
432 break;
433 case ETD_UPDATE:
434 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
435 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
436 break;
438 case CMD_UPDATE:
439 tdu->tdu_Busy = TRUE;
440 iotd->iotd_Req.io_Error = td_update(tdu, tdb);
441 tdu->tdu_Busy = FALSE;
442 break;
443 case ETD_WRITE:
444 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
445 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
446 break;
448 case CMD_WRITE:
449 tdu->tdu_Busy = TRUE;
450 iotd->iotd_Req.io_Error = td_write(iotd, tdb);
451 tdu->tdu_Busy = FALSE;
452 break;
453 case TD_ADDCHANGEINT:
454 Forbid();
455 AddTail(&tdu->tdu_Listeners,(struct Node *)iotd);
456 Permit();
457 reply = FALSE;
458 break;
459 case TD_CHANGENUM:
460 iotd->iotd_Req.io_Actual = tdu->pub.tdu_Counter;
461 iotd->iotd_Req.io_Error=0;
462 break;
463 case TD_CHANGESTATE:
464 if ((tdu->pub.tdu_PubFlags & TDPF_NOCLICK) && (tdu->tdu_DiskIn == TDU_NODISK)) {
465 TestInsert(tdb, tdu);
466 if (!tdu->tdu_MotorOn)
467 td_motoroff(tdu->tdu_UnitNum, tdb);
469 if (tdu->tdu_DiskIn == TDU_DISK)
471 /* test if disk is still in there */
472 temp = td_getDiskChange();
473 iotd->iotd_Req.io_Actual = temp;
474 tdu->tdu_DiskIn = temp ^ 1;
476 else
478 /* No disk in drive */
479 iotd->iotd_Req.io_Actual = 1;
481 iotd->iotd_Req.io_Error=0;
482 break;
483 case ETD_FORMAT:
484 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
485 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
486 break;
488 case TD_FORMAT:
489 tdu->tdu_Busy = TRUE;
490 iotd->iotd_Req.io_Error = td_format(iotd,tdb);
491 tdu->tdu_Busy = FALSE;
492 break;
493 case ETD_MOTOR:
494 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
495 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
496 break;
498 case TD_MOTOR:
499 iotd->iotd_Req.io_Error=0;
500 switch (iotd->iotd_Req.io_Length)
502 case 0:
503 tdu->tdu_MotorOn = 0;
504 td_motoroff(tdu->tdu_UnitNum,tdb);
505 break;
506 case 1:
507 tdu->tdu_MotorOn = 1;
508 td_motoron(tdu->tdu_UnitNum,tdb,TRUE);
509 break;
510 default:
511 iotd->iotd_Req.io_Error = TDERR_NotSpecified;
512 break;
514 break;
515 case TD_PROTSTATUS:
516 iotd->iotd_Req.io_Actual = tdu->tdu_ProtStatus;
517 iotd->iotd_Req.io_Error=0;
518 break;
519 case TD_REMCHANGEINT:
520 Forbid();
521 Remove((struct Node *)iotd);
522 Permit();
523 break;
524 case TD_GETGEOMETRY:
525 geo = (struct DriveGeometry *)iotd->iotd_Req.io_Data;
526 geo->dg_SectorSize = 512;
527 geo->dg_TotalSectors = DP_STOTAL;
528 geo->dg_Cylinders = DP_TRACKS;
529 geo->dg_CylSectors = DP_SECTORS*2;
530 geo->dg_Heads = 2;
531 geo->dg_TrackSectors = DP_SECTORS;
532 geo->dg_BufMemType = MEMF_PUBLIC;
533 geo->dg_DeviceType = DG_DIRECT_ACCESS;
534 geo->dg_Flags = DGF_REMOVABLE;
535 iotd->iotd_Req.io_Error=0;
536 break;
537 case TD_GETDRIVETYPE:
538 iotd->iotd_Req.io_Actual = DRIVE3_5;
539 iotd->iotd_Req.io_Error=0;
540 break;
541 case TD_GETNUMTRACKS:
542 iotd->iotd_Req.io_Actual = DP_TRACKS*2;
543 iotd->iotd_Req.io_Error=0;
544 break;
545 case ETD_SEEK:
546 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
547 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
548 break;
550 case TD_SEEK:
551 temp = (iotd->iotd_Req.io_Offset >> 10) / DP_SECTORS;
552 tdu->tdu_MotorOn = 1;
553 iotd->iotd_Req.io_Error = td_recalibrate(tdu->tdu_UnitNum, 0, temp, tdb);
554 break;
555 default:
556 /* Not supported */
557 D(bug("TD: Unknown command received\n"));
558 iotd->iotd_Req.io_Error = IOERR_NOCMD;
559 break;
560 } /* switch(iotd->iotd_Req.io_Command) */
561 return (reply);
564 ULONG TD_InitTask(struct TrackDiskBase *tdb)
566 struct TaskData *t;
567 struct MemList *ml;
568 struct Task *me;
570 /* Allocate Task Data structure */
571 t = AllocMem(sizeof(struct TaskData), MEMF_PUBLIC|MEMF_CLEAR);
572 /* Allocate Stack space */
573 if ((t) && ((t->td_Stack = AllocMem(STACK_SIZE, MEMF_PUBLIC|MEMF_CLEAR)) == NULL))
575 FreeMem(t, sizeof(struct TaskData));
576 t = NULL;
578 /* Allocate MemEntry for this task */
579 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
581 /* Find the current task */
582 me = FindTask(NULL);
584 if (t && ml)
586 D(bug("TD: Creating devicetask..."));
587 /* Save stack info into task structure */
588 t->td_Task.tc_SPLower = t->td_Stack;
589 t->td_Task.tc_SPUpper = (BYTE *)t->td_Stack + STACK_SIZE;
590 t->td_Task.tc_SPReg = (BYTE *)t->td_Task.tc_SPUpper - SP_OFFSET - sizeof(APTR);
592 /* Init MsgPort */
593 NEWLIST(&t->td_Port.mp_MsgList);
594 t->td_Port.mp_Node.ln_Type = NT_MSGPORT;
595 t->td_Port.mp_Flags = PA_SIGNAL;
596 t->td_Port.mp_SigBit = SIGBREAKB_CTRL_F;
597 t->td_Port.mp_SigTask = &t->td_Task;
598 t->td_Port.mp_Node.ln_Name = "trackdisk.device";
600 /* Init MemList */
601 ml->ml_NumEntries = 1;
602 ml->ml_ME[0].me_Addr = t;
603 ml->ml_ME[0].me_Length = sizeof(struct TaskData);
604 NEWLIST(&t->td_Task.tc_MemEntry);
605 AddHead(&t->td_Task.tc_MemEntry, &ml->ml_Node);
607 /* Init Task structure */
608 t->td_Task.tc_Node.ln_Name = "trackdisk.task";
609 t->td_Task.tc_Node.ln_Type = NT_TASK;
610 t->td_Task.tc_Node.ln_Pri = 5;
611 t->td_Task.tc_UserData = me;
613 tdb->td_TaskData = t;
615 struct TagItem task_Tags[] = {
616 { TASKTAG_ARG1, (IPTR)tdb },
617 { TAG_DONE, 0 },
619 /* Add task to system task list */
620 NewAddTask(&t->td_Task, &TD_DevTask, NULL, task_Tags );
622 /* Wait until started */
623 Wait(SIGBREAKF_CTRL_F);
625 D(bug(" OK\n"));
627 return 1;
629 else
631 if (t)
633 if (t->td_Stack) FreeMem(t->td_Stack, STACK_SIZE);
634 FreeMem(t, sizeof(struct TaskData));
636 if (ml) FreeMem(ml, sizeof(struct MemList));
639 return 0;
642 static void TD_DevTask(struct TrackDiskBase *tdb)
644 struct TaskData *td;
645 struct IOExtTD *iotd;
646 struct TDU *tdu;
647 ULONG tasig,tisig,sigs,i;
648 UBYTE dir;
650 D(bug("[TDTask] TD_DevTask(tdb=%p)\n", tdb));
652 td = tdb->td_TaskData;
654 D(bug("[TDTask] TD_DevTask: struct TaskData @ %p\n", td));
656 tdb->td_IntBit = AllocSignal(-1);
657 tdb->td_TmoBit = AllocSignal(-1);
658 tdb->td_TimerMP = CreateMsgPort();
659 tdb->td_TimerIO = (struct timerequest *) CreateIORequest(tdb->td_TimerMP, sizeof(struct timerequest));
660 OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tdb->td_TimerIO, 0);
662 /* Initialize FDC */
663 td_dinit(tdb);
665 /* Initial check for floppies */
666 for (i=0;i<TD_NUMUNITS;i++)
668 if(tdb->td_Units[i])
670 td_rseek(i, 0, 1, tdb);
671 tdb->td_Units[i]->tdu_Present = !td_recalibrate(tdb->td_Units[i]->tdu_UnitNum,1,0,tdb);
672 tdb->td_Units[i]->pub.tdu_CurrTrk = 0;
673 tdb->td_Units[i]->tdu_DiskIn = (td_getDiskChange() ^ 1);
674 tdb->td_Units[i]->tdu_ProtStatus = td_getprotstatus(i,tdb);
675 tdb->td_Units[i]->tdu_Busy = FALSE;
676 tdb->td_Units[i]->tdu_stepdir = 0;
677 if (((tdb->td_Units[i]->pub.tdu_PubFlags & TDPF_NOCLICK) && (tdb->td_Units[i]->tdu_DiskIn == TDU_NODISK))
678 || (!tdb->td_Units[i]->tdu_Present))
679 td_motoroff(i, tdb);
680 D(bug("Drive %d presence: %ld\n", i, tdb->td_Units[i]->tdu_Present));
684 tasig = 1L << td->td_Port.mp_SigBit;
685 tisig = 1L << tdb->td_TimerMP->mp_SigBit;
687 /* Reply to startup message */
688 Signal(td->td_Task.tc_UserData,SIGBREAKF_CTRL_F);
690 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
691 tdb->td_TimerIO->tr_time.tv_secs = 2;
692 tdb->td_TimerIO->tr_time.tv_micro = 500000;
693 SendIO((struct IORequest *)tdb->td_TimerIO);
695 /* Endless task loop */
696 for(;;)
698 sigs = 0L;
699 sigs = Wait(tasig | tisig); /* Wait for a message */
700 /* If unit was not active process message */
701 if (sigs & tasig)
703 /* We received a message. Deal with it */
704 while((iotd = (struct IOExtTD *)GetMsg(&td->td_Port)) != NULL)
706 /* Execute command */
707 if (TD_PerformIO( iotd, tdb))
709 /* Finish message */
710 ReplyMsg((struct Message *)iotd);
714 if (sigs & tisig)
716 /* We were woken up by the timer. */
717 WaitIO((struct IORequest *)tdb->td_TimerIO);
718 for(i=0;i<TD_NUMUNITS;i++)
720 /* If there is no floppy in drive, scan for changes */
721 if (tdb->td_Units[i])
723 tdu = tdb->td_Units[i];
724 switch (tdu->tdu_DiskIn)
726 case TDU_NODISK:
728 Unfortunately "NoClick" technology which works on Amiga will not
729 work on PC because i82077 does not send step pulse when told to
730 seek to "-1" track and the drive can't recognize disk insertion.
731 Many thanks to Intel! :-(((
733 Here we use another technique: in NoClick mode we just do nothing
734 if the disk is not in drive. We can perform this test only once
735 inside TD_CHANGESTATE command which is invoked by DISKCHANGE
736 CLI command. This means that we'll have to issue DISKCHANGE command
737 manually after wi insert the disk, but this is probably better
738 than those clicks.
740 if (tdu->pub.tdu_PubFlags & TDPF_NOCLICK) {
741 if (!tdu->tdu_MotorOn)
742 td_motoroff(tdu->tdu_UnitNum, tdb);
743 } else
744 TestInsert(tdb, tdu);
745 break;
746 case TDU_DISK:
748 Fortunately this part is completely silent so we don't have to
749 do any extra mess here
751 if (!tdu->tdu_Busy)
753 if (!tdu->tdu_MotorOn)
754 td_motoron(tdu->tdu_UnitNum,tdb,FALSE);
755 dir = (inb(FDC_DIR)>>7);
756 if (!tdu->tdu_MotorOn)
757 td_motoroff(tdu->tdu_UnitNum,tdb);
758 if (dir == 1)
760 D(bug("[Floppy] Removal detected\n"));
761 /* Go to cylinder 0 */
762 td_recalibrate(tdu->tdu_UnitNum,1,0,tdb);
763 tdu->tdu_DiskIn = TDU_NODISK;
764 tdu->pub.tdu_Counter++;
765 Forbid();
766 ForeachNode(&tdu->tdu_Listeners,iotd)
768 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
770 Permit();
771 tdu->tdu_stepdir = 0;
774 break;
779 /* Reload the timer again */
780 GetMsg(tdb->td_TimerMP);
781 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
782 tdb->td_TimerIO->tr_time.tv_secs = 2;
783 tdb->td_TimerIO->tr_time.tv_micro = 500000;
784 SendIO((struct IORequest *)tdb->td_TimerIO);