3 Copyright (C) 2004-2012 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 <utility/tagitem.h>
25 #include <libraries/prometheus.h>
27 #include <proto/exec.h>
28 #include <proto/expansion.h>
29 #include <proto/prometheus.h>
33 #include "pci_protos.h"
34 #include "device_protos.h"
35 #include "unit_protos.h"
43 struct DevBase
*device
;
46 const struct TagItem
*unit_tags
;
52 /* Private prototypes */
54 static struct DevUnit
*FindPCIUnit(ULONG index
, struct DevBase
*base
);
55 static struct DevUnit
*CreatePCIUnit(ULONG index
, struct DevBase
*base
);
56 static struct BusContext
*AllocCard(ULONG index
, struct DevBase
*base
);
57 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
);
58 static BOOL
AddPCIIntServer(APTR card
, struct Interrupt
*interrupt
,
59 struct DevBase
*base
);
60 static VOID
RemPCIIntServer(APTR card
, struct Interrupt
*interrupt
,
61 struct DevBase
*base
);
62 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
);
63 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
65 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
66 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
);
67 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
69 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
71 static APTR
AllocDMAMemHook(struct BusContext
*context
, UPINT size
,
73 static VOID
FreeDMAMemHook(struct BusContext
*context
, APTR mem
);
76 const UWORD product_codes
[] =
89 static const struct TagItem unit_tags
[] =
91 {IOTAG_ByteIn
, (UPINT
)ByteInHook
},
92 {IOTAG_ByteOut
, (UPINT
)ByteOutHook
},
93 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
94 {IOTAG_LELongIn
, (UPINT
)LELongInHook
},
95 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
96 {IOTAG_LELongOut
, (UPINT
)LELongOutHook
},
97 {IOTAG_AllocDMAMem
, (UPINT
)AllocDMAMemHook
},
98 {IOTAG_FreeDMAMem
, (UPINT
)FreeDMAMemHook
},
103 /****i* rhine.device/GetPCICount *******************************************
106 * GetPCICount -- Get the number of compatible PCI Cards.
109 * count = GetPCICount()
111 * ULONG GetPCICount();
113 ****************************************************************************
117 ULONG
GetPCICount(struct DevBase
*base
)
120 PCIBoard
*card
= NULL
;
121 UPINT vendor_id
, product_id
;
123 while((card
= Prm_FindBoardTagList(card
, NULL
)) != NULL
)
125 Prm_GetBoardAttrsTags(card
, PRM_Vendor
, (UPINT
)&vendor_id
,
126 PRM_Device
, (UPINT
)&product_id
, TAG_END
);
127 if(IsCardCompatible(vendor_id
, product_id
, base
))
136 /****i* rhine.device/GetPCIUnit ********************************************
139 * GetPCIUnit -- Get a unit by number.
142 * unit = GetPCIUnit(index)
144 * struct DevUnit *GetPCIUnit(ULONG);
146 ****************************************************************************
150 struct DevUnit
*GetPCIUnit(ULONG index
, struct DevBase
*base
)
152 struct DevUnit
*unit
;
154 unit
= FindPCIUnit(index
, base
);
158 unit
= CreatePCIUnit(index
, base
);
161 AddTail((APTR
)&base
->pci_units
, (APTR
)unit
);
170 /****i* rhine.device/FindPCIUnit *******************************************
173 * FindPCIUnit -- Find a unit by number.
176 * unit = FindPCIUnit(index)
178 * struct DevUnit *FindPCIUnit(ULONG);
180 ****************************************************************************
184 static struct DevUnit
*FindPCIUnit(ULONG index
, struct DevBase
*base
)
186 struct DevUnit
*unit
, *tail
;
189 unit
= (APTR
)base
->pci_units
.mlh_Head
;
190 tail
= (APTR
)&base
->pci_units
.mlh_Tail
;
192 while(unit
!= tail
&& !found
)
194 if(unit
->index
== index
)
197 unit
= (APTR
)unit
->node
.mln_Succ
;
208 /****i* rhine.device/CreatePCIUnit *****************************************
211 * CreatePCIUnit -- Create a PCI unit.
214 * unit = CreatePCIUnit(index)
216 * struct DevUnit *CreatePCIUnit(ULONG);
219 * Creates a new PCI unit.
221 ****************************************************************************
225 static struct DevUnit
*CreatePCIUnit(ULONG index
, struct DevBase
*base
)
228 struct BusContext
*context
;
229 struct DevUnit
*unit
= NULL
;
231 context
= AllocCard(index
, base
);
237 if(context
->unit_tags
== NULL
)
238 context
->unit_tags
= unit_tags
;
239 context
->device
= base
;
240 context
->unit
= unit
= CreateUnit(index
, context
, context
->unit_tags
,
250 if(!(WrapInt(&unit
->status_int
, base
)
251 && WrapInt(&unit
->rx_int
, base
)
252 && WrapInt(&unit
->tx_int
, base
)
253 && WrapInt(&unit
->tx_end_int
, base
)
254 && WrapInt(&unit
->reset_handler
, base
)))
258 /* Add hardware interrupt and reset handler */
262 if(AddPCIIntServer(context
->card
, &unit
->status_int
, base
))
263 unit
->flags
|= UNITF_INTADDED
;
267 if(AddResetCallback(&unit
->reset_handler
))
268 unit
->flags
|= UNITF_RESETADDED
;
277 DeleteUnit(context
->unit
, base
);
278 FreeCard(context
, base
);
288 /****i* rhine.device/DeletePCIUnit *****************************************
291 * DeletePCIUnit -- Delete a unit.
294 * DeletePCIUnit(unit)
296 * VOID DeletePCIUnit(struct DevUnit *);
302 * unit - Device unit (can be NULL).
307 ****************************************************************************
311 VOID
DeletePCIUnit(struct DevUnit
*unit
, struct DevBase
*base
)
313 struct BusContext
*context
;
317 context
= unit
->card
;
318 if((unit
->flags
& UNITF_RESETADDED
) != 0)
319 RemResetCallback(&unit
->reset_handler
);
320 if((unit
->flags
& UNITF_INTADDED
) != 0)
321 RemPCIIntServer(context
->card
, &unit
->status_int
, base
);
322 UnwrapInt(&unit
->reset_handler
, base
);
323 UnwrapInt(&unit
->tx_end_int
, base
);
324 UnwrapInt(&unit
->tx_int
, base
);
325 UnwrapInt(&unit
->rx_int
, base
);
326 UnwrapInt(&unit
->status_int
, base
);
327 DeleteUnit(unit
, base
);
328 FreeCard(context
, base
);
336 /****i* rhine.device/AllocCard *********************************************
339 * AllocCard -- Get card from system.
342 * context = AllocCard(index)
344 * struct BusContext *AllocCard(ULONG);
346 ****************************************************************************
350 static struct BusContext
*AllocCard(ULONG index
, struct DevBase
*base
)
353 struct BusContext
*context
;
354 PCIBoard
*card
= NULL
;
356 UPINT vendor_id
, product_id
;
358 /* Find a compatible card */
360 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
368 card
= Prm_FindBoardTagList(card
, NULL
);
369 Prm_GetBoardAttrsTags(card
, PRM_Vendor
, (UPINT
)&vendor_id
,
370 PRM_Device
, (UPINT
)&product_id
, TAG_END
);
371 if(IsCardCompatible(vendor_id
, product_id
, base
))
375 context
->card
= card
;
380 /* Get base address */
384 Prm_GetBoardAttrsTags(card
,
385 PRM_MemoryAddr0
+ BAR_NO
, (UPINT
)&context
->io_base
, TAG_END
);
386 if(context
->io_base
== 0)
394 if(!Prm_SetBoardAttrsTags(card
, PRM_BoardOwner
, (UPINT
)base
, TAG_END
))
400 FreeCard(context
, base
);
409 /****i* rhine.device/FreeCard **********************************************
417 * VOID FreeCard(struct BusContext *);
419 ****************************************************************************
423 static VOID
FreeCard(struct BusContext
*context
, struct DevBase
*base
)
430 card
= context
->card
;
435 Prm_GetBoardAttrsTags(card
, PRM_BoardOwner
, (UPINT
)&owner
,
438 Prm_SetBoardAttrsTags(card
, PRM_BoardOwner
, NULL
, TAG_END
);
441 FreeMem(context
, sizeof(struct BusContext
));
449 /****i* rhine.device/AddPCIIntServer ***************************************
455 * success = AddPCIIntServer(card, interrupt)
457 * BOOL AddPCIIntServer(APTR, struct Interrupt *);
459 ****************************************************************************
463 static BOOL
AddPCIIntServer(APTR card
, struct Interrupt
*interrupt
,
464 struct DevBase
*base
)
466 return Prm_AddIntServer(card
, interrupt
);
471 /****i* rhine.device/RemPCIIntServer ***************************************
477 * RemPCIIntServer(card, interrupt)
479 * VOID RemPCIIntServer(APTR, struct Interrupt *);
481 ****************************************************************************
485 static VOID
RemPCIIntServer(APTR card
, struct Interrupt
*interrupt
,
486 struct DevBase
*base
)
488 Prm_RemIntServer(card
, interrupt
);
495 /****i* rhine.device/IsCardCompatible **************************************
501 * compatible = IsCardCompatible(vendor_id, product_id)
503 * BOOL IsCardCompatible(UWORD, UWORD);
505 ****************************************************************************
509 BOOL
IsCardCompatible(UWORD vendor_id
, UWORD product_id
,
510 struct DevBase
*base
)
512 BOOL compatible
= FALSE
;
515 for(p
= product_codes
; p
[0] != 0xffff; p
+= 2)
517 if(p
[0] == vendor_id
&& p
[1] == product_id
)
526 /****i* rhine.device/ByteInHook ********************************************
532 * value = ByteInHook(context, offset)
534 * UBYTE ByteInHook(struct BusContext *, ULONG);
536 ****************************************************************************
540 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
)
542 return BYTEIN(context
->io_base
+ offset
);
547 /****i* rhine.device/ByteOutHook *******************************************
553 * ByteOutHook(context, offset, value)
555 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
557 ****************************************************************************
561 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
564 BYTEOUT(context
->io_base
+ offset
, value
);
571 /****i* rhine.device/LEWordInHook ******************************************
577 * value = LEWordInHook(context, offset)
579 * UWORD LEWordInHook(struct BusContext *, ULONG);
581 ****************************************************************************
585 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
587 return LEWORDIN(context
->io_base
+ offset
);
592 /****i* rhine.device/LELongInHook ******************************************
598 * value = LELongInHook(context, offset)
600 * ULONG LELongInHook(struct BusContext *, ULONG);
602 ****************************************************************************
606 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
)
608 return LELONGIN(context
->io_base
+ offset
);
613 /****i* rhine.device/LEWordOutHook *****************************************
619 * LEWordOutHook(context, offset, value)
621 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
623 ****************************************************************************
627 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
630 LEWORDOUT(context
->io_base
+ offset
, value
);
637 /****i* rhine.device/LELongOutHook *****************************************
643 * LELongOutHook(context, offset, value)
645 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
647 ****************************************************************************
651 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
654 LELONGOUT(context
->io_base
+ offset
, value
);
661 /****i* rhine.device/AllocDMAMemHook ***************************************
667 * mem = AllocDMAMemHook(context, size, alignment)
669 * APTR AllocDMAMemHook(struct BusContext *, UPINT, UWORD);
671 ****************************************************************************
675 static APTR
AllocDMAMemHook(struct BusContext
*context
, UPINT size
,
678 struct DevBase
*base
;
679 APTR mem
= NULL
, original_mem
;
681 base
= context
->device
;
684 size
+= 2 * sizeof(APTR
) + alignment
;
685 original_mem
= Prm_AllocDMABuffer(size
);
686 if(original_mem
!= NULL
)
688 mem
= (APTR
)((UPINT
)(original_mem
+ 2 * sizeof(APTR
) + alignment
- 1)
690 *((APTR
*)mem
- 1) = original_mem
;
691 *((UPINT
*)mem
- 2) = size
;
699 /****i* rhine.device/FreeDMAMemHook ****************************************
705 * FreeDMAMemHook(context, mem)
707 * VOID FreeDMAMemHook(struct BusContext *, APTR);
709 ****************************************************************************
713 static VOID
FreeDMAMemHook(struct BusContext
*context
, APTR mem
)
715 struct DevBase
*base
;
717 base
= context
->device
;
719 Prm_FreeDMABuffer(*((APTR
*)mem
- 1), *((UPINT
*)mem
- 2));