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 * $FreeBSD: releng/5.1/sys/pci/intpm.c 111547 2003-02-26 13:46:40Z nyan $
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 <sys/uio.h>
37 #include <sys/module.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41 #include <dev/smbus/smbconf.h>
42
43 #include "smbus_if.h"
44
45 /*This should be removed if force_pci_map_int supported*/
46 #include <sys/interrupt.h>
47
48 #include <pci/pcireg.h>
49 #include <pci/pcivar.h>
50 #include <pci/intpmreg.h>
51
52 #include "opt_intpm.h"
53
54 static struct _pcsid
55 {
56 u_int32_t type;
57 char *desc;
58 } pci_ids[] =
59 {
60 { 0x71138086,"Intel 82371AB Power management controller"},
61 { 0x719b8086,"Intel 82443MX Power management controller"},
62 #if 0
63 /* Not a good idea yet, this stops isab0 functioning */
64 { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"},
65 #endif
66
67 { 0x00000000, NULL }
68 };
69 static int intsmb_probe(device_t);
70 static int intsmb_attach(device_t);
71
72 static int intsmb_intr(device_t dev);
73 static int intsmb_slvintr(device_t dev);
74 static void intsmb_alrintr(device_t dev);
75 static int intsmb_callback(device_t dev, int index, caddr_t data);
76 static int intsmb_quick(device_t dev, u_char slave, int how);
77 static int intsmb_sendb(device_t dev, u_char slave, char byte);
78 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
79 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
80 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
81 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
82 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
83 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
84 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
85 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
86 static void intsmb_start(device_t dev,u_char cmd,int nointr);
87 static int intsmb_stop(device_t dev);
88 static int intsmb_stop_poll(device_t dev);
89 static int intsmb_free(device_t dev);
90 static int intpm_probe (device_t dev);
91 static int intpm_attach (device_t dev);
92 static devclass_t intsmb_devclass;
93
94 static device_method_t intpm_methods[]={
95 DEVMETHOD(device_probe,intsmb_probe),
96 DEVMETHOD(device_attach,intsmb_attach),
97
98 DEVMETHOD(bus_print_child, bus_generic_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
114 struct 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 device_t smbus;
120 };
121
122
123 struct intsmb_softc{
124 struct intpm_pci_softc *pci_sc;
125 bus_space_tag_t st;
126 bus_space_handle_t sh;
127 device_t smbus;
128 int isbusy;
129 };
130
131 static driver_t intpm_driver = {
132 "intsmb",
133 intpm_methods,
134 sizeof(struct intsmb_softc),
135 };
136
137 static devclass_t intpm_devclass;
138 static device_method_t intpm_pci_methods[] = {
139 DEVMETHOD(device_probe,intpm_probe),
140 DEVMETHOD(device_attach,intpm_attach),
141 {0,0}
142 };
143 static driver_t intpm_pci_driver = {
144 "intpm",
145 intpm_pci_methods,
146 sizeof(struct intpm_pci_softc)
147 };
148
149 static int
150 intsmb_probe(device_t dev)
151 {
152 struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
153 sc->smbus=device_add_child(dev, "smbus", -1);
154 if (!sc->smbus)
155 return (EINVAL); /* XXX don't know what to return else */
156 device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
157
158 return (0); /* XXX don't know what to return else */
159 }
160 static int
161 intsmb_attach(device_t dev)
162 {
163 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
164 sc->pci_sc=device_get_softc(device_get_parent(dev));
165 sc->isbusy=0;
166 sc->sh=sc->pci_sc->smbsh;
167 sc->st=sc->pci_sc->smbst;
168 sc->pci_sc->smbus=dev;
169 device_probe_and_attach(sc->smbus);
170 #ifdef ENABLE_ALART
171 /*Enable Arart*/
172 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
173 PIIX4_SMBSLVCNT_ALTEN);
174 #endif
175 return (0);
176 }
177
178 static int
179 intsmb_callback(device_t dev, int index, caddr_t data)
180 {
181 int error = 0;
182 intrmask_t s;
183 s=splnet();
184 switch (index) {
185 case SMB_REQUEST_BUS:
186 break;
187 case SMB_RELEASE_BUS:
188 break;
189 default:
190 error = EINVAL;
191 }
192 splx(s);
193 return (error);
194 }
195 /*counterpart of smbtx_smb_free*/
196 static int
197 intsmb_free(device_t dev){
198 intrmask_t s;
199 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
200 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
201 PIIX4_SMBHSTSTAT_BUSY)
202 #ifdef ENABLE_ALART
203 ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
204 PIIX4_SMBSLVSTS_BUSY)
205 #endif
206 || sc->isbusy)
207 return EBUSY;
208 s=splhigh();
209 sc->isbusy=1;
210 /*Disable Intrrupt in slave part*/
211 #ifndef ENABLE_ALART
212 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
213 #endif
214 /*Reset INTR Flag to prepare INTR*/
215 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
216 (PIIX4_SMBHSTSTAT_INTR|
217 PIIX4_SMBHSTSTAT_ERR|
218 PIIX4_SMBHSTSTAT_BUSC|
219 PIIX4_SMBHSTSTAT_FAIL)
220 );
221 splx(s);
222 return 0;
223 }
224
225 static int
226 intsmb_intr(device_t dev)
227 {
228 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
229 int status;
230 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
231 if(status&PIIX4_SMBHSTSTAT_BUSY){
232 return 1;
233
234 }
235 if(status&(PIIX4_SMBHSTSTAT_INTR|
236 PIIX4_SMBHSTSTAT_ERR|
237 PIIX4_SMBHSTSTAT_BUSC|
238 PIIX4_SMBHSTSTAT_FAIL)){
239 int tmp;
240 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
241 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
242 tmp&~PIIX4_SMBHSTCNT_INTREN);
243 if(sc->isbusy){
244 sc->isbusy=0;
245 wakeup(sc);
246 }
247 return 0;
248 }
249 return 1;/* Not Completed*/
250 }
251 static int
252 intsmb_slvintr(device_t dev)
253 {
254 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
255 int status,retval;
256 retval=1;
257 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
258 if(status&PIIX4_SMBSLVSTS_BUSY)
259 return retval;
260 if(status&PIIX4_SMBSLVSTS_ALART){
261 intsmb_alrintr(dev);
262 retval=0;
263 }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
264 |PIIX4_SMBSLVSTS_SDW1)){
265 retval=0;
266 }
267 /*Reset Status Register*/
268 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
269 PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
270 PIIX4_SMBSLVSTS_SLV);
271 return retval;
272 }
273
274 static void intsmb_alrintr(device_t dev)
275 {
276 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
277 int slvcnt;
278 #ifdef ENABLE_ALART
279 int error;
280 #endif
281
282 /*stop generating INTR from ALART*/
283 slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
284 #ifdef ENABLE_ALART
285 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
286 slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
287 #endif
288 DELAY(5);
289 /*ask bus who assert it and then ask it what's the matter. */
290 #ifdef ENABLE_ALART
291 error=intsmb_free(dev);
292 if(!error){
293 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
294 |LSB);
295 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
296 if(!(error=intsmb_stop_poll(dev))){
297 u_int8_t addr;
298 addr=bus_space_read_1(sc->st,sc->sh,
299 PIIX4_SMBHSTDAT0);
300 printf("ALART_RESPONSE: 0x%x\n", addr);
301 }
302 }else{
303 printf("ERROR\n");
304 }
305
306 /*Re-enable INTR from ALART*/
307 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
308 slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
309 DELAY(5);
310 #endif
311
312 return;
313 }
314 static void
315 intsmb_start(device_t dev,unsigned char cmd,int nointr)
316 {
317 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
318 unsigned char tmp;
319 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
320 tmp&= 0xe0;
321 tmp |= cmd;
322 tmp |=PIIX4_SMBHSTCNT_START;
323 /*While not in autoconfiguration Intrrupt Enabled*/
324 if(!cold||!nointr)
325 tmp |=PIIX4_SMBHSTCNT_INTREN;
326 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
327 }
328
329 /*Polling Code. Polling is not encouraged
330 * because It is required to wait for the device get busy.
331 *(29063505.pdf from Intel)
332 * But during boot,intrrupt cannot be used.
333 * so use polling code while in autoconfiguration.
334 */
335
336 static int
337 intsmb_stop_poll(device_t dev){
338 int error,i;
339 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
340
341 /*
342 * In smbtx driver ,Simply waiting.
343 * This loops 100-200 times.
344 */
345 for(i=0;i<0x7fff;i++){
346 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
347 &PIIX4_SMBHSTSTAT_BUSY)){
348 break;
349 }
350 }
351 for(i=0;i<0x7fff;i++){
352 int status;
353 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
354 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
355 sc->isbusy=0;
356 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
357 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
358 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
359 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
360 printf("unknown cause why?");
361 }
362 return error;
363 }
364 }
365 {
366 int tmp;
367 sc->isbusy=0;
368 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
369 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
370 tmp&~PIIX4_SMBHSTCNT_INTREN);
371 }
372 return EIO;
373 }
374 /*
375 *wait for completion and return result.
376 */
377 static int
378 intsmb_stop(device_t dev){
379 int error;
380 intrmask_t s;
381 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
382 if(cold){
383 /*So that it can use device during probing device on SMBus.*/
384 error=intsmb_stop_poll(dev);
385 return error;
386 }else{
387 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
388 int status;
389 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
390 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
391 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
392 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
393 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
394 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
395 printf("intsmb%d:unknown cause why?\n",
396 device_get_unit(dev));
397 }
398 #ifdef ENABLE_ALART
399 bus_space_write_1(sc->st,sc->sh,
400 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
401 #endif
402 return error;
403 }
404 }
405 }
406 /*Timeout Procedure*/
407 s=splhigh();
408 sc->isbusy=0;
409 /*Re-enable supressed intrrupt from slave part*/
410 bus_space_write_1(sc->st,sc->sh,
411 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
412 splx(s);
413 return EIO;
414 }
415
416 static int
417 intsmb_quick(device_t dev, u_char slave, int how)
418 {
419 int error=0;
420 u_char data;
421 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
422 data=slave;
423 /*Quick command is part of Address, I think*/
424 switch(how){
425 case SMB_QWRITE:
426 data&=~LSB;
427 break;
428 case SMB_QREAD:
429 data|=LSB;
430 break;
431 default:
432 error=EINVAL;
433 }
434 if(!error){
435 error=intsmb_free(dev);
436 if(!error){
437 bus_space_write_1(sc->st,sc->sh,
438 PIIX4_SMBHSTADD,data);
439 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
440 error=intsmb_stop(dev);
441 }
442 }
443
444 return (error);
445 }
446
447 static int
448 intsmb_sendb(device_t dev, u_char slave, char byte)
449 {
450 int error;
451 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
452 error=intsmb_free(dev);
453 if(!error){
454 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
455 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
456 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
457 error=intsmb_stop(dev);
458 }
459 return (error);
460 }
461 static int
462 intsmb_recvb(device_t dev, u_char slave, char *byte)
463 {
464 int error;
465 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
466 error=intsmb_free(dev);
467 if(!error){
468 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
469 |LSB);
470 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
471 if(!(error=intsmb_stop(dev))){
472 #ifdef RECV_IS_IN_CMD
473 /*Linux SMBus stuff also troubles
474 Because Intel's datasheet will not make clear.
475 */
476 *byte=bus_space_read_1(sc->st,sc->sh,
477 PIIX4_SMBHSTCMD);
478 #else
479 *byte=bus_space_read_1(sc->st,sc->sh,
480 PIIX4_SMBHSTDAT0);
481 #endif
482 }
483 }
484 return (error);
485 }
486 static int
487 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
488 {
489 int error;
490 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
491 error=intsmb_free(dev);
492 if(!error){
493 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
494 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
495 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
496 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
497 error=intsmb_stop(dev);
498 }
499 return (error);
500 }
501 static int
502 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
503 {
504 int error;
505 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
506 error=intsmb_free(dev);
507 if(!error){
508 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
509 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
510 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
511 word&0xff);
512 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
513 (word>>8)&0xff);
514 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
515 error=intsmb_stop(dev);
516 }
517 return (error);
518 }
519
520 static int
521 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
522 {
523 int error;
524 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
525 error=intsmb_free(dev);
526 if(!error){
527 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
528 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
529 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
530 if(!(error=intsmb_stop(dev))){
531 *byte=bus_space_read_1(sc->st,sc->sh,
532 PIIX4_SMBHSTDAT0);
533 }
534 }
535 return (error);
536 }
537 static int
538 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
539 {
540 int error;
541 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
542 error=intsmb_free(dev);
543 if(!error){
544 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
545 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
546 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
547 if(!(error=intsmb_stop(dev))){
548 *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
549 *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
550 }
551 }
552 return (error);
553 }
554 /*
555 * Data sheet claims that it implements all function, but also claims
556 * that it implements 7 function and not mention PCALL. So I don't know
557 * whether it will work.
558 */
559 static int
560 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
561 {
562 #ifdef PROCCALL_TEST
563 int error;
564 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
565 error=intsmb_free(dev);
566 if(!error){
567 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
568 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
569 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
570 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
571 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
572 }
573 if(!(error=intsmb_stop(dev))){
574 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
575 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
576 }
577 return error;
578 #else
579 return 0;
580 #endif
581 }
582 static int
583 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
584 {
585 int error,i;
586 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
587 error=intsmb_free(dev);
588 if(count>SMBBLOCKTRANS_MAX||count==0)
589 error=EINVAL;
590 if(!error){
591 /*Reset internal array index*/
592 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
593
594 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
595 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
596 for(i=0;i<count;i++){
597 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
598 }
599 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
600 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
601 error=intsmb_stop(dev);
602 }
603 return (error);
604 }
605
606 static int
607 intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
608 {
609 int error,i;
610 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
611 error=intsmb_free(dev);
612 if(count>SMBBLOCKTRANS_MAX||count==0)
613 error=EINVAL;
614 if(!error){
615 /*Reset internal array index*/
616 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
617
618 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
619 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
620 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
621 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
622 error=intsmb_stop(dev);
623 if(!error){
624 bzero(buf,count);/*Is it needed?*/
625 count= bus_space_read_1(sc->st,sc->sh,
626 PIIX4_SMBHSTDAT0);
627 if(count!=0&&count<=SMBBLOCKTRANS_MAX){
628 for(i=0;i<count;i++){
629 buf[i]=bus_space_read_1(sc->st,
630 sc->sh,
631 PIIX4_SMBBLKDAT);
632 }
633 }
634 else{
635 error=EIO;
636 }
637 }
638 }
639 return (error);
640 }
641
642 DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
643
644
645 static void intpm_intr(void *arg);
646 static int
647 intpm_attach(device_t dev)
648 {
649 int value;
650 int unit=device_get_unit(dev);
651 void *ih;
652 int error;
653 char * str;
654 {
655 struct intpm_pci_softc *sciic;
656 device_t smbinterface;
657 int rid;
658 struct resource *res;
659
660 sciic=device_get_softc(dev);
661 if(sciic==NULL){
662 return ENOMEM;
663 }
664
665 rid=PCI_BASE_ADDR_SMB;
666 res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
667 0,~0,1,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 0;
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: cf6d5825732ab23a8530954c8468b629
|