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