4 ISA-PnP -- A Plug And Play ISA software layer for AmigaOS.
5 Copyright (C) 2001 Martin Blom <martin@blom.org>
6 Copyright (C) 2009-2013 The AROS Development Team
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with this library; if not, write to the
20 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
26 #include "CompilerSpecific.h"
28 #include <exec/memory.h>
30 #include <clib/alib_protos.h>
31 #include <proto/exec.h>
32 #include <proto/timer.h>
34 #include <resources/isapnp.h>
35 #include "isapnp_private.h"
39 #include "controller.h"
43 #include "pnp_iterators.h"
44 #include "pnp_structs.h"
47 /******************************************************************************
48 ** PnP ISA helper functions ***************************************************
49 ******************************************************************************/
52 GetPnPReg( UBYTE pnp_reg
,
53 struct ISAPNPBase
* res
)
55 ISAC_SetRegByte( PNPISA_ADDRESS
, pnp_reg
, res
);
57 return ISAC_GetRegByte( ( res
->m_RegReadData
<< 2 ) | 3, res
);
62 GetLastPnPReg( struct ISAPNPBase
* res
)
64 return ISAC_GetRegByte( ( res
->m_RegReadData
<< 2 ) | 3, res
);
69 SetPnPReg( UBYTE pnp_reg
,
71 struct ISAPNPBase
* res
)
73 ISAC_SetRegByte( PNPISA_ADDRESS
, pnp_reg
, res
);
74 ISAC_SetRegByte( PNPISA_WRITE_DATA
, value
, res
);
79 GetNextResourceData( struct ISAPNPBase
* res
)
82 while( ( GetPnPReg( PNPISA_REG_STATUS
, res
) & PNPISA_SF_AVAILABLE
) == 0 );
84 return GetPnPReg( PNPISA_REG_RESOURCE_DATA
, res
);
90 BusyWait( ULONG micro_seconds
)
92 typedef unsigned long long uint64_t;
95 struct EClockVal eclock
;
99 freq
= ReadEClock( &eclock
);
101 current
= ( ( (uint64_t) eclock
.ev_hi
) << 32 ) + eclock
.ev_lo
;
102 end
= current
+ (uint64_t) freq
* micro_seconds
/ 1000000;
104 while( current
< end
)
106 ReadEClock( &eclock
);
108 current
= ( ( (uint64_t) eclock
.ev_hi
) << 32 ) + eclock
.ev_lo
;
114 DecodeID( UBYTE
* buf
, struct ISAPNP_Identifier
* id
)
116 // Decode information
118 if( buf
[ 0 ] & 0x80 )
123 id
->isapnpid_Vendor
[ 0 ] = 0x40 + ( buf
[ 0 ] >> 2 );
124 id
->isapnpid_Vendor
[ 1 ] = 0x40 + ( ( ( buf
[ 0 ] & 0x03 ) << 3 ) |
126 id
->isapnpid_Vendor
[ 2 ] = 0x40 + ( buf
[ 1 ] & 0x1f );
127 id
->isapnpid_Vendor
[ 3 ] = 0;
129 id
->isapnpid_ProductID
= ( buf
[ 2 ] << 4 ) | ( buf
[ 3 ] >> 4 );
130 id
->isapnpid_Revision
= buf
[ 3 ] & 0x0f;
136 /******************************************************************************
137 ** Move all cards to Sleep state **********************************************
138 ******************************************************************************/
141 SendInitiationKey( struct ISAPNPBase
* res
)
143 static const UBYTE key
[] =
145 PNPISA_INITIATION_KEY
150 // Make sure the LFSR is in its initial state
152 ISAC_SetRegByte( PNPISA_ADDRESS
, 0, res
);
153 ISAC_SetRegByte( PNPISA_ADDRESS
, 0, res
);
155 for( i
= 0; i
< sizeof( key
); ++i
)
157 ISAC_SetRegByte( PNPISA_ADDRESS
, key
[ i
], res
);
162 /******************************************************************************
163 ** Read the serial identifier from a card *************************************
164 ******************************************************************************/
167 ReadSerialIdentifier( struct ISAPNP_Card
* card
,
168 struct ISAPNPBase
* res
)
170 UBYTE buf
[ 9 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
174 ISAC_SetRegByte( PNPISA_ADDRESS
, PNPISA_REG_SERIAL_ISOLATION
, res
);
176 // Wait 1 ms before we read the first pair
182 for( i
= 0; i
< 72; ++i
)
187 value1
= GetLastPnPReg( res
);
188 value2
= GetLastPnPReg( res
);
190 if( value1
== 0x55 && value2
== 0xaa )
192 buf
[ i
>> 3 ] |= ( 1 << ( i
& 7 ) );
197 UBYTE bitten
= value1
== 0x55 && value2
== 0xaa ? 1 : 0;
199 check_sum
= PNPISA_LFSR( check_sum
, bitten
);
202 // Wait 250 µs before we read the next pair
207 if( check_sum
!= buf
[ 8 ] )
212 if( ! DecodeID( buf
, &card
->isapnpc_ID
) )
217 card
->isapnpc_SerialNumber
= ( buf
[ 7 ] << 25 ) |
226 /******************************************************************************
227 ** Read the resource data from a card *****************************************
228 ******************************************************************************/
231 ReadResourceData( struct ISAPNP_Card
* card
,
232 struct ISAPNPBase
* res
)
236 BOOL read_more
= TRUE
;
237 struct ISAPNP_Device
* dev
= NULL
;
238 struct ISAPNP_ResourceGroup
* options
= NULL
;
239 struct ISAPNP_ResourceGroup
* saved_options
= NULL
;
249 rd
= GetNextResourceData( res
);
253 if( rd
& PNPISA_RDF_LARGE
)
255 name
= PNPISA_RD_LARGE_ITEM_NAME( rd
);
256 length
= GetNextResourceData( res
);
257 length
|= GetNextResourceData( res
) << 8;
261 name
= PNPISA_RD_SMALL_ITEM_NAME( rd
);
262 length
= PNPISA_RD_SMALL_LENGTH( rd
);
267 case PNPISA_RDN_PNP_VERSION
:
271 ver
= GetNextResourceData( res
);
273 card
->isapnpc_MinorPnPVersion
= ver
& 0x0f;
274 card
->isapnpc_MajorPnPVersion
= ver
>> 4;
275 card
->isapnpc_VendorPnPVersion
= GetNextResourceData( res
);
281 case PNPISA_RDN_LOGICAL_DEVICE_ID
:
283 struct ISAPNP_Identifier
* id
;
286 dev
= ISAPNP_AllocDevice( res
);
293 dev
->isapnpd_Card
= card
;
295 id
= AllocVec( sizeof( *id
), MEMF_PUBLIC
| MEMF_CLEAR
);
299 ISAPNP_FreeDevice( dev
, res
);
304 buf
[ 0 ] = GetNextResourceData( res
);
305 buf
[ 1 ] = GetNextResourceData( res
);
306 buf
[ 2 ] = GetNextResourceData( res
);
307 buf
[ 3 ] = GetNextResourceData( res
);
311 if( ! DecodeID( buf
, id
) )
314 ISAPNP_FreeDevice( dev
, res
);
319 AddTail( (struct List
*) &dev
->isapnpd_IDs
, (struct Node
*) id
);
321 options
= dev
->isapnpd_Options
;
323 dev
->isapnpd_SupportedCommands
= GetNextResourceData( res
);
328 dev
->isapnpd_SupportedCommands
|= GetNextResourceData( res
) << 8;
331 dev
->isapnpd_DeviceNumber
= dev_num
;
334 AddTail( &card
->isapnpc_Devices
, (struct Node
*) dev
);
340 case PNPISA_RDN_COMPATIBLE_DEVICE_ID
:
342 struct ISAPNP_Identifier
* id
;
350 id
= AllocVec( sizeof( *id
), MEMF_PUBLIC
| MEMF_CLEAR
);
357 buf
[ 0 ] = GetNextResourceData( res
);
358 buf
[ 1 ] = GetNextResourceData( res
);
359 buf
[ 2 ] = GetNextResourceData( res
);
360 buf
[ 3 ] = GetNextResourceData( res
);
364 if( ! DecodeID( buf
, id
) )
370 AddTail( (struct List
*) &dev
->isapnpd_IDs
, (struct Node
*) id
);
375 case PNPISA_RDN_IRQ_FORMAT
:
377 struct ISAPNP_IRQResource
* r
;
379 r
= (struct ISAPNP_IRQResource
*)
380 ISAPNP_AllocResource( ISAPNP_NT_IRQ_RESOURCE
, res
);
387 r
->isapnpirqr_IRQMask
= GetNextResourceData( res
);
388 r
->isapnpirqr_IRQMask
|= GetNextResourceData( res
) << 8;
393 r
->isapnpirqr_IRQType
= GetNextResourceData( res
);
398 r
->isapnpirqr_IRQType
= ISAPNP_IRQRESOURCE_ITF_HIGH_EDGE
;
401 AddTail( (struct List
*) &options
->isapnprg_Resources
, (struct Node
*) r
);
407 case PNPISA_RDN_DMA_FORMAT
:
409 struct ISAPNP_DMAResource
* r
;
411 r
= (struct ISAPNP_DMAResource
*)
412 ISAPNP_AllocResource( ISAPNP_NT_DMA_RESOURCE
, res
);
419 r
->isapnpdmar_ChannelMask
= GetNextResourceData( res
);
420 r
->isapnpdmar_Flags
= GetNextResourceData( res
);
424 AddTail( (struct List
*) &options
->isapnprg_Resources
, (struct Node
*) r
);
429 case PNPISA_RDN_START_DF
:
431 struct ISAPNP_ResourceGroup
* rg
;
436 pri
= GetNextResourceData( res
);
447 pri
= ISAPNP_RG_PRI_GOOD
;
452 pri
= ISAPNP_RG_PRI_ACCEPTABLE
;
456 pri
= ISAPNP_RG_PRI_SUBOPTIMAL
;
460 rg
= ISAPNP_AllocResourceGroup( pri
, res
);
467 // Insert in priority order
469 if( saved_options
== NULL
)
471 saved_options
= options
;
474 Enqueue( (struct List
*) &saved_options
->isapnprg_ResourceGroups
,
483 case PNPISA_RDN_END_DF
:
485 options
= saved_options
;
486 saved_options
= NULL
;
491 case PNPISA_RDN_IO_PORT
:
493 struct ISAPNP_IOResource
* r
;
495 r
= (struct ISAPNP_IOResource
*)
496 ISAPNP_AllocResource( ISAPNP_NT_IO_RESOURCE
, res
);
503 r
->isapnpior_Flags
= GetNextResourceData( res
);
505 r
->isapnpior_MinBase
= GetNextResourceData( res
);
506 r
->isapnpior_MinBase
|= GetNextResourceData( res
) << 8;
508 r
->isapnpior_MaxBase
= GetNextResourceData( res
);
509 r
->isapnpior_MaxBase
|= GetNextResourceData( res
) << 8;
511 r
->isapnpior_Alignment
= GetNextResourceData( res
);
512 r
->isapnpior_Length
= GetNextResourceData( res
);
516 AddTail( (struct List
*) &options
->isapnprg_Resources
, (struct Node
*) r
);
522 case PNPISA_RDN_FIXED_IO_PORT
:
524 struct ISAPNP_IOResource
* r
;
526 r
= (struct ISAPNP_IOResource
*)
527 ISAPNP_AllocResource( ISAPNP_NT_IO_RESOURCE
, res
);
534 r
->isapnpior_Flags
= 0;
535 r
->isapnpior_MinBase
= GetNextResourceData( res
);
536 r
->isapnpior_MinBase
|= GetNextResourceData( res
) << 8;
537 r
->isapnpior_MaxBase
= r
->isapnpior_MinBase
;
538 r
->isapnpior_Alignment
= 1;
539 r
->isapnpior_Length
= GetNextResourceData( res
);
543 AddTail( (struct List
*) &options
->isapnprg_Resources
, (struct Node
*) r
);
549 case PNPISA_RDN_ANSI_IDENTIFIER
:
551 STRPTR id
= AllocVec( length
+ 1, MEMF_PUBLIC
);
558 // Attach identifier to either the card or the logical device
562 FreeVec( card
->isapnpc_Node
.ln_Name
);
564 card
->isapnpc_Node
.ln_Name
= id
;
568 FreeVec( dev
->isapnpd_Node
.ln_Name
);
570 dev
->isapnpd_Node
.ln_Name
= id
;
575 *id
= GetNextResourceData( res
);
581 // Terminate the string
589 case PNPISA_RDN_END_TAG
:
593 cs
= GetNextResourceData( res
);
611 bug( "UNKNOWN RESOURCE: %02lx, length %ld: ", name
, length
);
615 bug( "%02lx ", GetNextResourceData( res
) );
623 // Make sure we have read all data for this name
628 GetNextResourceData( res
);
633 D(bug( "Check sum: %ld\n", check_sum
));
639 /******************************************************************************
640 ** Assign a CSN to all cards and build the card/device database ***************
641 ******************************************************************************/
644 AddCards( UBYTE rd_data_port_value
,
645 struct ISAPNPBase
* res
)
651 struct ISAPNP_Card
* card
;
653 // Move all cards (without a CSN) to the isolate state and the card
654 // in config state to the sleep state.
656 SetPnPReg( PNPISA_REG_WAKE
, 0, res
);
658 // Set port to read from
660 SetPnPReg( PNPISA_REG_SET_RD_DATA_PORT
, rd_data_port_value
, res
);
661 res
->m_RegReadData
= rd_data_port_value
;
663 card
= ISAPNP_AllocCard( res
);
670 if( ReadSerialIdentifier( card
, res
) )
672 // Assign a CSN to the card and move it to the config state
675 SetPnPReg( PNPISA_REG_CARD_SELECT_NUMBER
, csn
, res
);
677 // Read the resource data
679 if( ReadResourceData( card
, res
) )
681 card
->isapnpc_CSN
= csn
;
683 AddTail( &res
->m_Cards
, (struct Node
*) card
);
687 ISAPNP_FreeCard( card
, res
);
692 ISAPNP_FreeCard( card
, res
);
702 /******************************************************************************
703 ** Scan for all PNP ISA cards *************************************************
704 ******************************************************************************/
706 AROS_LH0(BOOL
, ISAPNP_ScanCards
,
707 struct ISAPNPBase
*, res
, 26, ISAPNP
)
714 SendInitiationKey( res
);
716 // Make all cards lose their CSN
718 SetPnPReg( PNPISA_REG_CONFIG_CONTROL
,
719 PNPISA_CCF_RESET_CSN
,
722 for( read_port_value
= 0x80;
723 read_port_value
<= 0xff;
724 read_port_value
+= 0x10 )
726 cards
= AddCards( read_port_value
, res
);
736 SetPnPReg( PNPISA_REG_CONFIG_CONTROL,
738 PNPISA_CCF_WAIT_FOR_KEY |
739 PNPISA_CCF_RESET_CSN,
748 /******************************************************************************
749 ** Configure all cards ********************************************************
750 ******************************************************************************/
754 FindNextCardConfiguration( struct ISAPNP_Device
* dev
,
755 struct ResourceContext
* ctx
,
756 struct ISAPNPBase
* res
);
762 FindConfiguration( struct ISAPNP_Device
* dev
,
763 struct ResourceContext
* ctx
,
764 struct ISAPNPBase
* res
)
768 struct ISAPNP_ResourceGroup
* rg
;
769 struct ResourceIteratorList
* ril
= NULL
;
771 if( dev
->isapnpd_Disabled
|| dev
->isapnpd_Card
->isapnpc_Disabled
)
773 // Skip to next device
775 return FindNextCardConfiguration( dev
, ctx
, res
);
778 ril
= AllocResourceIteratorList( &dev
->isapnpd_Options
->isapnprg_Resources
, ctx
);
782 BOOL ril_iter_ok
= TRUE
;
784 while( ! rc
&& ril_iter_ok
)
786 if( dev
->isapnpd_Options
->isapnprg_ResourceGroups
.mlh_Head
->mln_Succ
!= NULL
)
788 // Handle resource options as well
790 for( rg
= (struct ISAPNP_ResourceGroup
*)
791 dev
->isapnpd_Options
->isapnprg_ResourceGroups
.mlh_Head
;
792 ! rc
&& rg
->isapnprg_MinNode
.mln_Succ
!= NULL
;
793 rg
= (struct ISAPNP_ResourceGroup
*) rg
->isapnprg_MinNode
.mln_Succ
)
795 struct ResourceIteratorList
* ril_option
= NULL
;
797 ril_option
= AllocResourceIteratorList( &rg
->isapnprg_Resources
, ctx
);
799 if( ril_option
!= NULL
)
801 BOOL ril2_iter_ok
= TRUE
;
803 while( ! rc
&& ril2_iter_ok
)
805 rc
= FindNextCardConfiguration( dev
, ctx
, res
);
807 //if( cp > 2 ) return FALSE; else ++cp;
811 ril2_iter_ok
= IncResourceIteratorList( ril_option
, ctx
);
815 // Allocate resources for current iterators
817 rc
= CreateResouces( ril_option
,
818 (struct List
*) &dev
->isapnpd_Resources
,
824 if( ! FreeResourceIteratorList( ril_option
, ctx
) )
833 // Fixed resources only
835 rc
= FindNextCardConfiguration( dev
, ctx
, res
);
840 ril_iter_ok
= IncResourceIteratorList( ril
, ctx
);
844 // Allocate resources for current iterators
846 // NOTE! These resources muct be FIRST in the resource list
847 // in order to maintain the descriptor order.
852 NewList( (struct List
* ) &tmp
);
854 rc
= CreateResouces( ril
, (struct List
*) &tmp
,
857 while( ( n
= RemTail( (struct List
* ) &tmp
) ) != NULL
)
859 AddHead( (struct List
*) &dev
->isapnpd_Resources
, n
);
866 FreeResourceIteratorList( ril
, ctx
);
874 FindNextCardConfiguration( struct ISAPNP_Device
* dev
,
875 struct ResourceContext
* ctx
,
876 struct ISAPNPBase
* res
)
880 // Configure next logical device, if any
882 if( dev
->isapnpd_Node
.ln_Succ
->ln_Succ
!= NULL
)
884 // Same card, next device
885 rc
= FindConfiguration( (struct ISAPNP_Device
*) dev
->isapnpd_Node
.ln_Succ
,
890 struct ISAPNP_Card
* next_card
= (struct ISAPNP_Card
*)
891 dev
->isapnpd_Card
->isapnpc_Node
.ln_Succ
;
893 if( next_card
->isapnpc_Node
.ln_Succ
!= NULL
&&
894 next_card
->isapnpc_Devices
.lh_Head
->ln_Succ
!= NULL
)
897 rc
= FindConfiguration( (struct ISAPNP_Device
*)
898 next_card
->isapnpc_Devices
.lh_Head
,
903 // This was the last device on the last card!
914 ProgramConfiguration( struct ISAPNPBase
* res
)
916 struct ISAPNP_Device
* dev
= NULL
;
920 while( ( dev
= ISAPNP_FindDevice( dev
, -1, -1, -1, res
) ) != NULL
)
922 struct ISAPNP_Resource
* resource
;
924 UBYTE mem_reg
= PNPISA_REG_MEMORY_BASE_ADDRESS_HIGH_0
;
925 UBYTE io_reg
= PNPISA_REG_IO_PORT_BASE_ADDRESS_HIGH_0
;
926 UBYTE int_reg
= PNPISA_REG_INTERRUPT_REQUEST_LEVEL_SELECT_0
;
927 UBYTE dma_reg
= PNPISA_REG_DMA_CHANNEL_SELECT_0
;
929 if( dev
->isapnpd_Card
->isapnpc_CSN
!= 0 )
931 // Don't program non-pnp devices!
933 if( dev
->isapnpd_Card
->isapnpc_CSN
!= csn
)
935 csn
= dev
->isapnpd_Card
->isapnpc_CSN
;
939 D(bug( "Woke up card %ld\n", dev
->isapnpd_Card
->isapnpc_CSN
));
940 SetPnPReg( PNPISA_REG_WAKE
, dev
->isapnpd_Card
->isapnpc_CSN
, res
);
943 // Select logical device
945 D(bug( "Selected device %ld\n", dev
->isapnpd_DeviceNumber
));
946 SetPnPReg( PNPISA_REG_LOGICAL_DEVICE_NUMBER
, dev
->isapnpd_DeviceNumber
, res
);
948 for( resource
= (struct ISAPNP_Resource
*) dev
->isapnpd_Resources
.mlh_Head
;
949 resource
->isapnpr_MinNode
.mln_Succ
!= NULL
;
950 resource
= (struct ISAPNP_Resource
*) resource
->isapnpr_MinNode
.mln_Succ
)
952 switch( resource
->isapnpr_Type
)
954 case ISAPNP_NT_IRQ_RESOURCE
:
956 struct ISAPNP_IRQResource
* r
= (struct ISAPNP_IRQResource
*) resource
;
959 for( b
= 0; b
< 16; ++b
)
961 if( r
->isapnpirqr_IRQMask
& ( 1 << b
) )
963 D(bug( "Programmed interrupt %ld in %lx\n", b
, int_reg
));
964 SetPnPReg( int_reg
, b
, res
);
971 if( ( r
->isapnpirqr_IRQType
& ISAPNP_IRQRESOURCE_ITF_HIGH_EDGE
) ||
972 ( r
->isapnpirqr_IRQType
& ISAPNP_IRQRESOURCE_ITF_HIGH_LEVEL
) )
977 if( ( r
->isapnpirqr_IRQType
& ISAPNP_IRQRESOURCE_ITF_HIGH_LEVEL
) ||
978 ( r
->isapnpirqr_IRQType
& ISAPNP_IRQRESOURCE_ITF_LOW_LEVEL
) )
983 D(bug( "Programmed interrupt mode %ld in %lx\n", b
, int_reg
+ 1 ));
984 SetPnPReg( int_reg
+ 1, b
, res
);
991 case ISAPNP_NT_DMA_RESOURCE
:
993 struct ISAPNP_DMAResource
* r
= (struct ISAPNP_DMAResource
*) resource
;
996 for( b
= 0; b
< 8; ++b
)
998 if( r
->isapnpdmar_ChannelMask
& ( 1 << b
) )
1000 D(bug( "Programmed dma channel %ld in %lx\n", b
, dma_reg
));
1001 SetPnPReg( dma_reg
, b
, res
);
1011 case ISAPNP_NT_IO_RESOURCE
:
1013 struct ISAPNP_IOResource
* r
= (struct ISAPNP_IOResource
*) resource
;
1015 D(bug( "Programmed IO base %04lx in %lx\n", r
->isapnpior_MinBase
, io_reg
));
1017 SetPnPReg( io_reg
, r
->isapnpior_MinBase
>> 8, res
);
1018 SetPnPReg( io_reg
+ 1, r
->isapnpior_MinBase
& 0xff, res
);
1026 bug( "Unsupported resource!\n" );
1031 // Activate the device
1032 D(bug( "Activated the device\n" ));
1033 SetPnPReg( PNPISA_REG_ACTIVATE
, 1, res
);
1037 // Move all cards to the wfk state
1039 D(bug( "Moved cards to wfk\n" ));
1041 SetPnPReg( PNPISA_REG_CONFIG_CONTROL
,
1042 PNPISA_CCF_WAIT_FOR_KEY
,
1049 AROS_LH0(BOOL
, ISAPNP_ConfigureCards
,
1050 struct ISAPNPBase
*, res
, 27, ISAPNP
)
1056 struct ISAPNP_Device
* dev
;
1058 dev
= ISAPNP_FindDevice( NULL
, -1, -1, -1, res
);
1062 struct ResourceContext
* ctx
;
1064 ctx
= AllocResourceIteratorContext();
1068 if( ! FindConfiguration( dev
, ctx
, res
) )
1070 D(bug( "Unable to find a usable configuration.\n" ));
1074 if( ! ProgramConfiguration( res
) )
1076 D(bug( "Failed to program configuration!\n" ));
1084 FreeResourceIteratorContext( ctx
);