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