]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pci/viapm.c
This commit was generated by cvs2svn to compensate for changes in r163820,
[FreeBSD/FreeBSD.git] / sys / pci / viapm.c
1 /*-
2  * Copyright (c) 2001 Alcove - Nicolas Souchu
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include "opt_isa.h"
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/uio.h>
38
39 #include <machine/bus.h>
40 #include <machine/resource.h>
41 #include <sys/rman.h>
42
43 #ifdef DEV_ISA
44 #include <isa/isavar.h>
45 #include <isa/isa_common.h>
46 #endif
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/pcireg.h>
49
50 #include <dev/iicbus/iiconf.h>
51
52 #include <dev/smbus/smbconf.h>
53
54 #include "iicbb_if.h"
55 #include "smbus_if.h"
56
57 #define VIAPM_DEBUG(x)  if (viapm_debug) (x)
58
59 #ifdef DEBUG
60 static int viapm_debug = 1;
61 #else
62 static int viapm_debug = 0;
63 #endif
64
65 #define VIA_586B_PMU_ID         0x30401106
66 #define VIA_596A_PMU_ID         0x30501106
67 #define VIA_596B_PMU_ID         0x30511106
68 #define VIA_686A_PMU_ID         0x30571106
69 #define VIA_8233_PMU_ID         0x30741106
70 #define VIA_8233A_PMU_ID        0x31471106
71 #define VIA_8235_PMU_ID         0x31771106
72
73 #define VIAPM_INB(port) \
74         ((u_char)bus_space_read_1(viapm->st, viapm->sh, port))
75 #define VIAPM_OUTB(port,val) \
76         (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)(val)))
77
78 #define VIAPM_TYP_UNKNOWN       0
79 #define VIAPM_TYP_586B_3040E    1
80 #define VIAPM_TYP_586B_3040F    2
81 #define VIAPM_TYP_596B          3
82 #define VIAPM_TYP_686A          4
83 #define VIAPM_TYP_8233          5
84
85 struct viapm_softc {
86         int type;
87         u_int32_t base;
88         bus_space_tag_t st;
89         bus_space_handle_t sh;
90         int iorid;
91         int irqrid;
92         struct resource *iores;
93         struct resource *irqres;
94         void *irqih;
95
96         device_t iicbb;
97         device_t smbus;
98 };
99
100 static devclass_t viapm_devclass;
101 static devclass_t viapropm_devclass;
102
103 /*
104  * VT82C586B definitions
105  */
106
107 #define VIAPM_586B_REVID        0x08
108
109 #define VIAPM_586B_3040E_BASE   0x20
110 #define VIAPM_586B_3040E_ACTIV  0x4             /* 16 bits */
111
112 #define VIAPM_586B_3040F_BASE   0x48
113 #define VIAPM_586B_3040F_ACTIV  0x41            /* 8 bits */
114
115 #define VIAPM_586B_OEM_REV_E    0x00
116 #define VIAPM_586B_OEM_REV_F    0x01
117 #define VIAPM_586B_PROD_REV_A   0x10
118
119 #define VIAPM_586B_BA_MASK      0x0000ff00
120
121 #define GPIO_DIR        0x40
122 #define GPIO_VAL        0x42
123 #define EXTSMI_VAL      0x44
124
125 #define VIAPM_SCL       0x02                    /* GPIO1_VAL */
126 #define VIAPM_SDA       0x04                    /* GPIO2_VAL */
127
128 /*
129  * VIAPRO common definitions
130  */
131
132 #define VIAPM_PRO_BA_MASK       0x0000fff0
133 #define VIAPM_PRO_SMBCTRL       0xd2
134 #define VIAPM_PRO_REVID         0xd6
135
136 /*
137  * VT82C686A definitions
138  */
139
140 #define VIAPM_PRO_BASE          0x90
141
142 #define SMBHST                  0x0
143 #define SMBHSL                  0x1
144 #define SMBHCTRL                0x2
145 #define SMBHCMD                 0x3
146 #define SMBHADDR                0x4
147 #define SMBHDATA0               0x5
148 #define SMBHDATA1               0x6
149 #define SMBHBLOCK               0x7
150
151 #define SMBSST                  0x1
152 #define SMBSCTRL                0x8
153 #define SMBSSDWCMD              0x9
154 #define SMBSEVENT               0xa
155 #define SMBSDATA                0xc
156
157 #define SMBHST_RESERVED         0xef    /* reserved bits */
158 #define SMBHST_FAILED           0x10    /* failed bus transaction */
159 #define SMBHST_COLLID           0x08    /* bus collision */
160 #define SMBHST_ERROR            0x04    /* device error */
161 #define SMBHST_INTR             0x02    /* command completed */
162 #define SMBHST_BUSY             0x01    /* host busy */
163
164 #define SMBHCTRL_START          0x40    /* start command */
165 #define SMBHCTRL_PROTO          0x1c    /* command protocol mask */
166 #define SMBHCTRL_QUICK          0x00
167 #define SMBHCTRL_SENDRECV       0x04
168 #define SMBHCTRL_BYTE           0x08
169 #define SMBHCTRL_WORD           0x0c
170 #define SMBHCTRL_BLOCK          0x14
171 #define SMBHCTRL_KILL           0x02    /* stop the current transaction */
172 #define SMBHCTRL_ENABLE         0x01    /* enable interrupts */
173
174 #define SMBSCTRL_ENABLE         0x01    /* enable slave */
175
176
177 /*
178  * VIA8233 definitions
179  */
180
181 #define VIAPM_8233_BASE         0xD0
182
183 static int
184 viapm_586b_probe(device_t dev)
185 {
186         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
187         u_int32_t l;
188         u_int16_t s;
189         u_int8_t c;
190
191         switch (pci_get_devid(dev)) {
192         case VIA_586B_PMU_ID:
193
194                 bzero(viapm, sizeof(struct viapm_softc));
195
196                 l = pci_read_config(dev, VIAPM_586B_REVID, 1);
197                 switch (l) {
198                 case VIAPM_586B_OEM_REV_E:
199                         viapm->type = VIAPM_TYP_586B_3040E;
200                         viapm->iorid = VIAPM_586B_3040E_BASE;
201
202                         /* Activate IO block access */
203                         s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
204                         pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
205                         break;
206
207                 case VIAPM_586B_OEM_REV_F:
208                 case VIAPM_586B_PROD_REV_A:
209                 default:
210                         viapm->type = VIAPM_TYP_586B_3040F;
211                         viapm->iorid = VIAPM_586B_3040F_BASE;
212
213                         /* Activate IO block access */
214                         c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
215                         pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
216                         break;
217                 }
218
219                 viapm->base = pci_read_config(dev, viapm->iorid, 4) &
220                                 VIAPM_586B_BA_MASK;
221
222                 /*
223                  * We have to set the I/O resources by hand because it is
224                  * described outside the viapmope of the traditional maps
225                  */
226                 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
227                                                         viapm->base, 256)) {
228                         device_printf(dev, "could not set bus resource\n");
229                         return ENXIO;
230                 }
231                 device_set_desc(dev, "VIA VT82C586B Power Management Unit");
232                 return (BUS_PROBE_DEFAULT);
233
234         default:
235                 break;
236         }
237
238         return ENXIO;
239 }
240
241
242 static int
243 viapm_pro_probe(device_t dev)
244 {
245         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
246 #ifdef VIAPM_BASE_ADDR
247         u_int32_t l;
248 #endif
249         u_int32_t base_cfgreg;
250         char *desc;
251
252         switch (pci_get_devid(dev)) {
253         case VIA_596A_PMU_ID:
254                 desc = "VIA VT82C596A Power Management Unit";
255                 viapm->type = VIAPM_TYP_596B;
256                 base_cfgreg = VIAPM_PRO_BASE;
257                 goto viapro;
258
259         case VIA_596B_PMU_ID:
260                 desc = "VIA VT82C596B Power Management Unit";
261                 viapm->type = VIAPM_TYP_596B;
262                 base_cfgreg = VIAPM_PRO_BASE;
263                 goto viapro;
264
265         case VIA_686A_PMU_ID:
266                 desc = "VIA VT82C686A Power Management Unit";
267                 viapm->type = VIAPM_TYP_686A;
268                 base_cfgreg = VIAPM_PRO_BASE;
269                 goto viapro;
270
271         case VIA_8233_PMU_ID:
272         case VIA_8233A_PMU_ID:
273                 desc = "VIA VT8233 Power Management Unit";
274                 viapm->type = VIAPM_TYP_UNKNOWN;
275                 base_cfgreg = VIAPM_8233_BASE;
276                 goto viapro;
277
278         case VIA_8235_PMU_ID:
279                 desc = "VIA VT8235 Power Management Unit";
280                 viapm->type = VIAPM_TYP_UNKNOWN;
281                 base_cfgreg = VIAPM_8233_BASE;
282                 goto viapro;
283
284         viapro:
285
286 #ifdef VIAPM_BASE_ADDR
287                 /* force VIAPM I/O base address */
288
289                 /* enable the SMBus controller function */
290                 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
291                 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
292
293                 /* write the base address */
294                 pci_write_config(dev, base_cfgreg,
295                                  VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
296 #endif
297
298                 viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
299
300                 /*
301                  * We have to set the I/O resources by hand because it is
302                  * described outside the viapmope of the traditional maps
303                  */
304                 viapm->iorid = base_cfgreg;
305                 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
306                                      viapm->base, 16)) {
307                         device_printf(dev, "could not set bus resource 0x%x\n",
308                                         viapm->base);
309                         return ENXIO;
310                 }
311
312                 if (1 || bootverbose) {
313                         device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
314                 }
315
316                 device_set_desc(dev, desc);
317                 return (BUS_PROBE_DEFAULT);
318
319         default:
320                 break;
321         }
322
323         return ENXIO;
324 }
325
326 static int
327 viapm_pro_attach(device_t dev)
328 {
329         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
330         u_int32_t l;
331
332         if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
333                 &viapm->iorid, RF_ACTIVE))) {
334                 device_printf(dev, "could not allocate bus space\n");
335                 goto error;
336         }
337         viapm->st = rman_get_bustag(viapm->iores);
338         viapm->sh = rman_get_bushandle(viapm->iores);
339
340 #ifdef notyet
341         /* force irq 9 */
342         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
343         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
344
345         viapm->irqrid = 0;
346         if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
347                                 &viapm->irqrid, 9, 9, 1,
348                                 RF_SHAREABLE | RF_ACTIVE))) {
349                 device_printf(dev, "could not allocate irq\n");
350                 goto error;
351         }
352
353         if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC,
354                         (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
355                 device_printf(dev, "could not setup irq\n");
356                 goto error;
357         }
358 #endif
359
360         if (1 | bootverbose) {
361                 l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
362                 device_printf(dev, "SMBus revision code 0x%x\n", l);
363         }
364
365         viapm->smbus = device_add_child(dev, "smbus", -1);
366
367         /* probe and attach the smbus */
368         bus_generic_attach(dev);
369
370         /* disable slave function */
371         VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
372
373         /* enable the SMBus controller function */
374         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
375         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
376
377 #ifdef notyet
378         /* enable interrupts */
379         VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
380 #endif
381
382 #ifdef DEV_ISA
383         /* If this device is a PCI-ISA bridge, then attach an ISA bus. */
384         if ((pci_get_class(dev) == PCIC_BRIDGE) &&
385             (pci_get_subclass(dev) == PCIS_BRIDGE_ISA))
386                 isab_attach(dev);
387 #endif
388         return 0;
389
390 error:
391         if (viapm->iores)
392                 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
393 #ifdef notyet
394         if (viapm->irqres)
395                 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
396 #endif
397
398         return ENXIO;
399 }
400
401 static int
402 viapm_586b_attach(device_t dev)
403 {
404         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
405         
406         if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
407                 &viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) {
408                 device_printf(dev, "could not allocate bus resource\n");
409                 return ENXIO;
410         }
411         viapm->st = rman_get_bustag(viapm->iores);
412         viapm->sh = rman_get_bushandle(viapm->iores);
413
414         VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
415
416         /* add generic bit-banging code */
417         if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
418                 goto error;
419
420         bus_generic_attach(dev);
421
422         return 0;
423
424 error:
425         if (viapm->iores)
426                 bus_release_resource(dev, SYS_RES_IOPORT,
427                                         viapm->iorid, viapm->iores);
428         return ENXIO;
429 }
430
431 static int
432 viapm_586b_detach(device_t dev)
433 {
434         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
435         int error;
436
437         bus_generic_detach(dev);
438         if (viapm->iicbb) {
439                 device_delete_child(dev, viapm->iicbb);
440         }
441
442         if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT,
443                                                 viapm->iorid, viapm->iores)))
444                 return (error);
445
446         return 0;
447 }
448
449 static int
450 viapm_pro_detach(device_t dev)
451 {
452         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
453         int error;
454
455         bus_generic_detach(dev);
456         if (viapm->smbus) {
457                 device_delete_child(dev, viapm->smbus);
458         }
459
460         if ((error = bus_release_resource(dev, SYS_RES_IOPORT,
461                                 viapm->iorid, viapm->iores)))
462                 return (error);
463
464 #ifdef notyet
465         if ((error = bus_release_resource(dev, SYS_RES_IRQ,
466                                         viapm->irqrid, viapm->irqres))
467                 return (error);
468 #endif
469
470         return 0;
471 }
472
473 static int
474 viabb_callback(device_t dev, int index, caddr_t *data)
475 {
476         return 0;
477 }
478
479 static void
480 viabb_setscl(device_t dev, int ctrl)
481 {
482         struct viapm_softc *viapm = device_get_softc(dev);
483         u_char val;
484
485         val = VIAPM_INB(GPIO_VAL);
486
487         if (ctrl)
488                 val |= VIAPM_SCL;
489         else
490                 val &= ~VIAPM_SCL;
491
492         VIAPM_OUTB(GPIO_VAL, val);
493
494         return;
495 }
496
497 static void
498 viabb_setsda(device_t dev, int data)
499 {
500         struct viapm_softc *viapm = device_get_softc(dev);
501         u_char val;
502
503         val = VIAPM_INB(GPIO_VAL);
504
505         if (data)
506                 val |= VIAPM_SDA;
507         else
508                 val &= ~VIAPM_SDA;
509
510         VIAPM_OUTB(GPIO_VAL, val);
511
512         return;
513 }
514         
515 static int
516 viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
517 {
518         /* reset bus */
519         viabb_setsda(dev, 1);
520         viabb_setscl(dev, 1);
521
522         return (IIC_ENOADDR);
523 }
524
525 static int
526 viabb_getscl(device_t dev)
527 {
528         struct viapm_softc *viapm = device_get_softc(dev);
529
530         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0);
531 }
532
533 static int
534 viabb_getsda(device_t dev)
535 {
536         struct viapm_softc *viapm = device_get_softc(dev);
537
538         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0);
539 }
540
541 static int
542 viapm_abort(struct viapm_softc *viapm)
543 {
544         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
545         DELAY(10);
546
547         return (0);
548 }
549
550 static int
551 viapm_clear(struct viapm_softc *viapm)
552 {
553         VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
554                 SMBHST_ERROR | SMBHST_INTR);
555         DELAY(10);
556
557         return (0);
558 }
559
560 static int
561 viapm_busy(struct viapm_softc *viapm)
562 {
563         u_char sts;
564
565         sts = VIAPM_INB(SMBHST);
566
567         VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
568
569         return (sts & SMBHST_BUSY);
570 }
571
572 /*
573  * Poll the SMBus controller
574  */
575 static int
576 viapm_wait(struct viapm_softc *viapm)
577 {
578         int count = 10000;
579         u_char sts = 0;
580         int error;
581
582         /* wait for command to complete and SMBus controller is idle */
583         while(count--) {
584                 DELAY(10);
585                 sts = VIAPM_INB(SMBHST);
586
587                 /* check if the controller is processing a command */
588                 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
589                         break;
590         }
591
592         VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
593
594         error = SMB_ENOERR;
595
596         if (!count)
597                 error |= SMB_ETIMEOUT;
598
599         if (sts & SMBHST_FAILED)
600                 error |= SMB_EABORT;
601
602         if (sts & SMBHST_COLLID)
603                 error |= SMB_ENOACK;
604
605         if (sts & SMBHST_ERROR)
606                 error |= SMB_EBUSERR;
607
608         if (error != SMB_ENOERR)
609                 viapm_abort(viapm);
610
611         viapm_clear(viapm);
612
613         return (error);
614 }
615
616 static int
617 viasmb_callback(device_t dev, int index, caddr_t *data)
618 {
619         int error = 0;
620
621         switch (index) {
622         case SMB_REQUEST_BUS:
623         case SMB_RELEASE_BUS:
624                 /* ok, bus allocation accepted */
625                 break;
626         default:
627                 error = EINVAL;
628         }
629
630         return (error);
631 }
632
633 static int
634 viasmb_quick(device_t dev, u_char slave, int how)
635 {
636         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
637         int error;
638
639         viapm_clear(viapm);
640         if (viapm_busy(viapm))
641                 return (SMB_EBUSY);
642
643         switch (how) {
644         case SMB_QWRITE:
645                 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
646                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
647                 break;
648         case SMB_QREAD:
649                 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
650                 VIAPM_OUTB(SMBHADDR, slave | LSB);
651                 break;
652         default:
653                 panic("%s: unknown QUICK command (%x)!", __func__, how);
654         }
655
656         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
657
658         error = viapm_wait(viapm);
659
660         return (error);
661 }
662
663 static int
664 viasmb_sendb(device_t dev, u_char slave, char byte)
665 {
666         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
667         int error;
668
669         viapm_clear(viapm);
670         if (viapm_busy(viapm))
671                 return (SMB_EBUSY);
672
673         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
674         VIAPM_OUTB(SMBHCMD, byte);
675
676         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
677
678         error = viapm_wait(viapm);
679
680         VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
681
682         return (error);
683 }
684
685 static int
686 viasmb_recvb(device_t dev, u_char slave, char *byte)
687 {
688         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
689         int error;
690
691         viapm_clear(viapm);
692         if (viapm_busy(viapm))
693                 return (SMB_EBUSY);
694
695         VIAPM_OUTB(SMBHADDR, slave | LSB);
696
697         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
698
699         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
700                 *byte = VIAPM_INB(SMBHDATA0);
701
702         VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
703
704         return (error);
705 }
706
707 static int
708 viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
709 {
710         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
711         int error;
712
713         viapm_clear(viapm);
714         if (viapm_busy(viapm))
715                 return (SMB_EBUSY);
716
717         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
718         VIAPM_OUTB(SMBHCMD, cmd);
719         VIAPM_OUTB(SMBHDATA0, byte);
720
721         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
722
723         error = viapm_wait(viapm);
724
725         VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
726
727         return (error);
728 }
729
730 static int
731 viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
732 {
733         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
734         int error;
735
736         viapm_clear(viapm);
737         if (viapm_busy(viapm))
738                 return (SMB_EBUSY);
739
740         VIAPM_OUTB(SMBHADDR, slave | LSB);
741         VIAPM_OUTB(SMBHCMD, cmd);
742
743         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
744
745         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
746                 *byte = VIAPM_INB(SMBHDATA0);
747
748         VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
749
750         return (error);
751 }
752
753 static int
754 viasmb_writew(device_t dev, u_char slave, char cmd, short word)
755 {
756         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
757         int error;
758
759         viapm_clear(viapm);
760         if (viapm_busy(viapm))
761                 return (SMB_EBUSY);
762
763         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
764         VIAPM_OUTB(SMBHCMD, cmd);
765         VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
766         VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
767
768         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
769
770         error = viapm_wait(viapm);
771
772         VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
773
774         return (error);
775 }
776
777 static int
778 viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
779 {
780         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
781         int error;
782         u_char high, low;
783
784         viapm_clear(viapm);
785         if (viapm_busy(viapm))
786                 return (SMB_EBUSY);
787
788         VIAPM_OUTB(SMBHADDR, slave | LSB);
789         VIAPM_OUTB(SMBHCMD, cmd);
790
791         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
792
793         if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
794                 low = VIAPM_INB(SMBHDATA0);
795                 high = VIAPM_INB(SMBHDATA1);
796
797                 *word = ((high & 0xff) << 8) | (low & 0xff);
798         }
799
800         VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
801
802         return (error);
803 }
804
805 static int
806 viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
807 {
808         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
809         u_char i;
810         int error;
811
812         if (count < 1 || count > 32)
813                 return (SMB_EINVAL);
814
815         viapm_clear(viapm);
816         if (viapm_busy(viapm))
817                 return (SMB_EBUSY);
818
819         VIAPM_OUTB(SMBHADDR, slave & ~LSB);
820         VIAPM_OUTB(SMBHCMD, cmd);
821         VIAPM_OUTB(SMBHDATA0, count);
822         i = VIAPM_INB(SMBHCTRL);
823
824         /* fill the 32-byte internal buffer */
825         for (i = 0; i < count; i++) {
826                 VIAPM_OUTB(SMBHBLOCK, buf[i]);
827                 DELAY(2);
828         }
829         VIAPM_OUTB(SMBHCMD, cmd);
830         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
831
832         error = viapm_wait(viapm);
833
834         VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
835
836         return (error);
837
838 }
839
840 static int
841 viasmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
842 {
843         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
844         u_char data, len, i;
845         int error;
846
847         if (*count < 1 || *count > 32)
848                 return (SMB_EINVAL);
849
850         viapm_clear(viapm);
851         if (viapm_busy(viapm))
852                 return (SMB_EBUSY);
853
854         VIAPM_OUTB(SMBHADDR, slave | LSB);
855         VIAPM_OUTB(SMBHCMD, cmd);
856         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
857
858         if ((error = viapm_wait(viapm)) != SMB_ENOERR)
859                 goto error;
860
861         len = VIAPM_INB(SMBHDATA0);
862         i = VIAPM_INB(SMBHCTRL);                /* reset counter */
863
864         /* read the 32-byte internal buffer */
865         for (i = 0; i < len; i++) {
866                 data = VIAPM_INB(SMBHBLOCK);
867                 if (i < *count)
868                         buf[i] = data;
869                 DELAY(2);
870         }
871         *count = len;
872
873 error:
874         VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
875
876         return (error);
877 }
878
879 static device_method_t viapm_methods[] = {
880         /* device interface */
881         DEVMETHOD(device_probe,         viapm_586b_probe),
882         DEVMETHOD(device_attach,        viapm_586b_attach),
883         DEVMETHOD(device_detach,        viapm_586b_detach),
884
885         /* iicbb interface */
886         DEVMETHOD(iicbb_callback,       viabb_callback),
887         DEVMETHOD(iicbb_setscl,         viabb_setscl),
888         DEVMETHOD(iicbb_setsda,         viabb_setsda),
889         DEVMETHOD(iicbb_getscl,         viabb_getscl),
890         DEVMETHOD(iicbb_getsda,         viabb_getsda),
891         DEVMETHOD(iicbb_reset,          viabb_reset),
892
893         /* Bus interface */
894         DEVMETHOD(bus_print_child,      bus_generic_print_child),
895         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
896         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
897         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
898         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
899         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
900         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
901
902         { 0, 0 }
903 };
904
905 static driver_t viapm_driver = {
906         "viapm",
907         viapm_methods,
908         sizeof(struct viapm_softc),
909 };
910
911 static device_method_t viapropm_methods[] = {
912         /* device interface */
913         DEVMETHOD(device_probe,         viapm_pro_probe),
914         DEVMETHOD(device_attach,        viapm_pro_attach),
915         DEVMETHOD(device_detach,        viapm_pro_detach),
916
917         /* smbus interface */
918         DEVMETHOD(smbus_callback,       viasmb_callback),
919         DEVMETHOD(smbus_quick,          viasmb_quick),
920         DEVMETHOD(smbus_sendb,          viasmb_sendb),
921         DEVMETHOD(smbus_recvb,          viasmb_recvb),
922         DEVMETHOD(smbus_writeb,         viasmb_writeb),
923         DEVMETHOD(smbus_readb,          viasmb_readb),
924         DEVMETHOD(smbus_writew,         viasmb_writew),
925         DEVMETHOD(smbus_readw,          viasmb_readw),
926         DEVMETHOD(smbus_bwrite,         viasmb_bwrite),
927         DEVMETHOD(smbus_bread,          viasmb_bread),
928         
929         /* Bus interface */
930         DEVMETHOD(bus_print_child,      bus_generic_print_child),
931         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
932         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
933         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
934         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
935         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
936         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
937
938         { 0, 0 }
939 };
940
941 static driver_t viapropm_driver = {
942         "viapropm",
943         viapropm_methods,
944         sizeof(struct viapm_softc),
945 };
946
947 DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
948 DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
949 DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0);
950
951 MODULE_DEPEND(viapm, pci, 1, 1, 1);
952 MODULE_DEPEND(viapropm, pci, 1, 1, 1);
953 MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
954 MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
955 MODULE_VERSION(viapm, 1);
956
957 #ifdef DEV_ISA
958 DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0);
959 DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0);
960 MODULE_DEPEND(viapm, isa, 1, 1, 1);
961 MODULE_DEPEND(viapropm, isa, 1, 1, 1);
962 #endif