Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[pandora-kernel.git] / drivers / watchdog / iTCO_wdt.c
1 /*
2  *      intel TCO Watchdog Driver
3  *
4  *      (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>.
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License
8  *      as published by the Free Software Foundation; either version
9  *      2 of the License, or (at your option) any later version.
10  *
11  *      Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
12  *      provide warranty for any of this software. This material is
13  *      provided "AS-IS" and at no charge.
14  *
15  *      The TCO watchdog is implemented in the following I/O controller hubs:
16  *      (See the intel documentation on http://developer.intel.com.)
17  *      document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
18  *      document number 290687-002, 298242-027: 82801BA (ICH2)
19  *      document number 290733-003, 290739-013: 82801CA (ICH3-S)
20  *      document number 290716-001, 290718-007: 82801CAM (ICH3-M)
21  *      document number 290744-001, 290745-025: 82801DB (ICH4)
22  *      document number 252337-001, 252663-008: 82801DBM (ICH4-M)
23  *      document number 273599-001, 273645-002: 82801E (C-ICH)
24  *      document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
25  *      document number 300641-004, 300884-013: 6300ESB
26  *      document number 301473-002, 301474-026: 82801F (ICH6)
27  *      document number 313082-001, 313075-006: 631xESB, 632xESB
28  *      document number 307013-003, 307014-024: 82801G (ICH7)
29  *      document number 322896-001, 322897-001: NM10
30  *      document number 313056-003, 313057-017: 82801H (ICH8)
31  *      document number 316972-004, 316973-012: 82801I (ICH9)
32  *      document number 319973-002, 319974-002: 82801J (ICH10)
33  *      document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
34  *      document number 320066-003, 320257-008: EP80597 (IICH)
35  *      document number 324645-001, 324646-001: Cougar Point (CPT)
36  *      document number TBD                   : Patsburg (PBG)
37  *      document number TBD                   : DH89xxCC
38  *      document number TBD                   : Panther Point
39  */
40
41 /*
42  *      Includes, defines, variables, module parameters, ...
43  */
44
45 /* Module and version information */
46 #define DRV_NAME        "iTCO_wdt"
47 #define DRV_VERSION     "1.06"
48 #define PFX             DRV_NAME ": "
49
50 /* Includes */
51 #include <linux/module.h>               /* For module specific items */
52 #include <linux/moduleparam.h>          /* For new moduleparam's */
53 #include <linux/types.h>                /* For standard types (like size_t) */
54 #include <linux/errno.h>                /* For the -ENODEV/... values */
55 #include <linux/kernel.h>               /* For printk/panic/... */
56 #include <linux/miscdevice.h>           /* For MODULE_ALIAS_MISCDEV
57                                                         (WATCHDOG_MINOR) */
58 #include <linux/watchdog.h>             /* For the watchdog specific items */
59 #include <linux/init.h>                 /* For __init/__exit/... */
60 #include <linux/fs.h>                   /* For file operations */
61 #include <linux/platform_device.h>      /* For platform_driver framework */
62 #include <linux/pci.h>                  /* For pci functions */
63 #include <linux/ioport.h>               /* For io-port access */
64 #include <linux/spinlock.h>             /* For spin_lock/spin_unlock/... */
65 #include <linux/uaccess.h>              /* For copy_to_user/put_user/... */
66 #include <linux/io.h>                   /* For inb/outb/... */
67
68 #include "iTCO_vendor.h"
69
70 /* TCO related info */
71 enum iTCO_chipsets {
72         TCO_ICH = 0,    /* ICH */
73         TCO_ICH0,       /* ICH0 */
74         TCO_ICH2,       /* ICH2 */
75         TCO_ICH2M,      /* ICH2-M */
76         TCO_ICH3,       /* ICH3-S */
77         TCO_ICH3M,      /* ICH3-M */
78         TCO_ICH4,       /* ICH4 */
79         TCO_ICH4M,      /* ICH4-M */
80         TCO_CICH,       /* C-ICH */
81         TCO_ICH5,       /* ICH5 & ICH5R */
82         TCO_6300ESB,    /* 6300ESB */
83         TCO_ICH6,       /* ICH6 & ICH6R */
84         TCO_ICH6M,      /* ICH6-M */
85         TCO_ICH6W,      /* ICH6W & ICH6RW */
86         TCO_631XESB,    /* 631xESB/632xESB */
87         TCO_ICH7,       /* ICH7 & ICH7R */
88         TCO_ICH7DH,     /* ICH7DH */
89         TCO_ICH7M,      /* ICH7-M & ICH7-U */
90         TCO_ICH7MDH,    /* ICH7-M DH */
91         TCO_NM10,       /* NM10 */
92         TCO_ICH8,       /* ICH8 & ICH8R */
93         TCO_ICH8DH,     /* ICH8DH */
94         TCO_ICH8DO,     /* ICH8DO */
95         TCO_ICH8M,      /* ICH8M */
96         TCO_ICH8ME,     /* ICH8M-E */
97         TCO_ICH9,       /* ICH9 */
98         TCO_ICH9R,      /* ICH9R */
99         TCO_ICH9DH,     /* ICH9DH */
100         TCO_ICH9DO,     /* ICH9DO */
101         TCO_ICH9M,      /* ICH9M */
102         TCO_ICH9ME,     /* ICH9M-E */
103         TCO_ICH10,      /* ICH10 */
104         TCO_ICH10R,     /* ICH10R */
105         TCO_ICH10D,     /* ICH10D */
106         TCO_ICH10DO,    /* ICH10DO */
107         TCO_PCH,        /* PCH Desktop Full Featured */
108         TCO_PCHM,       /* PCH Mobile Full Featured */
109         TCO_P55,        /* P55 */
110         TCO_PM55,       /* PM55 */
111         TCO_H55,        /* H55 */
112         TCO_QM57,       /* QM57 */
113         TCO_H57,        /* H57 */
114         TCO_HM55,       /* HM55 */
115         TCO_Q57,        /* Q57 */
116         TCO_HM57,       /* HM57 */
117         TCO_PCHMSFF,    /* PCH Mobile SFF Full Featured */
118         TCO_QS57,       /* QS57 */
119         TCO_3400,       /* 3400 */
120         TCO_3420,       /* 3420 */
121         TCO_3450,       /* 3450 */
122         TCO_EP80579,    /* EP80579 */
123         TCO_CPT1,       /* Cougar Point */
124         TCO_CPT2,       /* Cougar Point Desktop */
125         TCO_CPT3,       /* Cougar Point Mobile */
126         TCO_CPT4,       /* Cougar Point */
127         TCO_CPT5,       /* Cougar Point */
128         TCO_CPT6,       /* Cougar Point */
129         TCO_CPT7,       /* Cougar Point */
130         TCO_CPT8,       /* Cougar Point */
131         TCO_CPT9,       /* Cougar Point */
132         TCO_CPT10,      /* Cougar Point */
133         TCO_CPT11,      /* Cougar Point */
134         TCO_CPT12,      /* Cougar Point */
135         TCO_CPT13,      /* Cougar Point */
136         TCO_CPT14,      /* Cougar Point */
137         TCO_CPT15,      /* Cougar Point */
138         TCO_CPT16,      /* Cougar Point */
139         TCO_CPT17,      /* Cougar Point */
140         TCO_CPT18,      /* Cougar Point */
141         TCO_CPT19,      /* Cougar Point */
142         TCO_CPT20,      /* Cougar Point */
143         TCO_CPT21,      /* Cougar Point */
144         TCO_CPT22,      /* Cougar Point */
145         TCO_CPT23,      /* Cougar Point */
146         TCO_CPT24,      /* Cougar Point */
147         TCO_CPT25,      /* Cougar Point */
148         TCO_CPT26,      /* Cougar Point */
149         TCO_CPT27,      /* Cougar Point */
150         TCO_CPT28,      /* Cougar Point */
151         TCO_CPT29,      /* Cougar Point */
152         TCO_CPT30,      /* Cougar Point */
153         TCO_CPT31,      /* Cougar Point */
154         TCO_PBG1,       /* Patsburg */
155         TCO_PBG2,       /* Patsburg */
156         TCO_DH89XXCC,   /* DH89xxCC */
157         TCO_PPT0,       /* Panther Point */
158         TCO_PPT1,       /* Panther Point */
159         TCO_PPT2,       /* Panther Point */
160         TCO_PPT3,       /* Panther Point */
161         TCO_PPT4,       /* Panther Point */
162         TCO_PPT5,       /* Panther Point */
163         TCO_PPT6,       /* Panther Point */
164         TCO_PPT7,       /* Panther Point */
165         TCO_PPT8,       /* Panther Point */
166         TCO_PPT9,       /* Panther Point */
167         TCO_PPT10,      /* Panther Point */
168         TCO_PPT11,      /* Panther Point */
169         TCO_PPT12,      /* Panther Point */
170         TCO_PPT13,      /* Panther Point */
171         TCO_PPT14,      /* Panther Point */
172         TCO_PPT15,      /* Panther Point */
173         TCO_PPT16,      /* Panther Point */
174         TCO_PPT17,      /* Panther Point */
175         TCO_PPT18,      /* Panther Point */
176         TCO_PPT19,      /* Panther Point */
177         TCO_PPT20,      /* Panther Point */
178         TCO_PPT21,      /* Panther Point */
179         TCO_PPT22,      /* Panther Point */
180         TCO_PPT23,      /* Panther Point */
181         TCO_PPT24,      /* Panther Point */
182         TCO_PPT25,      /* Panther Point */
183         TCO_PPT26,      /* Panther Point */
184         TCO_PPT27,      /* Panther Point */
185         TCO_PPT28,      /* Panther Point */
186         TCO_PPT29,      /* Panther Point */
187         TCO_PPT30,      /* Panther Point */
188         TCO_PPT31,      /* Panther Point */
189 };
190
191 static struct {
192         char *name;
193         unsigned int iTCO_version;
194 } iTCO_chipset_info[] __devinitdata = {
195         {"ICH", 1},
196         {"ICH0", 1},
197         {"ICH2", 1},
198         {"ICH2-M", 1},
199         {"ICH3-S", 1},
200         {"ICH3-M", 1},
201         {"ICH4", 1},
202         {"ICH4-M", 1},
203         {"C-ICH", 1},
204         {"ICH5 or ICH5R", 1},
205         {"6300ESB", 1},
206         {"ICH6 or ICH6R", 2},
207         {"ICH6-M", 2},
208         {"ICH6W or ICH6RW", 2},
209         {"631xESB/632xESB", 2},
210         {"ICH7 or ICH7R", 2},
211         {"ICH7DH", 2},
212         {"ICH7-M or ICH7-U", 2},
213         {"ICH7-M DH", 2},
214         {"NM10", 2},
215         {"ICH8 or ICH8R", 2},
216         {"ICH8DH", 2},
217         {"ICH8DO", 2},
218         {"ICH8M", 2},
219         {"ICH8M-E", 2},
220         {"ICH9", 2},
221         {"ICH9R", 2},
222         {"ICH9DH", 2},
223         {"ICH9DO", 2},
224         {"ICH9M", 2},
225         {"ICH9M-E", 2},
226         {"ICH10", 2},
227         {"ICH10R", 2},
228         {"ICH10D", 2},
229         {"ICH10DO", 2},
230         {"PCH Desktop Full Featured", 2},
231         {"PCH Mobile Full Featured", 2},
232         {"P55", 2},
233         {"PM55", 2},
234         {"H55", 2},
235         {"QM57", 2},
236         {"H57", 2},
237         {"HM55", 2},
238         {"Q57", 2},
239         {"HM57", 2},
240         {"PCH Mobile SFF Full Featured", 2},
241         {"QS57", 2},
242         {"3400", 2},
243         {"3420", 2},
244         {"3450", 2},
245         {"EP80579", 2},
246         {"Cougar Point", 2},
247         {"Cougar Point", 2},
248         {"Cougar Point", 2},
249         {"Cougar Point", 2},
250         {"Cougar Point", 2},
251         {"Cougar Point", 2},
252         {"Cougar Point", 2},
253         {"Cougar Point", 2},
254         {"Cougar Point", 2},
255         {"Cougar Point", 2},
256         {"Cougar Point", 2},
257         {"Cougar Point", 2},
258         {"Cougar Point", 2},
259         {"Cougar Point", 2},
260         {"Cougar Point", 2},
261         {"Cougar Point", 2},
262         {"Cougar Point", 2},
263         {"Cougar Point", 2},
264         {"Cougar Point", 2},
265         {"Cougar Point", 2},
266         {"Cougar Point", 2},
267         {"Cougar Point", 2},
268         {"Cougar Point", 2},
269         {"Cougar Point", 2},
270         {"Cougar Point", 2},
271         {"Cougar Point", 2},
272         {"Cougar Point", 2},
273         {"Cougar Point", 2},
274         {"Cougar Point", 2},
275         {"Cougar Point", 2},
276         {"Cougar Point", 2},
277         {"Patsburg", 2},
278         {"Patsburg", 2},
279         {"DH89xxCC", 2},
280         {"Panther Point", 2},
281         {"Panther Point", 2},
282         {"Panther Point", 2},
283         {"Panther Point", 2},
284         {"Panther Point", 2},
285         {"Panther Point", 2},
286         {"Panther Point", 2},
287         {"Panther Point", 2},
288         {"Panther Point", 2},
289         {"Panther Point", 2},
290         {"Panther Point", 2},
291         {"Panther Point", 2},
292         {"Panther Point", 2},
293         {"Panther Point", 2},
294         {"Panther Point", 2},
295         {"Panther Point", 2},
296         {"Panther Point", 2},
297         {"Panther Point", 2},
298         {"Panther Point", 2},
299         {"Panther Point", 2},
300         {"Panther Point", 2},
301         {"Panther Point", 2},
302         {"Panther Point", 2},
303         {"Panther Point", 2},
304         {"Panther Point", 2},
305         {"Panther Point", 2},
306         {"Panther Point", 2},
307         {"Panther Point", 2},
308         {"Panther Point", 2},
309         {"Panther Point", 2},
310         {"Panther Point", 2},
311         {"Panther Point", 2},
312         {NULL, 0}
313 };
314
315 #define ITCO_PCI_DEVICE(dev, data) \
316         .vendor = PCI_VENDOR_ID_INTEL,  \
317         .device = dev,                  \
318         .subvendor = PCI_ANY_ID,        \
319         .subdevice = PCI_ANY_ID,        \
320         .class = 0,                     \
321         .class_mask = 0,                \
322         .driver_data = data
323
324 /*
325  * This data only exists for exporting the supported PCI ids
326  * via MODULE_DEVICE_TABLE.  We do not actually register a
327  * pci_driver, because the I/O Controller Hub has also other
328  * functions that probably will be registered by other drivers.
329  */
330 static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
331         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0,        TCO_ICH)},
332         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0,        TCO_ICH0)},
333         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0,        TCO_ICH2)},
334         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10,       TCO_ICH2M)},
335         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0,        TCO_ICH3)},
336         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12,       TCO_ICH3M)},
337         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0,        TCO_ICH4)},
338         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12,       TCO_ICH4M)},
339         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0,         TCO_CICH)},
340         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0,        TCO_ICH5)},
341         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1,            TCO_6300ESB)},
342         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0,           TCO_ICH6)},
343         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1,           TCO_ICH6M)},
344         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2,           TCO_ICH6W)},
345         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0,           TCO_631XESB)},
346         { ITCO_PCI_DEVICE(0x2671,                               TCO_631XESB)},
347         { ITCO_PCI_DEVICE(0x2672,                               TCO_631XESB)},
348         { ITCO_PCI_DEVICE(0x2673,                               TCO_631XESB)},
349         { ITCO_PCI_DEVICE(0x2674,                               TCO_631XESB)},
350         { ITCO_PCI_DEVICE(0x2675,                               TCO_631XESB)},
351         { ITCO_PCI_DEVICE(0x2676,                               TCO_631XESB)},
352         { ITCO_PCI_DEVICE(0x2677,                               TCO_631XESB)},
353         { ITCO_PCI_DEVICE(0x2678,                               TCO_631XESB)},
354         { ITCO_PCI_DEVICE(0x2679,                               TCO_631XESB)},
355         { ITCO_PCI_DEVICE(0x267a,                               TCO_631XESB)},
356         { ITCO_PCI_DEVICE(0x267b,                               TCO_631XESB)},
357         { ITCO_PCI_DEVICE(0x267c,                               TCO_631XESB)},
358         { ITCO_PCI_DEVICE(0x267d,                               TCO_631XESB)},
359         { ITCO_PCI_DEVICE(0x267e,                               TCO_631XESB)},
360         { ITCO_PCI_DEVICE(0x267f,                               TCO_631XESB)},
361         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0,           TCO_ICH7)},
362         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30,          TCO_ICH7DH)},
363         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1,           TCO_ICH7M)},
364         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31,          TCO_ICH7MDH)},
365         { ITCO_PCI_DEVICE(0x27bc,                               TCO_NM10)},
366         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0,           TCO_ICH8)},
367         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2,           TCO_ICH8DH)},
368         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3,           TCO_ICH8DO)},
369         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4,           TCO_ICH8M)},
370         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1,           TCO_ICH8ME)},
371         { ITCO_PCI_DEVICE(0x2918,                               TCO_ICH9)},
372         { ITCO_PCI_DEVICE(0x2916,                               TCO_ICH9R)},
373         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2,           TCO_ICH9DH)},
374         { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4,           TCO_ICH9DO)},
375         { ITCO_PCI_DEVICE(0x2919,                               TCO_ICH9M)},
376         { ITCO_PCI_DEVICE(0x2917,                               TCO_ICH9ME)},
377         { ITCO_PCI_DEVICE(0x3a18,                               TCO_ICH10)},
378         { ITCO_PCI_DEVICE(0x3a16,                               TCO_ICH10R)},
379         { ITCO_PCI_DEVICE(0x3a1a,                               TCO_ICH10D)},
380         { ITCO_PCI_DEVICE(0x3a14,                               TCO_ICH10DO)},
381         { ITCO_PCI_DEVICE(0x3b00,                               TCO_PCH)},
382         { ITCO_PCI_DEVICE(0x3b01,                               TCO_PCHM)},
383         { ITCO_PCI_DEVICE(0x3b02,                               TCO_P55)},
384         { ITCO_PCI_DEVICE(0x3b03,                               TCO_PM55)},
385         { ITCO_PCI_DEVICE(0x3b06,                               TCO_H55)},
386         { ITCO_PCI_DEVICE(0x3b07,                               TCO_QM57)},
387         { ITCO_PCI_DEVICE(0x3b08,                               TCO_H57)},
388         { ITCO_PCI_DEVICE(0x3b09,                               TCO_HM55)},
389         { ITCO_PCI_DEVICE(0x3b0a,                               TCO_Q57)},
390         { ITCO_PCI_DEVICE(0x3b0b,                               TCO_HM57)},
391         { ITCO_PCI_DEVICE(0x3b0d,                               TCO_PCHMSFF)},
392         { ITCO_PCI_DEVICE(0x3b0f,                               TCO_QS57)},
393         { ITCO_PCI_DEVICE(0x3b12,                               TCO_3400)},
394         { ITCO_PCI_DEVICE(0x3b14,                               TCO_3420)},
395         { ITCO_PCI_DEVICE(0x3b16,                               TCO_3450)},
396         { ITCO_PCI_DEVICE(0x5031,                               TCO_EP80579)},
397         { ITCO_PCI_DEVICE(0x1c41,                               TCO_CPT1)},
398         { ITCO_PCI_DEVICE(0x1c42,                               TCO_CPT2)},
399         { ITCO_PCI_DEVICE(0x1c43,                               TCO_CPT3)},
400         { ITCO_PCI_DEVICE(0x1c44,                               TCO_CPT4)},
401         { ITCO_PCI_DEVICE(0x1c45,                               TCO_CPT5)},
402         { ITCO_PCI_DEVICE(0x1c46,                               TCO_CPT6)},
403         { ITCO_PCI_DEVICE(0x1c47,                               TCO_CPT7)},
404         { ITCO_PCI_DEVICE(0x1c48,                               TCO_CPT8)},
405         { ITCO_PCI_DEVICE(0x1c49,                               TCO_CPT9)},
406         { ITCO_PCI_DEVICE(0x1c4a,                               TCO_CPT10)},
407         { ITCO_PCI_DEVICE(0x1c4b,                               TCO_CPT11)},
408         { ITCO_PCI_DEVICE(0x1c4c,                               TCO_CPT12)},
409         { ITCO_PCI_DEVICE(0x1c4d,                               TCO_CPT13)},
410         { ITCO_PCI_DEVICE(0x1c4e,                               TCO_CPT14)},
411         { ITCO_PCI_DEVICE(0x1c4f,                               TCO_CPT15)},
412         { ITCO_PCI_DEVICE(0x1c50,                               TCO_CPT16)},
413         { ITCO_PCI_DEVICE(0x1c51,                               TCO_CPT17)},
414         { ITCO_PCI_DEVICE(0x1c52,                               TCO_CPT18)},
415         { ITCO_PCI_DEVICE(0x1c53,                               TCO_CPT19)},
416         { ITCO_PCI_DEVICE(0x1c54,                               TCO_CPT20)},
417         { ITCO_PCI_DEVICE(0x1c55,                               TCO_CPT21)},
418         { ITCO_PCI_DEVICE(0x1c56,                               TCO_CPT22)},
419         { ITCO_PCI_DEVICE(0x1c57,                               TCO_CPT23)},
420         { ITCO_PCI_DEVICE(0x1c58,                               TCO_CPT24)},
421         { ITCO_PCI_DEVICE(0x1c59,                               TCO_CPT25)},
422         { ITCO_PCI_DEVICE(0x1c5a,                               TCO_CPT26)},
423         { ITCO_PCI_DEVICE(0x1c5b,                               TCO_CPT27)},
424         { ITCO_PCI_DEVICE(0x1c5c,                               TCO_CPT28)},
425         { ITCO_PCI_DEVICE(0x1c5d,                               TCO_CPT29)},
426         { ITCO_PCI_DEVICE(0x1c5e,                               TCO_CPT30)},
427         { ITCO_PCI_DEVICE(0x1c5f,                               TCO_CPT31)},
428         { ITCO_PCI_DEVICE(0x1d40,                               TCO_PBG1)},
429         { ITCO_PCI_DEVICE(0x1d41,                               TCO_PBG2)},
430         { ITCO_PCI_DEVICE(0x2310,                               TCO_DH89XXCC)},
431         { ITCO_PCI_DEVICE(0x1e40,                               TCO_PPT0)},
432         { ITCO_PCI_DEVICE(0x1e41,                               TCO_PPT1)},
433         { ITCO_PCI_DEVICE(0x1e42,                               TCO_PPT2)},
434         { ITCO_PCI_DEVICE(0x1e43,                               TCO_PPT3)},
435         { ITCO_PCI_DEVICE(0x1e44,                               TCO_PPT4)},
436         { ITCO_PCI_DEVICE(0x1e45,                               TCO_PPT5)},
437         { ITCO_PCI_DEVICE(0x1e46,                               TCO_PPT6)},
438         { ITCO_PCI_DEVICE(0x1e47,                               TCO_PPT7)},
439         { ITCO_PCI_DEVICE(0x1e48,                               TCO_PPT8)},
440         { ITCO_PCI_DEVICE(0x1e49,                               TCO_PPT9)},
441         { ITCO_PCI_DEVICE(0x1e4a,                               TCO_PPT10)},
442         { ITCO_PCI_DEVICE(0x1e4b,                               TCO_PPT11)},
443         { ITCO_PCI_DEVICE(0x1e4c,                               TCO_PPT12)},
444         { ITCO_PCI_DEVICE(0x1e4d,                               TCO_PPT13)},
445         { ITCO_PCI_DEVICE(0x1e4e,                               TCO_PPT14)},
446         { ITCO_PCI_DEVICE(0x1e4f,                               TCO_PPT15)},
447         { ITCO_PCI_DEVICE(0x1e50,                               TCO_PPT16)},
448         { ITCO_PCI_DEVICE(0x1e51,                               TCO_PPT17)},
449         { ITCO_PCI_DEVICE(0x1e52,                               TCO_PPT18)},
450         { ITCO_PCI_DEVICE(0x1e53,                               TCO_PPT19)},
451         { ITCO_PCI_DEVICE(0x1e54,                               TCO_PPT20)},
452         { ITCO_PCI_DEVICE(0x1e55,                               TCO_PPT21)},
453         { ITCO_PCI_DEVICE(0x1e56,                               TCO_PPT22)},
454         { ITCO_PCI_DEVICE(0x1e57,                               TCO_PPT23)},
455         { ITCO_PCI_DEVICE(0x1e58,                               TCO_PPT24)},
456         { ITCO_PCI_DEVICE(0x1e59,                               TCO_PPT25)},
457         { ITCO_PCI_DEVICE(0x1e5a,                               TCO_PPT26)},
458         { ITCO_PCI_DEVICE(0x1e5b,                               TCO_PPT27)},
459         { ITCO_PCI_DEVICE(0x1e5c,                               TCO_PPT28)},
460         { ITCO_PCI_DEVICE(0x1e5d,                               TCO_PPT29)},
461         { ITCO_PCI_DEVICE(0x1e5e,                               TCO_PPT30)},
462         { ITCO_PCI_DEVICE(0x1e5f,                               TCO_PPT31)},
463         { 0, },                 /* End of list */
464 };
465 MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
466
467 /* Address definitions for the TCO */
468 /* TCO base address */
469 #define TCOBASE         (iTCO_wdt_private.ACPIBASE + 0x60)
470 /* SMI Control and Enable Register */
471 #define SMI_EN          (iTCO_wdt_private.ACPIBASE + 0x30)
472
473 #define TCO_RLD         (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */
474 #define TCOv1_TMR       (TCOBASE + 0x01) /* TCOv1 Timer Initial Value   */
475 #define TCO_DAT_IN      (TCOBASE + 0x02) /* TCO Data In Register        */
476 #define TCO_DAT_OUT     (TCOBASE + 0x03) /* TCO Data Out Register       */
477 #define TCO1_STS        (TCOBASE + 0x04) /* TCO1 Status Register        */
478 #define TCO2_STS        (TCOBASE + 0x06) /* TCO2 Status Register        */
479 #define TCO1_CNT        (TCOBASE + 0x08) /* TCO1 Control Register       */
480 #define TCO2_CNT        (TCOBASE + 0x0a) /* TCO2 Control Register       */
481 #define TCOv2_TMR       (TCOBASE + 0x12) /* TCOv2 Timer Initial Value   */
482
483 /* internal variables */
484 static unsigned long is_active;
485 static char expect_release;
486 static struct {         /* this is private data for the iTCO_wdt device */
487         /* TCO version/generation */
488         unsigned int iTCO_version;
489         /* The device's ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
490         unsigned long ACPIBASE;
491         /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
492         unsigned long __iomem *gcs;
493         /* the lock for io operations */
494         spinlock_t io_lock;
495         /* the PCI-device */
496         struct pci_dev *pdev;
497 } iTCO_wdt_private;
498
499 /* the watchdog platform device */
500 static struct platform_device *iTCO_wdt_platform_device;
501
502 /* module parameters */
503 #define WATCHDOG_HEARTBEAT 30   /* 30 sec default heartbeat */
504 static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
505 module_param(heartbeat, int, 0);
506 MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
507         "5..76 (TCO v1) or 3..614 (TCO v2), default="
508                                 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
509
510 static int nowayout = WATCHDOG_NOWAYOUT;
511 module_param(nowayout, int, 0);
512 MODULE_PARM_DESC(nowayout,
513         "Watchdog cannot be stopped once started (default="
514                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
515
516 /*
517  * Some TCO specific functions
518  */
519
520 static inline unsigned int seconds_to_ticks(int seconds)
521 {
522         /* the internal timer is stored as ticks which decrement
523          * every 0.6 seconds */
524         return (seconds * 10) / 6;
525 }
526
527 static void iTCO_wdt_set_NO_REBOOT_bit(void)
528 {
529         u32 val32;
530
531         /* Set the NO_REBOOT bit: this disables reboots */
532         if (iTCO_wdt_private.iTCO_version == 2) {
533                 val32 = readl(iTCO_wdt_private.gcs);
534                 val32 |= 0x00000020;
535                 writel(val32, iTCO_wdt_private.gcs);
536         } else if (iTCO_wdt_private.iTCO_version == 1) {
537                 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
538                 val32 |= 0x00000002;
539                 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
540         }
541 }
542
543 static int iTCO_wdt_unset_NO_REBOOT_bit(void)
544 {
545         int ret = 0;
546         u32 val32;
547
548         /* Unset the NO_REBOOT bit: this enables reboots */
549         if (iTCO_wdt_private.iTCO_version == 2) {
550                 val32 = readl(iTCO_wdt_private.gcs);
551                 val32 &= 0xffffffdf;
552                 writel(val32, iTCO_wdt_private.gcs);
553
554                 val32 = readl(iTCO_wdt_private.gcs);
555                 if (val32 & 0x00000020)
556                         ret = -EIO;
557         } else if (iTCO_wdt_private.iTCO_version == 1) {
558                 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
559                 val32 &= 0xfffffffd;
560                 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
561
562                 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
563                 if (val32 & 0x00000002)
564                         ret = -EIO;
565         }
566
567         return ret; /* returns: 0 = OK, -EIO = Error */
568 }
569
570 static int iTCO_wdt_start(void)
571 {
572         unsigned int val;
573
574         spin_lock(&iTCO_wdt_private.io_lock);
575
576         iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
577
578         /* disable chipset's NO_REBOOT bit */
579         if (iTCO_wdt_unset_NO_REBOOT_bit()) {
580                 spin_unlock(&iTCO_wdt_private.io_lock);
581                 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
582                                         "reboot disabled by hardware/BIOS\n");
583                 return -EIO;
584         }
585
586         /* Force the timer to its reload value by writing to the TCO_RLD
587            register */
588         if (iTCO_wdt_private.iTCO_version == 2)
589                 outw(0x01, TCO_RLD);
590         else if (iTCO_wdt_private.iTCO_version == 1)
591                 outb(0x01, TCO_RLD);
592
593         /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
594         val = inw(TCO1_CNT);
595         val &= 0xf7ff;
596         outw(val, TCO1_CNT);
597         val = inw(TCO1_CNT);
598         spin_unlock(&iTCO_wdt_private.io_lock);
599
600         if (val & 0x0800)
601                 return -1;
602         return 0;
603 }
604
605 static int iTCO_wdt_stop(void)
606 {
607         unsigned int val;
608
609         spin_lock(&iTCO_wdt_private.io_lock);
610
611         iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
612
613         /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
614         val = inw(TCO1_CNT);
615         val |= 0x0800;
616         outw(val, TCO1_CNT);
617         val = inw(TCO1_CNT);
618
619         /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
620         iTCO_wdt_set_NO_REBOOT_bit();
621
622         spin_unlock(&iTCO_wdt_private.io_lock);
623
624         if ((val & 0x0800) == 0)
625                 return -1;
626         return 0;
627 }
628
629 static int iTCO_wdt_keepalive(void)
630 {
631         spin_lock(&iTCO_wdt_private.io_lock);
632
633         iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
634
635         /* Reload the timer by writing to the TCO Timer Counter register */
636         if (iTCO_wdt_private.iTCO_version == 2)
637                 outw(0x01, TCO_RLD);
638         else if (iTCO_wdt_private.iTCO_version == 1) {
639                 /* Reset the timeout status bit so that the timer
640                  * needs to count down twice again before rebooting */
641                 outw(0x0008, TCO1_STS); /* write 1 to clear bit */
642
643                 outb(0x01, TCO_RLD);
644         }
645
646         spin_unlock(&iTCO_wdt_private.io_lock);
647         return 0;
648 }
649
650 static int iTCO_wdt_set_heartbeat(int t)
651 {
652         unsigned int val16;
653         unsigned char val8;
654         unsigned int tmrval;
655
656         tmrval = seconds_to_ticks(t);
657
658         /* For TCO v1 the timer counts down twice before rebooting */
659         if (iTCO_wdt_private.iTCO_version == 1)
660                 tmrval /= 2;
661
662         /* from the specs: */
663         /* "Values of 0h-3h are ignored and should not be attempted" */
664         if (tmrval < 0x04)
665                 return -EINVAL;
666         if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
667             ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
668                 return -EINVAL;
669
670         iTCO_vendor_pre_set_heartbeat(tmrval);
671
672         /* Write new heartbeat to watchdog */
673         if (iTCO_wdt_private.iTCO_version == 2) {
674                 spin_lock(&iTCO_wdt_private.io_lock);
675                 val16 = inw(TCOv2_TMR);
676                 val16 &= 0xfc00;
677                 val16 |= tmrval;
678                 outw(val16, TCOv2_TMR);
679                 val16 = inw(TCOv2_TMR);
680                 spin_unlock(&iTCO_wdt_private.io_lock);
681
682                 if ((val16 & 0x3ff) != tmrval)
683                         return -EINVAL;
684         } else if (iTCO_wdt_private.iTCO_version == 1) {
685                 spin_lock(&iTCO_wdt_private.io_lock);
686                 val8 = inb(TCOv1_TMR);
687                 val8 &= 0xc0;
688                 val8 |= (tmrval & 0xff);
689                 outb(val8, TCOv1_TMR);
690                 val8 = inb(TCOv1_TMR);
691                 spin_unlock(&iTCO_wdt_private.io_lock);
692
693                 if ((val8 & 0x3f) != tmrval)
694                         return -EINVAL;
695         }
696
697         heartbeat = t;
698         return 0;
699 }
700
701 static int iTCO_wdt_get_timeleft(int *time_left)
702 {
703         unsigned int val16;
704         unsigned char val8;
705
706         /* read the TCO Timer */
707         if (iTCO_wdt_private.iTCO_version == 2) {
708                 spin_lock(&iTCO_wdt_private.io_lock);
709                 val16 = inw(TCO_RLD);
710                 val16 &= 0x3ff;
711                 spin_unlock(&iTCO_wdt_private.io_lock);
712
713                 *time_left = (val16 * 6) / 10;
714         } else if (iTCO_wdt_private.iTCO_version == 1) {
715                 spin_lock(&iTCO_wdt_private.io_lock);
716                 val8 = inb(TCO_RLD);
717                 val8 &= 0x3f;
718                 if (!(inw(TCO1_STS) & 0x0008))
719                         val8 += (inb(TCOv1_TMR) & 0x3f);
720                 spin_unlock(&iTCO_wdt_private.io_lock);
721
722                 *time_left = (val8 * 6) / 10;
723         } else
724                 return -EINVAL;
725         return 0;
726 }
727
728 /*
729  *      /dev/watchdog handling
730  */
731
732 static int iTCO_wdt_open(struct inode *inode, struct file *file)
733 {
734         /* /dev/watchdog can only be opened once */
735         if (test_and_set_bit(0, &is_active))
736                 return -EBUSY;
737
738         /*
739          *      Reload and activate timer
740          */
741         iTCO_wdt_start();
742         return nonseekable_open(inode, file);
743 }
744
745 static int iTCO_wdt_release(struct inode *inode, struct file *file)
746 {
747         /*
748          *      Shut off the timer.
749          */
750         if (expect_release == 42) {
751                 iTCO_wdt_stop();
752         } else {
753                 printk(KERN_CRIT PFX
754                         "Unexpected close, not stopping watchdog!\n");
755                 iTCO_wdt_keepalive();
756         }
757         clear_bit(0, &is_active);
758         expect_release = 0;
759         return 0;
760 }
761
762 static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
763                               size_t len, loff_t *ppos)
764 {
765         /* See if we got the magic character 'V' and reload the timer */
766         if (len) {
767                 if (!nowayout) {
768                         size_t i;
769
770                         /* note: just in case someone wrote the magic
771                            character five months ago... */
772                         expect_release = 0;
773
774                         /* scan to see whether or not we got the
775                            magic character */
776                         for (i = 0; i != len; i++) {
777                                 char c;
778                                 if (get_user(c, data + i))
779                                         return -EFAULT;
780                                 if (c == 'V')
781                                         expect_release = 42;
782                         }
783                 }
784
785                 /* someone wrote to us, we should reload the timer */
786                 iTCO_wdt_keepalive();
787         }
788         return len;
789 }
790
791 static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
792                                                         unsigned long arg)
793 {
794         int new_options, retval = -EINVAL;
795         int new_heartbeat;
796         void __user *argp = (void __user *)arg;
797         int __user *p = argp;
798         static const struct watchdog_info ident = {
799                 .options =              WDIOF_SETTIMEOUT |
800                                         WDIOF_KEEPALIVEPING |
801                                         WDIOF_MAGICCLOSE,
802                 .firmware_version =     0,
803                 .identity =             DRV_NAME,
804         };
805
806         switch (cmd) {
807         case WDIOC_GETSUPPORT:
808                 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
809         case WDIOC_GETSTATUS:
810         case WDIOC_GETBOOTSTATUS:
811                 return put_user(0, p);
812
813         case WDIOC_SETOPTIONS:
814         {
815                 if (get_user(new_options, p))
816                         return -EFAULT;
817
818                 if (new_options & WDIOS_DISABLECARD) {
819                         iTCO_wdt_stop();
820                         retval = 0;
821                 }
822                 if (new_options & WDIOS_ENABLECARD) {
823                         iTCO_wdt_keepalive();
824                         iTCO_wdt_start();
825                         retval = 0;
826                 }
827                 return retval;
828         }
829         case WDIOC_KEEPALIVE:
830                 iTCO_wdt_keepalive();
831                 return 0;
832
833         case WDIOC_SETTIMEOUT:
834         {
835                 if (get_user(new_heartbeat, p))
836                         return -EFAULT;
837                 if (iTCO_wdt_set_heartbeat(new_heartbeat))
838                         return -EINVAL;
839                 iTCO_wdt_keepalive();
840                 /* Fall */
841         }
842         case WDIOC_GETTIMEOUT:
843                 return put_user(heartbeat, p);
844         case WDIOC_GETTIMELEFT:
845         {
846                 int time_left;
847                 if (iTCO_wdt_get_timeleft(&time_left))
848                         return -EINVAL;
849                 return put_user(time_left, p);
850         }
851         default:
852                 return -ENOTTY;
853         }
854 }
855
856 /*
857  *      Kernel Interfaces
858  */
859
860 static const struct file_operations iTCO_wdt_fops = {
861         .owner =                THIS_MODULE,
862         .llseek =               no_llseek,
863         .write =                iTCO_wdt_write,
864         .unlocked_ioctl =       iTCO_wdt_ioctl,
865         .open =                 iTCO_wdt_open,
866         .release =              iTCO_wdt_release,
867 };
868
869 static struct miscdevice iTCO_wdt_miscdev = {
870         .minor =        WATCHDOG_MINOR,
871         .name =         "watchdog",
872         .fops =         &iTCO_wdt_fops,
873 };
874
875 /*
876  *      Init & exit routines
877  */
878
879 static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
880                 const struct pci_device_id *ent, struct platform_device *dev)
881 {
882         int ret;
883         u32 base_address;
884         unsigned long RCBA;
885         unsigned long val32;
886
887         /*
888          *      Find the ACPI/PM base I/O address which is the base
889          *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
890          *      ACPIBASE is bits [15:7] from 0x40-0x43
891          */
892         pci_read_config_dword(pdev, 0x40, &base_address);
893         base_address &= 0x0000ff80;
894         if (base_address == 0x00000000) {
895                 /* Something's wrong here, ACPIBASE has to be set */
896                 printk(KERN_ERR PFX "failed to get TCOBASE address, "
897                                         "device disabled by hardware/BIOS\n");
898                 return -ENODEV;
899         }
900         iTCO_wdt_private.iTCO_version =
901                         iTCO_chipset_info[ent->driver_data].iTCO_version;
902         iTCO_wdt_private.ACPIBASE = base_address;
903         iTCO_wdt_private.pdev = pdev;
904
905         /* Get the Memory-Mapped GCS register, we need it for the
906            NO_REBOOT flag (TCO v2). To get access to it you have to
907            read RCBA from PCI Config space 0xf0 and use it as base.
908            GCS = RCBA + ICH6_GCS(0x3410). */
909         if (iTCO_wdt_private.iTCO_version == 2) {
910                 pci_read_config_dword(pdev, 0xf0, &base_address);
911                 if ((base_address & 1) == 0) {
912                         printk(KERN_ERR PFX "RCBA is disabled by hardware"
913                                                 "/BIOS, device disabled\n");
914                         ret = -ENODEV;
915                         goto out;
916                 }
917                 RCBA = base_address & 0xffffc000;
918                 iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
919         }
920
921         /* Check chipset's NO_REBOOT bit */
922         if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
923                 printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
924                                         "device disabled by hardware/BIOS\n");
925                 ret = -ENODEV;  /* Cannot reset NO_REBOOT bit */
926                 goto out_unmap;
927         }
928
929         /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
930         iTCO_wdt_set_NO_REBOOT_bit();
931
932         /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
933         if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
934                 printk(KERN_ERR PFX
935                         "I/O address 0x%04lx already in use, "
936                                                 "device disabled\n", SMI_EN);
937                 ret = -EIO;
938                 goto out_unmap;
939         }
940         /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
941         val32 = inl(SMI_EN);
942         val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
943         outl(val32, SMI_EN);
944
945         /* The TCO I/O registers reside in a 32-byte range pointed to
946            by the TCOBASE value */
947         if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
948                 printk(KERN_ERR PFX "I/O address 0x%04lx already in use "
949                                                 "device disabled\n", TCOBASE);
950                 ret = -EIO;
951                 goto unreg_smi_en;
952         }
953
954         printk(KERN_INFO PFX
955                 "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
956                         iTCO_chipset_info[ent->driver_data].name,
957                         iTCO_chipset_info[ent->driver_data].iTCO_version,
958                         TCOBASE);
959
960         /* Clear out the (probably old) status */
961         outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
962         outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
963         outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
964
965         /* Make sure the watchdog is not running */
966         iTCO_wdt_stop();
967
968         /* Check that the heartbeat value is within it's range;
969            if not reset to the default */
970         if (iTCO_wdt_set_heartbeat(heartbeat)) {
971                 iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
972                 printk(KERN_INFO PFX
973                         "timeout value out of range, using %d\n", heartbeat);
974         }
975
976         ret = misc_register(&iTCO_wdt_miscdev);
977         if (ret != 0) {
978                 printk(KERN_ERR PFX
979                         "cannot register miscdev on minor=%d (err=%d)\n",
980                                                         WATCHDOG_MINOR, ret);
981                 goto unreg_region;
982         }
983
984         printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
985                                                         heartbeat, nowayout);
986
987         return 0;
988
989 unreg_region:
990         release_region(TCOBASE, 0x20);
991 unreg_smi_en:
992         release_region(SMI_EN, 4);
993 out_unmap:
994         if (iTCO_wdt_private.iTCO_version == 2)
995                 iounmap(iTCO_wdt_private.gcs);
996 out:
997         iTCO_wdt_private.ACPIBASE = 0;
998         return ret;
999 }
1000
1001 static void __devexit iTCO_wdt_cleanup(void)
1002 {
1003         /* Stop the timer before we leave */
1004         if (!nowayout)
1005                 iTCO_wdt_stop();
1006
1007         /* Deregister */
1008         misc_deregister(&iTCO_wdt_miscdev);
1009         release_region(TCOBASE, 0x20);
1010         release_region(SMI_EN, 4);
1011         if (iTCO_wdt_private.iTCO_version == 2)
1012                 iounmap(iTCO_wdt_private.gcs);
1013         pci_dev_put(iTCO_wdt_private.pdev);
1014         iTCO_wdt_private.ACPIBASE = 0;
1015 }
1016
1017 static int __devinit iTCO_wdt_probe(struct platform_device *dev)
1018 {
1019         int ret = -ENODEV;
1020         int found = 0;
1021         struct pci_dev *pdev = NULL;
1022         const struct pci_device_id *ent;
1023
1024         spin_lock_init(&iTCO_wdt_private.io_lock);
1025
1026         for_each_pci_dev(pdev) {
1027                 ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
1028                 if (ent) {
1029                         found++;
1030                         ret = iTCO_wdt_init(pdev, ent, dev);
1031                         if (!ret)
1032                                 break;
1033                 }
1034         }
1035
1036         if (!found)
1037                 printk(KERN_INFO PFX "No device detected.\n");
1038
1039         return ret;
1040 }
1041
1042 static int __devexit iTCO_wdt_remove(struct platform_device *dev)
1043 {
1044         if (iTCO_wdt_private.ACPIBASE)
1045                 iTCO_wdt_cleanup();
1046
1047         return 0;
1048 }
1049
1050 static void iTCO_wdt_shutdown(struct platform_device *dev)
1051 {
1052         iTCO_wdt_stop();
1053 }
1054
1055 #define iTCO_wdt_suspend NULL
1056 #define iTCO_wdt_resume  NULL
1057
1058 static struct platform_driver iTCO_wdt_driver = {
1059         .probe          = iTCO_wdt_probe,
1060         .remove         = __devexit_p(iTCO_wdt_remove),
1061         .shutdown       = iTCO_wdt_shutdown,
1062         .suspend        = iTCO_wdt_suspend,
1063         .resume         = iTCO_wdt_resume,
1064         .driver         = {
1065                 .owner  = THIS_MODULE,
1066                 .name   = DRV_NAME,
1067         },
1068 };
1069
1070 static int __init iTCO_wdt_init_module(void)
1071 {
1072         int err;
1073
1074         printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
1075                 DRV_VERSION);
1076
1077         err = platform_driver_register(&iTCO_wdt_driver);
1078         if (err)
1079                 return err;
1080
1081         iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
1082                                                                 -1, NULL, 0);
1083         if (IS_ERR(iTCO_wdt_platform_device)) {
1084                 err = PTR_ERR(iTCO_wdt_platform_device);
1085                 goto unreg_platform_driver;
1086         }
1087
1088         return 0;
1089
1090 unreg_platform_driver:
1091         platform_driver_unregister(&iTCO_wdt_driver);
1092         return err;
1093 }
1094
1095 static void __exit iTCO_wdt_cleanup_module(void)
1096 {
1097         platform_device_unregister(iTCO_wdt_platform_device);
1098         platform_driver_unregister(&iTCO_wdt_driver);
1099         printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
1100 }
1101
1102 module_init(iTCO_wdt_init_module);
1103 module_exit(iTCO_wdt_cleanup_module);
1104
1105 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
1106 MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
1107 MODULE_VERSION(DRV_VERSION);
1108 MODULE_LICENSE("GPL");
1109 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);