root/lm-sensors/trunk/prog/hotplug/p4b_smbus.c @ 1331

Revision 1331, 6.5 KB (checked in by mds, 11 years ago)

#ifdef around MODULE_LICENSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * p4b_smbus.c
3 *
4 * Initialize the I801SMBus device on ASUS P4B Bords
5 */
6/*
7    Copyright (c) 2002 Ilja Rauhut <IljaRauhut@web.de>,
8
9    Based on the m7101.c hotplug example by:
10
11    Copyright (c) 2000 Burkhard Kohl <buk@buks.ipn.de>,
12    Frank Bauer <frank.bauer@nikocity.de>, and
13    Mark D. Studebaker <mdsxyz123@yahoo.com>
14
15    This program is free software; you can redistribute it and/or modify
16    it under the terms of the GNU General Public License as published by
17    the Free Software Foundation; either version 2 of the License, or
18    (at your option) any later version.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23    GNU General Public License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29/* CHANGES:
30 * February 13,2002 IR First Version
31 *
32 * This code is absolutely experimental - use it at your own
33 * risk.
34 *
35 * Warning, this module will work only with 2.4.x kernels.
36 * If it works with earlier kernels then it is by luck.
37 *
38 * Warning, this module does not work with egcs < 2.95.2, use
39 * gcc > 2.7.2 or egcs >= 2.95.2.
40 *
41 */
42
43
44#ifdef P4Bsmbus_DEBUG
45#define DBG(x...) printk(x)
46#else
47#define DBG(x...)
48#endif
49
50#ifndef TRUE
51#define TRUE 1
52#define FALSE !TRUE
53#endif
54
55#include <linux/config.h>
56#ifndef CONFIG_HOTPLUG
57#error ERROR - You must have 'Support for hot-pluggable devices' enabled in your kernel (under 'general setup')!!
58#endif
59
60/* Deal with CONFIG_MODVERSIONS */
61#ifdef CONFIG_MODVERSIONS
62#define MODVERSIONS
63#include <linux/modversions.h>
64#endif
65
66#include <linux/module.h>
67#include <linux/kernel.h>
68#include <linux/pci.h>
69#include <linux/stddef.h>
70#include <linux/ioport.h>
71#include <linux/errno.h>
72#include <linux/slab.h>
73#include <linux/interrupt.h>
74#include <asm/types.h>
75
76#include <linux/sched.h>
77#include <linux/signal.h>
78#include <asm/irq.h>
79
80/*
81rmm    from lm_sensors-2.3.3:
82 */
83
84#define SMB_IO_SIZE  0xF
85#define SMB_BASE 0x20
86
87/* status, used to indicate that io space needs to be freed */
88static struct pci_dev *i801smbus = NULL;
89static int i801smbus_inserted = FALSE;
90extern void cleanup_module();
91 
92static rwlock_t i801smbus_lock = RW_LOCK_UNLOCKED;
93static unsigned long i801smbus_lock_flags = 0;
94
95/*
96 * Checks whether SMBus is enabled and turns it on in case they are not.
97 * It's done by clearing Bit 8 and 4 in i801 config space F2h, PCI-Device 0x8086:0x2440
98 */
99static int
100i801smbus_enable(struct pci_dev *dev){
101        u16  val   = 0;
102
103        pci_read_config_word(dev, 0xF2, &val);
104        DBG("i801smbus: i801smbus config byte reading 0x%X.\n", val);
105        if (val & 0x008) {
106                pci_write_config_word(dev, 0xF2, val & 0x77);
107                pci_read_config_word(dev, 0xF2, &val);
108                if(val & 0x008) 
109                  {
110                    DBG("i801smbus: i801smbus config byte locked:-(\n");
111                    return -EIO;
112                  }
113                else
114                  printk("SMBus activated in LPC!\n");
115        }
116        return 0;
117
118}
119
120/*
121 * Builds the basic pci_dev for the i801smbus
122 */
123static int i801smbus_build(struct pci_dev **i801smbus, struct pci_bus *bus) 
124{
125        u32 devfn;
126        u16 id = 0;
127        u16 vid = 0;
128        int ret;
129
130        DBG("i801smbus: requesting kernel space for the i801smbus entry.\n");
131        *i801smbus = kmalloc(sizeof(**i801smbus), GFP_ATOMIC);
132        if(NULL == *i801smbus) {
133                printk("i801smbus: out of memory.\n");
134                return -ENOMEM;
135        }
136
137        /* minimally fill in structure for search */
138        /* The device should be on the same bus as the i801. */
139        memset(*i801smbus, 0, sizeof(**i801smbus));
140        (*i801smbus)->bus    = bus;
141        (*i801smbus)->sysdata = bus->sysdata;
142        (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL;
143
144        DBG("i801smbus: now looking for i801smbus.\n");
145        for  (id = 0, devfn = 0; devfn < 0xFF; devfn++) {
146                (*i801smbus)->devfn = devfn;
147                ret = pci_read_config_word(*i801smbus, PCI_DEVICE_ID, &id);
148                if (ret == 0 && 0x2443 == id) {
149                        pci_read_config_word(*i801smbus, PCI_VENDOR_ID, &vid);
150                        if(vid == 0x8086)
151                                break;
152                }
153        }
154        if (0x2443 != id) {     
155                DBG("i801smbus: i801smbus not found although i801 present - strange.\n");
156                return -EACCES;
157        } else {
158                DBG("i801smbus: i801smbus found and enabled. Devfn: 0x%X.\n", devfn);
159        }
160        /* We now have the devfn and bus of the i801smbus device.
161         * let's put the rest of the device data together.
162         */
163
164        (*i801smbus)->vendor = 0x8086;
165        (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL;
166        (*i801smbus)->device = 0x2443;
167 
168        return(pci_setup_device(*i801smbus));
169}
170
171
172
173
174/* Initialize the module */
175int init_module(void)
176{
177        struct pci_bus *bus = NULL;
178        struct pci_dev *dev = NULL;
179        int ret = 0;
180
181        DBG("i801smbus: init_module().\n");
182
183        /* Are we on a PCI-Board? */
184        if (!pci_present()) {
185                printk("i801smbus: No PCI bus found - sorry.\n");
186                return -ENODEV;
187        }
188
189        /* We want to be sure that the i801smbus is not present yet. */
190        dev = pci_find_device(0x8086,0x2443, NULL);
191
192        if (dev) 
193          {
194            printk("i801smbus: SMBus already actve\n");
195            return -EPERM;
196          }
197       
198        /* Are we operating a i801 chipset */
199        dev = pci_find_device(0x8086,0x2440, NULL);
200        if (NULL == dev) 
201          {
202            printk("INTEL ICH2 type 82801BA not found.\n");
203            return -ENODEV ;
204          }
205        /* we need the bus pointer later */
206        bus = dev->bus;
207
208
209        if ( (ret = i801smbus_enable(dev)) ) 
210          {
211            printk("i801smbus: Unable to turn on i801smbus device - sorry!\n");
212            return ret;
213          }
214     
215        if ( (ret = i801smbus_build(&i801smbus, bus)) )
216                return ret;
217
218
219        if ( (ret = pci_enable_device(i801smbus)) ) {
220                printk("i801smbus: Unable to pci_enable i801smbus device!\n");
221                return ret;
222        }
223   
224        DBG("i801smbus: now inserting.\n");
225        pci_insert_device(i801smbus, i801smbus->bus);
226        printk("i801smbus: Enabled\n");
227        i801smbus_inserted = TRUE;
228        return 0;
229}
230
231
232void cleanup_module()
233{
234        write_lock_irqsave(i801smbus_lock, i801smbus_lock_flags);
235        if (i801smbus_inserted) {
236                pci_remove_device(i801smbus);
237                i801smbus_inserted = FALSE;
238        }
239        write_unlock_irqrestore(i801smbus_lock, i801smbus_lock_flags);
240
241        if (NULL != i801smbus)
242          {
243            kfree(i801smbus);
244          }
245        printk("i801smbus: SMBus device removed\n");
246}
247
248EXPORT_NO_SYMBOLS;
249
250#ifdef MODULE
251#ifdef MODULE_LICENSE
252MODULE_LICENSE("GPL");
253#endif
254MODULE_AUTHOR("Ilja Rauhut <IljaRauhut@web.de>, "
255              "Burkhard Kohl <bku@buks.ipn.de>, "
256              "Frank Bauer <frank.bauer@nikocity.de>, "
257              "and Mark Studebaker <mdsxyz123@yahoo.com>");
258MODULE_DESCRIPTION("i801smbus PCI Inserter");
259
260#endif                          /* MODULE */
261
262
263
264
265
266
267
268
269
270
Note: See TracBrowser for help on using the browser.