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

Revision 1404, 7.4 KB (checked in by mds, 11 years ago)

add support for ICH4; patch from

Klaus Woltereck <kw42@…>

  • 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/* Deal with CONFIG_MODVERSIONS */
64#ifdef CONFIG_MODVERSIONS
65#define MODVERSIONS
66#include <linux/modversions.h>
67#endif
68
69#include <linux/module.h>
70#include <linux/kernel.h>
71#include <linux/pci.h>
72#include <linux/stddef.h>
73#include <linux/ioport.h>
74#include <linux/errno.h>
75#include <linux/slab.h>
76#include <linux/interrupt.h>
77#include <asm/types.h>
78
79#include <linux/sched.h>
80#include <linux/signal.h>
81#include <asm/irq.h>
82
83/*
84rmm    from lm_sensors-2.3.3:
85 */
86
87#define SMB_IO_SIZE  0xF
88#define SMB_BASE 0x20
89
90
91/*
92 * some shorter definitions for the ICHx PCI device IDs
93 */
94
95#define ICH2 PCI_DEVICE_ID_INTEL_82801BA_0
96#define ICH2_SMBUS PCI_DEVICE_ID_INTEL_82801BA_3
97
98
99#ifndef PCI_DEVICE_ID_INTEL_82801DB_0
100#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0
101#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3
102#endif
103
104#define ICH4 PCI_DEVICE_ID_INTEL_82801DB_0
105#define ICH4_SMBUS PCI_DEVICE_ID_INTEL_82801DB_3
106
107/* status, used to indicate that io space needs to be freed */
108static struct pci_dev *i801smbus = NULL;
109static int i801smbus_inserted = FALSE;
110extern void cleanup_module(void);
111 
112static rwlock_t i801smbus_lock = RW_LOCK_UNLOCKED;
113static unsigned long i801smbus_lock_flags = 0;
114
115/*
116 * Checks whether SMBus is enabled and turns it on in case they are not.
117 * It's done by clearing Bit 8 and 4 in i801 config space F2h, PCI-Device 0x8086:0x2440(ICH2)/0x24c0(ICH4)
118 */
119static int
120i801smbus_enable(struct pci_dev *dev){
121        u16  val   = 0;
122
123        pci_read_config_word(dev, 0xF2, &val);
124        DBG("i801smbus: i801smbus config byte reading 0x%X.\n", val);
125        if (val & 0x008) {
126                pci_write_config_word(dev, 0xF2, val & 0x77);
127                pci_read_config_word(dev, 0xF2, &val);
128                if(val & 0x008) 
129                  {
130                    DBG("i801smbus: i801smbus config byte locked:-(\n");
131                    return -EIO;
132                  }
133                else
134                  printk("SMBus activated in LPC!\n");
135        }
136        return 0;
137
138}
139
140/*
141 * Builds the basic pci_dev for the i801smbus
142 */
143static int i801smbus_build(struct pci_dev **i801smbus, struct pci_bus *bus) 
144{
145        u32 devfn;
146        u16 id = 0;
147        u16 vid = 0;
148        int ret;
149
150        DBG("i801smbus: requesting kernel space for the i801smbus entry.\n");
151        *i801smbus = kmalloc(sizeof(**i801smbus), GFP_ATOMIC);
152        if(NULL == *i801smbus) {
153                printk("i801smbus: out of memory.\n");
154                return -ENOMEM;
155        }
156
157        /* minimally fill in structure for search */
158        /* The device should be on the same bus as the i801. */
159        memset(*i801smbus, 0, sizeof(**i801smbus));
160        (*i801smbus)->bus    = bus;
161        (*i801smbus)->sysdata = bus->sysdata;
162        (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL;
163
164        DBG("i801smbus: now looking for i801smbus.\n");
165        for  (id = 0, devfn = 0; devfn < 0xFF; devfn++) {
166                (*i801smbus)->devfn = devfn;
167                ret = pci_read_config_word(*i801smbus, PCI_DEVICE_ID, &id);
168                if (ret == 0 && (ICH2_SMBUS == id || ICH4_SMBUS == id)) {
169                        pci_read_config_word(*i801smbus, PCI_VENDOR_ID, &vid);
170                        if(vid == 0x8086)
171                                break;
172                }
173        }
174        if (!(ICH2_SMBUS == id || ICH4_SMBUS == id)) { 
175                DBG("i801smbus: i801smbus not found although i801 present - strange.\n");
176                return -EACCES;
177        } else {
178                DBG("i801smbus: i801smbus found and enabled. Devfn: 0x%X.\n", devfn);
179        }
180        /* We now have the devfn and bus of the i801smbus device.
181         * let's put the rest of the device data together.
182         */
183
184        (*i801smbus)->vendor = 0x8086;
185        (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL;
186        (*i801smbus)->device = id;
187 
188        return(pci_setup_device(*i801smbus));
189}
190
191
192
193
194/* Initialize the module */
195int init_module(void)
196{
197        struct pci_bus *bus = NULL;
198        struct pci_dev *dev = NULL;
199        int ret = 0;
200
201        DBG("i801smbus: init_module().\n");
202
203        /* Are we on a PCI-Board? */
204        if (!pci_present()) {
205                printk("i801smbus: No PCI bus found - sorry.\n");
206                return -ENODEV;
207        }
208
209        /* We want to be sure that the i801smbus is not present yet. */
210        dev = pci_find_device(0x8086, ICH2_SMBUS, NULL);
211
212        if (dev) 
213          {
214            printk("i801smbus: SMBus already active\n");
215            return -EPERM;
216          }
217       
218        dev = pci_find_device(0x8086, ICH4_SMBUS, NULL);
219
220        if (dev) 
221          {
222            printk("i801smbus: SMBus already active\n");
223            return -EPERM;
224          }
225       
226        /* Are we operating a i801 chipset */
227        dev = pci_find_device(0x8086, ICH2, NULL);
228        if (NULL == dev) 
229          {
230            dev = pci_find_device(0x8086, ICH4, NULL);
231            if (NULL == dev) 
232              {
233                printk("INTEL ICH2/4 (82801AB/DB) not found.\n");
234                return -ENODEV ;
235              }
236            else
237              {
238                printk("found Intel ICH4 (82801DB).\n");
239              }
240          }
241        else
242          {
243            printk("found Intel ICH2 (82801AB).\n");
244          }
245
246        /* we need the bus pointer later */
247        bus = dev->bus;
248
249
250        if ( (ret = i801smbus_enable(dev)) ) 
251          {
252            printk("i801smbus: Unable to turn on i801smbus device - sorry!\n");
253            return ret;
254          }
255     
256        if ( (ret = i801smbus_build(&i801smbus, bus)) )
257                return ret;
258
259
260        if ( (ret = pci_enable_device(i801smbus)) ) {
261                printk("i801smbus: Unable to pci_enable i801smbus device!\n");
262                return ret;
263        }
264   
265        DBG("i801smbus: now inserting.\n");
266        pci_insert_device(i801smbus, i801smbus->bus);
267        printk("i801smbus: Enabled\n");
268        i801smbus_inserted = TRUE;
269        return 0;
270}
271
272
273void cleanup_module(void)
274{
275        write_lock_irqsave(i801smbus_lock, i801smbus_lock_flags);
276        if (i801smbus_inserted) {
277                pci_remove_device(i801smbus);
278                i801smbus_inserted = FALSE;
279        }
280        write_unlock_irqrestore(i801smbus_lock, i801smbus_lock_flags);
281
282        if (NULL != i801smbus)
283          {
284            kfree(i801smbus);
285          }
286        printk("i801smbus: SMBus device removed\n");
287}
288
289EXPORT_NO_SYMBOLS;
290
291#ifdef MODULE
292#ifdef MODULE_LICENSE
293MODULE_LICENSE("GPL");
294#endif
295MODULE_AUTHOR("Ilja Rauhut <IljaRauhut@web.de>, "
296              "Burkhard Kohl <bku@buks.ipn.de>, "
297              "Frank Bauer <frank.bauer@nikocity.de>, "
298              "Mark Studebaker <mdsxyz123@yahoo.com>,"
299              "and Klaus Woltereck <kw42@gmx.net>");
300MODULE_DESCRIPTION("i801smbus PCI Inserter");
301
302#endif                          /* MODULE */
303
304
305
306
307
308
309
310
311
312
Note: See TracBrowser for help on using the browser.