Subversion Repositories HelenOS-historic

Rev

Rev 1302 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1301 jermar 1
/*
2
 *  The PCI Library -- Generic Direct Access Functions
3
 *
4
 *  Copyright (c) 1997--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *  Modified and ported to HelenOS by Jakub Jermar.
7
 *
8
 *  Can be freely distributed and used under the terms of the GNU GPL.
9
 */
10
 
11
#include <string.h>
12
 
13
#include "internal.h"
14
 
15
void
16
pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
17
{
18
  int dev, multi, ht;
19
  struct pci_dev *t;
20
 
21
  a->debug("Scanning bus %02x for devices...\n", bus);
22
  if (busmap[bus])
23
    {
24
      a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus);
25
      return;
26
    }
27
  busmap[bus] = 1;
28
  t = pci_alloc_dev(a);
29
  t->bus = bus;
30
  for(dev=0; dev<32; dev++)
31
    {
32
      t->dev = dev;
33
      multi = 0;
34
      for(t->func=0; !t->func || multi && t->func<8; t->func++)
35
    {
36
      u32 vd = pci_read_long(t, PCI_VENDOR_ID);
37
      struct pci_dev *d;
38
 
39
      if (!vd || vd == 0xffffffff)
40
        continue;
41
      ht = pci_read_byte(t, PCI_HEADER_TYPE);
42
      if (!t->func)
43
        multi = ht & 0x80;
44
      ht &= 0x7f;
45
      d = pci_alloc_dev(a);
46
      d->bus = t->bus;
47
      d->dev = t->dev;
48
      d->func = t->func;
49
      d->vendor_id = vd & 0xffff;
50
      d->device_id = vd >> 16U;
51
      d->known_fields = PCI_FILL_IDENT;
52
      d->hdrtype = ht;
53
      pci_link_dev(a, d);
54
      switch (ht)
55
        {
56
        case PCI_HEADER_TYPE_NORMAL:
57
          break;
58
        case PCI_HEADER_TYPE_BRIDGE:
59
        case PCI_HEADER_TYPE_CARDBUS:
60
          pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS));
61
          break;
62
        default:
63
          a->debug("Device %04x:%02x:%02x.%d has unknown header type %02x.\n", d->domain, d->bus, d->dev, d->func, ht);
64
        }
65
    }
66
    }
67
  pci_free_dev(t);
68
}
69
 
70
void
71
pci_generic_scan(struct pci_access *a)
72
{
73
  byte busmap[256];
74
 
75
  bzero(busmap, sizeof(busmap));
76
  pci_generic_scan_bus(a, busmap, 0);
77
}
78
 
79
int
80
pci_generic_fill_info(struct pci_dev *d, int flags)
81
{
82
  struct pci_access *a = d->access;
83
 
84
  if ((flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE)) && d->hdrtype < 0)
85
    d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f;
86
  if (flags & PCI_FILL_IDENT)
87
    {
88
      d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
89
      d->device_id = pci_read_word(d, PCI_DEVICE_ID);
90
    }
91
  if (flags & PCI_FILL_IRQ)
92
    d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
93
  if (flags & PCI_FILL_BASES)
94
    {
95
      int cnt = 0, i;
96
      bzero(d->base_addr, sizeof(d->base_addr));
97
      switch (d->hdrtype)
98
    {
99
    case PCI_HEADER_TYPE_NORMAL:
100
      cnt = 6;
101
      break;
102
    case PCI_HEADER_TYPE_BRIDGE:
103
      cnt = 2;
104
      break;
105
    case PCI_HEADER_TYPE_CARDBUS:
106
      cnt = 1;
107
      break;
108
    }
109
      if (cnt)
110
    {
111
      for(i=0; i<cnt; i++)
112
        {
113
          u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
114
          if (!x || x == (u32) ~0)
115
        continue;
116
          if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
117
        d->base_addr[i] = x;
118
          else
119
        {
120
          if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64)
121
            d->base_addr[i] = x;
122
          else if (i >= cnt-1)
123
            a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.", d->domain, d->bus, d->dev, d->func, i);
124
          else
125
            {
126
              u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
127
#ifdef PCI_HAVE_64BIT_ADDRESS
128
              d->base_addr[i-1] = x | (((pciaddr_t) y) << 32);
129
#else
130
              if (y)
131
            a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func);
132
              else
133
            d->base_addr[i-1] = x;
134
#endif
135
            }
136
        }
137
        }
138
    }
139
    }
140
  if (flags & PCI_FILL_ROM_BASE)
141
    {
142
      int reg = 0;
143
      d->rom_base_addr = 0;
144
      switch (d->hdrtype)
145
    {
146
    case PCI_HEADER_TYPE_NORMAL:
147
      reg = PCI_ROM_ADDRESS;
148
      break;
149
    case PCI_HEADER_TYPE_BRIDGE:
150
      reg = PCI_ROM_ADDRESS1;
151
      break;
152
    }
153
      if (reg)
154
    {
155
      u32 u = pci_read_long(d, reg);
156
      if (u != 0xffffffff)
157
        d->rom_base_addr = u;
158
    }
159
    }
160
  return flags & ~PCI_FILL_SIZES;
161
}
162
 
163
static int
164
pci_generic_block_op(struct pci_dev *d, int pos, byte *buf, int len,
165
         int (*r)(struct pci_dev *d, int pos, byte *buf, int len))
166
{
167
  if ((pos & 1) && len >= 1)
168
    {
169
      if (!r(d, pos, buf, 1))
170
    return 0;
171
      pos++; buf++; len--;
172
    }
173
  if ((pos & 3) && len >= 2)
174
    {
175
      if (!r(d, pos, buf, 2))
176
    return 0;
177
      pos += 2; buf += 2; len -= 2;
178
    }
179
  while (len >= 4)
180
    {
181
      if (!r(d, pos, buf, 4))
182
    return 0;
183
      pos += 4; buf += 4; len -= 4;
184
    }
185
  if (len >= 2)
186
    {
187
      if (!r(d, pos, buf, 2))
188
    return 0;
189
      pos += 2; buf += 2; len -= 2;
190
    }
191
  if (len && !r(d, pos, buf, 1))
192
    return 0;
193
  return 1;
194
}
195
 
196
int
197
pci_generic_block_read(struct pci_dev *d, int pos, byte *buf, int len)
198
{
199
  return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
200
}
201
 
202
int
203
pci_generic_block_write(struct pci_dev *d, int pos, byte *buf, int len)
204
{
205
  return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
206
}