revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / etherlink3 / expansion.c
blobd90c23ec9b3328b89314b08fdee9a3141afcd712
1 /*
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,
18 MA 02111-1307, USA.
23 #include <exec/types.h>
24 #include <expansion/pci.h>
26 #include <proto/exec.h>
27 #include <proto/expansion.h>
29 #include "device.h"
30 #include "pci.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,
41 UBYTE value);
42 static VOID WordOutHook(struct BusContext *context, ULONG offset,
43 UWORD value);
44 static VOID LongOutHook(struct BusContext *context, ULONG offset,
45 ULONG value);
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,
51 UWORD value);
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,
55 UWORD value);
56 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
57 ULONG value);
58 static APTR AllocDMAMemHook(struct BusContext *context, UPINT size,
59 UWORD alignment);
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},
82 {TAG_END, 0}
86 /****i* etherlink3.device/GetExpansionCount ********************************
88 * NAME
89 * GetExpansionCount -- Get the number of compatible PCI Cards.
91 * SYNOPSIS
92 * count = GetExpansionCount()
94 * ULONG GetExpansionCount();
96 ****************************************************************************
100 ULONG GetExpansionCount(struct DevBase *base)
102 ULONG count = 0;
103 struct PCIDevice *card;
105 if(base->i_pci != NULL)
107 while((card =
108 base->i_pci->FindDeviceTags(FDT_CandidateList, product_codes,
109 FDT_Index, count, TAG_END)) != NULL)
111 base->i_pci->FreeDevice(card);
112 count++;
116 return count;
121 /****i* etherlink3.device/AllocExpansionCard *******************************
123 * NAME
124 * AllocExpansionCard -- Take control of a card.
126 * SYNOPSIS
127 * context = AllocExpansionCard(index)
129 * struct BusContext *AllocExpansionCard(ULONG);
131 ****************************************************************************
135 struct BusContext *AllocExpansionCard(ULONG index, struct DevBase *base)
137 BOOL success = TRUE;
138 struct BusContext *context;
139 struct PCIDevice *card = NULL;
140 struct PCIResourceRange *io_range = NULL;
141 UWORD product_id;
143 /* Find a compatible card */
145 context = AllocMem(sizeof(struct BusContext), MEMF_PUBLIC | MEMF_CLEAR);
146 if(context == NULL)
147 success = FALSE;
149 if(success)
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);
155 if(card == NULL)
156 success = FALSE;
159 /* Lock card */
161 if(success)
162 success = card->Lock(PCI_LOCK_EXCLUSIVE);
164 /* Get base address and generation */
166 if(success)
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);
177 if(!success)
179 FreeExpansionCard(context, base);
180 context = NULL;
183 return context;
188 /****i* etherlink3.device/FreeExpansionCard ********************************
190 * NAME
191 * FreeExpansionCard -- Release a card.
193 * SYNOPSIS
194 * FreeExpansionCard(context)
196 * VOID FreeExpansionCard(struct BusContext *);
198 ****************************************************************************
202 VOID FreeExpansionCard(struct BusContext *context, struct DevBase *base)
204 struct PCIDevice *card;
206 if(context != NULL)
208 card = context->card;
209 if(card != NULL)
211 if(context->have_card)
212 card->Unlock();
213 base->i_pci->FreeDevice(card);
214 FreeMem(context, sizeof(struct BusContext));
218 return;
223 /****i* etherlink3.device/AddExpansionIntServer ****************************
225 * NAME
226 * AddExpansionIntServer
228 * SYNOPSIS
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(),
241 interrupt);
246 /****i* etherlink3.device/RemExpansionIntServer ****************************
248 * NAME
249 * RemExpansionIntServer
251 * SYNOPSIS
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);
265 return;
270 /****i* etherlink3.device/ByteInHook ***************************************
272 * NAME
273 * ByteInHook
275 * SYNOPSIS
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 ***************************************
296 * NAME
297 * LongInHook
299 * SYNOPSIS
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 **************************************
320 * NAME
321 * ByteOutHook
323 * SYNOPSIS
324 * ByteOutHook(context, offset, value)
326 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
328 ****************************************************************************
332 static VOID ByteOutHook(struct BusContext *context, ULONG offset,
333 UBYTE value)
335 struct PCIDevice *card;
337 card = context->card;
338 card->OutByte(context->io_base + offset, value);
340 return;
345 /****i* etherlink3.device/WordOutHook **************************************
347 * NAME
348 * WordOutHook
350 * SYNOPSIS
351 * WordOutHook(context, offset, value)
353 * VOID WordOutHook(struct BusContext *, ULONG, UWORD);
355 ****************************************************************************
359 static VOID WordOutHook(struct BusContext *context, ULONG offset,
360 UWORD value)
362 struct PCIDevice *card;
364 card = context->card;
365 card->OutWord(context->io_base + offset, value);
367 return;
372 /****i* etherlink3.device/LongOutHook **************************************
374 * NAME
375 * LongOutHook
377 * SYNOPSIS
378 * LongOutHook(context, offset, value)
380 * VOID LongOutHook(struct BusContext *, ULONG, ULONG);
382 ****************************************************************************
386 static VOID LongOutHook(struct BusContext *context, ULONG offset,
387 ULONG value)
389 struct PCIDevice *card;
391 card = context->card;
392 card->OutLong(context->io_base + offset, value);
394 return;
399 /****i* etherlink3.device/LongsInHook **************************************
401 * NAME
402 * LongsInHook
404 * SYNOPSIS
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;
419 while(count-- > 0)
420 *buffer++ = card->InLong(context->io_base + offset);
422 return;
427 /****i* etherlink3.device/LongsOutHook *************************************
429 * NAME
430 * LongsOutHook
432 * SYNOPSIS
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;
447 while(count-- > 0)
448 card->OutLong(context->io_base + offset, *buffer++);
450 return;
455 /****i* etherlink3.device/BEWordOutHook ************************************
457 * NAME
458 * BEWordOutHook
460 * SYNOPSIS
461 * BEWordOutHook(context, offset, value)
463 * VOID BEWordOutHook(struct BusContext *, ULONG, UWORD);
465 ****************************************************************************
469 static VOID BEWordOutHook(struct BusContext *context, ULONG offset,
470 UWORD value)
472 struct PCIDevice *card;
474 card = context->card;
475 card->OutWord(context->io_base + offset, MakeBEWord(value));
477 return;
482 /****i* etherlink3.device/LEWordInHook *************************************
484 * NAME
485 * LEWordInHook
487 * SYNOPSIS
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 *************************************
508 * NAME
509 * LELongInHook
511 * SYNOPSIS
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 ************************************
532 * NAME
533 * LEWordOutHook
535 * SYNOPSIS
536 * LEWordOutHook(context, offset, value)
538 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
540 ****************************************************************************
544 static VOID LEWordOutHook(struct BusContext *context, ULONG offset,
545 UWORD value)
547 struct PCIDevice *card;
549 card = context->card;
550 card->OutWord(context->io_base + offset, MakeLEWord(value));
552 return;
557 /****i* etherlink3.device/LELongOutHook ************************************
559 * NAME
560 * LELongOutHook
562 * SYNOPSIS
563 * LELongOutHook(context, offset, value)
565 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
567 ****************************************************************************
571 static VOID LELongOutHook(struct BusContext *context, ULONG offset,
572 ULONG value)
574 struct PCIDevice *card;
576 card = context->card;
577 card->OutLong(context->io_base + offset, MakeLELong(value));
579 return;
584 /****i* etherlink3.device/AllocDMAMemHook **********************************
586 * NAME
587 * AllocDMAMemHook
589 * SYNOPSIS
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,
601 UWORD alignment)
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)
612 & ~(alignment - 1));
613 *((APTR *)mem - 1) = original_mem;
614 *((UPINT *)mem - 2) = size;
617 return mem;
622 /****i* etherlink3.device/FreeDMAMemHook ***********************************
624 * NAME
625 * FreeDMAMemHook
627 * SYNOPSIS
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;
641 if(mem != NULL)
642 FreeMem(*((APTR *)mem - 1), *((UPINT *)mem - 2));
644 return;