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

Revision 1503, 7.1 KB (checked in by mds, 11 years ago)

fix #define thinko

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