superio.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*      National Semiconductor NS87560UBD Super I/O controller used in
  2.  *      HP [BCJ]x000 workstations.
  3.  *
  4.  *      This chip is a horrid piece of engineering, and National
  5.  *      denies any knowledge of its existence. Thus no datasheet is
  6.  *      available off www.national.com. 
  7.  *
  8.  * (C) Copyright 2000 Linuxcare, Inc.
  9.  *  (C) Copyright 2000 Linuxcare Canada, Inc.
  10.  * (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
  11.  *  (C) Copyright 2000 Alex deVries <alex@linuxcare.com>
  12.  *      (C) Copyright 2001 John Marvin <jsm@fc.hp.com>
  13.  *
  14.  * This program is free software; you can redistribute it and/or
  15.  * modify it under the terms of the GNU General Public License as
  16.  * published by the Free Software Foundation; either version 2 of
  17.  * the License, or (at your option) any later version.  
  18.  *
  19.  * The initial version of this is by Martin Peterson.  Alex deVries
  20.  * has spent a bit of time trying to coax it into working.
  21.  *
  22.  *      Major changes to get basic interrupt infrastructure working to
  23.  *      hopefully be able to support all SuperIO devices. Currently
  24.  *      works with serial. -- John Marvin <jsm@fc.hp.com>
  25.  */
  26. /* NOTES:
  27.  * 
  28.  * Function 0 is an IDE controller. It is identical to a PC87415 IDE
  29.  * controller (and identifies itself as such).
  30.  *
  31.  * Function 1 is a "Legacy I/O" controller. Under this function is a
  32.  * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled
  33.  * all the functionality in hardware, but the following is available:
  34.  *
  35.  *      Two 16550A compatible serial controllers
  36.  *      An IEEE 1284 compatible parallel port
  37.  *      A floppy disk controller
  38.  *
  39.  * Function 2 is a USB controller.
  40.  *
  41.  * We must be incredibly careful during initialization.  Since all
  42.  * interrupts are routed through function 1 (which is not allowed by
  43.  * the PCI spec), we need to program the PICs on the legacy I/O port
  44.  * *before* we attempt to set up IDE and USB.  @#$!&
  45.  *
  46.  * According to HP, devices are only enabled by firmware if they have
  47.  * a physical device connected.
  48.  *
  49.  * Configuration register bits:
  50.  *     0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92
  51.  *     0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM
  52.  *
  53.  */
  54. #include <linux/errno.h>
  55. #include <linux/init.h>
  56. #include <linux/module.h>
  57. #include <linux/types.h>
  58. #include <linux/interrupt.h>
  59. #include <linux/ioport.h>
  60. #include <linux/serial.h>
  61. #include <linux/pci.h>
  62. #include <linux/ioport.h>
  63. #include <linux/parport.h>
  64. #include <linux/parport_pc.h>
  65. #include <linux/serial_reg.h>
  66. #include <asm/io.h>
  67. #include <asm/hardware.h>
  68. #include <asm/gsc.h>
  69. #include <asm/irq.h>
  70. #include <asm/superio.h>
  71. static struct superio_device sio_dev = {
  72. iosapic_irq: -1
  73. };
  74. #undef DEBUG_INIT
  75. void
  76. superio_inform_irq(int irq)
  77. {
  78.     if (sio_dev.iosapic_irq != -1) {
  79. printk(KERN_ERR "SuperIO: superio_inform_irq called twice! (more than one SuperIO?)n");
  80. BUG();
  81. return;
  82.     }
  83.     sio_dev.iosapic_irq = irq;
  84. }
  85. static void
  86. superio_interrupt(int irq, void *devp, struct pt_regs *regs)
  87. {
  88. struct superio_device *sio = (struct superio_device *)devp;
  89. u8 results;
  90. u8 local_irq;
  91. /* Poll the 8259 to see if there's an interrupt. */
  92. outb (OCW3_POLL,IC_PIC1+0);
  93. results = inb(IC_PIC1+0);
  94. if ((results & 0x80) == 0) {
  95. #ifndef CONFIG_SMP
  96. /* HACK: need to investigate why this happens if SMP enabled */
  97. BUG(); /* This shouldn't happen */
  98. #endif
  99. return;
  100. }
  101. /* Check to see which device is interrupting */
  102. local_irq = results & 0x0f;
  103. if (local_irq == 2 || local_irq > 7) {
  104. printk(KERN_ERR "SuperIO: slave interrupted!n");
  105. BUG();
  106. return;
  107. }
  108. if (local_irq == 7) {
  109. /* Could be spurious. Check in service bits */
  110. outb(OCW3_ISR,IC_PIC1+0);
  111. results = inb(IC_PIC1+0);
  112. if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */
  113. printk(KERN_WARNING "SuperIO: spurious interrupt!n");
  114. return;
  115. }
  116. }
  117. /* Call the appropriate device's interrupt */
  118. do_irq(&sio->irq_region->action[local_irq],
  119. sio->irq_region->data.irqbase + local_irq,
  120. regs);
  121. /* set EOI */
  122. outb((OCW2_SEOI|local_irq),IC_PIC1 + 0);
  123. return;
  124. }
  125. /* Initialize Super I/O device */
  126. static void __devinit
  127. superio_init(struct superio_device *sio)
  128. {
  129. struct pci_dev *pdev = sio->lio_pdev;
  130. u16 word;
  131. u8  i;
  132. if (!pdev || sio->iosapic_irq == -1) {
  133. printk(KERN_ERR "All SuperIO functions not found!n");
  134. BUG();
  135. return;
  136. }
  137. printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) n",
  138. pdev->slot_name,sio->iosapic_irq);
  139. /* Find our I/O devices */
  140. pci_read_config_word (pdev, SIO_SP1BAR, &sio->sp1_base);
  141. sio->sp1_base &= ~1;
  142. printk (KERN_INFO "SuperIO: Serial port 1 at 0x%xn", sio->sp1_base);
  143. pci_read_config_word (pdev, SIO_SP2BAR, &sio->sp2_base);
  144. sio->sp2_base &= ~1;
  145. printk (KERN_INFO "SuperIO: Serial port 2 at 0x%xn", sio->sp2_base);
  146. pci_read_config_word (pdev, SIO_PPBAR, &sio->pp_base);
  147. sio->pp_base &= ~1;
  148. printk (KERN_INFO "SuperIO: Parallel port at 0x%xn", sio->pp_base);
  149. pci_read_config_word (pdev, SIO_FDCBAR, &sio->fdc_base);
  150. sio->fdc_base &= ~1;
  151. printk (KERN_INFO "SuperIO: Floppy controller at 0x%xn", sio->fdc_base);
  152. pci_read_config_word (pdev, SIO_ACPIBAR, &sio->acpi_base);
  153. sio->acpi_base &= ~1;
  154. printk (KERN_INFO "SuperIO: ACPI at 0x%xn", sio->acpi_base);
  155. request_region (IC_PIC1, 0x1f, "pic1");
  156. request_region (IC_PIC2, 0x1f, "pic2");
  157. request_region (sio->acpi_base, 0x1f, "acpi");
  158. /* Enable the legacy I/O function */
  159.         pci_read_config_word (pdev, PCI_COMMAND, &word);
  160. word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
  161. pci_write_config_word (pdev, PCI_COMMAND, word);
  162. pci_set_master (pdev);
  163. /* Next project is programming the onboard interrupt
  164.  * controllers.  PDC hasn't done this for us, since it's using
  165.  * polled I/O.
  166.  */
  167. /* Set PIC interrupts to edge triggered */
  168. pci_write_config_byte (pdev, TRIGGER_1, 0x0);
  169. pci_write_config_byte (pdev, TRIGGER_2, 0x0);
  170. /* Disable all interrupt routing */
  171. for (i = IR_LOW ; i < IR_HIGH ; i++)
  172. pci_write_config_byte (pdev, i, 0x0);
  173. /* PIC1 Initialization Command Word register programming */
  174. outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */
  175. outb (0x00,IC_PIC1+1); /* ICW2: N/A */
  176. outb (0x04,IC_PIC1+1); /* ICW3: Cascade */
  177. outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */
  178. /* PIC1 Program Operational Control Words */
  179. outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */
  180. outb (0xc2,IC_PIC1+0);  /* OCW2: priority (3-7,0-2) */
  181. /* PIC2 Initialization Command Word register programming */
  182. outb (0x11,IC_PIC2+0); /* ICW1: ICW4 write req | ICW1 */
  183. outb (0x00,IC_PIC2+1); /* ICW2: N/A */
  184. outb (0x02,IC_PIC2+1); /* ICW3: Slave ID code */
  185. outb (0x01,IC_PIC2+1); /* ICW4: x86 mode */
  186. /* Program Operational Control Words */
  187. outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */
  188. outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */
  189. /* Write master mask reg */
  190. outb (0xff,IC_PIC1+1);
  191. /* Set up interrupt routing */
  192. pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */
  193. pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */
  194. pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */
  195. pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE1 on IRQ7 */
  196. /* Set USB and IDE to level triggered interrupts, rest to edge */
  197. pci_write_config_byte (pdev, TRIGGER_1, 0x82); /* IRQ 1 and 7 */
  198. /* Setup USB power regulation */
  199. outb(1, sio->acpi_base + USB_REG_CR);
  200. if (inb(sio->acpi_base + USB_REG_CR) & 1)
  201. printk(KERN_INFO "SuperIO: USB regulator enabledn");
  202. else
  203. printk(KERN_ERR "USB regulator not initialized!n");
  204. pci_enable_device(pdev);
  205. if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT,
  206. "SuperIO",(void *)sio)) {
  207. printk(KERN_ERR "SuperIO: could not get irqn");
  208. BUG();
  209. return;
  210. }
  211. sio->iosapic_irq_enabled = 1;
  212. }
  213. static void
  214. superio_disable_irq(void *dev, int local_irq)
  215. {
  216. u8 r8;
  217. if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
  218.     printk(KERN_ERR "SuperIO: Illegal irq number.n");
  219.     BUG();
  220.     return;
  221. }
  222. /* Mask interrupt */
  223. r8 = inb(IC_PIC1+1);
  224. r8 |= (1 << local_irq);
  225. outb (r8,IC_PIC1+1);
  226. }
  227. static void
  228. superio_enable_irq(void *dev, int local_irq)
  229. {
  230. struct superio_device *sio = (struct superio_device *)dev;
  231. u8 r8;
  232. if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
  233.     printk(KERN_ERR "SuperIO: Illegal irq number.n");
  234.     BUG();
  235.     return;
  236. }
  237. /*
  238.  * It's possible that we haven't initialized the legacy IO
  239.  * function yet. If not, do it now.
  240.  */
  241. if (!sio->iosapic_irq_enabled)
  242. superio_init(sio);
  243. /* Unmask interrupt */
  244. r8 = inb(IC_PIC1+1);
  245. r8 &= ~(1 << local_irq);
  246. outb (r8,IC_PIC1+1);
  247. }
  248. static void
  249. superio_mask_irq(void *dev, int local_irq)
  250. {
  251. BUG();
  252. }
  253. static void
  254. superio_unmask_irq(void *dev, int local_irq)
  255. {
  256. BUG();
  257. }
  258. static struct irq_region_ops superio_irq_ops = {
  259. disable_irq: superio_disable_irq,
  260. enable_irq: superio_enable_irq,
  261. mask_irq: superio_mask_irq,
  262. unmask_irq: superio_unmask_irq
  263. };
  264. #ifdef DEBUG_INIT
  265. static unsigned short expected_device[3] = {
  266. PCI_DEVICE_ID_NS_87415,
  267. PCI_DEVICE_ID_NS_87560_LIO,
  268. PCI_DEVICE_ID_NS_87560_USB
  269. };
  270. #endif
  271. int superio_fixup_irq(struct pci_dev *pcidev)
  272. {
  273. int local_irq;
  274. #ifdef DEBUG_INIT
  275. int fn;
  276. fn = PCI_FUNC(pcidev->devfn);
  277. /* Verify the function number matches the expected device id. */
  278. if (expected_device[fn] != pcidev->device) {
  279. BUG();
  280. return -1;
  281. }
  282. printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pn",
  283. pcidev->slot_name,
  284. pcidev->vendor, pcidev->device,
  285. __builtin_return_address(0));
  286. #endif
  287. if (!sio_dev.irq_region) {
  288. /* Allocate an irq region for SuperIO devices */
  289. sio_dev.irq_region = alloc_irq_region(SUPERIO_NIRQS,
  290. &superio_irq_ops,
  291. "SuperIO", (void *) &sio_dev);
  292. if (!sio_dev.irq_region) {
  293. printk(KERN_WARNING "SuperIO: alloc_irq_region failedn");
  294. return -1;
  295. }
  296. }
  297. /*
  298.  * We don't allocate a SuperIO irq for the legacy IO function,
  299.  * since it is a "bridge". Instead, we will allocate irq's for
  300.  * each legacy device as they are initialized.
  301.  */
  302. switch(pcidev->device) {
  303. case PCI_DEVICE_ID_NS_87415: /* Function 0 */
  304. local_irq = IDE_IRQ;
  305. break;
  306. case PCI_DEVICE_ID_NS_87560_LIO: /* Function 1 */
  307. sio_dev.lio_pdev = pcidev; /* save for later initialization */
  308. return -1;
  309. case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */
  310. local_irq = USB_IRQ;
  311. break;
  312. default:
  313. local_irq = -1;
  314. BUG();
  315. break;
  316. }
  317. return(sio_dev.irq_region->data.irqbase + local_irq);
  318. }
  319. void __devinit
  320. superio_serial_init(void)
  321. {
  322. #ifdef CONFIG_SERIAL
  323. struct serial_struct *serial;
  324. int retval;
  325. if (!sio_dev.irq_region)
  326. return; /* superio not present */
  327. if (!sio_dev.iosapic_irq_enabled)
  328. superio_init(&sio_dev);
  329. serial = kmalloc(2 * sizeof (struct serial_struct), GFP_KERNEL);
  330. if (!serial) {
  331. printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.n");
  332. return;
  333. }
  334. memset(serial, 0, 2 * sizeof (struct serial_struct));
  335. serial->type = PORT_16550A;
  336. serial->line = 0;
  337. serial->port = sio_dev.sp1_base;
  338. serial->port_high = 0;
  339. serial->irq = sio_dev.irq_region->data.irqbase + SP1_IRQ;
  340. serial->io_type = SERIAL_IO_PORT;
  341. serial->flags = 0;
  342. serial->xmit_fifo_size = 16;
  343. serial->custom_divisor = 0;
  344. serial->baud_base = 115200;
  345. retval = register_serial(serial);
  346. if (retval < 0) {
  347. printk(KERN_WARNING "SuperIO: Register Serial #0 failed.n");
  348. kfree (serial);
  349. return;
  350. }
  351. serial++;
  352. serial->type = PORT_16550A;
  353. serial->line = 1;
  354. serial->port = sio_dev.sp2_base;
  355. serial->port_high = 0;
  356. serial->irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
  357. serial->io_type = SERIAL_IO_PORT;
  358. serial->flags = 0;
  359. serial->xmit_fifo_size = 16;
  360. serial->custom_divisor = 0;
  361. serial->baud_base = 115200;
  362. retval = register_serial(serial);
  363. if (retval < 0)
  364. printk(KERN_WARNING "SuperIO: Register Serial #1 failed.n");
  365. #endif /* CONFIG_SERIAL */
  366. }
  367. EXPORT_SYMBOL(superio_serial_init);
  368. #ifdef CONFIG_PARPORT_PC
  369. void __devinit
  370. superio_parport_init(void)
  371. {
  372. if (!sio_dev.irq_region)
  373. return; /* superio not present */
  374. if (!sio_dev.iosapic_irq_enabled)
  375. superio_init(&sio_dev);
  376. if (!parport_pc_probe_port(sio_dev.pp_base, 
  377. 0 /*base_hi*/,
  378. sio_dev.irq_region->data.irqbase + PAR_IRQ, 
  379. PARPORT_DMA_NONE /* dma */,
  380. NULL /*struct pci_dev* */))
  381. printk(KERN_WARNING "SuperIO: Probing parallel port failed.n");
  382. }
  383. EXPORT_SYMBOL(superio_parport_init);
  384. #endif /* CONFIG_PARPORT_PC */
  385. int
  386. superio_get_ide_irq(void)
  387. {
  388. if (sio_dev.irq_region)
  389. return sio_dev.irq_region->data.irqbase + IDE_IRQ;
  390. else
  391. return 0;
  392. }
  393. EXPORT_SYMBOL(superio_get_ide_irq);
  394. static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
  395. {
  396. #ifdef DEBUG_INIT
  397. printk("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%xn",
  398. dev->slot_name,
  399. dev->vendor, dev->device,
  400. dev->subsystem_vendor, dev->subsystem_device,
  401. dev->class);
  402. /*
  403. ** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
  404. ** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
  405. ** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
  406. */
  407. #endif
  408. /* superio_fixup_irq(dev); */
  409. if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {
  410. #ifdef CONFIG_PARPORT_PC
  411. superio_parport_init();
  412. #endif
  413. /* Don't call superio_serial_init() - see rs_init() */
  414. /* REVISIT : superio_fdc_init() ? */
  415. return 0;
  416. }
  417. else
  418. {
  419. /* don't claim this device; let whatever either driver
  420.  * do it 
  421.  */ 
  422. return -1;
  423. }
  424. }
  425. static struct pci_device_id superio_tbl[] __devinitdata = {
  426. { PCI_VENDOR_ID_NS, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
  427. { 0, }
  428. };
  429. static struct pci_driver superio_driver = {
  430. name: "SuperIO",
  431. id_table: superio_tbl,
  432. probe: superio_probe,
  433. };
  434. static int __init superio_modinit(void)
  435. {
  436. return pci_module_init(&superio_driver);
  437. }
  438. static void __exit superio_exit(void)
  439. {
  440. pci_unregister_driver(&superio_driver);
  441. }
  442. module_init(superio_modinit);
  443. module_exit(superio_exit);