mca.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:26k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/i386/kernel/mca.c
  3.  *  Written by Martin Kolinek, February 1996
  4.  *
  5.  * Changes:
  6.  *
  7.  * Chris Beauregard July 28th, 1996
  8.  * - Fixed up integrated SCSI detection
  9.  *
  10.  * Chris Beauregard August 3rd, 1996
  11.  * - Made mca_info local
  12.  * - Made integrated registers accessible through standard function calls
  13.  * - Added name field
  14.  * - More sanity checking
  15.  *
  16.  * Chris Beauregard August 9th, 1996
  17.  * - Rewrote /proc/mca
  18.  *
  19.  * Chris Beauregard January 7th, 1997
  20.  * - Added basic NMI-processing
  21.  * - Added more information to mca_info structure
  22.  *
  23.  * David Weinehall October 12th, 1998
  24.  * - Made a lot of cleaning up in the source
  25.  * - Added use of save_flags / restore_flags
  26.  * - Added the 'driver_loaded' flag in MCA_adapter
  27.  * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter
  28.  *
  29.  * David Weinehall March 24th, 1999
  30.  * - Fixed the output of 'Driver Installed' in /proc/mca/pos
  31.  * - Made the Integrated Video & SCSI show up even if they have id 0000
  32.  *
  33.  * Alexander Viro November 9th, 1999
  34.  * - Switched to regular procfs methods
  35.  *
  36.  * Alfred Arnold & David Weinehall August 23rd, 2000
  37.  * - Added support for Planar POS-registers
  38.  */
  39. #include <linux/module.h>
  40. #include <linux/types.h>
  41. #include <linux/errno.h>
  42. #include <linux/kernel.h>
  43. #include <linux/mca.h>
  44. #include <asm/system.h>
  45. #include <asm/io.h>
  46. #include <linux/proc_fs.h>
  47. #include <linux/mman.h>
  48. #include <linux/config.h>
  49. #include <linux/mm.h>
  50. #include <linux/pagemap.h>
  51. #include <linux/ioport.h>
  52. #include <asm/uaccess.h>
  53. #include <linux/init.h>
  54. /* This structure holds MCA information. Each (plug-in) adapter has
  55.  * eight POS registers. Then the machine may have integrated video and
  56.  * SCSI subsystems, which also have eight POS registers.
  57.  * Finally, the motherboard (planar) has got POS-registers.
  58.  * Other miscellaneous information follows.
  59.  */
  60. typedef enum {
  61. MCA_ADAPTER_NORMAL = 0,
  62. MCA_ADAPTER_NONE = 1,
  63. MCA_ADAPTER_DISABLED = 2,
  64. MCA_ADAPTER_ERROR = 3
  65. } MCA_AdapterStatus;
  66. struct MCA_adapter {
  67. MCA_AdapterStatus status; /* is there a valid adapter? */
  68. int id; /* adapter id value */
  69. unsigned char pos[8]; /* POS registers */
  70. int driver_loaded; /* is there a driver installed? */
  71. /* 0 - No, 1 - Yes */
  72. char name[48]; /* adapter-name provided by driver */
  73. char procname[8]; /* name of /proc/mca file */
  74. MCA_ProcFn procfn; /* /proc info callback */
  75. void* dev; /* device/context info for callback */
  76. };
  77. struct MCA_info {
  78. /* one for each of the 8 possible slots, plus one for integrated SCSI
  79.  * and one for integrated video.
  80.  */
  81. struct MCA_adapter slot[MCA_NUMADAPTERS];
  82. /* two potential addresses for integrated SCSI adapter - this will
  83.  * track which one we think it is.
  84.  */
  85. unsigned char which_scsi;
  86. };
  87. /* The mca_info structure pointer. If MCA bus is present, the function
  88.  * mca_probe() is invoked. The function puts motherboard, then all
  89.  * adapters into setup mode, allocates and fills an MCA_info structure,
  90.  * and points this pointer to the structure. Otherwise the pointer
  91.  * is set to zero.
  92.  */
  93. static struct MCA_info* mca_info = NULL;
  94. /* MCA registers */
  95. #define MCA_MOTHERBOARD_SETUP_REG 0x94
  96. #define MCA_ADAPTER_SETUP_REG 0x96
  97. #define MCA_POS_REG(n) (0x100+(n))
  98. #define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
  99. /*--------------------------------------------------------------------*/
  100. #ifdef CONFIG_PROC_FS
  101. static void mca_do_proc_init(void);
  102. #endif
  103. /*--------------------------------------------------------------------*/
  104. /* Build the status info for the adapter */
  105. static void mca_configure_adapter_status(int slot) {
  106. mca_info->slot[slot].status = MCA_ADAPTER_NONE;
  107. mca_info->slot[slot].id = mca_info->slot[slot].pos[0]
  108. + (mca_info->slot[slot].pos[1] << 8);
  109. if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) {
  110. /* id = 0x0000 usually indicates hardware failure,
  111.  * however, ZP Gu (zpg@castle.net> reports that his 9556
  112.  * has 0x0000 as id and everything still works. There
  113.  * also seem to be an adapter with id = 0x0000; the
  114.  * NCR Parallel Bus Memory Card. Until this is confirmed,
  115.  * however, this code will stay.
  116.  */
  117. mca_info->slot[slot].status = MCA_ADAPTER_ERROR;
  118. return;
  119. } else if(mca_info->slot[slot].id != 0xffff) {
  120. /* 0xffff usually indicates that there's no adapter,
  121.  * however, some integrated adapters may have 0xffff as
  122.  * their id and still be valid. Examples are on-board
  123.  * VGA of the 55sx, the integrated SCSI of the 56 & 57,
  124.  * and possibly also the 95 ULTIMEDIA.
  125.  */
  126. mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
  127. }
  128. if((mca_info->slot[slot].id == 0xffff ||
  129.    mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) {
  130. int j;
  131. for(j = 2; j < 8; j++) {
  132. if(mca_info->slot[slot].pos[j] != 0xff) {
  133. mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
  134. break;
  135. }
  136. }
  137. }
  138. if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) {
  139. /* enabled bit is in POS 2 */
  140. mca_info->slot[slot].status = MCA_ADAPTER_DISABLED;
  141. }
  142. } /* mca_configure_adapter_status */
  143. /*--------------------------------------------------------------------*/
  144. struct resource mca_standard_resources[] = {
  145. { "system control port B (MCA)", 0x60, 0x60 },
  146. { "arbitration (MCA)", 0x90, 0x90 },
  147. { "card Select Feedback (MCA)", 0x91, 0x91 },
  148. { "system Control port A (MCA)", 0x92, 0x92 },
  149. { "system board setup (MCA)", 0x94, 0x94 },
  150. { "POS (MCA)", 0x96, 0x97 },
  151. { "POS (MCA)", 0x100, 0x107 }
  152. };
  153. #define MCA_STANDARD_RESOURCES (sizeof(mca_standard_resources)/sizeof(struct resource))
  154. void __init mca_init(void)
  155. {
  156. unsigned int i, j;
  157. unsigned long flags;
  158. /* WARNING: Be careful when making changes here. Putting an adapter
  159.  * and the motherboard simultaneously into setup mode may result in
  160.  * damage to chips (according to The Indispensible PC Hardware Book
  161.  * by Hans-Peter Messmer). Also, we disable system interrupts (so
  162.  * that we are not disturbed in the middle of this).
  163.  */
  164. /* Make sure the MCA bus is present */
  165. if(!MCA_bus)
  166. return;
  167. printk("Micro Channel bus detected.n");
  168. /* Allocate MCA_info structure (at address divisible by 8) */
  169. mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
  170. if(mca_info == NULL) {
  171. printk("Failed to allocate memory for mca_info!");
  172. return;
  173. }
  174. memset(mca_info, 0, sizeof(struct MCA_info));
  175. save_flags(flags);
  176. cli();
  177. /* Make sure adapter setup is off */
  178. outb_p(0, MCA_ADAPTER_SETUP_REG);
  179. /* Read motherboard POS registers */
  180. outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
  181. mca_info->slot[MCA_MOTHERBOARD].name[0] = 0;
  182. for(j=0; j<8; j++) {
  183. mca_info->slot[MCA_MOTHERBOARD].pos[j] = inb_p(MCA_POS_REG(j));
  184. }
  185. mca_configure_adapter_status(MCA_MOTHERBOARD);
  186. /* Put motherboard into video setup mode, read integrated video
  187.  * POS registers, and turn motherboard setup off.
  188.  */
  189. outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
  190. mca_info->slot[MCA_INTEGVIDEO].name[0] = 0;
  191. for(j=0; j<8; j++) {
  192. mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j));
  193. }
  194. mca_configure_adapter_status(MCA_INTEGVIDEO);
  195. /* Put motherboard into scsi setup mode, read integrated scsi
  196.  * POS registers, and turn motherboard setup off.
  197.  *
  198.  * It seems there are two possible SCSI registers. Martin says that
  199.  * for the 56,57, 0xf7 is the one, but fails on the 76.
  200.  * Alfredo (apena@vnet.ibm.com) says
  201.  * 0xfd works on his machine. We'll try both of them. I figure it's
  202.  * a good bet that only one could be valid at a time. This could
  203.  * screw up though if one is used for something else on the other
  204.  * machine.
  205.  */
  206. outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG);
  207. mca_info->slot[MCA_INTEGSCSI].name[0] = 0;
  208. for(j=0; j<8; j++) {
  209. if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff)
  210. {
  211. /* 0xff all across means no device. 0x00 means
  212.  * something's broken, but a device is probably there.
  213.  * However, if you get 0x00 from a motherboard
  214.  * register it won't matter what we find.  For the
  215.  * record, on the 57SLC, the integrated SCSI
  216.  * adapter has 0xffff for the adapter ID, but
  217.  * nonzero for other registers.
  218.  */
  219. mca_info->which_scsi = 0xf7;
  220. }
  221. }
  222. if(!mca_info->which_scsi) {
  223. /* Didn't find it at 0xf7, try somewhere else... */
  224. mca_info->which_scsi = 0xfd;
  225. outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG);
  226. for(j=0; j<8; j++)
  227. mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j));
  228. }
  229. mca_configure_adapter_status(MCA_INTEGSCSI);
  230. /* Turn off motherboard setup */
  231. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  232. /* Now loop over MCA slots: put each adapter into setup mode, and
  233.  * read its POS registers. Then put adapter setup off.
  234.  */
  235. for(i=0; i<MCA_MAX_SLOT_NR; i++) {
  236. outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
  237. for(j=0; j<8; j++) {
  238. mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j));
  239. }
  240. mca_info->slot[i].name[0] = 0;
  241. mca_info->slot[i].driver_loaded = 0;
  242. mca_configure_adapter_status(i);
  243. }
  244. outb_p(0, MCA_ADAPTER_SETUP_REG);
  245. /* Enable interrupts and return memory start */
  246. restore_flags(flags);
  247. for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
  248. request_resource(&ioport_resource, mca_standard_resources + i);
  249. #ifdef CONFIG_PROC_FS
  250. mca_do_proc_init();
  251. #endif
  252. }
  253. /*--------------------------------------------------------------------*/
  254. static void mca_handle_nmi_slot(int slot, int check_flag)
  255. {
  256. if(slot < MCA_MAX_SLOT_NR) {
  257. printk("NMI: caused by MCA adapter in slot %d (%s)n", slot+1,
  258. mca_info->slot[slot].name);
  259. } else if(slot == MCA_INTEGSCSI) {
  260. printk("NMI: caused by MCA integrated SCSI adapter (%s)n",
  261. mca_info->slot[slot].name);
  262. } else if(slot == MCA_INTEGVIDEO) {
  263. printk("NMI: caused by MCA integrated video adapter (%s)n",
  264. mca_info->slot[slot].name);
  265. } else if(slot == MCA_MOTHERBOARD) {
  266. printk("NMI: caused by motherboard (%s)n",
  267. mca_info->slot[slot].name);
  268. }
  269. /* More info available in POS 6 and 7? */
  270. if(check_flag) {
  271. unsigned char pos6, pos7;
  272. pos6 = mca_read_pos(slot, 6);
  273. pos7 = mca_read_pos(slot, 7);
  274. printk("NMI: POS 6 = 0x%x, POS 7 = 0x%xn", pos6, pos7);
  275. }
  276. } /* mca_handle_nmi_slot */
  277. /*--------------------------------------------------------------------*/
  278. void mca_handle_nmi(void)
  279. {
  280. int i;
  281. unsigned char pos5;
  282. /* First try - scan the various adapters and see if a specific
  283.  * adapter was responsible for the error.
  284.  */
  285. for(i = 0; i < MCA_NUMADAPTERS; i++) {
  286. /* Bit 7 of POS 5 is reset when this adapter has a hardware
  287.  * error. Bit 7 it reset if there's error information
  288.  * available in POS 6 and 7.
  289.  */
  290. pos5 = mca_read_pos(i, 5);
  291. if(!(pos5 & 0x80)) {
  292. mca_handle_nmi_slot(i, !(pos5 & 0x40));
  293. return;
  294. }
  295. }
  296. /* If I recall correctly, there's a whole bunch of other things that
  297.  * we can do to check for NMI problems, but that's all I know about
  298.  * at the moment.
  299.  */
  300. printk("NMI generated from unknown source!n");
  301. } /* mca_handle_nmi */
  302. /*--------------------------------------------------------------------*/
  303. /**
  304.  * mca_find_adapter - scan for adapters
  305.  * @id: MCA identification to search for
  306.  * @start: starting slot
  307.  *
  308.  * Search the MCA configuration for adapters matching the 16bit
  309.  * ID given. The first time it should be called with start as zero
  310.  * and then further calls made passing the return value of the
  311.  * previous call until %MCA_NOTFOUND is returned.
  312.  *
  313.  * Disabled adapters are not reported.
  314.  */
  315. int mca_find_adapter(int id, int start)
  316. {
  317. if(mca_info == NULL || id == 0xffff) {
  318. return MCA_NOTFOUND;
  319. }
  320. for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
  321. /* Not sure about this. There's no point in returning
  322.  * adapters that aren't enabled, since they can't actually
  323.  * be used. However, they might be needed for statistical
  324.  * purposes or something... But if that is the case, the
  325.  * user is free to write a routine that manually iterates
  326.  * through the adapters.
  327.  */
  328. if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) {
  329. continue;
  330. }
  331. if(id == mca_info->slot[start].id) {
  332. return start;
  333. }
  334. }
  335. return MCA_NOTFOUND;
  336. } /* mca_find_adapter() */
  337. EXPORT_SYMBOL(mca_find_adapter);
  338. /*--------------------------------------------------------------------*/
  339. /**
  340.  * mca_find_unused_adapter - scan for unused adapters
  341.  * @id: MCA identification to search for
  342.  * @start: starting slot
  343.  *
  344.  * Search the MCA configuration for adapters matching the 16bit
  345.  * ID given. The first time it should be called with start as zero
  346.  * and then further calls made passing the return value of the
  347.  * previous call until %MCA_NOTFOUND is returned.
  348.  *
  349.  * Adapters that have been claimed by drivers and those that
  350.  * are disabled are not reported. This function thus allows a driver
  351.  * to scan for further cards when some may already be driven.
  352.  */
  353. int mca_find_unused_adapter(int id, int start)
  354. {
  355. if(mca_info == NULL || id == 0xffff) {
  356. return MCA_NOTFOUND;
  357. }
  358. for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
  359. /* not sure about this. There's no point in returning
  360.  * adapters that aren't enabled, since they can't actually
  361.  * be used. However, they might be needed for statistical
  362.  * purposes or something... But if that is the case, the
  363.  * user is free to write a routine that manually iterates
  364.  * through the adapters.
  365.  */
  366. if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED ||
  367.    mca_info->slot[start].driver_loaded) {
  368. continue;
  369. }
  370. if(id == mca_info->slot[start].id) {
  371. return start;
  372. }
  373. }
  374. return MCA_NOTFOUND;
  375. } /* mca_find_unused_adapter() */
  376. EXPORT_SYMBOL(mca_find_unused_adapter);
  377. /*--------------------------------------------------------------------*/
  378. /**
  379.  * mca_read_stored_pos - read POS register from boot data
  380.  * @slot: slot number to read from
  381.  * @reg:  register to read from
  382.  *
  383.  * Fetch a POS value that was stored at boot time by the kernel
  384.  * when it scanned the MCA space. The register value is returned.
  385.  * Missing or invalid registers report 0.
  386.  */
  387. unsigned char mca_read_stored_pos(int slot, int reg)
  388. {
  389. if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
  390. if(reg < 0 || reg >= 8) return 0;
  391. return mca_info->slot[slot].pos[reg];
  392. } /* mca_read_stored_pos() */
  393. EXPORT_SYMBOL(mca_read_stored_pos);
  394. /*--------------------------------------------------------------------*/
  395. /**
  396.  * mca_read_pos - read POS register from card
  397.  * @slot: slot number to read from
  398.  * @reg:  register to read from
  399.  *
  400.  * Fetch a POS value directly from the hardware to obtain the
  401.  * current value. This is much slower than mca_read_stored_pos and
  402.  * may not be invoked from interrupt context. It handles the
  403.  * deep magic required for onboard devices transparently.
  404.  */
  405. unsigned char mca_read_pos(int slot, int reg)
  406. {
  407. unsigned int byte = 0;
  408. unsigned long flags;
  409. if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
  410. if(reg < 0 || reg >= 8) return 0;
  411. save_flags(flags);
  412. cli();
  413. /* Make sure motherboard setup is off */
  414. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  415. /* Read in the appropriate register */
  416. if(slot == MCA_INTEGSCSI && mca_info->which_scsi) {
  417. /* Disable adapter setup, enable motherboard setup */
  418. outb_p(0, MCA_ADAPTER_SETUP_REG);
  419. outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG);
  420. byte = inb_p(MCA_POS_REG(reg));
  421. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  422. } else if(slot == MCA_INTEGVIDEO) {
  423. /* Disable adapter setup, enable motherboard setup */
  424. outb_p(0, MCA_ADAPTER_SETUP_REG);
  425. outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
  426. byte = inb_p(MCA_POS_REG(reg));
  427. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  428. } else if(slot == MCA_MOTHERBOARD) {
  429. /* Disable adapter setup, enable motherboard setup */
  430. outb_p(0, MCA_ADAPTER_SETUP_REG);
  431. outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
  432. byte = inb_p(MCA_POS_REG(reg));
  433. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  434. } else if(slot < MCA_MAX_SLOT_NR) {
  435. /* Make sure motherboard setup is off */
  436. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  437. /* Read the appropriate register */
  438. outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
  439. byte = inb_p(MCA_POS_REG(reg));
  440. outb_p(0, MCA_ADAPTER_SETUP_REG);
  441. }
  442. /* Make sure the stored values are consistent, while we're here */
  443. mca_info->slot[slot].pos[reg] = byte;
  444. restore_flags(flags);
  445. return byte;
  446. } /* mca_read_pos() */
  447. EXPORT_SYMBOL(mca_read_pos);
  448. /*--------------------------------------------------------------------*/
  449. /**
  450.  * mca_write_pos - read POS register from card
  451.  * @slot: slot number to read from
  452.  * @reg:  register to read from
  453.  * @byte: byte to write to the POS registers
  454.  *
  455.  * Store a POS value directly from the hardware. You should not
  456.  * normally need to use this function and should have a very good
  457.  * knowledge of MCA bus before you do so. Doing this wrongly can
  458.  * damage the hardware.
  459.  *
  460.  * This function may not be used from interrupt context.
  461.  *
  462.  * Note that this a technically a Bad Thing, as IBM tech stuff says
  463.  * you should only set POS values through their utilities.
  464.  * However, some devices such as the 3c523 recommend that you write
  465.  * back some data to make sure the configuration is consistent.
  466.  * I'd say that IBM is right, but I like my drivers to work.
  467.  *
  468.  * This function can't do checks to see if multiple devices end up
  469.  * with the same resources, so you might see magic smoke if someone
  470.  * screws up.
  471.  */
  472. void mca_write_pos(int slot, int reg, unsigned char byte)
  473. {
  474. unsigned long flags;
  475. if(slot < 0 || slot >= MCA_MAX_SLOT_NR)
  476. return;
  477. if(reg < 0 || reg >= 8)
  478. return;
  479. if(mca_info == NULL)
  480. return;
  481. save_flags(flags);
  482. cli();
  483. /* Make sure motherboard setup is off */
  484. outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
  485. /* Read in the appropriate register */
  486. outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
  487. outb_p(byte, MCA_POS_REG(reg));
  488. outb_p(0, MCA_ADAPTER_SETUP_REG);
  489. restore_flags(flags);
  490. /* Update the global register list, while we have the byte */
  491. mca_info->slot[slot].pos[reg] = byte;
  492. } /* mca_write_pos() */
  493. EXPORT_SYMBOL(mca_write_pos);
  494. /*--------------------------------------------------------------------*/
  495. /**
  496.  * mca_set_adapter_name - Set the description of the card
  497.  * @slot: slot to name
  498.  * @name: text string for the namen
  499.  *
  500.  * This function sets the name reported via /proc for this
  501.  * adapter slot. This is for user information only. Setting a
  502.  * name deletes any previous name.
  503.  */
  504. void mca_set_adapter_name(int slot, char* name)
  505. {
  506. if(mca_info == NULL) return;
  507. if(slot >= 0 && slot < MCA_NUMADAPTERS) {
  508. if(name != NULL) {
  509. strncpy(mca_info->slot[slot].name, name,
  510. sizeof(mca_info->slot[slot].name)-1);
  511. mca_info->slot[slot].name[
  512. sizeof(mca_info->slot[slot].name)-1] = 0;
  513. } else {
  514. mca_info->slot[slot].name[0] = 0;
  515. }
  516. }
  517. }
  518. EXPORT_SYMBOL(mca_set_adapter_name);
  519. /**
  520.  * mca_set_adapter_procfn - Set the /proc callback
  521.  * @slot: slot to configure
  522.  * @procfn: callback function to call for /proc
  523.  * @dev: device information passed to the callback
  524.  *
  525.  * This sets up an information callback for /proc/mca/slot?.  The
  526.  * function is called with the buffer, slot, and device pointer (or
  527.  * some equally informative context information, or nothing, if you
  528.  * prefer), and is expected to put useful information into the
  529.  * buffer.  The adapter name, ID, and POS registers get printed
  530.  * before this is called though, so don't do it again.
  531.  *
  532.  * This should be called with a %NULL @procfn when a module
  533.  * unregisters, thus preventing kernel crashes and other such
  534.  * nastiness.
  535.  */
  536. void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev)
  537. {
  538. if(mca_info == NULL) return;
  539. if(slot >= 0 && slot < MCA_NUMADAPTERS) {
  540. mca_info->slot[slot].procfn = procfn;
  541. mca_info->slot[slot].dev = dev;
  542. }
  543. }
  544. EXPORT_SYMBOL(mca_set_adapter_procfn);
  545. /**
  546.  * mca_is_adapter_used - check if claimed by driver
  547.  * @slot: slot to check
  548.  *
  549.  * Returns 1 if the slot has been claimed by a driver
  550.  */
  551. int mca_is_adapter_used(int slot)
  552. {
  553. return mca_info->slot[slot].driver_loaded;
  554. }
  555. EXPORT_SYMBOL(mca_is_adapter_used);
  556. /**
  557.  * mca_mark_as_used - claim an MCA device
  558.  * @slot: slot to claim
  559.  * FIXME:  should we make this threadsafe
  560.  *
  561.  * Claim an MCA slot for a device driver. If the
  562.  * slot is already taken the function returns 1,
  563.  * if it is not taken it is claimed and 0 is
  564.  * returned.
  565.  */
  566. int mca_mark_as_used(int slot)
  567. {
  568. if(mca_info->slot[slot].driver_loaded) return 1;
  569. mca_info->slot[slot].driver_loaded = 1;
  570. return 0;
  571. }
  572. EXPORT_SYMBOL(mca_mark_as_used);
  573. /**
  574.  * mca_mark_as_unused - release an MCA device
  575.  * @slot: slot to claim
  576.  *
  577.  * Release the slot for other drives to use.
  578.  */
  579. void mca_mark_as_unused(int slot)
  580. {
  581. mca_info->slot[slot].driver_loaded = 0;
  582. }
  583. EXPORT_SYMBOL(mca_mark_as_unused);
  584. /**
  585.  * mca_get_adapter_name - get the adapter description
  586.  * @slot: slot to query
  587.  *
  588.  * Return the adapter description if set. If it has not been
  589.  * set or the slot is out range then return NULL.
  590.  */
  591. char *mca_get_adapter_name(int slot)
  592. {
  593. if(mca_info == NULL) return 0;
  594. if(slot >= 0 && slot < MCA_NUMADAPTERS) {
  595. return mca_info->slot[slot].name;
  596. }
  597. return 0;
  598. }
  599. EXPORT_SYMBOL(mca_get_adapter_name);
  600. /**
  601.  * mca_isadapter - check if the slot holds an adapter
  602.  * @slot: slot to query
  603.  *
  604.  * Returns zero if the slot does not hold an adapter, non zero if
  605.  * it does.
  606.  */
  607. int mca_isadapter(int slot)
  608. {
  609. if(mca_info == NULL) return 0;
  610. if(slot >= 0 && slot < MCA_NUMADAPTERS) {
  611. return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL)
  612. || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED));
  613. }
  614. return 0;
  615. }
  616. EXPORT_SYMBOL(mca_isadapter);
  617. /**
  618.  * mca_isadapter - check if the slot holds an adapter
  619.  * @slot: slot to query
  620.  *
  621.  * Returns a non zero value if the slot holds an enabled adapter
  622.  * and zero for any other case.
  623.  */
  624. int mca_isenabled(int slot)
  625. {
  626. if(mca_info == NULL) return 0;
  627. if(slot >= 0 && slot < MCA_NUMADAPTERS) {
  628. return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL);
  629. }
  630. return 0;
  631. }
  632. EXPORT_SYMBOL(mca_isenabled);
  633. /*--------------------------------------------------------------------*/
  634. #ifdef CONFIG_PROC_FS
  635. int get_mca_info(char *page, char **start, off_t off,
  636.  int count, int *eof, void *data)
  637. {
  638. int i, j, len = 0;
  639. if(MCA_bus && mca_info != NULL) {
  640. /* Format POS registers of eight MCA slots */
  641. for(i=0; i<MCA_MAX_SLOT_NR; i++) {
  642. len += sprintf(page+len, "Slot %d: ", i+1);
  643. for(j=0; j<8; j++)
  644. len += sprintf(page+len, "%02x ", mca_info->slot[i].pos[j]);
  645. len += sprintf(page+len, " %sn", mca_info->slot[i].name);
  646. }
  647. /* Format POS registers of integrated video subsystem */
  648. len += sprintf(page+len, "Video : ");
  649. for(j=0; j<8; j++)
  650. len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]);
  651. len += sprintf(page+len, " %sn", mca_info->slot[MCA_INTEGVIDEO].name);
  652. /* Format POS registers of integrated SCSI subsystem */
  653. len += sprintf(page+len, "SCSI  : ");
  654. for(j=0; j<8; j++)
  655. len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]);
  656. len += sprintf(page+len, " %sn", mca_info->slot[MCA_INTEGSCSI].name);
  657. /* Format POS registers of motherboard */
  658. len += sprintf(page+len, "Planar: ");
  659. for(j=0; j<8; j++)
  660. len += sprintf(page+len, "%02x ", mca_info->slot[MCA_MOTHERBOARD].pos[j]);
  661. len += sprintf(page+len, " %sn", mca_info->slot[MCA_MOTHERBOARD].name);
  662. } else {
  663. /* Leave it empty if MCA not detected - this should *never*
  664.  * happen!
  665.  */
  666. }
  667. if (len <= off+count) *eof = 1;
  668. *start = page + off;
  669. len -= off;
  670. if (len>count) len = count;
  671. if (len<0) len = 0;
  672. return len;
  673. }
  674. /*--------------------------------------------------------------------*/
  675. static int mca_default_procfn(char* buf, struct MCA_adapter *p)
  676. {
  677. int len = 0, i;
  678. int slot = p - mca_info->slot;
  679. /* Print out the basic information */
  680. if(slot < MCA_MAX_SLOT_NR) {
  681. len += sprintf(buf+len, "Slot: %dn", slot+1);
  682. } else if(slot == MCA_INTEGSCSI) {
  683. len += sprintf(buf+len, "Integrated SCSI Adaptern");
  684. } else if(slot == MCA_INTEGVIDEO) {
  685. len += sprintf(buf+len, "Integrated Video Adaptern");
  686. } else if(slot == MCA_MOTHERBOARD) {
  687. len += sprintf(buf+len, "Motherboardn");
  688. }
  689. if(p->name[0]) {
  690. /* Drivers might register a name without /proc handler... */
  691. len += sprintf(buf+len, "Adapter Name: %sn",
  692. p->name);
  693. } else {
  694. len += sprintf(buf+len, "Adapter Name: Unknownn");
  695. }
  696. len += sprintf(buf+len, "Id: %02x%02xn",
  697. p->pos[1], p->pos[0]);
  698. len += sprintf(buf+len, "Enabled: %snPOS: ",
  699. mca_isenabled(slot) ? "Yes" : "No");
  700. for(i=0; i<8; i++) {
  701. len += sprintf(buf+len, "%02x ", p->pos[i]);
  702. }
  703. len += sprintf(buf+len, "nDriver Installed: %s",
  704. mca_is_adapter_used(slot) ? "Yes" : "No");
  705. buf[len++] = 'n';
  706. buf[len] = 0;
  707. return len;
  708. } /* mca_default_procfn() */
  709. static int get_mca_machine_info(char* page, char **start, off_t off,
  710.  int count, int *eof, void *data)
  711. {
  712. int len = 0;
  713. len += sprintf(page+len, "Model Id: 0x%xn", machine_id);
  714. len += sprintf(page+len, "Submodel Id: 0x%xn", machine_submodel_id);
  715. len += sprintf(page+len, "BIOS Revision: 0x%xn", BIOS_revision);
  716. if (len <= off+count) *eof = 1;
  717. *start = page + off;
  718. len -= off;
  719. if (len>count) len = count;
  720. if (len<0) len = 0;
  721. return len;
  722. }
  723. static int mca_read_proc(char *page, char **start, off_t off,
  724.  int count, int *eof, void *data)
  725. {
  726. struct MCA_adapter *p = (struct MCA_adapter *)data;
  727. int len = 0;
  728. /* Get the standard info */
  729. len = mca_default_procfn(page, p);
  730. /* Do any device-specific processing, if there is any */
  731. if(p->procfn) {
  732. len += p->procfn(page+len, p-mca_info->slot, p->dev);
  733. }
  734. if (len <= off+count) *eof = 1;
  735. *start = page + off;
  736. len -= off;
  737. if (len>count) len = count;
  738. if (len<0) len = 0;
  739. return len;
  740. } /* mca_read_proc() */
  741. /*--------------------------------------------------------------------*/
  742. void __init mca_do_proc_init(void)
  743. {
  744. int i;
  745. struct proc_dir_entry *proc_mca;
  746. struct proc_dir_entry* node = NULL;
  747. struct MCA_adapter *p;
  748. if(mca_info == NULL) return; /* Should never happen */
  749. proc_mca = proc_mkdir("mca", &proc_root);
  750. create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
  751. create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
  752. /* Initialize /proc/mca entries for existing adapters */
  753. for(i = 0; i < MCA_NUMADAPTERS; i++) {
  754. p = &mca_info->slot[i];
  755. p->procfn = 0;
  756. if(i < MCA_MAX_SLOT_NR) sprintf(p->procname,"slot%d", i+1);
  757. else if(i == MCA_INTEGVIDEO) sprintf(p->procname,"video");
  758. else if(i == MCA_INTEGSCSI) sprintf(p->procname,"scsi");
  759. else if(i == MCA_MOTHERBOARD) sprintf(p->procname,"planar");
  760. if(!mca_isadapter(i)) continue;
  761. node = create_proc_read_entry(p->procname, 0, proc_mca,
  762. mca_read_proc, (void *)p);
  763. if(node == NULL) {
  764. printk("Failed to allocate memory for MCA proc-entries!");
  765. return;
  766. }
  767. }
  768. } /* mca_do_proc_init() */
  769. #endif