1 #include <aros/debug.h>
5 #include <utility/tagitem.h>
6 #include <proto/exec.h>
8 #include <proto/utility.h>
14 static void Hidd_ATABus_HandleIRQ(UBYTE status
, struct ata_Bus
*bus
)
16 struct ata_Unit
*unit
= bus
->ab_SelectedUnit
;
19 * don't waste your time on checking other devices.
20 * pass irq ONLY if task is expecting one;
22 if (unit
&& bus
->ab_HandleIRQ
)
24 /* ok, we have a routine to handle any form of transmission etc. */
25 DIRQ(bug("[ATA%02d] IRQ: Calling dedicated handler 0x%p... \n",
26 unit
->au_UnitNum
, bus
->ab_HandleIRQ
));
27 bus
->ab_HandleIRQ(unit
, status
);
34 * if we got *here* then device is most likely not expected to have an irq.
36 bug("[ATA%02d] Spurious IRQ\n", unit
? unit
->au_UnitNum
: -1);
38 if (0 == (ATAF_BUSY
& status
))
40 bug("[ATA ] STATUS: %02lx\n" , status
);
41 bug("[ATA ] ALT STATUS: %02lx\n" , PIO_InAlt(bus
, ata_AltStatus
));
42 bug("[ATA ] ERROR: %02lx\n" , PIO_In(bus
, ata_Error
));
43 bug("[ATA ] IRQ: REASON: %02lx\n", PIO_In(bus
, atapi_Reason
));
48 static AROS_INTH1(ataBus_Reset
, struct ata_Bus
*, bus
)
52 struct ataBase
*ATABase
= bus
->ab_Base
;
53 OOP_Object
*obj
= (void *)bus
- ATABase
->ataClass
->InstOffset
;
55 HIDD_ATABus_Shutdown(obj
);
61 /*****************************************************************************************
70 This class serves as a base class for implementing IDE (ATA) bus drivers.
71 One particularity of this class is that IDE bus is very speed-critical.
72 At the other hand, the driver implements very lowlevel operations which
73 are called quite often. OOP_DoMethod() call is not fast enough, and in
74 order to curcumvent this limitation, additionally to normal OOP API
75 IDE bus drivers offer two additional non-standard interfaces. Internally
76 they are implemented as library-alike function table plus driver-specific
77 data. For the purpose of some performance optimizations the function
78 table is private to ata.device and managed entirely by the base class.
79 Driver classes have access only to data portion.
81 These interfaces are documented below.
83 *****************************************************************************************/
84 /*****************************************************************************************
93 PIO interface is responsible for accessing I/O registers on the IDE
94 bus, as well as performing PIO-mode 16- and 32-bit data transfers.
95 This interface is mandatory and must be implemented by the driver,
96 however some functions are optional. They can be either omitted
97 entirely from the function table, or set to NULL pointers.
99 Control functions table for the interface consists of the following
100 functions (listed in their order in the array):
102 VOID ata_out(void *obj, UBYTE val, UWORD offset)
103 - Write byte into primary register bank with the given offset.
105 UBYTE ata_in(void *obj, UWORD offset)
106 - Read byte from primary register bank with the given offset.
108 VOID ata_out_alt(void *obj, UBYTE val, UWORD offset)
109 - Write byte into alternate register bank with the given offset.
110 This function is optional.
112 UBYTE ata_in_alt(void *obj, UWORD offset)
113 - Read byte from alternate register bank with the given offset.
114 This function is optional.
116 Transfer functions table for the interface consists of the following
117 functions (listed in their order in the array):
119 VOID ata_outsw(void *obj, APTR address, ULONG count)
120 - Perform 16-bit PIO data write operation from the given memory
121 region of the given size.
123 VOID ata_insw(void *obj, APTR address, ULONG count)
124 - Perform 16-bit PIO data read operation into the given memory
125 region of the given size.
127 VOID ata_outsl(void *obj, APTR address, ULONG count)
128 - Perform 32-bit PIO data write operation from the given memory
129 region of the given size. This function is optional.
131 UBYTE ata_insl(void *obj, APTR address, ULONG count)
132 - Perform 32-bit PIO data read operation into the given memory
133 region of the given size. This function is optional.
135 *****************************************************************************************/
136 /*****************************************************************************************
145 DMA interface is optional, and is needed in order to support DMA data
148 Function table for the interface consists of the following functions:
150 BOOL dma_Setup(void *obj, APTR buffer, IPTR size, BOOL read)
151 - Prepare the controller to DMA data transfer. The last argument is
152 TRUE for read operation and FALSE for write. The function should
153 return TRUE for success or FALSE for failure.
155 VOID dma_Start(void *obj)
156 - Start DMA transfer.
158 VOID dma_End(void *obj, APTR buffer, IPTR size, BOOL read)
159 - End DMA transfer and perform post-transfer cleanup of the given region.
161 ULONG dma_Result(void *obj)
162 - Get resulting status of the operation. The function should return 0
163 for succesful completion or error code to be passed up to ata.device
164 caller in io_Result field of the IORequest.
166 *****************************************************************************************/
167 /*****************************************************************************************
170 aoHidd_ATABus_Use80Wire
179 Tells whether the bus currently uses 80-conductor cable.
191 *****************************************************************************************/
192 /*****************************************************************************************
195 aoHidd_ATABus_Use32Bit
204 When queried, tells whether the bus supports 32-bit PIO data transfers.
205 When set, enables or disables 32-bit mode for PIO data transfers.
217 *****************************************************************************************/
218 /*****************************************************************************************
230 Tells whether the bus supports DMA transfers.
241 Default implementation in base class returns value depending on whether
242 the subclass provided DMA interface function table during object creation.
244 *****************************************************************************************/
245 /*****************************************************************************************
248 aoHidd_ATABus_PIODataSize
257 Specifies size of PIO interface data structure.
269 *****************************************************************************************/
270 /*****************************************************************************************
273 aoHidd_ATABus_DMADataSize
282 Specifies size of DMA interface data structure.
294 *****************************************************************************************/
295 /*****************************************************************************************
298 aoHidd_ATABus_BusVectors
307 Specifies control functions table for building PIO interface object.
308 The function table is an array of function pointers terminated
309 by -1 value. The terminator must be present for purpose of
310 binary compatibility with future extensions.
313 This function table is mandatory to be implemented by the driver.
323 *****************************************************************************************/
324 /*****************************************************************************************
327 aoHidd_ATABus_PIOVectors
336 Specifies transfers function table for building PIO interface object.
337 The function table is an array of function pointers terminated
338 by -1 value. The terminator must be present for purpose of
339 binary compatibility with future extensions.
342 This function table is mandatory to be implemented by the driver.
352 *****************************************************************************************/
353 /*****************************************************************************************
356 aoHidd_ATABus_DMAVectors
365 Specifies function table for building DMA interface object. If not supplied,
366 the bus is considered not DMA-capable.
375 aoHidd_ATABus_PIOVectors
379 *****************************************************************************************/
380 /*****************************************************************************************
383 aoHidd_ATABus_IRQHandler
392 Specifies IRQ handler function to be called when bus interrupt arrives.
393 The function shoule be called using "C" calling convention and has the
396 void ata_HandleIRQ(UBYTE status, APTR userdata);
398 Your driver should pass the following arguments to this function:
399 status - value read from ATA main status register.
400 userdata - value of aoHidd_ATABus_IRQData attribute.
403 Reading drive status register is a part of interrupt acknowledge
404 process, thus it has to be done by the driver.
406 It is driver's job to check whether the interrupt really belongs to
407 the IDE bus. A generic way to do this is to test ATAF_BUSY bit of
408 the status register for being zero. However, this may not work
409 reliably with IRQ sharing, so advanced IDE controllers may offer
410 different, better way to do this.
417 aoHidd_ATABus_IRQData
421 *****************************************************************************************/
422 /*****************************************************************************************
425 aoHidd_ATABus_IRQData
434 Caller's private data to be supplied to IRQ handler function.
443 aoHidd_ATABus_IRQData
447 *****************************************************************************************/
449 OOP_Object
*ATABus__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
451 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
454 struct ataBase
*ATABase
= cl
->UserData
;
455 struct ata_Bus
*data
= OOP_INST_DATA(cl
, o
);
456 struct TagItem
*tstate
= msg
->attrList
;
459 while ((tag
= NextTagItem(&tstate
)))
463 Hidd_ATABus_Switch(tag
->ti_Tag
, idx
)
465 case aoHidd_ATABus_PIODataSize
:
466 data
->pioDataSize
= tag
->ti_Data
;
469 case aoHidd_ATABus_DMADataSize
:
470 data
->dmaDataSize
= tag
->ti_Data
;
473 case aoHidd_ATABus_BusVectors
:
474 data
->busVectors
= (APTR
*)tag
->ti_Data
;
477 case aoHidd_ATABus_PIOVectors
:
478 data
->pioVectors
= (struct ATA_PIOInterface
*)tag
->ti_Data
;
481 case aoHidd_ATABus_DMAVectors
:
482 data
->dmaVectors
= (APTR
*)tag
->ti_Data
;
487 /* Cache device base pointer. Useful. */
488 data
->ab_Base
= ATABase
;
490 /* Install reset callback */
491 data
->ab_ResetInt
.is_Node
.ln_Name
= ATABase
->ata_Device
.dd_Library
.lib_Node
.ln_Name
;
492 data
->ab_ResetInt
.is_Code
= (VOID_FUNC
)ataBus_Reset
;
493 data
->ab_ResetInt
.is_Data
= data
;
494 AddResetCallback(&data
->ab_ResetInt
);
499 void ATABus__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
501 struct ata_Bus
*data
= OOP_INST_DATA(cl
, o
);
503 RemResetCallback(&data
->ab_ResetInt
);
505 if (data
->dmaInterface
)
507 void *ptr
= data
->dmaInterface
- sizeof(struct ATA_DMAInterface
);
509 FreeMem(ptr
, sizeof(struct ATA_DMAInterface
) + data
->dmaDataSize
);
511 if (data
->pioInterface
)
513 void *ptr
= data
->pioInterface
- sizeof(struct ATA_BusInterface
);
515 FreeMem(ptr
, sizeof(struct ATA_BusInterface
) + data
->pioDataSize
);
518 OOP_DoSuperMethod(cl
, o
, msg
);
521 void ATABus__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
523 struct ataBase
*ATABase
= cl
->UserData
;
524 struct ata_Bus
*data
= OOP_INST_DATA(cl
, o
);
527 Hidd_ATABus_Switch (msg
->attrID
, idx
)
529 case aoHidd_ATABus_Use80Wire
:
530 /* CHECKME: Is there any generic way to check this ? */
531 *msg
->storage
= FALSE
;
534 case aoHidd_ATABus_Use32Bit
:
535 *msg
->storage
= (data
->pioVectors
->ata_outsl
&&
536 data
->pioVectors
->ata_insl
) ? TRUE
: FALSE
;
539 case aoHidd_ATABus_UseDMA
:
540 *msg
->storage
= data
->dmaVectors
? TRUE
: FALSE
;
544 OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
547 /* Default ata_out_alt does nothing */
548 static void default_out_alt(void *obj
, UBYTE val
, UWORD offset
)
553 /* Default ata_in_alt wraps AltStatus to status */
554 static UBYTE
default_in_alt(void *obj
, UWORD offset
)
556 struct ATA_BusInterface
*vec
= obj
- sizeof(struct ATA_BusInterface
);
558 return vec
->ata_in(obj
, ata_Status
);
561 static void CopyVectors(APTR
*dest
, APTR
*src
, unsigned int num
)
565 for (i
= 0; i
< num
; i
++)
567 if (src
[i
] == (APTR
*)-1)
574 /*****************************************************************************************
577 moHidd_ATABus_GetPIOInterface
580 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_ATABus_GetPIOInterface *Msg);
582 APTR HIDD_ATABus_GetPIOInterface(void);
588 Instantiates encapsulated PIO interface object and returns its
595 A pointer to opaque PIO interface object or NULL in case of failure.
598 This method should be overloaded by driver subclasses in order to
599 initialize data portion of the interface object.
606 moHidd_ATABus_GetDMAInterface
609 Interface objects contain not only driver-specific data, but also
610 a private vector table. Because of this you cannot just AllocMem()
611 the necessary structure in your driver. Always call OOP_DoSuperMethod()
612 in order for the base class to instantiate the interface correctly.
614 *****************************************************************************************/
616 APTR
ATABus__Hidd_ATABus__GetPIOInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
618 struct ata_Bus
*data
= OOP_INST_DATA(cl
, o
);
619 struct ATA_BusInterface
*vec
;
621 vec
= AllocMem(sizeof(struct ATA_BusInterface
) + data
->pioDataSize
,
622 MEMF_PUBLIC
|MEMF_CLEAR
);
625 /* Some default vectors for simplicity */
626 vec
->ata_out_alt
= default_out_alt
;
627 vec
->ata_in_alt
= default_in_alt
;
629 CopyVectors((APTR
*)vec
, data
->busVectors
,
630 sizeof(struct ATA_BusInterface
) / sizeof(APTR
));
632 data
->pioInterface
= &vec
[1];
633 return data
->pioInterface
;
639 /*****************************************************************************************
642 moHidd_ATABus_GetDMAInterface
645 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_ATABus_GetDMAInterface *Msg);
647 APTR HIDD_ATABus_GetDMAInterface(void);
653 Instantiates encapsulated DMA interface object and returns its
660 A pointer to opaque DMA interface object or NULL upon failure or
661 if DMA is not supported by this bus.
664 This method should be overloaded by driver subclasses in order to
665 initialize data portion of the interface object.
672 moHidd_ATABus_GetPIOInterface
675 Interface objects contain not only driver-specific data, but also
676 a private vector table. Because of this you cannot just AllocMem()
677 the necessary structure in your driver. Always call OOP_DoSuperMethod()
678 in order for the base class to instantiate the interface correctly.
680 *****************************************************************************************/
682 APTR
ATABus__Hidd_ATABus__GetDMAInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
684 struct ata_Bus
*data
= OOP_INST_DATA(cl
, o
);
685 struct ATA_DMAInterface
*vec
;
687 if (!data
->dmaVectors
)
690 vec
= AllocMem(sizeof(struct ATA_DMAInterface
) + data
->dmaDataSize
,
691 MEMF_PUBLIC
|MEMF_CLEAR
);
694 CopyVectors((APTR
*)vec
, data
->dmaVectors
,
695 sizeof(struct ATA_DMAInterface
) / sizeof(APTR
));
697 data
->dmaInterface
= &vec
[1];
698 return data
->dmaInterface
;
704 /*****************************************************************************************
707 moHidd_ATABus_SetXferMode
710 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_ATABus_SetXferMode *Msg);
712 APTR HIDD_ATABus_SetXferMode(UBYTE unit, ata_XferMode mode);
718 Sets the desired transfer mode for the given drive on the bus controller.
721 unit - drive number (0 for master and 1 for slave)
722 mode - Mode number (see hidd/ata.h)
725 TRUE if succesful or FALSE if the desired mode is not supported
729 The default implementation is provided for drivers not supporting
730 DMA and always returns FALSE if the caller attempts to set any of
741 *****************************************************************************************/
743 BOOL
ATABus__Hidd_ATABus__SetXferMode(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_ATABus_SetXferMode
*msg
)
745 if ((msg
->mode
>= AB_XFER_MDMA0
) && (msg
->mode
<= AB_XFER_UDMA6
))
747 /* DMA is not supported, we cannot set DMA modes */
754 /*****************************************************************************************
757 moHidd_ATABus_Shutdown
760 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_ATABus_Shutdown *Msg);
762 APTR HIDD_ATABus_Shutdown(void);
768 Instantly shutdown all activity on the bus.
777 This method is called by ata.device during system reset handler execution.
786 Default implementation disables interrupt using AltControl register.
788 *****************************************************************************************/
790 void ATABus__Hidd_ATABus__Shutdown(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg
*msg
)
792 struct ata_Bus
*data
= OOP_INST_DATA(cl
, o
);
794 if (data
->pioInterface
)
796 struct ATA_BusInterface
*vec
= data
->pioInterface
- sizeof(struct ATA_BusInterface
);
798 vec
->ata_out_alt(data
->pioInterface
, ATACTLF_INT_DISABLE
, ata_AltControl
);
802 /***************** Private nonvirtual methods follow *****************/
804 BOOL
Hidd_ATABus_Start(OOP_Object
*o
, struct ataBase
*ATABase
)
806 struct ata_Bus
*ab
= OOP_INST_DATA(ATABase
->busClass
, o
);
808 /* Attach IRQ handler */
809 OOP_SetAttrsTags(o
, aHidd_ATABus_IRQHandler
, Hidd_ATABus_HandleIRQ
,
810 aHidd_ATABus_IRQData
, ab
,
815 * TODO: This does not take into account possibility to
816 * unload drivers. In this case existing units will disappear,
817 * freeing up their numbers. These numbers should be reused.
819 ab
->ab_BusNum
= ATABase
->ata__buscount
++;
821 /* scan bus - try to locate all devices (disables irq) */
825 * Start up bus task. It will perform scanning asynchronously, and
826 * then, if succesful, insert units. This allows to keep things parallel.
828 D(bug("[ATA>>] Start: Bus %u: Unit 0 - %d, Unit 1 - %d\n", ab
->ab_BusNum
, ab
->ab_Dev
[0], ab
->ab_Dev
[1]));
829 return NewCreateTask(TASKTAG_PC
, BusTaskCode
,
830 TASKTAG_NAME
, "ATA[PI] Subsystem",
831 TASKTAG_STACKSIZE
, STACK_SIZE
,
832 TASKTAG_PRI
, TASK_PRI
,
833 TASKTAG_TASKMSGPORT
, &ab
->ab_MsgPort
,
835 TASKTAG_ARG2
, ATABase
,
836 TAG_DONE
) ? TRUE
: FALSE
;
839 AROS_UFH3(BOOL
, Hidd_ATABus_Open
,
840 AROS_UFHA(struct Hook
*, h
, A0
),
841 AROS_UFHA(OOP_Object
*, obj
, A2
),
842 AROS_UFHA(IPTR
, reqUnit
, A1
))
846 struct IORequest
*req
= h
->h_Data
;
847 struct ataBase
*ATABase
= (struct ataBase
*)req
->io_Device
;
848 struct ata_Bus
*b
= (struct ata_Bus
*)OOP_INST_DATA(ATABase
->busClass
, obj
);
849 ULONG bus
= reqUnit
>> 1;
850 UBYTE dev
= reqUnit
& 1;
852 D(bug("[ATA%02ld] Checking bus %u dev %u\n", reqUnit
, bus
, dev
));
854 if ((b
->ab_BusNum
== bus
) && b
->ab_Units
[dev
])
857 req
->io_Unit
= &b
->ab_Units
[dev
]->au_Unit
;
860 b
->ab_Units
[dev
]->au_Unit
.unit_OpenCnt
++;
869 AROS_UFH3(BOOL
, Hidd_ATABus_Tick
,
870 AROS_UFHA(struct Hook
*, h
, A0
),
871 AROS_UFHA(OOP_Object
*, obj
, A2
),
872 AROS_UFHA(struct ataBase
*, ATABase
, A1
))
876 struct ata_Bus
*bus
= (struct ata_Bus
*)OOP_INST_DATA(ATABase
->busClass
, obj
);
880 * This compare-decrement-fetch should be atomic, so we
882 * Not a good design, can anybody invent better one ?
885 if (bus
->ab_Timeout
>= 0)
886 timeout
= --bus
->ab_Timeout
;
890 Signal(bus
->ab_Task
, SIGBREAKF_CTRL_C
);