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 35static 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 46static 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 95static 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 136static 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 153static 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 179void __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 239void 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} 249EXPORT_SYMBOL(mca_set_adapter_procfn); 250