1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
/*
* pcibios code from linuxbios
*/
#include <pci.h>
#undef __KERNEL__
#include <io.h>
void printk(const char *fmt, ...);
#define printk_debug printk
#define printk_err printk
enum {
CHECK = 0xb001,
FINDDEV = 0xb102,
READCONFBYTE = 0xb108,
READCONFWORD = 0xb109,
READCONFDWORD = 0xb10a,
WRITECONFBYTE = 0xb10b,
WRITECONFWORD = 0xb10c,
WRITECONFDWORD = 0xb10d
};
// errors go in AH. Just set these up so that word assigns
// will work. KISS.
enum {
PCIBIOS_NODEV = 0x8600,
PCIBIOS_BADREG = 0x8700
};
int
pcibios(
unsigned long *pedi,
unsigned long *pesi,
unsigned long *pebp,
unsigned long *pesp,
unsigned long *pebx,
unsigned long *pedx,
unsigned long *pecx,
unsigned long *peax,
unsigned long *pflags
) {
unsigned long edi = *pedi;
unsigned long esi = *pesi;
unsigned long ebp = *pebp;
unsigned long esp = *pesp;
unsigned long ebx = *pebx;
unsigned long edx = *pedx;
unsigned long ecx = *pecx;
unsigned long eax = *peax;
unsigned long flags = *pflags;
unsigned short func = (unsigned short) eax;
int retval = -1;
unsigned short devid, vendorid, devfn;
short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */
unsigned char bus;
struct pci_dev *dev;
switch(func) {
case CHECK:
*pedx = 0x4350;
*pecx = 0x2049;
retval = 0;
break;
case FINDDEV:
{
devid = *pecx;
vendorid = *pedx;
devindex = *pesi;
dev = 0;
while ((dev = pci_find_device(vendorid, devid, dev))) {
if (devindex <= 0)
break;
devindex--;
}
if (dev) {
unsigned short busdevfn;
*peax = 0;
// busnum is an unsigned char;
// devfn is an int, so we mask it off.
busdevfn = (dev->bus << 8)
| (dev->devfn & 0xff);
printk_debug("0x%x: return 0x%x\n", func, busdevfn);
*pebx = busdevfn;
retval = 0;
} else {
*peax = PCIBIOS_NODEV;
retval = -1;
}
}
break;
case READCONFDWORD:
case READCONFWORD:
case READCONFBYTE:
case WRITECONFDWORD:
case WRITECONFWORD:
case WRITECONFBYTE:
{
unsigned int dword;
unsigned short word;
unsigned char byte;
unsigned char reg;
devfn = *pebx & 0xff;
bus = *pebx >> 8;
reg = *pedi;
dev = pci_find_slot(bus, devfn);
if (! dev) {
printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
*peax = PCIBIOS_BADREG;
retval = -1;
}
switch(func) {
case READCONFBYTE:
retval = pci_read_config_byte(dev, reg, &byte);
*pecx = byte;
break;
case READCONFWORD:
retval = pci_read_config_word(dev, reg, &word);
*pecx = word;
break;
case READCONFDWORD:
retval = pci_read_config_dword(dev, reg, &dword);
*pecx = dword;
break;
case WRITECONFBYTE:
byte = *pecx;
retval = pci_write_config_byte(dev, reg, byte);
break;
case WRITECONFWORD:
word = *pecx;
retval = pci_write_config_word(dev, reg, word);
break;
case WRITECONFDWORD:
word = *pecx;
retval = pci_write_config_dword(dev, reg, dword);
break;
}
if (retval)
retval = PCIBIOS_BADREG;
printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n", func, bus, devfn, reg, *pecx);
*peax = 0;
retval = 0;
}
break;
default:
printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
break;
}
return retval;
}
|