3 Copyright (C) 2004-2011 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <exec/types.h>
24 #include <expansion/pci.h>
26 #include <proto/exec.h>
27 #include <proto/expansion.h>
32 #include "pci_protos.h"
33 #include "expansion_protos.h"
36 /* Private prototypes */
38 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
);
39 static ULONG
LongInHook(struct BusContext
*context
, ULONG offset
);
40 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
42 static VOID
WordOutHook(struct BusContext
*context
, ULONG offset
,
44 static VOID
LongOutHook(struct BusContext
*context
, ULONG offset
,
46 static VOID
LongsInHook(struct BusContext
*context
, ULONG offset
,
47 ULONG
*buffer
, ULONG count
);
48 static VOID
LongsOutHook(struct BusContext
*context
, ULONG offset
,
49 const ULONG
*buffer
, ULONG count
);
50 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
52 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
53 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
);
54 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
56 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
58 static APTR
AllocDMAMemHook(struct BusContext
*context
, UPINT size
,
60 static VOID
FreeDMAMemHook(struct BusContext
*context
, APTR mem
);
63 IMPORT
const UWORD product_codes
[];
66 static const struct TagItem unit_tags
[] =
68 {IOTAG_ByteIn
, (UPINT
)ByteInHook
},
69 {IOTAG_LongIn
, (UPINT
)LongInHook
},
70 {IOTAG_ByteOut
, (UPINT
)ByteOutHook
},
71 {IOTAG_WordOut
, (UPINT
)WordOutHook
},
72 {IOTAG_LongOut
, (UPINT
)LongOutHook
},
73 {IOTAG_LongsIn
, (UPINT
)LongsInHook
},
74 {IOTAG_LongsOut
, (UPINT
)LongsOutHook
},
75 {IOTAG_BEWordOut
, (UPINT
)BEWordOutHook
},
76 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
77 {IOTAG_LELongIn
, (UPINT
)LELongInHook
},
78 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
79 {IOTAG_LELongOut
, (UPINT
)LELongOutHook
},
80 {IOTAG_AllocDMAMem
, (UPINT
)AllocDMAMemHook
},
81 {IOTAG_FreeDMAMem
, (UPINT
)FreeDMAMemHook
},
86 /****i* etherlink3.device/GetExpansionCount ********************************
89 * GetExpansionCount -- Get the number of compatible PCI Cards.
92 * count = GetExpansionCount()
94 * ULONG GetExpansionCount();
96 ****************************************************************************
100 ULONG
GetExpansionCount(struct DevBase
*base
)
103 struct PCIDevice
*card
;
105 if(base
->i_pci
!= NULL
)
108 base
->i_pci
->FindDeviceTags(FDT_CandidateList
, product_codes
,
109 FDT_Index
, count
, TAG_END
)) != NULL
)
111 base
->i_pci
->FreeDevice(card
);
121 /****i* etherlink3.device/AllocExpansionCard *******************************
124 * AllocExpansionCard -- Take control of a card.
127 * context = AllocExpansionCard(index)
129 * struct BusContext *AllocExpansionCard(ULONG);
131 ****************************************************************************
135 struct BusContext
*AllocExpansionCard(ULONG index
, struct DevBase
*base
)
138 struct BusContext
*context
;
139 struct PCIDevice
*card
= NULL
;
140 struct PCIResourceRange
*io_range
= NULL
;
143 /* Find a compatible card */
145 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
151 context
->card
= card
=
152 base
->i_pci
->FindDeviceTags(FDT_CandidateList
, product_codes
,
153 FDT_Index
, index
, TAG_END
);
154 product_id
= card
->ReadConfigWord(PCI_DEVICE_ID
);
162 success
= card
->Lock(PCI_LOCK_EXCLUSIVE
);
164 /* Get base address and generation */
168 context
->have_card
= TRUE
;
169 card
->SetEndian(PCI_MODE_LITTLE_ENDIAN
);
170 io_range
= card
->GetResourceRange(BAR_NO
);
171 context
->io_base
= io_range
->BaseAddress
;
172 card
->FreeResourceRange(io_range
);
173 context
->unit_tags
= unit_tags
;
174 context
->generation
= GetGeneration(product_id
, base
);
179 FreeExpansionCard(context
, base
);
188 /****i* etherlink3.device/FreeExpansionCard ********************************
191 * FreeExpansionCard -- Release a card.
194 * FreeExpansionCard(context)
196 * VOID FreeExpansionCard(struct BusContext *);
198 ****************************************************************************
202 VOID
FreeExpansionCard(struct BusContext
*context
, struct DevBase
*base
)
204 struct PCIDevice
*card
;
208 card
= context
->card
;
211 if(context
->have_card
)
213 base
->i_pci
->FreeDevice(card
);
214 FreeMem(context
, sizeof(struct BusContext
));
223 /****i* etherlink3.device/AddExpansionIntServer ****************************
226 * AddExpansionIntServer
229 * success = AddExpansionIntServer(card, interrupt)
231 * BOOL AddExpansionIntServer(APTR, struct Interrupt *);
233 ****************************************************************************
237 BOOL
AddExpansionIntServer(APTR card
, struct Interrupt
*interrupt
,
238 struct DevBase
*base
)
240 return AddIntServer(((struct PCIDevice
*)card
)->MapInterrupt(),
246 /****i* etherlink3.device/RemExpansionIntServer ****************************
249 * RemExpansionIntServer
252 * RemExpansionIntServer(card, interrupt)
254 * VOID RemExpansionIntServer(APTR, struct Interrupt *);
256 ****************************************************************************
260 VOID
RemExpansionIntServer(APTR card
, struct Interrupt
*interrupt
,
261 struct DevBase
*base
)
263 RemIntServer(((struct PCIDevice
*)card
)->MapInterrupt(), interrupt
);
270 /****i* etherlink3.device/ByteInHook ***************************************
276 * value = ByteInHook(context, offset)
278 * UBYTE ByteInHook(struct BusContext *, ULONG);
280 ****************************************************************************
284 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
)
286 struct PCIDevice
*card
;
288 card
= context
->card
;
289 return card
->InByte(context
->io_base
+ offset
);
294 /****i* etherlink3.device/LongInHook ***************************************
300 * value = LongInHook(context, offset)
302 * ULONG LongInHook(struct BusContext *, ULONG);
304 ****************************************************************************
308 static ULONG
LongInHook(struct BusContext
*context
, ULONG offset
)
310 struct PCIDevice
*card
;
312 card
= context
->card
;
313 return card
->InLong(context
->io_base
+ offset
);
318 /****i* etherlink3.device/ByteOutHook **************************************
324 * ByteOutHook(context, offset, value)
326 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
328 ****************************************************************************
332 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
335 struct PCIDevice
*card
;
337 card
= context
->card
;
338 card
->OutByte(context
->io_base
+ offset
, value
);
345 /****i* etherlink3.device/WordOutHook **************************************
351 * WordOutHook(context, offset, value)
353 * VOID WordOutHook(struct BusContext *, ULONG, UWORD);
355 ****************************************************************************
359 static VOID
WordOutHook(struct BusContext
*context
, ULONG offset
,
362 struct PCIDevice
*card
;
364 card
= context
->card
;
365 card
->OutWord(context
->io_base
+ offset
, value
);
372 /****i* etherlink3.device/LongOutHook **************************************
378 * LongOutHook(context, offset, value)
380 * VOID LongOutHook(struct BusContext *, ULONG, ULONG);
382 ****************************************************************************
386 static VOID
LongOutHook(struct BusContext
*context
, ULONG offset
,
389 struct PCIDevice
*card
;
391 card
= context
->card
;
392 card
->OutLong(context
->io_base
+ offset
, value
);
399 /****i* etherlink3.device/LongsInHook **************************************
405 * LongsInHook(context, offset, buffer, count)
407 * VOID LongsInHook(struct BusContext *, ULONG, ULONG *, ULONG);
409 ****************************************************************************
413 static VOID
LongsInHook(struct BusContext
*context
, ULONG offset
,
414 ULONG
*buffer
, ULONG count
)
416 struct PCIDevice
*card
;
418 card
= context
->card
;
420 *buffer
++ = card
->InLong(context
->io_base
+ offset
);
427 /****i* etherlink3.device/LongsOutHook *************************************
433 * LongsOutHook(context, offset, buffer, count)
435 * VOID LongsOutHook(struct BusContext *, ULONG, const ULONG *, ULONG);
437 ****************************************************************************
441 static VOID
LongsOutHook(struct BusContext
*context
, ULONG offset
,
442 const ULONG
*buffer
, ULONG count
)
444 struct PCIDevice
*card
;
446 card
= context
->card
;
448 card
->OutLong(context
->io_base
+ offset
, *buffer
++);
455 /****i* etherlink3.device/BEWordOutHook ************************************
461 * BEWordOutHook(context, offset, value)
463 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
465 ****************************************************************************
469 static VOID
BEWordOutHook(struct BusContext
*context
, ULONG offset
,
472 struct PCIDevice
*card
;
474 card
= context
->card
;
475 card
->OutWord(context
->io_base
+ offset
, MakeBEWord(value
));
482 /****i* etherlink3.device/LEWordInHook *************************************
488 * value = LEWordInHook(context, offset)
490 * UWORD LEWordInHook(struct BusContext *, ULONG);
492 ****************************************************************************
496 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
498 struct PCIDevice
*card
;
500 card
= context
->card
;
501 return LEWord(card
->InWord(context
->io_base
+ offset
));
506 /****i* etherlink3.device/LELongInHook *************************************
512 * value = LELongInHook(context, offset)
514 * ULONG LELongInHook(struct BusContext *, ULONG);
516 ****************************************************************************
520 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
)
522 struct PCIDevice
*card
;
524 card
= context
->card
;
525 return LELong(card
->InLong(context
->io_base
+ offset
));
530 /****i* etherlink3.device/LEWordOutHook ************************************
536 * LEWordOutHook(context, offset, value)
538 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
540 ****************************************************************************
544 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
547 struct PCIDevice
*card
;
549 card
= context
->card
;
550 card
->OutWord(context
->io_base
+ offset
, MakeLEWord(value
));
557 /****i* etherlink3.device/LELongOutHook ************************************
563 * LELongOutHook(context, offset, value)
565 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
567 ****************************************************************************
571 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
574 struct PCIDevice
*card
;
576 card
= context
->card
;
577 card
->OutLong(context
->io_base
+ offset
, MakeLELong(value
));
584 /****i* etherlink3.device/AllocDMAMemHook **********************************
590 * mem = AllocDMAMemHook(context, size, alignment)
592 * APTR AllocDMAMemHook(struct BusContext *, UPINT, UWORD);
594 ****************************************************************************
596 * Alignment currently must be minimum of 8 bytes.
600 static APTR
AllocDMAMemHook(struct BusContext
*context
, UPINT size
,
603 struct DevBase
*base
;
604 APTR mem
= NULL
, original_mem
;
606 base
= context
->device
;
607 size
+= 2 * sizeof(APTR
) + alignment
;
608 original_mem
= AllocMem(size
, MEMF_PUBLIC
);
609 if(original_mem
!= NULL
)
611 mem
= (APTR
)((UPINT
)(original_mem
+ 2 * sizeof(APTR
) + alignment
- 1)
613 *((APTR
*)mem
- 1) = original_mem
;
614 *((UPINT
*)mem
- 2) = size
;
622 /****i* etherlink3.device/FreeDMAMemHook ***********************************
628 * FreeDMAMemHook(context, mem)
630 * VOID FreeDMAMemHook(struct BusContext *, APTR);
632 ****************************************************************************
636 static VOID
FreeDMAMemHook(struct BusContext
*context
, APTR mem
)
638 struct DevBase
*base
;
640 base
= context
->device
;
642 FreeMem(*((APTR
*)mem
- 1), *((UPINT
*)mem
- 2));