intpm.c revision 48528
1/*-
2 * Copyright (c) 1998, 1999 Takanori Watanabe
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 *	$Id: intpm.c,v 1.10 1999/05/09 09:56:43 phk Exp $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
32#include <machine/bus_pio.h>
33#include <machine/bus_memio.h>
34#include <machine/bus.h>
35
36#include <machine/clock.h>
37#include <sys/uio.h>
38#include <sys/module.h>
39#include <sys/bus.h>
40#include <sys/conf.h>
41#include <sys/malloc.h>
42#include <sys/buf.h>
43#include <sys/rman.h>
44#include <machine/resource.h>
45#include <dev/smbus/smbconf.h>
46
47#include "smbus_if.h"
48
49/*This should be removed if force_pci_map_int supported*/
50#include <sys/interrupt.h>
51
52#include <pci/pcireg.h>
53#include <pci/pcivar.h>
54#include <pci/intpmreg.h>
55
56#include "opt_intpm.h"
57
58static struct _pcsid
59{
60        pcidi_t type;
61	char	*desc;
62} pci_ids[] =
63{
64	{ 0x71138086,"Intel 82371AB Power management controller"},
65
66	{ 0x00000000,	NULL					}
67};
68static int intsmb_probe(device_t);
69static int intsmb_attach(device_t);
70static void intsmb_print_child(device_t, device_t);
71
72static int intsmb_intr(device_t dev);
73static int intsmb_slvintr(device_t dev);
74static void  intsmb_alrintr(device_t dev);
75static int intsmb_callback(device_t dev, int index, caddr_t data);
76static int intsmb_quick(device_t dev, u_char slave, int how);
77static int intsmb_sendb(device_t dev, u_char slave, char byte);
78static int intsmb_recvb(device_t dev, u_char slave, char *byte);
79static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
80static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
81static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
82static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
83static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
84static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
85static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
86static void intsmb_start(device_t dev,u_char cmd,int nointr);
87static int intsmb_stop(device_t dev);
88static int intsmb_stop_poll(device_t dev);
89static int intsmb_free(device_t dev);
90static int intpm_probe (device_t dev);
91static int intpm_attach (device_t dev);
92static devclass_t intsmb_devclass;
93
94static device_method_t intpm_methods[]={
95        DEVMETHOD(device_probe,intsmb_probe),
96        DEVMETHOD(device_attach,intsmb_attach),
97
98        DEVMETHOD(bus_print_child, intsmb_print_child),
99
100        DEVMETHOD(smbus_callback,intsmb_callback),
101        DEVMETHOD(smbus_quick,intsmb_quick),
102        DEVMETHOD(smbus_sendb,intsmb_sendb),
103        DEVMETHOD(smbus_recvb,intsmb_recvb),
104        DEVMETHOD(smbus_writeb,intsmb_writeb),
105        DEVMETHOD(smbus_writew,intsmb_writew),
106        DEVMETHOD(smbus_readb,intsmb_readb),
107        DEVMETHOD(smbus_readw,intsmb_readw),
108        DEVMETHOD(smbus_pcall,intsmb_pcall),
109        DEVMETHOD(smbus_bwrite,intsmb_bwrite),
110        DEVMETHOD(smbus_bread,intsmb_bread),
111        {0,0}
112};
113
114struct intpm_pci_softc{
115        bus_space_tag_t smbst;
116        bus_space_handle_t smbsh;
117	bus_space_tag_t pmst;
118	bus_space_handle_t pmsh;
119        pcici_t cfg;
120	device_t  smbus;
121};
122
123
124struct intsmb_softc{
125        struct intpm_pci_softc *pci_sc;
126        bus_space_tag_t st;
127        bus_space_handle_t sh;
128        device_t smbus;
129        int isbusy;
130};
131
132static driver_t intpm_driver = {
133        "intsmb",
134        intpm_methods,
135        sizeof(struct intsmb_softc),
136};
137
138static devclass_t intpm_devclass;
139static device_method_t intpm_pci_methods[] = {
140  DEVMETHOD(device_probe,intpm_probe),
141  DEVMETHOD(device_attach,intpm_attach),
142  {0,0}
143};
144static driver_t intpm_pci_driver = {
145  "intpm",
146  intpm_pci_methods,
147  sizeof(struct intpm_pci_softc)
148};
149
150static int
151intsmb_probe(device_t dev)
152{
153        struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
154        sc->smbus=smbus_alloc_bus(dev);
155        if (!sc->smbus)
156                return (EINVAL);    /* XXX don't know what to return else */
157        device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
158
159        return (0);          /* XXX don't know what to return else */
160}
161static int
162intsmb_attach(device_t dev)
163{
164        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
165        sc->pci_sc=device_get_softc(device_get_parent(dev));
166        sc->isbusy=0;
167	sc->sh=sc->pci_sc->smbsh;
168	sc->st=sc->pci_sc->smbst;
169	sc->pci_sc->smbus=dev;
170        device_probe_and_attach(sc->smbus);
171#ifdef ENABLE_ALART
172	/*Enable Arart*/
173	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
174			  PIIX4_SMBSLVCNT_ALTEN);
175#endif
176        return (0);
177}
178
179static void
180intsmb_print_child(device_t bus, device_t dev)
181{
182	printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
183	return;
184}
185static int
186intsmb_callback(device_t dev, int index, caddr_t data)
187{
188	int error = 0;
189	intrmask_t s;
190	s=splnet();
191	switch (index) {
192	case SMB_REQUEST_BUS:
193		break;
194	case SMB_RELEASE_BUS:
195		break;
196	default:
197		error = EINVAL;
198	}
199	splx(s);
200	return (error);
201}
202/*counterpart of smbtx_smb_free*/
203static        int
204intsmb_free(device_t dev){
205        intrmask_t s;
206        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
207        if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
208	    PIIX4_SMBHSTSTAT_BUSY)
209#ifdef ENABLE_ALART
210	   ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
211	      PIIX4_SMBSLVSTS_BUSY)
212#endif
213	   || sc->isbusy)
214                return EBUSY;
215	s=splhigh();
216        sc->isbusy=1;
217	/*Disable Intrrupt in slave part*/
218#ifndef ENABLE_ALART
219	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
220#endif
221        /*Reset INTR Flag to prepare INTR*/
222	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
223			  (PIIX4_SMBHSTSTAT_INTR|
224			   PIIX4_SMBHSTSTAT_ERR|
225			   PIIX4_SMBHSTSTAT_BUSC|
226			   PIIX4_SMBHSTSTAT_FAIL)
227		);
228	splx(s);
229        return 0;
230}
231
232static int
233intsmb_intr(device_t dev)
234{
235	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
236	int status;
237	status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
238	if(status&PIIX4_SMBHSTSTAT_BUSY){
239		return 1;
240
241	}
242	if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR|
243				PIIX4_SMBHSTSTAT_ERR|
244				PIIX4_SMBHSTSTAT_BUSC|
245				PIIX4_SMBHSTSTAT_FAIL))){
246		int tmp;
247		sc->isbusy=0;
248		tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
249		bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
250				  tmp&~PIIX4_SMBHSTCNT_INTREN);
251		wakeup(sc);
252		return 0;
253	}
254	return 1;/* Not Completed*/
255}
256static int
257intsmb_slvintr(device_t dev)
258{
259	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
260        int status,retval;
261	retval=1;
262        status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
263	if(status&PIIX4_SMBSLVSTS_BUSY)
264		return retval;
265	if(status&PIIX4_SMBSLVSTS_ALART){
266		intsmb_alrintr(dev);
267		retval=0;
268	}else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
269			  |PIIX4_SMBSLVSTS_SDW1)){
270		retval=0;
271	}
272	/*Reset Status Register*/
273	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
274			  PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
275			  PIIX4_SMBSLVSTS_SLV);
276	return retval;
277}
278
279static void intsmb_alrintr(device_t dev)
280{
281	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
282	int slvcnt;
283#ifdef ENABLE_ALART
284	int error;
285#endif
286
287	/*stop generating INTR from ALART*/
288	slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
289#ifdef ENABLE_ALART
290	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
291			  slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
292#endif
293	DELAY(5);
294	/*ask bus who assert it and then ask it what's the matter. */
295#ifdef ENABLE_ALART
296	error=intsmb_free(dev);
297	if(!error){
298                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
299                                  |LSB);
300		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
301		if(!(error=intsmb_stop_poll(dev))){
302			volatile u_int8_t *addr;
303			addr=bus_space_read_1(sc->st,sc->sh,
304					      PIIX4_SMBHSTDAT0);
305			printf("ALART_RESPONSE: %p\n", addr);
306		}
307	}else{
308	        printf("ERROR\n");
309	}
310
311	/*Re-enable INTR from ALART*/
312	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
313			  slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
314	DELAY(5);
315#endif
316
317	return;
318}
319static void
320intsmb_start(device_t dev,unsigned char cmd,int nointr)
321{
322	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
323	unsigned char tmp;
324	tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
325	tmp&= 0xe0;
326	tmp |= cmd;
327	tmp |=PIIX4_SMBHSTCNT_START;
328	/*While not in autoconfiguration Intrrupt Enabled*/
329	if(!cold||!nointr)
330		tmp |=PIIX4_SMBHSTCNT_INTREN;
331	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
332}
333
334/*Polling Code. Polling is not encouraged
335 * because It is required to wait for the device get busy.
336 *(29063505.pdf from Intel)
337 * But during boot,intrrupt cannot be used.
338 * so use polling code while in autoconfiguration.
339 */
340
341static        int
342intsmb_stop_poll(device_t dev){
343        int error,i;
344        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
345	/*
346	 *  In smbtx driver ,Simply waiting.
347	 *  This loops 100-200 times.
348	 */
349	for(i=0;i<0x7fff;i++){
350                if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
351		    &PIIX4_SMBHSTSTAT_BUSY)){
352                        break;
353                }
354	}
355	for(i=0;i<0x7fff;i++){
356		int status;
357		status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
358		if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
359			sc->isbusy=0;
360			error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
361				(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
362				(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
363			if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
364				printf("unknown cause why?");
365			}
366			return error;
367		}
368	}
369	sc->isbusy=0;
370	return EIO;
371}
372/*
373 *wait for completion and return result.
374 */
375static        int
376intsmb_stop(device_t dev){
377        int error;
378	intrmask_t s;
379        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
380	if(cold){
381		/*So that it can use device during probing device on SMBus.*/
382		error=intsmb_stop_poll(dev);
383		return error;
384	}else{
385		if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
386			int status;
387			status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
388			if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
389				error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
390					(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
391					(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
392				if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
393					printf("intsmb%d:unknown cause why?\n",
394					       device_get_unit(dev));
395				}
396#ifdef ENABLE_ALART
397				bus_space_write_1(sc->st,sc->sh,
398						  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
399#endif
400				return error;
401			}
402		}
403	}
404	/*Timeout Procedure*/
405	s=splhigh();
406	sc->isbusy=0;
407	/*Re-enable supressed intrrupt from slave part*/
408	bus_space_write_1(sc->st,sc->sh,
409			  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
410	splx(s);
411        return EIO;
412}
413
414static int
415intsmb_quick(device_t dev, u_char slave, int how)
416{
417        int error=0;
418        u_char data;
419        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
420        data=slave;
421	/*Quick command is part of Address, I think*/
422        switch(how){
423        case SMB_QWRITE:
424                data&=~LSB;
425		break;
426        case SMB_QREAD:
427                data|=LSB;
428                break;
429        default:
430                error=EINVAL;
431        }
432        if(!error){
433	        error=intsmb_free(dev);
434                if(!error){
435                        bus_space_write_1(sc->st,sc->sh,
436					  PIIX4_SMBHSTADD,data);
437			intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
438                        error=intsmb_stop(dev);
439                }
440        }
441
442        return (error);
443}
444
445static int
446intsmb_sendb(device_t dev, u_char slave, char byte)
447{
448        int error;
449        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
450        error=intsmb_free(dev);
451        if(!error){
452                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
453                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
454		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
455                error=intsmb_stop(dev);
456        }
457        return (error);
458}
459static int
460intsmb_recvb(device_t dev, u_char slave, char *byte)
461{
462        int error;
463        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
464        error=intsmb_free(dev);
465        if(!error){
466                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
467				  |LSB);
468                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
469                if(!(error=intsmb_stop(dev))){
470#ifdef RECV_IS_IN_CMD
471		        /*Linux SMBus stuff also troubles
472			  Because Intel's datasheet will not make clear.
473			 */
474                        *byte=bus_space_read_1(sc->st,sc->sh,
475					       PIIX4_SMBHSTCMD);
476#else
477                        *byte=bus_space_read_1(sc->st,sc->sh,
478					       PIIX4_SMBHSTDAT0);
479#endif
480                }
481        }
482        return (error);
483}
484static int
485intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
486{
487        int error;
488        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
489        error=intsmb_free(dev);
490        if(!error){
491                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
492                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
493                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
494		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
495                error=intsmb_stop(dev);
496        }
497        return (error);
498}
499static int
500intsmb_writew(device_t dev, u_char slave, char cmd, short word)
501{
502        int error;
503        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
504        error=intsmb_free(dev);
505        if(!error){
506                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
507                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
508                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
509				  word&0xff);
510                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
511				  (word>>8)&0xff);
512		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
513                error=intsmb_stop(dev);
514        }
515        return (error);
516}
517
518static int
519intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
520{
521        int error;
522        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
523        error=intsmb_free(dev);
524        if(!error){
525                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
526                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
527		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
528                if(!(error=intsmb_stop(dev))){
529		        *byte=bus_space_read_1(sc->st,sc->sh,
530					       PIIX4_SMBHSTDAT0);
531                }
532        }
533        return (error);
534}
535static int
536intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
537{
538        int error;
539        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
540        error=intsmb_free(dev);
541        if(!error){
542                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
543                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
544		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
545                if(!(error=intsmb_stop(dev))){
546                        *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
547                        *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
548                }
549        }
550        return (error);
551}
552/*
553 * Data sheet claims that it implements all function, but also claims
554 * that it implements 7 function and not mention PCALL. So I don't know
555 * whether it will work.
556 */
557static int
558intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
559{
560#ifdef PROCCALL_TEST
561        int error;
562        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
563        error=intsmb_free(dev);
564        if(!error){
565                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
566                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
567                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
568                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
569                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
570        }
571        if(!(error=intsmb_stop(dev))){
572                *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
573                *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
574        }
575        return error;
576#else
577	return 0;
578#endif
579}
580static int
581intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
582{
583        int error,i;
584        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
585        error=intsmb_free(dev);
586        if(count>SMBBLOCKTRANS_MAX||count==0)
587                error=EINVAL;
588        if(!error){
589                /*Reset internal array index*/
590                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
591
592                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
593                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
594                for(i=0;i<count;i++){
595                        bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
596                }
597                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
598                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
599                error=intsmb_stop(dev);
600        }
601        return (error);
602}
603
604static int
605intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
606{
607        int error,i;
608        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
609        error=intsmb_free(dev);
610        if(count>SMBBLOCKTRANS_MAX||count==0)
611                error=EINVAL;
612        if(!error){
613                /*Reset internal array index*/
614                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
615
616                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
617                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
618                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
619                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
620                error=intsmb_stop(dev);
621                if(!error){
622                        bzero(buf,count);/*Is it needed?*/
623                        count= bus_space_read_1(sc->st,sc->sh,
624						PIIX4_SMBHSTDAT0);
625                        if(count!=0&&count<=SMBBLOCKTRANS_MAX){
626			        for(i=0;i<count;i++){
627				        buf[i]=bus_space_read_1(sc->st,
628								sc->sh,
629								PIIX4_SMBBLKDAT);
630				}
631			}
632                        else{
633				error=EIO;
634                        }
635		}
636	}
637        return (error);
638}
639
640DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
641
642
643static void intpm_intr __P((void *arg));
644static int
645intpm_attach(device_t dev)
646{
647        int value;
648        int unit=device_get_unit(dev);
649	void *ih;
650	int error;
651        char * str;
652        {
653                struct intpm_pci_softc *sciic;
654                device_t smbinterface;
655		int rid;
656		struct resource *res;
657
658                sciic=device_get_softc(dev);
659                if(sciic==NULL){
660                        return ENOMEM;
661                }
662
663		rid=PCI_BASE_ADDR_SMB;
664#if 0
665		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
666				       0,~0,1,RF_ACTIVE);
667		if(res==NULL){
668		  device_printf(dev,"IO FAILED Trying Memory\n");
669		  res=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0,
670					 1,RF_ACTIVE);
671		}
672#else
673		/*Do as I tell!*/
674		value=pci_read_config(dev,rid,4);
675		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,value&(~1),
676				       (value&(~1))+256,256,RF_ACTIVE);
677#endif
678		if(res==NULL){
679		  device_printf(dev,"Could not allocate Bus space\n");
680		  return ENXIO;
681		}
682		sciic->smbst=rman_get_bustag(res);
683		sciic->smbsh=rman_get_bushandle(res);
684
685		device_printf(dev,"%s %x\n",
686			      (sciic->smbst==I386_BUS_SPACE_IO)?
687			      "I/O mapped":"Memory",
688			      sciic->smbsh);
689
690
691#ifndef NO_CHANGE_PCICONF
692		pci_write_config(dev,PCIR_INTLINE,0x9,1);
693		pci_write_config(dev,PCI_HST_CFG_SMB,
694				 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
695#endif
696                value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
697                switch(value&0xe){
698                case PCI_INTR_SMB_SMI:
699		        str="SMI";
700                        break;
701                case PCI_INTR_SMB_IRQ9:
702                        str="IRQ 9";
703                        break;
704                default:
705                        str="BOGUS";
706                }
707                device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
708                value=pci_read_config(dev,PCI_REVID_SMB,1);
709                printf("revision %d\n",value);
710                /*
711                 * Install intr HANDLER here
712                 */
713		rid=0;
714		res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
715		if(res==NULL){
716		  device_printf(dev,"could not allocate irq");
717		  return ENOMEM;
718		}
719		error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
720                if(error){
721                        device_printf(dev,"Failed to map intr\n");
722			return error;
723                }
724                smbinterface=device_add_child(dev,"intsmb",unit,NULL);
725		if(!smbinterface){
726		     printf("intsmb%d:could not add SMBus device\n",unit);
727		}
728                device_probe_and_attach(smbinterface);
729        }
730
731        value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
732        printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
733        return 0;
734}
735static int
736intpm_probe(device_t dev)
737{
738    struct _pcsid *ep =pci_ids;
739    u_int32_t device_id=pci_get_devid(dev);
740    while (ep->type && ep->type != device_id)
741	  ++ep;
742    if(ep->desc!=NULL){
743      device_set_desc(dev,ep->desc);
744      return 0;
745    }else{
746      return ENXIO;
747    }
748}
749DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
750
751static void intpm_intr(void *arg)
752{
753        struct intpm_pci_softc *sc;
754        sc=(struct intpm_pci_softc *)arg;
755	intsmb_intr(sc->smbus);
756	intsmb_slvintr(sc->smbus);
757}
758