- Now splits paragraphs into multiple lines, with each line fitting the
[AROS.git] / workbench / devs / networks / rhine / pci.c
blob60d933a123fa57962367f47cfff91c96cad54661
1 /*
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,
18 MA 02111-1307, USA.
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>
31 #include "device.h"
33 #include "pci_protos.h"
34 #include "device_protos.h"
35 #include "unit_protos.h"
37 #define BAR_NO 0
40 struct BusContext
42 struct DevUnit *unit;
43 struct DevBase *device;
44 VOID *card;
45 UPINT io_base;
46 const struct TagItem *unit_tags;
47 BOOL have_card;
48 UWORD generation;
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,
64 UBYTE value);
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,
68 UWORD value);
69 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
70 ULONG value);
71 static APTR AllocDMAMemHook(struct BusContext *context, UPINT size,
72 UWORD alignment);
73 static VOID FreeDMAMemHook(struct BusContext *context, APTR mem);
76 const UWORD product_codes[] =
78 0x1106, 0x3043,
79 0x1106, 0x3053,
80 0x1106, 0x3065,
81 0x1106, 0x3106,
82 0x1106, 0x6100,
83 0x1500, 0x1320,
84 0x4033, 0x1320,
85 0xffff, 0xffff
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},
99 {TAG_END, 0}
103 /****i* rhine.device/GetPCICount *******************************************
105 * NAME
106 * GetPCICount -- Get the number of compatible PCI Cards.
108 * SYNOPSIS
109 * count = GetPCICount()
111 * ULONG GetPCICount();
113 ****************************************************************************
117 ULONG GetPCICount(struct DevBase *base)
119 ULONG count = 0;
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))
128 count++;
131 return count;
136 /****i* rhine.device/GetPCIUnit ********************************************
138 * NAME
139 * GetPCIUnit -- Get a unit by number.
141 * SYNOPSIS
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);
156 if(unit == NULL)
158 unit = CreatePCIUnit(index, base);
159 if(unit != NULL)
161 AddTail((APTR)&base->pci_units, (APTR)unit);
165 return unit;
170 /****i* rhine.device/FindPCIUnit *******************************************
172 * NAME
173 * FindPCIUnit -- Find a unit by number.
175 * SYNOPSIS
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;
187 BOOL found = FALSE;
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)
195 found = TRUE;
196 else
197 unit = (APTR)unit->node.mln_Succ;
200 if(!found)
201 unit = NULL;
203 return unit;
208 /****i* rhine.device/CreatePCIUnit *****************************************
210 * NAME
211 * CreatePCIUnit -- Create a PCI unit.
213 * SYNOPSIS
214 * unit = CreatePCIUnit(index)
216 * struct DevUnit *CreatePCIUnit(ULONG);
218 * FUNCTION
219 * Creates a new PCI unit.
221 ****************************************************************************
225 static struct DevUnit *CreatePCIUnit(ULONG index, struct DevBase *base)
227 BOOL success = TRUE;
228 struct BusContext *context;
229 struct DevUnit *unit = NULL;
231 context = AllocCard(index, base);
232 if(context == NULL)
233 success = FALSE;
235 if(success)
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,
241 PCI_BUS, base);
242 if(unit == NULL)
243 success = FALSE;
246 /* Add interrupt */
248 if(success)
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)))
255 success = FALSE;
258 /* Add hardware interrupt and reset handler */
260 if(success)
262 if(AddPCIIntServer(context->card, &unit->status_int, base))
263 unit->flags |= UNITF_INTADDED;
264 else
265 success = FALSE;
267 if(AddResetCallback(&unit->reset_handler))
268 unit->flags |= UNITF_RESETADDED;
269 else
270 success = FALSE;
273 if(!success)
275 if(context != NULL)
277 DeleteUnit(context->unit, base);
278 FreeCard(context, base);
280 unit = NULL;
283 return unit;
288 /****i* rhine.device/DeletePCIUnit *****************************************
290 * NAME
291 * DeletePCIUnit -- Delete a unit.
293 * SYNOPSIS
294 * DeletePCIUnit(unit)
296 * VOID DeletePCIUnit(struct DevUnit *);
298 * FUNCTION
299 * Deletes a unit.
301 * INPUTS
302 * unit - Device unit (can be NULL).
304 * RESULT
305 * None.
307 ****************************************************************************
311 VOID DeletePCIUnit(struct DevUnit *unit, struct DevBase *base)
313 struct BusContext *context;
315 if(unit != NULL)
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);
331 return;
336 /****i* rhine.device/AllocCard *********************************************
338 * NAME
339 * AllocCard -- Get card from system.
341 * SYNOPSIS
342 * context = AllocCard(index)
344 * struct BusContext *AllocCard(ULONG);
346 ****************************************************************************
350 static struct BusContext *AllocCard(ULONG index, struct DevBase *base)
352 BOOL success = TRUE;
353 struct BusContext *context;
354 PCIBoard *card = NULL;
355 UWORD i = 0;
356 UPINT vendor_id, product_id;
358 /* Find a compatible card */
360 context = AllocMem(sizeof(struct BusContext), MEMF_PUBLIC | MEMF_CLEAR);
361 if(context == NULL)
362 success = FALSE;
364 if(success)
366 while(i <= index)
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))
372 i++;
375 context->card = card;
376 if(card == NULL)
377 success = FALSE;
380 /* Get base address */
382 if(success)
384 Prm_GetBoardAttrsTags(card,
385 PRM_MemoryAddr0 + BAR_NO, (UPINT)&context->io_base, TAG_END);
386 if(context->io_base == 0)
387 success = FALSE;
390 /* Lock card */
392 if(success)
394 if(!Prm_SetBoardAttrsTags(card, PRM_BoardOwner, (UPINT)base, TAG_END))
395 success = FALSE;
398 if(!success)
400 FreeCard(context, base);
401 context = NULL;
404 return context;
409 /****i* rhine.device/FreeCard **********************************************
411 * NAME
412 * FreeCard
414 * SYNOPSIS
415 * FreeCard(context)
417 * VOID FreeCard(struct BusContext *);
419 ****************************************************************************
423 static VOID FreeCard(struct BusContext *context, struct DevBase *base)
425 PCIBoard *card;
426 APTR owner;
428 if(context != NULL)
430 card = context->card;
431 if(card != NULL)
433 /* Unlock board */
435 Prm_GetBoardAttrsTags(card, PRM_BoardOwner, (UPINT)&owner,
436 TAG_END);
437 if(owner == base)
438 Prm_SetBoardAttrsTags(card, PRM_BoardOwner, NULL, TAG_END);
441 FreeMem(context, sizeof(struct BusContext));
444 return;
449 /****i* rhine.device/AddPCIIntServer ***************************************
451 * NAME
452 * AddPCIIntServer
454 * SYNOPSIS
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 ***************************************
473 * NAME
474 * RemPCIIntServer
476 * SYNOPSIS
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);
490 return;
495 /****i* rhine.device/IsCardCompatible **************************************
497 * NAME
498 * IsCardCompatible
500 * SYNOPSIS
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;
513 const UWORD *p;
515 for(p = product_codes; p[0] != 0xffff; p += 2)
517 if(p[0] == vendor_id && p[1] == product_id)
518 compatible = TRUE;
521 return compatible;
526 /****i* rhine.device/ByteInHook ********************************************
528 * NAME
529 * ByteInHook
531 * SYNOPSIS
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 *******************************************
549 * NAME
550 * ByteOutHook
552 * SYNOPSIS
553 * ByteOutHook(context, offset, value)
555 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
557 ****************************************************************************
561 static VOID ByteOutHook(struct BusContext *context, ULONG offset,
562 UBYTE value)
564 BYTEOUT(context->io_base + offset, value);
566 return;
571 /****i* rhine.device/LEWordInHook ******************************************
573 * NAME
574 * LEWordInHook
576 * SYNOPSIS
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 ******************************************
594 * NAME
595 * LELongInHook
597 * SYNOPSIS
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 *****************************************
615 * NAME
616 * LEWordOutHook
618 * SYNOPSIS
619 * LEWordOutHook(context, offset, value)
621 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
623 ****************************************************************************
627 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
628 UWORD value)
630 LEWORDOUT(context->io_base + offset, value);
632 return;
637 /****i* rhine.device/LELongOutHook *****************************************
639 * NAME
640 * LELongOutHook
642 * SYNOPSIS
643 * LELongOutHook(context, offset, value)
645 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
647 ****************************************************************************
651 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
652 ULONG value)
654 LELONGOUT(context->io_base + offset, value);
656 return;
661 /****i* rhine.device/AllocDMAMemHook ***************************************
663 * NAME
664 * AllocDMAMemHook
666 * SYNOPSIS
667 * mem = AllocDMAMemHook(context, size, alignment)
669 * APTR AllocDMAMemHook(struct BusContext *, UPINT, UWORD);
671 ****************************************************************************
675 static APTR AllocDMAMemHook(struct BusContext *context, UPINT size,
676 UWORD alignment)
678 struct DevBase *base;
679 APTR mem = NULL, original_mem;
681 base = context->device;
682 if(alignment < 8)
683 alignment = 8;
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)
689 & ~(alignment - 1));
690 *((APTR *)mem - 1) = original_mem;
691 *((UPINT *)mem - 2) = size;
694 return mem;
699 /****i* rhine.device/FreeDMAMemHook ****************************************
701 * NAME
702 * FreeDMAMemHook
704 * SYNOPSIS
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;
718 if(mem != NULL)
719 Prm_FreeDMABuffer(*((APTR *)mem - 1), *((UPINT *)mem - 2));
721 return;