Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* -*- mode: c; c-basic-offset: 8 -*- */ |
2 | ||
3 | /* | |
4 | * MCA bus support functions for the proc fs. | |
5 | * | |
6 | * NOTE: this code *requires* the legacy MCA api. | |
7 | * | |
8 | * Legacy API means the API that operates in terms of MCA slot number | |
9 | * | |
10 | * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com> | |
11 | * | |
12 | **----------------------------------------------------------------------------- | |
13 | ** | |
14 | ** This program is free software; you can redistribute it and/or modify | |
15 | ** it under the terms of the GNU General Public License as published by | |
16 | ** the Free Software Foundation; either version 2 of the License, or | |
17 | ** (at your option) any later version. | |
18 | ** | |
19 | ** This program is distributed in the hope that it will be useful, | |
20 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | ** GNU General Public License for more details. | |
23 | ** | |
24 | ** You should have received a copy of the GNU General Public License | |
25 | ** along with this program; if not, write to the Free Software | |
26 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
27 | ** | |
28 | **----------------------------------------------------------------------------- | |
29 | */ | |
30 | #include <linux/module.h> | |
31 | #include <linux/init.h> | |
32 | #include <linux/proc_fs.h> | |
33 | #include <linux/mca.h> | |
34 | ||
35 | static int get_mca_info_helper(struct mca_device *mca_dev, char *page, int len) | |
36 | { | |
37 | int j; | |
38 | ||
39 | for(j=0; j<8; j++) | |
40 | len += sprintf(page+len, "%02x ", | |
41 | mca_dev ? mca_dev->pos[j] : 0xff); | |
42 | len += sprintf(page+len, " %s\n", mca_dev ? mca_dev->name : ""); | |
43 | return len; | |
44 | } | |
45 | ||
46 | static int get_mca_info(char *page, char **start, off_t off, | |
47 | int count, int *eof, void *data) | |
48 | { | |
49 | int i, len = 0; | |
50 | ||
51 | if(MCA_bus) { | |
52 | struct mca_device *mca_dev; | |
53 | /* Format POS registers of eight MCA slots */ | |
54 | ||
55 | for(i=0; i<MCA_MAX_SLOT_NR; i++) { | |
56 | mca_dev = mca_find_device_by_slot(i); | |
57 | ||
58 | len += sprintf(page+len, "Slot %d: ", i+1); | |
59 | len = get_mca_info_helper(mca_dev, page, len); | |
60 | } | |
61 | ||
62 | /* Format POS registers of integrated video subsystem */ | |
63 | ||
64 | mca_dev = mca_find_device_by_slot(MCA_INTEGVIDEO); | |
65 | len += sprintf(page+len, "Video : "); | |
66 | len = get_mca_info_helper(mca_dev, page, len); | |
67 | ||
68 | /* Format POS registers of integrated SCSI subsystem */ | |
69 | ||
70 | mca_dev = mca_find_device_by_slot(MCA_INTEGSCSI); | |
71 | len += sprintf(page+len, "SCSI : "); | |
72 | len = get_mca_info_helper(mca_dev, page, len); | |
73 | ||
74 | /* Format POS registers of motherboard */ | |
75 | ||
76 | mca_dev = mca_find_device_by_slot(MCA_MOTHERBOARD); | |
77 | len += sprintf(page+len, "Planar: "); | |
78 | len = get_mca_info_helper(mca_dev, page, len); | |
79 | } else { | |
80 | /* Leave it empty if MCA not detected - this should *never* | |
81 | * happen! | |
82 | */ | |
83 | } | |
84 | ||
85 | if (len <= off+count) *eof = 1; | |
86 | *start = page + off; | |
87 | len -= off; | |
88 | if (len>count) len = count; | |
89 | if (len<0) len = 0; | |
90 | return len; | |
91 | } | |
92 | ||
93 | /*--------------------------------------------------------------------*/ | |
94 | ||
95 | static int mca_default_procfn(char* buf, struct mca_device *mca_dev) | |
96 | { | |
97 | int len = 0, i; | |
98 | int slot = mca_dev->slot; | |
99 | ||
100 | /* Print out the basic information */ | |
101 | ||
102 | if(slot < MCA_MAX_SLOT_NR) { | |
103 | len += sprintf(buf+len, "Slot: %d\n", slot+1); | |
104 | } else if(slot == MCA_INTEGSCSI) { | |
105 | len += sprintf(buf+len, "Integrated SCSI Adapter\n"); | |
106 | } else if(slot == MCA_INTEGVIDEO) { | |
107 | len += sprintf(buf+len, "Integrated Video Adapter\n"); | |
108 | } else if(slot == MCA_MOTHERBOARD) { | |
109 | len += sprintf(buf+len, "Motherboard\n"); | |
110 | } | |
111 | if (mca_dev->name[0]) { | |
112 | ||
113 | /* Drivers might register a name without /proc handler... */ | |
114 | ||
115 | len += sprintf(buf+len, "Adapter Name: %s\n", | |
116 | mca_dev->name); | |
117 | } else { | |
118 | len += sprintf(buf+len, "Adapter Name: Unknown\n"); | |
119 | } | |
120 | len += sprintf(buf+len, "Id: %02x%02x\n", | |
121 | mca_dev->pos[1], mca_dev->pos[0]); | |
122 | len += sprintf(buf+len, "Enabled: %s\nPOS: ", | |
123 | mca_device_status(mca_dev) == MCA_ADAPTER_NORMAL ? | |
124 | "Yes" : "No"); | |
125 | for(i=0; i<8; i++) { | |
126 | len += sprintf(buf+len, "%02x ", mca_dev->pos[i]); | |
127 | } | |
128 | len += sprintf(buf+len, "\nDriver Installed: %s", | |
129 | mca_device_claimed(mca_dev) ? "Yes" : "No"); | |
130 | buf[len++] = '\n'; | |
131 | buf[len] = 0; | |
132 | ||
133 | return len; | |
134 | } /* mca_default_procfn() */ | |
135 | ||
136 | static int get_mca_machine_info(char* page, char **start, off_t off, | |
137 | int count, int *eof, void *data) | |
138 | { | |
139 | int len = 0; | |
140 | ||
141 | len += sprintf(page+len, "Model Id: 0x%x\n", machine_id); | |
142 | len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id); | |
143 | len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision); | |
144 | ||
145 | if (len <= off+count) *eof = 1; | |
146 | *start = page + off; | |
147 | len -= off; | |
148 | if (len>count) len = count; | |
149 | if (len<0) len = 0; | |
150 | return len; | |
151 | } | |
152 | ||
153 | static int mca_read_proc(char *page, char **start, off_t off, | |
154 | int count, int *eof, void *data) | |
155 | { | |
156 | struct mca_device *mca_dev = (struct mca_device *)data; | |
157 | int len = 0; | |
158 | ||
159 | /* Get the standard info */ | |
160 | ||
161 | len = mca_default_procfn(page, mca_dev); | |
162 | ||
163 | /* Do any device-specific processing, if there is any */ | |
164 | ||
165 | if(mca_dev->procfn) { | |
166 | len += mca_dev->procfn(page+len, mca_dev->slot, | |
167 | mca_dev->proc_dev); | |
168 | } | |
169 | if (len <= off+count) *eof = 1; | |
170 | *start = page + off; | |
171 | len -= off; | |
172 | if (len>count) len = count; | |
173 | if (len<0) len = 0; | |
174 | return len; | |
175 | } /* mca_read_proc() */ | |
176 | ||
177 | /*--------------------------------------------------------------------*/ | |
178 | ||
179 | void __init mca_do_proc_init(void) | |
180 | { | |
181 | int i; | |
182 | struct proc_dir_entry *proc_mca; | |
183 | struct proc_dir_entry* node = NULL; | |
184 | struct mca_device *mca_dev; | |
185 | ||
186 | proc_mca = proc_mkdir("mca", &proc_root); | |
187 | create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL); | |
188 | create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL); | |
189 | ||
190 | /* Initialize /proc/mca entries for existing adapters */ | |
191 | ||
192 | for(i = 0; i < MCA_NUMADAPTERS; i++) { | |
193 | enum MCA_AdapterStatus status; | |
194 | mca_dev = mca_find_device_by_slot(i); | |
195 | if(!mca_dev) | |
196 | continue; | |
197 | ||
198 | mca_dev->procfn = NULL; | |
199 | ||
200 | if(i < MCA_MAX_SLOT_NR) sprintf(mca_dev->procname,"slot%d", i+1); | |
201 | else if(i == MCA_INTEGVIDEO) sprintf(mca_dev->procname,"video"); | |
202 | else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi"); | |
203 | else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar"); | |
204 | ||
205 | status = mca_device_status(mca_dev); | |
206 | if (status != MCA_ADAPTER_NORMAL && | |
207 | status != MCA_ADAPTER_DISABLED) | |
208 | continue; | |
209 | ||
210 | node = create_proc_read_entry(mca_dev->procname, 0, proc_mca, | |
211 | mca_read_proc, (void *)mca_dev); | |
212 | ||
213 | if(node == NULL) { | |
214 | printk("Failed to allocate memory for MCA proc-entries!"); | |
215 | return; | |
216 | } | |
217 | } | |
218 | ||
219 | } /* mca_do_proc_init() */ | |
220 | ||
221 | /** | |
222 | * mca_set_adapter_procfn - Set the /proc callback | |
223 | * @slot: slot to configure | |
224 | * @procfn: callback function to call for /proc | |
225 | * @dev: device information passed to the callback | |
226 | * | |
227 | * This sets up an information callback for /proc/mca/slot?. The | |
228 | * function is called with the buffer, slot, and device pointer (or | |
229 | * some equally informative context information, or nothing, if you | |
230 | * prefer), and is expected to put useful information into the | |
231 | * buffer. The adapter name, ID, and POS registers get printed | |
232 | * before this is called though, so don't do it again. | |
233 | * | |
234 | * This should be called with a %NULL @procfn when a module | |
235 | * unregisters, thus preventing kernel crashes and other such | |
236 | * nastiness. | |
237 | */ | |
238 | ||
239 | void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* proc_dev) | |
240 | { | |
241 | struct mca_device *mca_dev = mca_find_device_by_slot(slot); | |
242 | ||
243 | if(!mca_dev) | |
244 | return; | |
245 | ||
246 | mca_dev->procfn = procfn; | |
247 | mca_dev->proc_dev = proc_dev; | |
248 | } | |
249 | EXPORT_SYMBOL(mca_set_adapter_procfn); |