/drivers/ddk/Makefile |
---|
34,15 → 34,26 |
string/_strncmp.S \ |
string/_strncpy.S \ |
string/_strnlen.S \ |
string/bcmp.S \ |
string/bcopy.S \ |
string/bzero.S \ |
string/index.S \ |
string/memchr.S \ |
string/memcmp.S \ |
string/memcpy.S \ |
string/memcmp.S \ |
string/memmove.S \ |
string/memset.S \ |
string/rindex.S \ |
string/strcat.S \ |
string/strchr.S \ |
string/strcmp.S \ |
string/strcpy.S \ |
string/strlen.S \ |
string/strncat.S \ |
string/strncmp.S \ |
string/strncpy.S \ |
string/strncmp.S \ |
string/strlen.S |
string/strnlen.S \ |
string/strrchr.S |
64,7 → 75,7 |
$(LD) -shared -s --out-implib $@ --output-def core.def -o core.dll core.o |
%.o: %.S Makefile |
$(AS) -o $@ $< |
$(CC) $(CFLAGS) -o $@ $< |
%.o: %.c Makefile |
$(CC) $(CFLAGS) -o $@ $< |
/drivers/ddk/string/_memmove.S |
---|
1,67 → 1,60 |
# _memmove() Author: Kees J. Bot 2 Jan 1994 |
/* _memmove() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
# void *_memmove(void *s1, const void *s2, size_t n) |
# Copy a chunk of memory. Handle overlap. |
/* void *_memmove(void *s1, const void *s2, size_t n) */ |
/* Copy a chunk of memory. Handle overlap. */ |
/* */ |
.intel_syntax |
#include "asm.h" |
.globl __memmove, __memcpy |
ENTRY(_memmove) |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
movl 8(%ebp), %edi /* String s1 */ |
movl 12(%ebp), %esi /* String s2 */ |
movl 16(%ebp), %ecx /* Length */ |
movl %edi, %eax |
subl %esi, %eax |
cmpl %ecx, %eax |
jb downwards /* if (s2 - s1) < n then copy downwards */ |
LABEL(_memcpy) |
cld /* Clear direction bit: upwards */ |
cmpl $16, %ecx |
jb upbyte /* Don't bother being smart with short arrays */ |
movl %esi, %eax |
orl %edi, %eax |
testb $1, %al |
jne upbyte /* Bit 0 set, use byte copy */ |
testb $2, %al |
jne upword /* Bit 1 set, use word copy */ |
uplword: |
shrdl $2, %ecx, %eax /* Save low 2 bits of ecx in eax */ |
shrl $2, %ecx |
.text |
rep movsl /* Copy longwords. */ |
shldl $2, %eax, %ecx /* Restore excess count */ |
upword: |
shrl $1, %ecx |
.align 16 |
__memmove: |
push ebp |
mov ebp, esp |
push esi |
push edi |
mov edi, [ebp+8] # String s1 |
mov esi, [ebp+12] # String s2 |
mov ecx, [ebp+16] # Length |
mov eax, edi |
sub eax, esi |
cmp eax, ecx |
jb downwards # if (s2 - s1) < n then copy downwards |
__memcpy: |
cld # Clear direction bit: upwards |
cmp ecx, 16 |
jb upbyte # Don't bother being smart with short arrays |
mov eax, esi |
or eax, edi |
testb al, 1 |
jnz upbyte # Bit 0 set, use byte copy |
testb al, 2 |
jnz upword # Bit 1 set, use word copy |
uplword: |
shrd eax, ecx, 2 # Save low 2 bits of ecx in eax |
shr ecx, 2 |
rep movsd # Copy longwords. |
shld ecx, eax, 2 # Restore excess count |
upword: |
shr ecx, 1 |
rep movsw # Copy words |
adc ecx, ecx # One more byte? |
rep movsw /* Copy words */ |
adcl %ecx, %ecx /* One more byte? */ |
upbyte: |
rep movsb # Copy bytes |
rep movsb /* Copy bytes */ |
done: |
mov eax, [ebp+8] # Absolutely noone cares about this value |
pop edi |
pop esi |
pop ebp |
movl 8(%ebp), %eax /* Absolutely noone cares about this value */ |
pop %edi |
pop %esi |
pop %ebp |
ret |
# Handle bad overlap by copying downwards, don't bother to do word copies. |
/* Handle bad overlap by copying downwards, don't bother to do word copies. */ |
downwards: |
std /* Set direction bit: downwards */ |
leal -1(%esi,%ecx,1), %esi |
leal -1(%edi,%ecx,1), %edi |
downwards: |
std # Set direction bit: downwards |
lea esi, [esi+ecx-1] |
lea edi, [edi+ecx-1] |
rep movsb # Copy bytes |
rep movsb /* Copy bytes */ |
cld |
jmp done |
/drivers/ddk/string/_strncat.S |
---|
1,43 → 1,40 |
# _strncat() Author: Kees J. Bot |
# 1 Jan 1994 |
# char *_strncat(char *s1, const char *s2, size_t edx) |
# Append string s2 to s1. |
# |
/* _strncat() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
.intel_syntax |
/* char *_strncat(char *s1, const char *s2, size_t edx) */ |
/* Append string s2 to s1. */ |
/* */ |
#include "asm.h" |
.global __strncat |
ENTRY(_strncat) |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
movl 8(%ebp), %edi /* String s1 */ |
movl $-1, %ecx |
xorb %al, %al /* Null byte */ |
cld |
.text |
.align 16 |
__strncat: |
push ebp |
mov ebp, esp |
push esi |
push edi |
mov edi, [ebp+8] # String s1 |
mov ecx, -1 |
xorb al, al # Null byte |
cld |
repne |
scasb # Look for the zero byte in s1 |
dec edi # Back one up (and clear 'Z' flag) |
push edi # Save end of s1 |
mov edi, [12+ebp] # edi = string s2 |
mov ecx, edx # Maximum count |
repne |
scasb # Look for the end of s2 |
repne scasb /* Look for the zero byte in s1 */ |
decl %edi /* Back one up (and clear 'Z' flag) */ |
push %edi /* Save end of s1 */ |
movl 12(%ebp), %edi /* edi = string s2 */ |
movl %edx, %ecx /* Maximum count */ |
repne scasb /* Look for the end of s2 */ |
jne no0 |
inc ecx # Exclude null byte |
no0: sub edx, ecx # Number of bytes in s2 |
mov ecx, edx |
mov esi, [12+ebp] # esi = string s2 |
pop edi # edi = end of string s1 |
rep |
movsb # Copy bytes |
stosb # Add a terminating null |
mov eax, [8+ebp] # Return s1 |
pop edi |
pop esi |
pop ebp |
incl %ecx /* Exclude null byte */ |
no0: |
subl %ecx, %edx /* Number of bytes in s2 */ |
movl %edx, %ecx |
movl 12(%ebp), %esi /* esi = string s2 */ |
pop %edi /* edi = end of string s1 */ |
rep movsb /* Copy bytes */ |
stosb /* Add a terminating null */ |
movl 8(%ebp), %eax /* Return s1 */ |
pop %edi |
pop %esi |
pop %ebp |
ret |
/drivers/ddk/string/_strncmp.S |
---|
1,44 → 1,34 |
# strncmp() Author: Kees J. Bot 1 Jan 1994 |
/* strncmp() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
# int strncmp(const char *s1, const char *s2, size_t ecx) |
# Compare two strings. |
# |
/* int strncmp(const char *s1, const char *s2, size_t ecx) */ |
/* Compare two strings. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
.globl __strncmp |
.text |
.align 16 |
__strncmp: |
push ebp |
mov ebp, esp |
push esi |
push edi |
test ecx, ecx # Max length is zero? |
ENTRY(_strncmp) |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
testl %ecx, %ecx /* Max length is zero? */ |
je done |
mov esi, [ebp+8] # esi = string s1 |
mov edi, [ebp+12] # edi = string s2 |
movl 8(%ebp), %esi /* esi = string s1 */ |
movl 12(%ebp), %edi /* edi = string s2 */ |
cld |
compare: |
cmpsb # Compare two bytes |
cmpsb /* Compare two bytes */ |
jne done |
cmpb [esi-1], 0 # End of string? |
cmpb $0, -1(%esi) /* End of string? */ |
je done |
dec ecx # Length limit reached? |
decl %ecx /* Length limit reached? */ |
jne compare |
done: |
seta al # al = (s1 > s2) |
setb ah # ah = (s1 < s2) |
subb al, ah |
movsx eax, al # eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1 |
pop edi |
pop esi |
pop ebp |
seta %al /* al = (s1 > s2) */ |
setb %ah /* ah = (s1 < s2) */ |
subb %ah, %al |
movsbl %al, %eax /* eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1 */ |
pop %edi |
pop %esi |
pop %ebp |
ret |
/drivers/ddk/string/_strncpy.S |
---|
1,27 → 1,22 |
# _strncpy() Author: Kees J. Bot |
# 1 Jan 1994 |
/* _strncpy() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
# char *_strncpy(char *s1, const char *s2, size_t ecx) |
# Copy string s2 to s1. |
# |
/* char *_strncpy(char *s1, const char *s2, size_t ecx) */ |
/* Copy string s2 to s1. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
ENTRY(_strncpy) |
movl 12(%ebp), %edi /* edi = string s2 */ |
xorb %al, %al /* Look for a zero byte */ |
movl %ecx, %edx /* Save maximum count */ |
cld |
.text |
.globl __strncpy |
.align 16 |
repne scasb /* Look for end of s2 */ |
subl %ecx, %edx /* Number of bytes in s2 including null */ |
xchgl %edx, %ecx |
movl 12(%ebp), %esi /* esi = string s2 */ |
movl 8(%ebp), %edi /* edi = string s1 */ |
__strncpy: |
mov edi, [ebp+12] # edi = string s2 |
xorb al, al # Look for a zero byte |
mov edx, ecx # Save maximum count |
cld |
repne |
scasb # Look for end of s2 |
sub edx, ecx # Number of bytes in s2 including null |
xchg ecx, edx |
mov esi, [ebp+12] # esi = string s2 |
mov edi, [ebp+8] # edi = string s1 |
rep |
movsb # Copy bytes |
rep movsb /* Copy bytes */ |
ret |
/drivers/ddk/string/_strnlen.S |
---|
1,30 → 1,27 |
# _strnlen() Author: Kees J. Bot 1 Jan 1994 |
/* _strnlen() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
# size_t _strnlen(const char *s, size_t ecx) |
# Return the length of a string. |
/* size_t _strnlen(const char *s, size_t ecx) */ |
/* Return the length of a string. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
ENTRY(_strnlen) |
push %ebp |
movl %esp, %ebp |
push %edi |
movl 8(%ebp), %edi /* edi = string */ |
xorb %al, %al /* Look for a zero byte */ |
movl %ecx, %edx /* Save maximum count */ |
cmpb $1, %cl /* 'Z' bit must be clear if ecx = 0 */ |
cld |
.globl __strnlen |
.text |
.align 16 |
__strnlen: |
push ebp |
mov ebp, esp |
push edi |
mov edi, [ebp+8] # edi = string |
xorb al, al # Look for a zero byte |
mov edx, ecx # Save maximum count |
cmpb cl, 1 # 'Z' bit must be clear if ecx = 0 |
cld |
repne |
scasb # Look for zero |
repne scasb /* Look for zero */ |
jne no0 |
inc ecx # Don't count zero byte |
incl %ecx /* Don't count zero byte */ |
no0: |
mov eax, edx |
sub eax, ecx # Compute bytes scanned |
pop edi |
pop ebp |
movl %edx, %eax |
subl %ecx, %eax /* Compute bytes scanned */ |
pop %edi |
pop %ebp |
ret |
/drivers/ddk/string/asm.h |
---|
0,0 → 1,61 |
/*- |
* Copyright (c) 1990 The Regents of the University of California. |
* All rights reserved. |
* |
* This code is derived from software contributed to Berkeley by |
* William Jolitz. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* |
* @(#)asm.h 5.5 (Berkeley) 5/7/91 |
*/ |
#ifndef _I386_ASM_H_ |
#define _I386_ASM_H_ |
#define _C_LABEL(x) _ ## x |
#define _ASM_LABEL(x) x |
/* allow overriding entrypoint alignment */ |
#if !defined(_ALIGN_TEXT) |
# define _ALIGN_TEXT .align 16 |
#endif |
#define _ENTRY(x) \ |
.text; _ALIGN_TEXT; .globl x; x: |
#define _LABEL(x) \ |
.globl x; x: |
#define ENTRY(y) _ENTRY(_C_LABEL(y)) |
#define NENTRY(y) _ENTRY(_C_LABEL(y)) |
#define ASENTRY(y) _ENTRY(_ASM_LABEL(y)) |
#define LABEL(y) _LABEL(_C_LABEL(y)) |
#define END(y) .size y, . - y |
#define IMPORT(sym) \ |
.extern _C_LABEL(sym) |
#endif /* !_I386_ASM_H_ */ |
/drivers/ddk/string/bcmp.S |
---|
0,0 → 1,27 |
/* bcmp() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* int bcmp(const void *s1, const void *s2, size_t n) */ |
/* Compare two chunks of memory. */ |
/* This is a BSD routine that escaped from the kernel. Don't use. */ |
/* (Alas it is not without some use, it reports the number of bytes */ |
/* after the bytes that are equal. So it can't be simply replaced.) */ |
/* */ |
#include "asm.h" |
ENTRY(bcmp) |
push %ebp |
movl %esp, %ebp |
push 16(%ebp) |
push 12(%ebp) |
push 8(%ebp) |
call _C_LABEL(memcmp) /* Let memcmp do the work */ |
testl %eax, %eax |
je equal |
subl 8(%ebp), %edx /* Memcmp was nice enough to leave "esi" in edx */ |
decl %edx /* Number of bytes that are equal */ |
movl 16(%ebp), %eax |
subl %edx, %eax /* Number of bytes that are unequal */ |
equal: |
leave |
ret |
/drivers/ddk/string/bcopy.S |
---|
0,0 → 1,14 |
/* bcopy() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* void bcopy(const void *s1, void *s2, size_t n) */ |
/* Copy a chunk of memory. Handle overlap. */ |
/* This is a BSD routine that escaped from the kernel. Don't use. */ |
/* */ |
#include "asm.h" |
ENTRY(bcopy) |
movl 4(%esp), %eax /* Exchange string arguments */ |
xchgl 8(%esp), %eax |
movl %eax, 4(%esp) |
jmp _C_LABEL(_memmove) /* Call the proper routine */ |
/drivers/ddk/string/bzero.S |
---|
0,0 → 1,18 |
/* bzero() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* void bzero(void *s, size_t n) */ |
/* Set a chunk of memory to zero. */ |
/* This is a BSD routine that escaped from the kernel. Don't use. */ |
/* */ |
#include "asm.h" |
ENTRY(bzero) |
push %ebp |
movl %esp, %ebp |
push 12(%ebp) /* Size */ |
push $0 /* Zero */ |
push 8(%ebp) /* String */ |
call _C_LABEL(memset) /* Call the proper routine */ |
leave |
ret |
/drivers/ddk/string/index.S |
---|
0,0 → 1,11 |
/* index() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* char *index(const char *s, int c) */ |
/* Look for a character in a string. Has suffered from a hostile */ |
/* takeover by strchr(). */ |
/* */ |
#include "asm.h" |
ENTRY(index) |
jmp _C_LABEL(strchr) |
/drivers/ddk/string/memchr.S |
---|
0,0 → 1,29 |
/* memchr() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* void *memchr(const void *s, int c, size_t n) */ |
/* Look for a character in a chunk of memory. */ |
/* */ |
#include "asm.h" |
ENTRY(memchr) |
push %ebp |
movl %esp, %ebp |
push %edi |
movl 8(%ebp), %edi /* edi = string */ |
movb 12(%ebp), %al /* The character to look for */ |
movl 16(%ebp), %ecx /* Length */ |
cmpb $1, %cl /* 'Z' bit must be clear if ecx = 0 */ |
cld |
repne scasb |
jne failure |
leal -1(%edi), %eax /* Found */ |
pop %edi |
pop %ebp |
ret |
failure: |
xorl %eax, %eax |
pop %edi |
pop %ebp |
ret |
/drivers/ddk/string/memcmp.S |
---|
1,59 → 1,57 |
# memcmp() Author: Kees J. Bot |
# 2 Jan 1994 |
/* memcmp() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
# int memcmp(const void *s1, const void *s2, size_t n) |
# Compare two chunks of memory. |
# |
/* int memcmp(const void *s1, const void *s2, size_t n) */ |
/* Compare two chunks of memory. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
ENTRY(memcmp) |
cld |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
movl 8(%ebp), %esi /* String s1 */ |
movl 12(%ebp), %edi /* String s2 */ |
movl 16(%ebp), %ecx /* Length */ |
cmpl $16, %ecx |
jb cbyte /* Don't bother being smart with short arrays */ |
movl %esi, %eax |
orl %edi, %eax |
testb $1, %al |
jne cbyte /* Bit 0 set, use byte compare */ |
testb $2, %al |
jne cword /* Bit 1 set, use word compare */ |
clword: |
shrdl $2, %ecx, %eax /* Save low two bits of ecx in eax */ |
shrl $2, %ecx |
.globl _memcmp |
repe cmpsl /* Compare longwords */ |
subl $4, %esi |
subl $4, %edi |
incl %ecx /* Recompare the last longword */ |
shldl $2, %eax, %ecx /* And any excess bytes */ |
jmp last |
cword: |
shrdl $1, %ecx, %eax /* Save low bit of ecx in eax */ |
shrl $1, %ecx |
.text |
.align 16 |
_memcmp: |
cld |
push ebp |
mov ebp, esp |
push esi |
push edi |
mov esi, [8+ebp] # String s1 |
mov edi, [12+ebp] # String s2 |
mov ecx, [16+ebp] # Length |
cmp ecx, 16 |
jb cbyte # Don't bother being smart with short arrays |
mov eax, esi |
or eax, edi |
testb al, 1 |
jnz cbyte # Bit 0 set, use byte compare |
testb al, 2 |
jnz cword # Bit 1 set, use word compare |
clword: shrd eax, ecx, 2 # Save low two bits of ecx in eax |
shr ecx, 2 |
repe |
cmpsd # Compare longwords |
sub esi, 4 |
sub edi, 4 |
inc ecx # Recompare the last longword |
shld ecx, eax, 2 # And any excess bytes |
jmp last |
cword: shrd eax, ecx, 1 # Save low bit of ecx in eax |
shr ecx, 1 |
repe |
cmpsw # Compare words |
sub esi, 2 |
sub edi, 2 |
inc ecx # Recompare the last word |
shld ecx, eax, 1 # And one more byte? |
cbyte: test ecx, ecx # Set 'Z' flag if ecx = 0 |
last: repe |
cmpsb # Look for the first differing byte |
seta al # al = (s1 > s2) |
setb ah # ah = (s1 < s2) |
subb al, ah |
movsxb eax, al # eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1 |
mov edx, esi # For bcmp() to play with |
pop edi |
pop esi |
pop ebp |
repe cmpsw /* Compare words */ |
subl $2, %esi |
subl $2, %edi |
incl %ecx /* Recompare the last word */ |
shldl $1, %eax, %ecx /* And one more byte? */ |
cbyte: |
testl %ecx, %ecx /* Set 'Z' flag if ecx = 0 */ |
last: |
repe cmpsb /* Look for the first differing byte */ |
seta %al /* al = (s1 > s2) */ |
setb %ah /* ah = (s1 < s2) */ |
subb %ah, %al |
movsbl %al, %eax /* eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1 */ |
movl %esi, %edx /* For bcmp() to play with */ |
pop %edi |
pop %esi |
pop %ebp |
ret |
/drivers/ddk/string/memcpy.S |
---|
1,26 → 1,22 |
# memcpy() Author: Kees J. Bot 2 Jan 1994 |
/* memcpy() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
# void *memcpy(void *s1, const void *s2, size_t n) |
# Copy a chunk of memory. |
# This routine need not handle overlap, so it does not handle overlap. |
# One could simply call __memmove, the cost of the overlap check is |
# negligible, but you are dealing with a programmer who believes that |
# if anything can go wrong, it should go wrong. |
/* void *memcpy(void *s1, const void *s2, size_t n) */ |
/* Copy a chunk of memory. */ |
/* This routine need not handle overlap, so it does not handle overlap. */ |
/* One could simply call __memmove, the cost of the overlap check is */ |
/* negligible, but you are dealing with a programmer who believes that if */ |
/* anything can go wrong, it should go wrong. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
.globl _memcpy |
.text |
.align 16 |
_memcpy: |
push ebp |
mov ebp, esp |
push esi |
push edi |
mov edi, [ebp+8] # String s1 |
mov esi, [ebp+12] # String s2 |
mov ecx, [ebp+16] # Length |
# No overlap check here |
jmp __memcpy # Call the part of __memmove that copies up |
ENTRY(memcpy) |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
movl 8(%ebp), %edi /* String s1 */ |
movl 12(%ebp), %esi /* String s2 */ |
movl 16(%ebp), %ecx /* Length */ |
/* No overlap check here */ |
jmp _C_LABEL(_memcpy) /* Call the part of __memmove that copies up */ |
/drivers/ddk/string/memmove.S |
---|
0,0 → 1,10 |
/* memmove() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* void *memmove(void *s1, const void *s2, size_t n) */ |
/* Copy a chunk of memory. Handle overlap. */ |
/* */ |
#include "asm.h" |
ENTRY(memmove) |
jmp _C_LABEL(_memmove) /* Call common code */ |
/drivers/ddk/string/memset.S |
---|
1,47 → 1,45 |
# memset() Author: Kees J. Bot |
# 2 Jan 1994 |
# void *memset(void *s, int c, size_t n) |
# Set a chunk of memory to the same byte value. |
# |
/* memset() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
.intel_syntax |
/* void *memset(void *s, int c, size_t n) */ |
/* Set a chunk of memory to the same byte value. */ |
/* */ |
#include "asm.h" |
.global _memset |
.text |
.align 16 |
_memset: |
push ebp |
mov ebp, esp |
push edi |
mov edi, [8+ebp] # The string |
movzx eax, byte ptr [12+ebp] # The fill byte |
mov ecx, [16+ebp] # Length |
ENTRY(memset) |
push %ebp |
movl %esp, %ebp |
push %edi |
movl 8(%ebp), %edi /* The string */ |
movzbl 12(%ebp), %eax /* The fill byte */ |
movl 16(%ebp), %ecx /* Length */ |
cld |
cmp ecx, 16 |
jb sbyte # Don't bother being smart with short arrays |
test edi, 1 |
jnz sbyte # Bit 0 set, use byte store |
test edi, 2 |
jnz sword # Bit 1 set, use word store |
cmpl $16, %ecx |
jb sbyte /* Don't bother being smart with short arrays */ |
testl $1, %edi |
jne sbyte /* Bit 0 set, use byte store */ |
testl $2, %edi |
jne sword /* Bit 1 set, use word store */ |
slword: |
movb ah, al |
mov edx, eax |
sal edx, 16 |
or eax, edx # One byte to four bytes |
shrd edx, ecx, 2 # Save low two bits of ecx in edx |
shr ecx, 2 |
rep stosd # Store longwords. |
shld ecx, edx, 2 # Restore low two bits |
movb %al, %ah |
movl %eax, %edx |
sall $16, %edx |
orl %edx, %eax /* One byte to four bytes */ |
shrdl $2, %ecx, %edx /* Save low two bits of ecx in edx */ |
shrl $2, %ecx |
rep stosl /* Store longwords. */ |
shldl $2, %edx, %ecx /* Restore low two bits */ |
sword: |
movb ah, al # One byte to two bytes |
shr ecx, 1 |
rep stosw # Store words |
adc ecx, ecx # One more byte? |
movb %al, %ah /* One byte to two bytes */ |
shrl $1, %ecx |
rep stosw /* Store words */ |
adcl %ecx, %ecx /* One more byte? */ |
sbyte: |
rep stosb # Store bytes |
rep stosb /* Store bytes */ |
done: |
mov eax, [8+ebp] # Return some value you have no need for |
pop edi |
pop ebp |
movl 8(%ebp), %eax /* Return some value you have no need for */ |
pop %edi |
pop %ebp |
ret |
/drivers/ddk/string/rindex.S |
---|
0,0 → 1,11 |
/* rindex() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* char *rindex(const char *s, int c) */ |
/* Look for the last occurrence a character in a string. Has suffered */ |
/* from a hostile takeover by strrchr(). */ |
/* */ |
#include "asm.h" |
ENTRY(rindex) |
jmp _C_LABEL(strrchr) |
/drivers/ddk/string/strcat.S |
---|
1,15 → 1,11 |
# strcat() Author: Kees J. Bot |
# 1 Jan 1994 |
# char *strcat(char *s1, const char *s2) |
# Append string s2 to s1. |
# |
/* strcat() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
.intel_syntax |
/* char *strcat(char *s1, const char *s2) */ |
/* Append string s2 to s1. */ |
/* */ |
#include "asm.h" |
.global _strcat |
.text |
.align 16 |
_strcat: |
mov edx, -1 # Unlimited length |
jmp __strncat # Common code |
ENTRY(strcat) |
movl $-1, %edx /* Unlimited length */ |
jmp _C_LABEL(_strncat) /* Common code */ |
/drivers/ddk/string/strchr.S |
---|
1,46 → 1,41 |
# strchr() Author: Kees J. Bot 1 Jan 1994 |
/* strchr() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
# char *strchr(const char *s, int c) |
# Look for a character in a string. |
/* char *strchr(const char *s, int c) */ |
/* Look for a character in a string. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
.globl _strchr |
.text |
.align 16 |
_strchr: |
push ebp |
mov ebp, esp |
push edi |
ENTRY(strchr) |
push %ebp |
movl %esp, %ebp |
push %edi |
cld |
mov edi, [ebp+8] # edi = string |
mov edx, 16 # Look at small chunks of the string |
movl 8(%ebp), %edi /* edi = string */ |
movl $16, %edx /* Look at small chunks of the string */ |
next: |
shl edx, 1 # Chunks become bigger each time |
mov ecx, edx |
xorb al, al # Look for the zero at the end |
shll $1, %edx /* Chunks become bigger each time */ |
movl %edx, %ecx |
xorb %al, %al /* Look for the zero at the end */ |
repne scasb |
pushf /* Remember the flags */ |
subl %edx, %ecx |
negl %ecx /* Some or all of the chunk */ |
subl %ecx, %edi /* Step back */ |
movb 12(%ebp), %al /* The character to look for */ |
pushf # Remember the flags |
sub ecx, edx |
neg ecx # Some or all of the chunk |
sub edi, ecx # Step back |
movb al, [ebp+12] # The character to look for |
repne scasb |
je found |
popf # Did we find the end of string earlier? |
jne next # No, try again |
xor eax, eax # Return NULL |
pop edi |
pop ebp |
popf /* Did we find the end of string earlier? */ |
jne next /* No, try again */ |
xorl %eax, %eax /* Return NULL */ |
pop %edi |
pop %ebp |
ret |
found: |
pop eax # Get rid of those flags |
lea eax, [edi-1] # Address of byte found |
pop edi |
pop ebp |
pop %eax /* Get rid of those flags */ |
leal -1(%edi), %eax /* Address of byte found */ |
pop %edi |
pop %ebp |
ret |
/drivers/ddk/string/strcmp.S |
---|
0,0 → 1,11 |
/* strcmp() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
/* int strcmp(const char *s1, const char *s2) */ |
/* Compare two strings. */ |
/* */ |
#include "asm.h" |
ENTRY(strcmp) |
movl $-1, %ecx /* Unlimited length */ |
jmp _C_LABEL(_strncmp) /* Common code */ |
/drivers/ddk/string/strcpy.S |
---|
1,24 → 1,20 |
# strcpy() Author: Kees J. Bot |
# 1 Jan 1994 |
# char *strcpy(char *s1, const char *s2) |
# Copy string s2 to s1. |
# |
/* strcpy() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
.intel_syntax |
/* char *strcpy(char *s1, const char *s2) */ |
/* Copy string s2 to s1. */ |
/* */ |
#include "asm.h" |
.global _strcpy |
.text |
.align 16 |
_strcpy: |
push ebp |
mov ebp, esp |
push esi |
push edi |
mov ecx, -1 # Unlimited length |
call _strncpy # Common code |
mov eax, [8+ebp] # Return s1 |
pop edi |
pop esi |
pop ebp |
ENTRY(strcpy) |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
movl $-1, %ecx /* Unlimited length */ |
call _C_LABEL(_strncpy) /* Common code */ |
movl 8(%ebp), %eax /* Return s1 */ |
pop %edi |
pop %esi |
pop %ebp |
ret |
/drivers/ddk/string/strlen.S |
---|
1,15 → 1,11 |
# strlen() Author: Kees J. Bot 1 Jan 1994 |
/* strlen() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
# size_t strlen(const char *s) |
# Return the length of a string. |
/* size_t strlen(const char *s) */ |
/* Return the length of a string. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
.globl _strlen |
.text |
.align 16 |
_strlen: |
mov ecx, -1 # Unlimited length |
jmp __strnlen # Common code |
ENTRY(strlen) |
movl $-1, %ecx /* Unlimited length */ |
jmp _C_LABEL(_strnlen) /* Common code */ |
/drivers/ddk/string/strncat.S |
---|
0,0 → 1,11 |
/* strncat() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
/* size_t strncat(char *s1, const char *s2, size_t n) */ |
/* Append string s2 to s1. */ |
/* */ |
#include "asm.h" |
ENTRY(strncat) |
movl 12(%esp), %edx /* Maximum length */ |
jmp _C_LABEL(_strncat) /* Common code */ |
/drivers/ddk/string/strncmp.S |
---|
1,22 → 1,11 |
# strncmp() Author: Kees J. Bot 1 Jan 1994 |
/* strncmp() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
# int strncmp(const char *s1, const char *s2, size_t n) |
# Compare two strings. |
# |
/* int strncmp(const char *s1, const char *s2, size_t n) */ |
/* Compare two strings. */ |
/* */ |
#include "asm.h" |
.intel_syntax |
.globl _strncmp |
.globl _strcmp |
.text |
.align 16 |
_strncmp: |
mov ecx, [esp+12] # Maximum length |
jmp __strncmp # Common code |
.align 16 |
_strcmp: |
mov ecx, -1 # Maximum length |
jmp __strncmp # Common code |
ENTRY(strncmp) |
movl 12(%esp), %ecx /* Maximum length */ |
jmp _C_LABEL(_strncmp) /* Common code */ |
/drivers/ddk/string/strncpy.S |
---|
1,28 → 1,23 |
# strncpy() Author: Kees J. Bot |
# 1 Jan 1994 |
# char *strncpy(char *s1, const char *s2, size_t n) |
# Copy string s2 to s1. |
# |
/* strncpy() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
.intel_syntax |
/* char *strncpy(char *s1, const char *s2, size_t n) */ |
/* Copy string s2 to s1. */ |
/* */ |
#include "asm.h" |
.text |
ENTRY(strncpy) |
push %ebp |
movl %esp, %ebp |
push %esi |
push %edi |
movl 16(%ebp), %ecx /* Maximum length */ |
call _C_LABEL(_strncpy) /* Common code */ |
movl %edx, %ecx /* Number of bytes not copied */ |
.globl _strncpy |
.align 16 |
_strncpy: |
push ebp |
mov ebp, esp |
push esi |
push edi |
mov ecx, [ebp+16] # Maximum length |
call __strncpy # Common code |
mov ecx, edx # Number of bytes not copied |
rep |
stosb # strncpy always copies n bytes by null padding |
mov eax, [ebp+8] # Return s1 |
pop edi |
pop esi |
pop ebp |
rep stosb /* strncpy always copies n bytes by null padding */ |
movl 8(%ebp), %eax /* Return s1 */ |
pop %edi |
pop %esi |
pop %ebp |
ret |
/drivers/ddk/string/strnlen.S |
---|
0,0 → 1,11 |
/* strnlen() Author: Kees J. Bot */ |
/* 1 Jan 1994 */ |
/* size_t strnlen(const char *s, size_t n) */ |
/* Return the length of a string. */ |
/* */ |
#include "asm.h" |
ENTRY(strnlen) |
movl 8(%esp), %ecx /* Maximum length */ |
jmp _C_LABEL(_strnlen) /* Common code */ |
/drivers/ddk/string/strrchr.S |
---|
0,0 → 1,35 |
/* strrchr() Author: Kees J. Bot */ |
/* 2 Jan 1994 */ |
/* char *strrchr(const char *s, int c) */ |
/* Look for the last occurrence a character in a string. */ |
/* */ |
#include "asm.h" |
ENTRY(strrchr) |
push %ebp |
movl %esp, %ebp |
push %edi |
movl 8(%ebp), %edi /* edi = string */ |
movl $-1, %ecx |
xorb %al, %al |
cld |
repne scasb /* Look for the end of the string */ |
notl %ecx /* -1 - ecx = Length of the string + null */ |
decl %edi /* Put edi back on the zero byte */ |
movb 12(%ebp), %al /* The character to look for */ |
std /* Downwards search */ |
repne scasb |
cld /* Direction bit back to default */ |
jne failure |
leal 1(%edi), %eax /* Found it */ |
pop %edi |
pop %ebp |
ret |
failure: |
xorl %eax, %eax /* Not there */ |
pop %edi |
pop %ebp |
ret |
/drivers/devman/Makefile |
---|
24,7 → 24,10 |
NAME= acpi |
NAME_SRCS= acpi.c |
NAME_SRCS= acpi.c \ |
scan.c \ |
pci_irq.c \ |
pci/pci.c |
all: $(NAME).dll |
/drivers/devman/acpi.c |
---|
6,7 → 6,10 |
#include <syscall.h> |
#include "acpi.h" |
#include "acpi_bus.h" |
#define PREFIX "ACPI: " |
#define ACPI_BUS_CLASS "system_bus" |
#define ACPI_BUS_HID "KLBSYBUS" |
#define ACPI_BUS_DEVICE_NAME "System Bus" |
16,8 → 19,8 |
static LIST_HEAD(acpi_device_list); |
static LIST_HEAD(acpi_bus_id_list); |
DEFINE_MUTEX(acpi_device_lock); |
struct acpi_device_bus_id |
{ |
char bus_id[15]; |
44,40 → 47,7 |
ACPI_BUS_REMOVAL_TYPE_COUNT |
}; |
enum acpi_bus_device_type { |
ACPI_BUS_TYPE_DEVICE = 0, |
ACPI_BUS_TYPE_POWER, |
ACPI_BUS_TYPE_PROCESSOR, |
ACPI_BUS_TYPE_THERMAL, |
ACPI_BUS_TYPE_POWER_BUTTON, |
ACPI_BUS_TYPE_SLEEP_BUTTON, |
ACPI_BUS_DEVICE_TYPE_COUNT |
}; |
/* |
* _HID definitions |
* HIDs must conform to ACPI spec(6.1.4) |
* KolibriOS specific HIDs do not apply to this and begin with KOS: |
*/ |
#define ACPI_POWER_HID "KLBPOWER" |
#define ACPI_PROCESSOR_OBJECT_HID "KLBCPU" |
#define ACPI_SYSTEM_HID "KLBSYSTM" |
#define ACPI_THERMAL_HID "KLBTHERM" |
#define ACPI_BUTTON_HID_POWERF "KLBPWRBN" |
#define ACPI_BUTTON_HID_SLEEPF "KLBSLPBN" |
#define ACPI_VIDEO_HID "KLBVIDEO" |
#define ACPI_BAY_HID "KLBIOBAY" |
#define ACPI_DOCK_HID "KLBDOCK" |
/* Quirk for broken IBM BIOSes */ |
#define ACPI_SMBUS_IBM_HID "SMBUSIBM" |
#define STRUCT_TO_INT(s) (*((int*)&s)) |
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
#define PCI_MAX_DEVICES 32 |
#define PCI_MAX_PINS 4 |
96,850 → 66,521 |
#define acpi_remap( addr ) MapIoMem((void*)(addr),4096, 0x01) |
struct acpi_bus_ops |
{ |
u32_t acpi_op_add:1; |
u32_t acpi_op_start:1; |
}; |
struct acpi_device *acpi_root; |
struct acpi_device_flags { |
u32 dynamic_status:1; |
u32 bus_address:1; |
u32 removable:1; |
u32 ejectable:1; |
u32 lockable:1; |
u32 suprise_removal_ok:1; |
u32 power_manageable:1; |
u32 performance_manageable:1; |
u32 wake_capable:1; /* Wakeup(_PRW) supported? */ |
u32 force_power_state:1; |
u32 reserved:22; |
}; |
extern struct resource iomem_resource; |
extern struct resource ioport_resource; |
struct acpi_device_status { |
u32 present:1; |
u32 enabled:1; |
u32 show_in_ui:1; |
u32 functional:1; |
u32 battery_present:1; |
u32 reserved:27; |
enum pic_mode |
{ |
IO_PIC = 0, |
IO_APIC |
}; |
static void set_pic_mode(enum pic_mode mode) |
{ |
ACPI_OBJECT arg1; |
ACPI_OBJECT_LIST args; |
ACPI_STATUS as; |
typedef char acpi_bus_id[8]; |
typedef unsigned long acpi_bus_address; |
typedef char acpi_device_name[40]; |
typedef char acpi_device_class[20]; |
arg1.Type = ACPI_TYPE_INTEGER; |
arg1.Integer.Value = mode; |
args.Count = 1; |
args.Pointer = &arg1; |
struct acpi_hardware_id { |
struct list_head list; |
char *id; |
}; |
as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL); |
/* |
* We can silently ignore failure as it may not be implemented, ACPI should |
* provide us with correct information anyway |
*/ |
if (ACPI_SUCCESS(as)) |
dbgprintf(PREFIX "machine set to %s mode\n", mode ? "APIC" : "PIC"); |
} |
struct acpi_device_pnp |
void print_device_tree(struct acpi_device *device) |
{ |
acpi_bus_id bus_id; /* Object name */ |
acpi_bus_address bus_address; /* _ADR */ |
char *unique_id; /* _UID */ |
struct list_head ids; /* _HID and _CIDs */ |
acpi_device_name device_name; /* Driver-determined */ |
acpi_device_class device_class; /* " */ |
}; |
struct acpi_device *child; |
dbgprintf("%s\n", device->pnp.bus_id); |
struct acpi_device |
list_for_each_entry(child, &device->children, node) |
{ |
int device_type; |
ACPI_HANDLE handle; /* no handle for fixed hardware */ |
struct acpi_device *parent; |
struct list_head children; |
struct list_head node; |
// struct list_head wakeup_list; |
struct acpi_device_status status; |
struct acpi_device_flags flags; |
struct acpi_device_pnp pnp; |
// struct acpi_device_power power; |
// struct acpi_device_wakeup wakeup; |
// struct acpi_device_perf performance; |
// struct acpi_device_dir dir; |
// struct acpi_device_ops ops; |
// struct acpi_driver *driver; |
void *driver_data; |
// struct device dev; |
struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ |
// enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ |
print_device_tree(child); |
}; |
}; |
struct acpi_device *acpi_root; |
static void |
acpi_util_eval_error(ACPI_HANDLE h, ACPI_STRING p, ACPI_STATUS s) |
/* |
int acpi_pci_bind_root(struct acpi_device *device) |
{ |
#ifdef ACPI_DEBUG_OUTPUT |
char prefix[80] = {'\0'}; |
ACPI_BUFFER buffer = {sizeof(prefix), prefix}; |
AcpiGetName(h, ACPI_FULL_PATHNAME, &buffer); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n", |
(char *) prefix, p, AcpiFormatException(s))); |
#else |
return; |
#endif |
} |
device->ops.bind = acpi_pci_bind; |
device->ops.unbind = acpi_pci_unbind; |
ACPI_STATUS |
acpi_evaluate_integer(ACPI_HANDLE handle, ACPI_STRING pathname, |
ACPI_OBJECT_LIST *arguments, unsigned long long *data) |
{ |
ACPI_STATUS status = AE_OK; |
ACPI_OBJECT element; |
ACPI_BUFFER buffer = { 0, NULL }; |
if (!data) |
return AE_BAD_PARAMETER; |
buffer.Length = sizeof(ACPI_OBJECT); |
buffer.Pointer = &element; |
status = AcpiEvaluateObject(handle, pathname, arguments, &buffer); |
if (ACPI_FAILURE(status)) { |
acpi_util_eval_error(handle, pathname, status); |
return status; |
return 0; |
} |
*/ |
if (element.Type != ACPI_TYPE_INTEGER) { |
acpi_util_eval_error(handle, pathname, AE_BAD_DATA); |
return AE_BAD_DATA; |
} |
static bool pci_use_crs = false; |
*data = element.Integer.Value; |
#define IORESOURCE_BUS 0x00001000 |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); |
struct acpi_pci_root { |
struct list_head node; |
struct acpi_device * device; |
struct acpi_pci_id id; |
struct pci_bus *bus; |
u16 segment; |
struct resource secondary; /* downstream bus range */ |
return AE_OK; |
} |
}; |
void acpi_bus_data_handler(ACPI_HANDLE handle, void *context) |
{ |
static LIST_HEAD(acpi_pci_roots); |
/* TBD */ |
#define ACPI_PCI_ROOT_CLASS "pci_bridge" |
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" |
return; |
} |
int acpi_bus_get_device(ACPI_HANDLE handle, struct acpi_device **device) |
static ACPI_STATUS |
get_root_bridge_busnr_callback(ACPI_RESOURCE *resource, void *data) |
{ |
ACPI_STATUS status = AE_OK; |
struct resource *res = data; |
ACPI_RESOURCE_ADDRESS64 address; |
if (!device) |
{ |
return -EINVAL; |
}; |
if (resource->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && |
resource->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && |
resource->Type != ACPI_RESOURCE_TYPE_ADDRESS64) |
return AE_OK; |
/* TBD: Support fixed-feature devices */ |
status = AcpiGetData(handle, acpi_bus_data_handler, (void **)device); |
if (ACPI_FAILURE(status) || !*device) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", |
handle)); |
return -ENODEV; |
AcpiResourceToAddress64(resource, &address); |
if ((address.AddressLength > 0) && |
(address.ResourceType == ACPI_BUS_NUMBER_RANGE)) { |
res->start = address.Minimum; |
res->end = address.Minimum + address.AddressLength - 1; |
} |
return 0; |
} |
ACPI_STATUS acpi_bus_get_status_handle(ACPI_HANDLE handle, |
unsigned long long *sta) |
{ |
ACPI_STATUS status; |
status = acpi_evaluate_integer(handle, "_STA", NULL, sta); |
if (ACPI_SUCCESS(status)) |
{ |
return AE_OK; |
}; |
if (status == AE_NOT_FOUND) |
{ |
*sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; |
return AE_OK; |
} |
return status; |
} |
static int acpi_bus_type_and_status(ACPI_HANDLE handle, int *type, |
unsigned long long *sta) |
static ACPI_STATUS try_get_root_bridge_busnr(ACPI_HANDLE handle, |
struct resource *res) |
{ |
ACPI_STATUS status; |
ACPI_OBJECT_TYPE acpi_type; |
status = AcpiGetType(handle, &acpi_type); |
res->start = -1; |
status = |
AcpiWalkResources(handle, METHOD_NAME__CRS, |
get_root_bridge_busnr_callback, res); |
if (ACPI_FAILURE(status)) |
{ |
return -ENODEV; |
}; |
return status; |
if (res->start == -1) |
return AE_ERROR; |
return AE_OK; |
} |
switch (acpi_type) |
{ |
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ |
case ACPI_TYPE_DEVICE: |
*type = ACPI_BUS_TYPE_DEVICE; |
status = acpi_bus_get_status_handle(handle, sta); |
if (ACPI_FAILURE(status)) |
{ |
return -ENODEV; |
}; |
break; |
case ACPI_TYPE_PROCESSOR: |
*type = ACPI_BUS_TYPE_PROCESSOR; |
status = acpi_bus_get_status_handle(handle, sta); |
if (ACPI_FAILURE(status)) |
struct pci_root_info |
{ |
return -ENODEV; |
struct acpi_device *bridge; |
char *name; |
unsigned int res_num; |
struct resource *res; |
struct pci_bus *bus; |
int busnum; |
}; |
break; |
case ACPI_TYPE_THERMAL: |
*type = ACPI_BUS_TYPE_THERMAL; |
*sta = ACPI_STA_DEFAULT; |
break; |
case ACPI_TYPE_POWER: |
*type = ACPI_BUS_TYPE_POWER; |
*sta = ACPI_STA_DEFAULT; |
break; |
default: |
return -ENODEV; |
} |
return 0; |
} |
static struct acpi_device *acpi_bus_get_parent(ACPI_HANDLE handle) |
static ACPI_STATUS |
resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr) |
{ |
ACPI_STATUS status; |
struct acpi_device *device; |
int ret; |
struct acpi_resource_memory24 *memory24; |
struct acpi_resource_memory32 *memory32; |
struct acpi_resource_fixed_memory32 *fixed_memory32; |
/* |
* Fixed hardware devices do not appear in the namespace and do not |
* have handles, but we fabricate acpi_devices for them, so we have |
* to deal with them specially. |
*/ |
if (handle == NULL) |
{ |
return acpi_root; |
}; |
do |
{ |
status = AcpiGetParent(handle, &handle); |
if (status == AE_NULL_ENTRY) |
{ |
return NULL; |
}; |
if (ACPI_FAILURE(status)) |
{ |
return acpi_root; |
}; |
ret = acpi_bus_get_device(handle, &device); |
if (ret == 0) |
{ |
return device; |
}; |
} while (1); |
memset(addr, 0, sizeof(*addr)); |
switch (resource->Type) { |
case ACPI_RESOURCE_TYPE_MEMORY24: |
memory24 = &resource->Data.Memory24; |
addr->ResourceType = ACPI_MEMORY_RANGE; |
addr->Minimum = memory24->Minimum; |
addr->AddressLength = memory24->AddressLength; |
addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
return AE_OK; |
case ACPI_RESOURCE_TYPE_MEMORY32: |
memory32 = &resource->Data.Memory32; |
addr->ResourceType = ACPI_MEMORY_RANGE; |
addr->Minimum = memory32->Minimum; |
addr->AddressLength = memory32->AddressLength; |
addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
return AE_OK; |
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
fixed_memory32 = &resource->Data.FixedMemory32; |
addr->ResourceType = ACPI_MEMORY_RANGE; |
addr->Minimum = fixed_memory32->Address; |
addr->AddressLength = fixed_memory32->AddressLength; |
addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
return AE_OK; |
case ACPI_RESOURCE_TYPE_ADDRESS16: |
case ACPI_RESOURCE_TYPE_ADDRESS32: |
case ACPI_RESOURCE_TYPE_ADDRESS64: |
status = AcpiResourceToAddress64(resource, addr); |
if (ACPI_SUCCESS(status) && |
(addr->ResourceType == ACPI_MEMORY_RANGE || |
addr->ResourceType == ACPI_IO_RANGE) && |
addr->AddressLength > 0) { |
return AE_OK; |
} |
static void acpi_device_get_busid(struct acpi_device *device) |
{ |
char bus_id[5] = { '?', 0 }; |
struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; |
int i = 0; |
/* |
* Bus ID |
* ------ |
* The device's Bus ID is simply the object name. |
* TBD: Shouldn't this value be unique (within the ACPI namespace)? |
*/ |
if (ACPI_IS_ROOT_DEVICE(device)) { |
strcpy(device->pnp.bus_id, "ACPI"); |
return; |
} |
switch (device->device_type) |
{ |
case ACPI_BUS_TYPE_POWER_BUTTON: |
strcpy(device->pnp.bus_id, "PWRF"); |
break; |
case ACPI_BUS_TYPE_SLEEP_BUTTON: |
strcpy(device->pnp.bus_id, "SLPF"); |
break; |
default: |
AcpiGetName(device->handle, ACPI_SINGLE_NAME, &buffer); |
/* Clean up trailing underscores (if any) */ |
for (i = 3; i > 1; i--) |
{ |
if (bus_id[i] == '_') |
bus_id[i] = '\0'; |
else |
break; |
} |
strcpy(device->pnp.bus_id, bus_id); |
break; |
return AE_ERROR; |
} |
} |
static int acpi_bus_get_flags(struct acpi_device *device) |
static ACPI_STATUS |
count_resource(ACPI_RESOURCE *acpi_res, void *data) |
{ |
ACPI_STATUS status = AE_OK; |
ACPI_HANDLE temp = NULL; |
struct pci_root_info *info = data; |
ACPI_RESOURCE_ADDRESS64 addr; |
ACPI_STATUS status; |
/* Presence of _STA indicates 'dynamic_status' */ |
status = AcpiGetHandle(device->handle, "_STA", &temp); |
status = resource_to_addr(acpi_res, &addr); |
if (ACPI_SUCCESS(status)) |
device->flags.dynamic_status = 1; |
/* Presence of _RMV indicates 'removable' */ |
status = AcpiGetHandle(device->handle, "_RMV", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.removable = 1; |
/* Presence of _EJD|_EJ0 indicates 'ejectable' */ |
status = AcpiGetHandle(device->handle, "_EJD", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.ejectable = 1; |
else { |
status = AcpiGetHandle(device->handle, "_EJ0", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.ejectable = 1; |
info->res_num++; |
return AE_OK; |
} |
/* Presence of _LCK indicates 'lockable' */ |
status = AcpiGetHandle(device->handle, "_LCK", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.lockable = 1; |
/* Presence of _PS0|_PR0 indicates 'power manageable' */ |
status = AcpiGetHandle(device->handle, "_PS0", &temp); |
if (ACPI_FAILURE(status)) |
status = AcpiGetHandle(device->handle, "_PR0", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.power_manageable = 1; |
static ACPI_STATUS setup_resource(ACPI_RESOURCE *acpi_res, void *data) |
{ |
struct pci_root_info *info = data; |
struct resource *res; |
struct acpi_resource_address64 addr; |
ACPI_STATUS status; |
unsigned long flags; |
struct resource *root, *conflict; |
u64 start, end; |
/* Presence of _PRW indicates wake capable */ |
status = AcpiGetHandle(device->handle, "_PRW", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.wake_capable = 1; |
status = resource_to_addr(acpi_res, &addr); |
if (!ACPI_SUCCESS(status)) |
return AE_OK; |
/* TBD: Performance management */ |
return 0; |
if (addr.ResourceType == ACPI_MEMORY_RANGE) |
{ |
root = &iomem_resource; |
flags = IORESOURCE_MEM; |
if (addr.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) |
flags |= IORESOURCE_PREFETCH; |
} |
else if (addr.ResourceType == ACPI_IO_RANGE) |
{ |
root = &ioport_resource; |
flags = IORESOURCE_IO; |
} else |
return AE_OK; |
/* |
* acpi_bay_match - see if a device is an ejectable driver bay |
* |
* If an acpi object is ejectable and has one of the ACPI ATA methods defined, |
* then we can safely call it an ejectable drive bay |
*/ |
static int acpi_bay_match(struct acpi_device *device){ |
ACPI_STATUS status; |
ACPI_HANDLE handle; |
ACPI_HANDLE tmp; |
ACPI_HANDLE phandle; |
start = addr.Minimum + addr.TranslationOffset; |
end = addr.Maximum + addr.TranslationOffset; |
handle = device->handle; |
res = &info->res[info->res_num]; |
res->name = info->name; |
res->flags = flags; |
res->start = start; |
res->end = end; |
res->child = NULL; |
status = AcpiGetHandle(handle, "_EJ0", &tmp); |
if (ACPI_FAILURE(status)) |
return -ENODEV; |
if ((ACPI_SUCCESS(AcpiGetHandle(handle, "_GTF", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(handle, "_GTM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(handle, "_STM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(handle, "_SDD", &tmp)))) |
return 0; |
if (AcpiGetParent(handle, &phandle)) |
return -ENODEV; |
if ((ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTF", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_STM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_SDD", &tmp)))) |
return 0; |
return -ENODEV; |
if (!pci_use_crs) { |
printk("host bridge window %pR (ignored)\n", res); |
return AE_OK; |
} |
/* |
* acpi_dock_match - see if a device has a _DCK method |
*/ |
static int acpi_dock_match(struct acpi_device *device) |
{ |
ACPI_HANDLE tmp; |
return AcpiGetHandle(device->handle, "_DCK", &tmp); |
#if 0 |
conflict = insert_resource_conflict(root, res); |
if (conflict) { |
dev_err(&info->bridge->dev, |
"address space collision: host bridge window %pR " |
"conflicts with %s %pR\n", |
res, conflict->name, conflict); |
} else { |
pci_bus_add_resource(info->bus, res, 0); |
info->res_num++; |
if (addr.translation_offset) |
dev_info(&info->bridge->dev, "host bridge window %pR " |
"(PCI address [%#llx-%#llx])\n", |
res, res->start - addr.translation_offset, |
res->end - addr.translation_offset); |
else |
dev_info(&info->bridge->dev, |
"host bridge window %pR\n", res); |
} |
char *acpi_device_hid(struct acpi_device *device) |
{ |
struct acpi_hardware_id *hid; |
hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); |
return hid->id; |
return AE_OK; |
#endif |
} |
static void acpi_add_id(struct acpi_device *device, const char *dev_id) |
static void |
get_current_resources(struct acpi_device *device, int busnum, |
int domain, struct pci_bus *bus) |
{ |
struct acpi_hardware_id *id; |
struct pci_root_info info; |
size_t size; |
id = kmalloc(sizeof(*id), GFP_KERNEL); |
if (!id) |
{ |
return; |
}; |
char buf[64]; |
INIT_LIST_HEAD(&id->list); |
// if (pci_use_crs) |
// pci_bus_remove_resources(bus); |
id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); |
if (!id->id) { |
kfree(id); |
info.bridge = device; |
info.bus = bus; |
info.res_num = 0; |
AcpiWalkResources(device->handle, METHOD_NAME__CRS, count_resource, |
&info); |
if (!info.res_num) |
return; |
} |
strcpy(id->id, dev_id); |
size = sizeof(*info.res) * info.res_num; |
info.res = kmalloc(size, GFP_KERNEL); |
if (!info.res) |
goto res_alloc_fail; |
list_add_tail(&id->list, &device->pnp.ids); |
} |
vsprintf(buf,"PCI Bus %04x:%02x", domain, busnum); |
info.name = strdup(buf); |
#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 |
#define ACPI_VIDEO_DEVICE_POSTING 0x0002 |
#define ACPI_VIDEO_ROM_AVAILABLE 0x0004 |
#define ACPI_VIDEO_BACKLIGHT 0x0008 |
#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 |
#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 |
#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 |
#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 |
if (!info.name) |
goto name_alloc_fail; |
info.res_num = 0; |
AcpiWalkResources(device->handle, METHOD_NAME__CRS, setup_resource, |
&info); |
long acpi_is_video_device(struct acpi_device *device) |
{ |
ACPI_HANDLE h_dummy; |
long video_caps = 0; |
return; |
if (!device) |
return 0; |
name_alloc_fail: |
kfree(info.res); |
res_alloc_fail: |
return; |
} |
/* Is this device able to support video switching ? */ |
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOD", &h_dummy)) || |
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOS", &h_dummy))) |
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; |
/* Is this device able to retrieve a video ROM ? */ |
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_ROM", &h_dummy))) |
video_caps |= ACPI_VIDEO_ROM_AVAILABLE; |
/* Is this device able to configure which video head to be POSTed ? */ |
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_VPO", &h_dummy)) && |
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_GPD", &h_dummy)) && |
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_SPD", &h_dummy))) |
video_caps |= ACPI_VIDEO_DEVICE_POSTING; |
return video_caps; |
} |
struct pci_ops pci_root_ops = { |
.read = NULL, |
.write = NULL, |
}; |
static void acpi_device_set_id(struct acpi_device *device) |
struct pci_bus* pci_acpi_scan_root(struct acpi_pci_root *root) |
{ |
ACPI_STATUS status; |
ACPI_DEVICE_INFO *info; |
ACPI_DEVICE_ID_LIST *cid_list; |
int i; |
struct acpi_device *device = root->device; |
int domain = root->segment; |
int busnum = root->secondary.start; |
struct pci_bus *bus; |
struct pci_sysdata *sd; |
int node = 0; |
switch (device->device_type) |
{ |
case ACPI_BUS_TYPE_DEVICE: |
if (ACPI_IS_ROOT_DEVICE(device)) |
{ |
acpi_add_id(device, ACPI_SYSTEM_HID); |
break; |
if (domain ) { |
printk(KERN_WARNING "pci_bus %04x:%02x: " |
"ignored (multiple domains not supported)\n", |
domain, busnum); |
return NULL; |
} |
status = AcpiGetObjectInfo(device->handle, &info); |
if (ACPI_FAILURE(status)) { |
printk(KERN_ERR "%s: Error reading device info\n", __func__); |
return; |
/* Allocate per-root-bus (not per bus) arch-specific data. |
* TODO: leak; this memory is never freed. |
* It's arguable whether it's worth the trouble to care. |
*/ |
sd = kzalloc(sizeof(*sd), GFP_KERNEL); |
if (!sd) { |
printk(KERN_WARNING "pci_bus %04x:%02x: " |
"ignored (out of memory)\n", domain, busnum); |
return NULL; |
} |
if (info->Valid & ACPI_VALID_HID) |
acpi_add_id(device, info->HardwareId.String); |
if (info->Valid & ACPI_VALID_CID) |
{ |
cid_list = &info->CompatibleIdList; |
for (i = 0; i < cid_list->Count; i++) |
acpi_add_id(device, cid_list->Ids[i].String); |
sd->domain = domain; |
sd->node = node; |
/* |
* Maybe the desired pci bus has been already scanned. In such case |
* it is unnecessary to scan the pci bus with the given domain,busnum. |
*/ |
bus = pci_find_bus(domain, busnum); |
if (bus) { |
/* |
* If the desired bus exits, the content of bus->sysdata will |
* be replaced by sd. |
*/ |
memcpy(bus->sysdata, sd, sizeof(*sd)); |
kfree(sd); |
} else { |
bus = pci_create_bus(busnum, &pci_root_ops, sd); |
if (bus) { |
get_current_resources(device, busnum, domain, bus); |
// bus->subordinate = pci_scan_child_bus(bus); |
} |
if (info->Valid & ACPI_VALID_ADR) { |
device->pnp.bus_address = info->Address; |
device->flags.bus_address = 1; |
} |
kfree(info); |
if (!bus) |
kfree(sd); |
/* |
* Some devices don't reliably have _HIDs & _CIDs, so add |
* synthetic HIDs to make sure drivers can find them. |
*/ |
if (acpi_is_video_device(device)) |
acpi_add_id(device, ACPI_VIDEO_HID); |
else if (ACPI_SUCCESS(acpi_bay_match(device))) |
acpi_add_id(device, ACPI_BAY_HID); |
else if (ACPI_SUCCESS(acpi_dock_match(device))) |
acpi_add_id(device, ACPI_DOCK_HID); |
else if (!acpi_device_hid(device) && |
ACPI_IS_ROOT_DEVICE(device->parent)) { |
acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ |
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); |
strcpy(device->pnp.device_class, ACPI_BUS_CLASS); |
if (bus && node != -1) { |
printk("on NUMA node %d\n", node); |
} |
break; |
case ACPI_BUS_TYPE_POWER: |
acpi_add_id(device, ACPI_POWER_HID); |
break; |
case ACPI_BUS_TYPE_PROCESSOR: |
acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID); |
break; |
case ACPI_BUS_TYPE_THERMAL: |
acpi_add_id(device, ACPI_THERMAL_HID); |
break; |
case ACPI_BUS_TYPE_POWER_BUTTON: |
acpi_add_id(device, ACPI_BUTTON_HID_POWERF); |
break; |
case ACPI_BUS_TYPE_SLEEP_BUTTON: |
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); |
break; |
return bus; |
} |
/* |
* We build acpi_devices for some objects that don't have _HID or _CID, |
* e.g., PCI bridges and slots. Drivers can't bind to these objects, |
* but we do use them indirectly by traversing the acpi_device tree. |
* This generic ID isn't useful for driver binding, but it provides |
* the useful property that "every acpi_device has an ID." |
*/ |
if (list_empty(&device->pnp.ids)) |
acpi_add_id(device, "device"); |
} |
static int acpi_device_set_context(struct acpi_device *device) |
static int acpi_pci_root_add(struct acpi_device *device) |
{ |
unsigned long long segment, bus; |
ACPI_STATUS status; |
int result; |
struct acpi_pci_root *root; |
ACPI_HANDLE handle; |
struct acpi_device *child; |
u32 flags, base_flags; |
/* |
* Context |
* ------- |
* Attach this 'struct acpi_device' to the ACPI object. This makes |
* resolutions from handle->device very efficient. Fixed hardware |
* devices have no handles, so we skip them. |
*/ |
if (!device->handle) |
return 0; |
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); |
if (!root) |
return -ENOMEM; |
status = AcpiAttachData(device->handle, |
acpi_bus_data_handler, device); |
if (ACPI_SUCCESS(status)) |
return 0; |
dbgprintf(KERN_ERR "Error attaching device data\n"); |
return -ENODEV; |
segment = 0; |
status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, |
&segment); |
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); |
result = -ENODEV; |
goto end; |
} |
static int acpi_device_register(struct acpi_device *device) |
/* Check _CRS first, then _BBN. If no _BBN, default to zero. */ |
root->secondary.flags = IORESOURCE_BUS; |
status = try_get_root_bridge_busnr(device->handle, &root->secondary); |
if (ACPI_FAILURE(status)) |
{ |
int result; |
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
int found = 0; |
/* |
* Linkage |
* ------- |
* Link this device to its parent and siblings. |
* We need both the start and end of the downstream bus range |
* to interpret _CBA (MMCONFIG base address), so it really is |
* supposed to be in _CRS. If we don't find it there, all we |
* can do is assume [_BBN-0xFF] or [0-0xFF]. |
*/ |
INIT_LIST_HEAD(&device->children); |
INIT_LIST_HEAD(&device->node); |
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
if (!new_bus_id) { |
dbgprintf(KERN_ERR "Memory allocation error\n"); |
return -ENOMEM; |
root->secondary.end = 0xFF; |
printk(KERN_WARNING PREFIX |
"no secondary bus range in _CRS\n"); |
status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); |
if (ACPI_SUCCESS(status)) |
root->secondary.start = bus; |
else if (status == AE_NOT_FOUND) |
root->secondary.start = 0; |
else { |
printk(KERN_ERR PREFIX "can't evaluate _BBN\n"); |
result = -ENODEV; |
goto end; |
} |
mutex_lock(&acpi_device_lock); |
/* |
* Find suitable bus_id and instance number in acpi_bus_id_list |
* If failed, create one and link it into acpi_bus_id_list |
*/ |
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) |
{ |
if (!strcmp(acpi_device_bus_id->bus_id, acpi_device_hid(device))) |
{ |
acpi_device_bus_id->instance_no++; |
found = 1; |
kfree(new_bus_id); |
break; |
} |
} |
if (!found) |
{ |
acpi_device_bus_id = new_bus_id; |
strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device)); |
acpi_device_bus_id->instance_no = 0; |
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); |
} |
// dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); |
INIT_LIST_HEAD(&root->node); |
root->device = device; |
root->segment = segment & 0xFFFF; |
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); |
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); |
device->driver_data = root; |
if (device->parent) |
list_add_tail(&device->node, &device->parent->children); |
mutex_unlock(&acpi_device_lock); |
// device->dev.bus = &acpi_bus_type; |
// device->dev.release = &acpi_device_release; |
// result = device_register(&device->dev); |
// if (result) { |
// dev_err(&device->dev, "Error registering device\n"); |
// goto end; |
// } |
// device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
return 0; |
end: |
mutex_lock(&acpi_device_lock); |
if (device->parent) |
list_del(&device->node); |
mutex_unlock(&acpi_device_lock); |
return result; |
} |
static int acpi_add_single_object(struct acpi_device **child, |
ACPI_HANDLE handle, int type, |
unsigned long long sta, |
struct acpi_bus_ops *ops) |
{ |
int result; |
struct acpi_device *device; |
ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); |
if (!device) { |
dbgprintf("%s: Memory allocation error\n", __FUNCTION__); |
return -ENOMEM; |
} |
INIT_LIST_HEAD(&device->pnp.ids); |
device->device_type = type; |
device->handle = handle; |
device->parent = acpi_bus_get_parent(handle); |
device->bus_ops = *ops; /* workround for not call .start */ |
STRUCT_TO_INT(device->status) = sta; |
acpi_device_get_busid(device); |
/* |
* Flags |
* ----- |
* Note that we only look for object handles -- cannot evaluate objects |
* until we know the device is present and properly initialized. |
* All supported architectures that use ACPI have support for |
* PCI domains, so we indicate this in _OSC support capabilities. |
*/ |
result = acpi_bus_get_flags(device); |
if (result) |
goto end; |
// flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; |
// acpi_pci_osc_support(root, flags); |
/* |
* Initialize Device |
* ----------------- |
* TBD: Synch with Core's enumeration/initialization process. |
* TBD: Need PCI interface for enumeration/configuration of roots. |
*/ |
acpi_device_set_id(device); |
/* TBD: Locking */ |
list_add_tail(&root->node, &acpi_pci_roots); |
if ((result = acpi_device_set_context(device))) |
goto end; |
printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", |
acpi_device_name(device), acpi_device_bid(device), |
root->segment, &root->secondary); |
result = acpi_device_register(device); |
/* |
* Bind _ADR-Based Devices when hot add |
* Scan the Root Bridge |
* -------------------- |
* Must do this prior to any attempt to bind the root device, as the |
* PCI namespace does not get created until this call is made (and |
* thus the root bridge's pci_dev does not exist). |
*/ |
// if (device->flags.bus_address) { |
// if (device->parent && device->parent->ops.bind) |
// device->parent->ops.bind(device); |
// } |
end: |
if (!result) { |
AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer); |
dbgprintf("Adding [%s]\n", (char *)buffer.Pointer); |
kfree(buffer.Pointer); |
*child = device; |
}; |
return result; |
root->bus = pci_acpi_scan_root(root); |
if (!root->bus) { |
printk(KERN_ERR PREFIX |
"Bus %04x:%02x not present in PCI namespace\n", |
root->segment, (unsigned int)root->secondary.start); |
result = -ENODEV; |
goto end; |
} |
static ACPI_STATUS acpi_bus_check_add(ACPI_HANDLE handle, u32 lvl, |
void *context, void **return_value) |
{ |
struct acpi_bus_ops *ops = context; |
int type; |
unsigned long long sta; |
struct acpi_device *device; |
ACPI_STATUS status; |
int result; |
result = acpi_bus_type_and_status(handle, &type, &sta); |
if (result) |
{ |
return AE_OK; |
}; |
if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) |
{ |
return AE_CTRL_DEPTH; |
}; |
/* |
* We may already have an acpi_device from a previous enumeration. If |
* so, we needn't add it again, but we may still have to start it. |
* Attach ACPI-PCI Context |
* ----------------------- |
* Thus binding the ACPI and PCI devices. |
*/ |
device = NULL; |
acpi_bus_get_device(handle, &device); |
if (ops->acpi_op_add && !device) |
acpi_add_single_object(&device, handle, type, sta, ops); |
// result = acpi_pci_bind_root(device); |
// if (result) |
// goto end; |
if (!device) |
{ |
return AE_CTRL_DEPTH; |
}; |
/* |
if (ops->acpi_op_start && !(ops->acpi_op_add)) { |
status = acpi_start_single_object(device); |
if (ACPI_FAILURE(status)) |
return AE_CTRL_DEPTH; |
} |
* PCI Routing Table |
* ----------------- |
* Evaluate and parse _PRT, if exists. |
*/ |
if (!*return_value) |
*return_value = device; |
return AE_OK; |
} |
static int acpi_bus_scan(ACPI_HANDLE handle, struct acpi_bus_ops *ops, |
struct acpi_device **child) |
{ |
ACPI_STATUS status; |
void *device = NULL; |
ENTER(); |
status = acpi_bus_check_add(handle, 0, ops, &device); |
status = AcpiGetHandle(device->handle, METHOD_NAME__PRT, &handle); |
if (ACPI_SUCCESS(status)) |
AcpiWalkNamespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
acpi_bus_check_add, NULL, ops, &device); |
result = acpi_pci_irq_add_prt(device->handle, root->bus); |
if (child) |
*child = device; |
/* |
* Scan and bind all _ADR-Based Devices |
*/ |
// list_for_each_entry(child, &device->children, node) |
// acpi_pci_bridge_scan(child); |
LEAVE(); |
return 0; |
if (device) |
return 0; |
else |
return -ENODEV; |
end: |
if (!list_empty(&root->node)) |
list_del(&root->node); |
kfree(root); |
return result; |
} |
int acpi_scan() |
static const struct acpi_device_ids root_device_ids[] = |
{ |
int err; |
struct acpi_bus_ops ops; |
memset(&ops, 0, sizeof(ops)); |
ops.acpi_op_add = 1; |
ops.acpi_op_start = 1; |
err = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); |
return err; |
{"PNP0A03", 0}, |
{"", 0}, |
}; |
void acpi_init_pci(struct acpi_device *device) |
{ |
struct acpi_device *child; |
enum pic_mode |
if ( !acpi_match_device_ids(device, root_device_ids) ) |
{ |
IO_PIC = 0, |
IO_APIC |
dbgprintf(PREFIX "PCI root %s\n", device->pnp.bus_id); |
acpi_pci_root_add(device); |
}; |
static void set_pic_mode(enum pic_mode mode) |
{ |
ACPI_OBJECT arg1; |
ACPI_OBJECT_LIST args; |
ACPI_STATUS as; |
arg1.Type = ACPI_TYPE_INTEGER; |
arg1.Integer.Value = mode; |
args.Count = 1; |
args.Pointer = &arg1; |
as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL); |
/* |
* We can silently ignore failure as it may not be implemented, ACPI should |
* provide us with correct information anyway |
*/ |
if (ACPI_SUCCESS(as)) |
dbgprintf("ACPI: machine set to %s mode\n", mode ? "APIC" : "PIC"); |
} |
void print_device_tree(struct acpi_device *device) |
{ |
struct acpi_device *child; |
dbgprintf("%s\n", device->pnp.bus_id); |
list_for_each_entry(child, &device->children, node) |
{ |
print_device_tree(child); |
acpi_init_pci(child); |
}; |
}; |
u32_t drvEntry(int action, char *cmdline) |
{ |
u32_t retval; |
1004,74 → 645,12 |
set_pic_mode(IO_APIC); |
#if 0 |
scan_devices(); |
acpi_scan(); |
{ |
bool retval = false; |
u32_t bus, last_bus; |
// print_device_tree(acpi_root); |
if( (last_bus = PciApi(1))==-1) |
return retval; |
acpi_init_pci(acpi_root); |
dbgprintf("last bus %x\n", last_bus); |
for(bus=0; bus <= last_bus; bus++) |
{ |
u32_t dev; |
for(dev = 0; dev < 32; dev++) |
{ |
u32_t fn; |
for(fn = 0; fn < 8; fn++) |
{ |
u32_t id; |
u32_t irq_bios, irq_acpi; |
u32_t irq_pin; |
u16_t pcicmd; |
u32_t tmp; |
u32_t devfn = (dev<<3 )|fn; |
id = PciRead32(bus,devfn, PCI_VENDOR_ID); |
/* some broken boards return 0 or ~0 if a slot is empty: */ |
if (id == 0xffffffff || id == 0x00000000 || |
id == 0x0000ffff || id == 0xffff0000) |
continue; |
pcicmd = PciRead16(bus,devfn, PCI_COMMAND); |
if (! pcicmd & PCI_COMMAND_IO) |
continue; |
tmp = PciRead32(bus,devfn, 0x3C); |
irq_bios = tmp & 0xFF; |
irq_pin = (tmp >> 8) & 0xFF; |
int slot = (fn >> 3) & 0x1f; |
irq_acpi = irqtable[ dev * PCI_MAX_PINS +(irq_pin-1) ]; |
if( irq_acpi < 0) |
dbgprintf("PCI: no ACPI IRQ routing for " |
"device %d.%d.%d INT%c\n",bus,dev,fn,'A'+irq_pin-1); |
dbgprintf("pci device %x_%x bus %d dev %d fn %d," |
"IRQ PIN %d BIOS IRQ %d ACPI IRQ %d\n", |
id & 0xFFFF, id>>16, bus, dev, fn, irq_pin, irq_bios, irq_acpi); |
}; |
} |
}; |
}; |
#endif |
acpi_scan(); |
print_device_tree(acpi_root); |
/* |
ACPI_HANDLE bus_handle; |
ACPI_HANDLE pci_root; |
1182,7 → 761,71 |
}; |
#if 0 |
scan_devices(); |
{ |
bool retval = false; |
u32_t bus, last_bus; |
if( (last_bus = PciApi(1))==-1) |
return retval; |
dbgprintf("last bus %x\n", last_bus); |
for(bus=0; bus <= last_bus; bus++) |
{ |
u32_t dev; |
for(dev = 0; dev < 32; dev++) |
{ |
u32_t fn; |
for(fn = 0; fn < 8; fn++) |
{ |
u32_t id; |
u32_t irq_bios, irq_acpi; |
u32_t irq_pin; |
u16_t pcicmd; |
u32_t tmp; |
u32_t devfn = (dev<<3 )|fn; |
id = PciRead32(bus,devfn, PCI_VENDOR_ID); |
/* some broken boards return 0 or ~0 if a slot is empty: */ |
if (id == 0xffffffff || id == 0x00000000 || |
id == 0x0000ffff || id == 0xffff0000) |
continue; |
pcicmd = PciRead16(bus,devfn, PCI_COMMAND); |
if (! pcicmd & PCI_COMMAND_IO) |
continue; |
tmp = PciRead32(bus,devfn, 0x3C); |
irq_bios = tmp & 0xFF; |
irq_pin = (tmp >> 8) & 0xFF; |
int slot = (fn >> 3) & 0x1f; |
irq_acpi = irqtable[ dev * PCI_MAX_PINS +(irq_pin-1) ]; |
if( irq_acpi < 0) |
dbgprintf("PCI: no ACPI IRQ routing for " |
"device %d.%d.%d INT%c\n",bus,dev,fn,'A'+irq_pin-1); |
dbgprintf("pci device %x_%x bus %d dev %d fn %d," |
"IRQ PIN %d BIOS IRQ %d ACPI IRQ %d\n", |
id & 0xFFFF, id>>16, bus, dev, fn, irq_pin, irq_bios, irq_acpi); |
}; |
} |
}; |
}; |
#endif |
#if 0 |
ACPI_STATUS |
1379,3 → 1022,15 |
} |
#endif |
char* strdup(const char *str) |
{ |
size_t len = strlen (str) + 1; |
char *copy = malloc(len); |
if (copy) |
{ |
memcpy (copy, str, len); |
} |
return copy; |
} |
/drivers/devman/acpi_bus.h |
---|
0,0 → 1,128 |
struct resource_list { |
struct resource_list *next; |
struct resource *res; |
// struct pci_dev *dev; |
}; |
enum acpi_bus_device_type { |
ACPI_BUS_TYPE_DEVICE = 0, |
ACPI_BUS_TYPE_POWER, |
ACPI_BUS_TYPE_PROCESSOR, |
ACPI_BUS_TYPE_THERMAL, |
ACPI_BUS_TYPE_POWER_BUTTON, |
ACPI_BUS_TYPE_SLEEP_BUTTON, |
ACPI_BUS_DEVICE_TYPE_COUNT |
}; |
/* |
* _HID definitions |
* HIDs must conform to ACPI spec(6.1.4) |
* KolibriOS specific HIDs do not apply to this and begin with KOS: |
*/ |
#define ACPI_POWER_HID "KLBPOWER" |
#define ACPI_PROCESSOR_OBJECT_HID "KLBCPU" |
#define ACPI_SYSTEM_HID "KLBSYSTM" |
#define ACPI_THERMAL_HID "KLBTHERM" |
#define ACPI_BUTTON_HID_POWERF "KLBPWRBN" |
#define ACPI_BUTTON_HID_SLEEPF "KLBSLPBN" |
#define ACPI_VIDEO_HID "KLBVIDEO" |
#define ACPI_BAY_HID "KLBIOBAY" |
#define ACPI_DOCK_HID "KLBDOCK" |
/* Quirk for broken IBM BIOSes */ |
#define ACPI_SMBUS_IBM_HID "SMBUSIBM" |
struct acpi_bus_ops |
{ |
u32_t acpi_op_add:1; |
u32_t acpi_op_start:1; |
}; |
#define ACPI_ID_LEN 16 /* only 9 bytes needed here, 16 bytes are used */ |
/* to workaround crosscompile issues */ |
struct acpi_device_ids |
{ |
u8 id[ACPI_ID_LEN]; |
u32 driver_data; |
}; |
struct acpi_device_flags { |
u32 dynamic_status:1; |
u32 bus_address:1; |
u32 removable:1; |
u32 ejectable:1; |
u32 lockable:1; |
u32 suprise_removal_ok:1; |
u32 power_manageable:1; |
u32 performance_manageable:1; |
u32 wake_capable:1; /* Wakeup(_PRW) supported? */ |
u32 force_power_state:1; |
u32 reserved:22; |
}; |
struct acpi_device_status { |
u32 present:1; |
u32 enabled:1; |
u32 show_in_ui:1; |
u32 functional:1; |
u32 battery_present:1; |
u32 reserved:27; |
}; |
typedef char acpi_bus_id[8]; |
typedef unsigned long acpi_bus_address; |
typedef char acpi_device_name[40]; |
typedef char acpi_device_class[20]; |
struct acpi_device_pnp |
{ |
acpi_bus_id bus_id; /* Object name */ |
acpi_bus_address bus_address; /* _ADR */ |
char *unique_id; /* _UID */ |
struct list_head ids; /* _HID and _CIDs */ |
acpi_device_name device_name; /* Driver-determined */ |
acpi_device_class device_class; /* " */ |
}; |
struct acpi_device |
{ |
int device_type; |
ACPI_HANDLE handle; /* no handle for fixed hardware */ |
struct acpi_device *parent; |
struct list_head children; |
struct list_head node; |
// struct list_head wakeup_list; |
struct acpi_device_status status; |
struct acpi_device_flags flags; |
struct acpi_device_pnp pnp; |
// struct acpi_device_power power; |
// struct acpi_device_wakeup wakeup; |
// struct acpi_device_perf performance; |
// struct acpi_device_dir dir; |
// struct acpi_device_ops ops; |
// struct acpi_driver *driver; |
void *driver_data; |
// struct device dev; |
struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ |
// enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ |
}; |
#define acpi_device_bid(d) ((d)->pnp.bus_id) |
#define acpi_device_adr(d) ((d)->pnp.bus_address) |
char *acpi_device_hid(struct acpi_device *device); |
#define acpi_device_name(d) ((d)->pnp.device_name) |
#define acpi_device_class(d) ((d)->pnp.device_class) |
int acpi_match_device_ids(struct acpi_device *device, |
const struct acpi_device_ids *ids); |
int acpi_pci_irq_add_prt(ACPI_HANDLE handle, struct pci_bus *bus); |
/drivers/devman/pci/pci.c |
---|
0,0 → 1,151 |
#include <ddk.h> |
#include <linux/errno.h> |
#include <mutex.h> |
#include <pci.h> |
#include <syscall.h> |
LIST_HEAD(pci_root_buses); |
#define IO_SPACE_LIMIT 0xffff |
struct resource ioport_resource = { |
.name = "PCI IO", |
.start = 0, |
.end = IO_SPACE_LIMIT, |
.flags = IORESOURCE_IO, |
}; |
struct resource iomem_resource = { |
.name = "PCI mem", |
.start = 0, |
.end = -1, |
.flags = IORESOURCE_MEM, |
}; |
static inline int pci_domain_nr(struct pci_bus *bus) |
{ |
struct pci_sysdata *sd = bus->sysdata; |
return sd->domain; |
} |
static struct pci_bus * pci_alloc_bus(void) |
{ |
struct pci_bus *b; |
b = kzalloc(sizeof(*b), GFP_KERNEL); |
if (b) { |
INIT_LIST_HEAD(&b->node); |
INIT_LIST_HEAD(&b->children); |
INIT_LIST_HEAD(&b->devices); |
INIT_LIST_HEAD(&b->slots); |
INIT_LIST_HEAD(&b->resources); |
} |
return b; |
} |
struct pci_bus * pci_create_bus(int bus, struct pci_ops *ops, void *sysdata) |
{ |
int error; |
struct pci_bus *b, *b2; |
b = pci_alloc_bus(); |
if (!b) |
return NULL; |
b->sysdata = sysdata; |
b->ops = ops; |
b2 = pci_find_bus(pci_domain_nr(b), bus); |
if (b2) { |
/* If we already got to this bus through a different bridge, ignore it */ |
dbgprintf("bus already known\n"); |
goto err_out; |
} |
// down_write(&pci_bus_sem); |
list_add_tail(&b->node, &pci_root_buses); |
// up_write(&pci_bus_sem); |
b->number = b->secondary = bus; |
b->resource[0] = &ioport_resource; |
b->resource[1] = &iomem_resource; |
return b; |
err_out: |
kfree(b); |
return NULL; |
} |
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) |
{ |
struct pci_bus* child; |
struct list_head *tmp; |
if(bus->number == busnr) |
return bus; |
list_for_each(tmp, &bus->children) { |
child = pci_do_find_bus(pci_bus_b(tmp), busnr); |
if(child) |
return child; |
} |
return NULL; |
} |
/** |
* pci_find_bus - locate PCI bus from a given domain and bus number |
* @domain: number of PCI domain to search |
* @busnr: number of desired PCI bus |
* |
* Given a PCI bus number and domain number, the desired PCI bus is located |
* in the global list of PCI buses. If the bus is found, a pointer to its |
* data structure is returned. If no bus is found, %NULL is returned. |
*/ |
struct pci_bus * pci_find_bus(int domain, int busnr) |
{ |
struct pci_bus *bus = NULL; |
struct pci_bus *tmp_bus; |
while ((bus = pci_find_next_bus(bus)) != NULL) { |
if (pci_domain_nr(bus) != domain) |
continue; |
tmp_bus = pci_do_find_bus(bus, busnr); |
if (tmp_bus) |
return tmp_bus; |
} |
return NULL; |
} |
/** |
* pci_find_next_bus - begin or continue searching for a PCI bus |
* @from: Previous PCI bus found, or %NULL for new search. |
* |
* Iterates through the list of known PCI busses. A new search is |
* initiated by passing %NULL as the @from argument. Otherwise if |
* @from is not %NULL, searches continue from next device on the |
* global list. |
*/ |
struct pci_bus * |
pci_find_next_bus(const struct pci_bus *from) |
{ |
struct list_head *n; |
struct pci_bus *b = NULL; |
// WARN_ON(in_interrupt()); |
// down_read(&pci_bus_sem); |
n = from ? from->node.next : pci_root_buses.next; |
if (n != &pci_root_buses) |
b = pci_bus_b(n); |
// up_read(&pci_bus_sem); |
return b; |
} |
/drivers/devman/pci_irq.c |
---|
0,0 → 1,131 |
#include <ddk.h> |
#include <linux/errno.h> |
#include <mutex.h> |
#include <linux/spinlock.h> |
#include <pci.h> |
#include <syscall.h> |
#include "acpi.h" |
#include "acpi_bus.h" |
#define PREFIX "ACPI: " |
struct acpi_prt_entry |
{ |
struct list_head list; |
ACPI_PCI_ID id; |
u8 pin; |
ACPI_HANDLE link; |
u32 index; /* GSI, or link _CRS index */ |
}; |
static LIST_HEAD(acpi_prt_list); |
static DEFINE_SPINLOCK(acpi_prt_lock); |
static inline char pin_name(int pin) |
{ |
return 'A' + pin - 1; |
} |
static int acpi_pci_irq_add_entry(ACPI_HANDLE handle, struct pci_bus *bus, |
struct acpi_pci_routing_table *prt) |
{ |
struct acpi_prt_entry *entry; |
entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); |
if (!entry) |
return -ENOMEM; |
/* |
* Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses |
* 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert |
* it here. |
*/ |
entry->id.Segment = pci_domain_nr(bus); |
entry->id.Bus = bus->number; |
entry->id.Device = (prt->Address >> 16) & 0xFFFF; |
entry->pin = prt->Pin + 1; |
// do_prt_fixups(entry, prt); |
entry->index = prt->SourceIndex; |
/* |
* Type 1: Dynamic |
* --------------- |
* The 'source' field specifies the PCI interrupt link device used to |
* configure the IRQ assigned to this slot|dev|pin. The 'source_index' |
* indicates which resource descriptor in the resource template (of |
* the link device) this interrupt is allocated from. |
* |
* NOTE: Don't query the Link Device for IRQ information at this time |
* because Link Device enumeration may not have occurred yet |
* (e.g. exists somewhere 'below' this _PRT entry in the ACPI |
* namespace). |
*/ |
if (prt->Source[0]) |
AcpiGetHandle(handle, prt->Source, &entry->link); |
/* |
* Type 2: Static |
* -------------- |
* The 'source' field is NULL, and the 'source_index' field specifies |
* the IRQ value, which is hardwired to specific interrupt inputs on |
* the interrupt controller. |
*/ |
dbgprintf(PREFIX " %04x:%02x:%02x[%c] -> %s[%d]\n", |
entry->id.Segment, entry->id.Bus, |
entry->id.Device, pin_name(entry->pin), |
prt->Source, entry->index); |
spin_lock(&acpi_prt_lock); |
list_add_tail(&entry->list, &acpi_prt_list); |
spin_unlock(&acpi_prt_lock); |
return 0; |
} |
int acpi_pci_irq_add_prt(ACPI_HANDLE handle, struct pci_bus *bus) |
{ |
ACPI_STATUS status; |
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
struct acpi_pci_routing_table *entry; |
/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ |
status = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer); |
if (ACPI_FAILURE(status)) |
return -ENODEV; |
printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", |
(char *) buffer.Pointer); |
kfree(buffer.Pointer); |
buffer.Length = ACPI_ALLOCATE_BUFFER; |
buffer.Pointer = NULL; |
status = AcpiGetIrqRoutingTable(handle, &buffer); |
if (ACPI_FAILURE(status)) |
{ |
dbgprintf("AcpiGetIrqRoutingTable failed " |
"evaluating _PRT [%s]\n",AcpiFormatException(status)); |
kfree(buffer.Pointer); |
return -ENODEV; |
} |
entry = buffer.Pointer; |
while (entry && (entry->Length > 0)) { |
acpi_pci_irq_add_entry(handle, bus, entry); |
entry = (struct acpi_pci_routing_table *) |
((unsigned long)entry + entry->Length); |
} |
kfree(buffer.Pointer); |
return 0; |
} |
/drivers/devman/scan.c |
---|
0,0 → 1,766 |
#include <ddk.h> |
#include <linux/errno.h> |
#include <mutex.h> |
#include <pci.h> |
#include <syscall.h> |
#include "acpi.h" |
#include "acpi_bus.h" |
#define PREFIX "ACPI: " |
#define ACPI_BUS_CLASS "system_bus" |
#define ACPI_BUS_HID "KLBSYBUS" |
#define ACPI_BUS_DEVICE_NAME "System Bus" |
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) |
#define STRUCT_TO_INT(s) (*((int*)&s)) |
extern struct acpi_device *acpi_root; |
static LIST_HEAD(acpi_device_list); |
static LIST_HEAD(acpi_bus_id_list); |
DEFINE_MUTEX(acpi_device_lock); |
struct acpi_device_bus_id{ |
char bus_id[15]; |
unsigned int instance_no; |
struct list_head node; |
}; |
struct acpi_hardware_id { |
struct list_head list; |
char *id; |
}; |
#define acpi_device_name(d) ((d)->pnp.device_name) |
#define acpi_device_class(d) ((d)->pnp.device_class) |
static void |
acpi_util_eval_error(ACPI_HANDLE h, ACPI_STRING p, ACPI_STATUS s) |
{ |
#ifdef ACPI_DEBUG_OUTPUT |
char prefix[80] = {'\0'}; |
ACPI_BUFFER buffer = {sizeof(prefix), prefix}; |
AcpiGetName(h, ACPI_FULL_PATHNAME, &buffer); |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n", |
(char *) prefix, p, AcpiFormatException(s))); |
#else |
return; |
#endif |
} |
ACPI_STATUS |
acpi_evaluate_integer(ACPI_HANDLE handle, ACPI_STRING pathname, |
ACPI_OBJECT_LIST *arguments, unsigned long long *data) |
{ |
ACPI_STATUS status = AE_OK; |
ACPI_OBJECT element; |
ACPI_BUFFER buffer = { 0, NULL }; |
if (!data) |
return AE_BAD_PARAMETER; |
buffer.Length = sizeof(ACPI_OBJECT); |
buffer.Pointer = &element; |
status = AcpiEvaluateObject(handle, pathname, arguments, &buffer); |
if (ACPI_FAILURE(status)) { |
acpi_util_eval_error(handle, pathname, status); |
return status; |
} |
if (element.Type != ACPI_TYPE_INTEGER) { |
acpi_util_eval_error(handle, pathname, AE_BAD_DATA); |
return AE_BAD_DATA; |
} |
*data = element.Integer.Value; |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); |
return AE_OK; |
} |
void acpi_bus_data_handler(ACPI_HANDLE handle, void *context) |
{ |
/* TBD */ |
return; |
} |
int acpi_bus_get_device(ACPI_HANDLE handle, struct acpi_device **device) |
{ |
ACPI_STATUS status = AE_OK; |
if (!device) |
{ |
return -EINVAL; |
}; |
/* TBD: Support fixed-feature devices */ |
status = AcpiGetData(handle, acpi_bus_data_handler, (void **)device); |
if (ACPI_FAILURE(status) || !*device) { |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", |
handle)); |
return -ENODEV; |
} |
return 0; |
} |
ACPI_STATUS acpi_bus_get_status_handle(ACPI_HANDLE handle, |
unsigned long long *sta) |
{ |
ACPI_STATUS status; |
status = acpi_evaluate_integer(handle, "_STA", NULL, sta); |
if (ACPI_SUCCESS(status)) |
{ |
return AE_OK; |
}; |
if (status == AE_NOT_FOUND) |
{ |
*sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; |
return AE_OK; |
} |
return status; |
} |
/* -------------------------------------------------------------------------- |
ACPI Bus operations |
-------------------------------------------------------------------------- */ |
int acpi_match_device_ids(struct acpi_device *device, |
const struct acpi_device_ids *ids) |
{ |
const struct acpi_device_ids *id; |
struct acpi_hardware_id *hwid; |
/* |
* If the device is not present, it is unnecessary to load device |
* driver for it. |
*/ |
// if (!device->status.present) |
// return -ENODEV; |
for (id = ids; id->id[0]; id++) |
list_for_each_entry(hwid, &device->pnp.ids, list) |
if (!strcmp((char *) id->id, hwid->id)) |
return 0; |
return -ENOENT; |
} |
static int acpi_device_register(struct acpi_device *device) |
{ |
int result; |
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
int found = 0; |
/* |
* Linkage |
* ------- |
* Link this device to its parent and siblings. |
*/ |
INIT_LIST_HEAD(&device->children); |
INIT_LIST_HEAD(&device->node); |
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
if (!new_bus_id) { |
printk(KERN_ERR PREFIX "Memory allocation error\n"); |
return -ENOMEM; |
} |
mutex_lock(&acpi_device_lock); |
/* |
* Find suitable bus_id and instance number in acpi_bus_id_list |
* If failed, create one and link it into acpi_bus_id_list |
*/ |
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) |
{ |
if (!strcmp(acpi_device_bus_id->bus_id, |
acpi_device_hid(device))) |
{ |
acpi_device_bus_id->instance_no++; |
found = 1; |
kfree(new_bus_id); |
break; |
} |
}; |
if (!found) |
{ |
acpi_device_bus_id = new_bus_id; |
strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device)); |
acpi_device_bus_id->instance_no = 0; |
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); |
} |
// dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); |
if (device->parent) |
list_add_tail(&device->node, &device->parent->children); |
mutex_unlock(&acpi_device_lock); |
// device->dev.bus = &acpi_bus_type; |
// device->dev.release = &acpi_device_release; |
// result = device_register(&device->dev); |
// if (result) { |
// dev_err(&device->dev, "Error registering device\n"); |
// goto end; |
// } |
// device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
return 0; |
end: |
mutex_lock(&acpi_device_lock); |
if (device->parent) |
list_del(&device->node); |
mutex_unlock(&acpi_device_lock); |
return result; |
} |
static struct acpi_device *acpi_bus_get_parent(ACPI_HANDLE handle) |
{ |
ACPI_STATUS status; |
struct acpi_device *device; |
int ret; |
/* |
* Fixed hardware devices do not appear in the namespace and do not |
* have handles, but we fabricate acpi_devices for them, so we have |
* to deal with them specially. |
*/ |
if (handle == NULL) |
return acpi_root; |
do { |
status = AcpiGetParent(handle, &handle); |
if (status == AE_NULL_ENTRY) |
return NULL; |
if (ACPI_FAILURE(status)) |
return acpi_root; |
ret = acpi_bus_get_device(handle, &device); |
if (ret == 0) |
return device; |
} while (1); |
} |
static int acpi_bus_get_flags(struct acpi_device *device) |
{ |
ACPI_STATUS status = AE_OK; |
ACPI_HANDLE temp = NULL; |
/* Presence of _STA indicates 'dynamic_status' */ |
status = AcpiGetHandle(device->handle, "_STA", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.dynamic_status = 1; |
/* Presence of _RMV indicates 'removable' */ |
status = AcpiGetHandle(device->handle, "_RMV", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.removable = 1; |
/* Presence of _EJD|_EJ0 indicates 'ejectable' */ |
status = AcpiGetHandle(device->handle, "_EJD", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.ejectable = 1; |
else { |
status = AcpiGetHandle(device->handle, "_EJ0", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.ejectable = 1; |
} |
/* Presence of _LCK indicates 'lockable' */ |
status = AcpiGetHandle(device->handle, "_LCK", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.lockable = 1; |
/* Presence of _PS0|_PR0 indicates 'power manageable' */ |
status = AcpiGetHandle(device->handle, "_PS0", &temp); |
if (ACPI_FAILURE(status)) |
status = AcpiGetHandle(device->handle, "_PR0", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.power_manageable = 1; |
/* Presence of _PRW indicates wake capable */ |
status = AcpiGetHandle(device->handle, "_PRW", &temp); |
if (ACPI_SUCCESS(status)) |
device->flags.wake_capable = 1; |
/* TBD: Performance management */ |
return 0; |
} |
static void acpi_device_get_busid(struct acpi_device *device) |
{ |
char bus_id[5] = { '?', 0 }; |
struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; |
int i = 0; |
/* |
* Bus ID |
* ------ |
* The device's Bus ID is simply the object name. |
* TBD: Shouldn't this value be unique (within the ACPI namespace)? |
*/ |
if (ACPI_IS_ROOT_DEVICE(device)) { |
strcpy(device->pnp.bus_id, "ACPI"); |
return; |
} |
switch (device->device_type) |
{ |
case ACPI_BUS_TYPE_POWER_BUTTON: |
strcpy(device->pnp.bus_id, "PWRF"); |
break; |
case ACPI_BUS_TYPE_SLEEP_BUTTON: |
strcpy(device->pnp.bus_id, "SLPF"); |
break; |
default: |
AcpiGetName(device->handle, ACPI_SINGLE_NAME, &buffer); |
/* Clean up trailing underscores (if any) */ |
for (i = 3; i > 1; i--) { |
if (bus_id[i] == '_') |
bus_id[i] = '\0'; |
else |
break; |
} |
strcpy(device->pnp.bus_id, bus_id); |
break; |
} |
} |
#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 |
#define ACPI_VIDEO_DEVICE_POSTING 0x0002 |
#define ACPI_VIDEO_ROM_AVAILABLE 0x0004 |
#define ACPI_VIDEO_BACKLIGHT 0x0008 |
#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 |
#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 |
#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 |
#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 |
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 |
long acpi_is_video_device(struct acpi_device *device) |
{ |
ACPI_HANDLE h_dummy; |
long video_caps = 0; |
if (!device) |
return 0; |
/* Is this device able to support video switching ? */ |
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOD", &h_dummy)) || |
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOS", &h_dummy))) |
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; |
/* Is this device able to retrieve a video ROM ? */ |
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_ROM", &h_dummy))) |
video_caps |= ACPI_VIDEO_ROM_AVAILABLE; |
/* Is this device able to configure which video head to be POSTed ? */ |
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_VPO", &h_dummy)) && |
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_GPD", &h_dummy)) && |
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_SPD", &h_dummy))) |
video_caps |= ACPI_VIDEO_DEVICE_POSTING; |
return video_caps; |
} |
/* |
* acpi_bay_match - see if a device is an ejectable driver bay |
* |
* If an acpi object is ejectable and has one of the ACPI ATA methods defined, |
* then we can safely call it an ejectable drive bay |
*/ |
static int acpi_bay_match(struct acpi_device *device){ |
ACPI_STATUS status; |
ACPI_HANDLE handle; |
ACPI_HANDLE tmp; |
ACPI_HANDLE phandle; |
handle = device->handle; |
status = AcpiGetHandle(handle, "_EJ0", &tmp); |
if (ACPI_FAILURE(status)) |
return -ENODEV; |
if ((ACPI_SUCCESS(AcpiGetHandle(handle, "_GTF", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(handle, "_GTM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(handle, "_STM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(handle, "_SDD", &tmp)))) |
return 0; |
if (AcpiGetParent(handle, &phandle)) |
return -ENODEV; |
if ((ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTF", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_STM", &tmp))) || |
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_SDD", &tmp)))) |
return 0; |
return -ENODEV; |
} |
/* |
* acpi_dock_match - see if a device has a _DCK method |
*/ |
static int acpi_dock_match(struct acpi_device *device) |
{ |
ACPI_HANDLE tmp; |
return AcpiGetHandle(device->handle, "_DCK", &tmp); |
} |
char *acpi_device_hid(struct acpi_device *device) |
{ |
struct acpi_hardware_id *hid; |
hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); |
return hid->id; |
} |
static void acpi_add_id(struct acpi_device *device, const char *dev_id) |
{ |
struct acpi_hardware_id *id; |
id = kmalloc(sizeof(*id), GFP_KERNEL); |
if (!id) |
return; |
INIT_LIST_HEAD(&id->list); |
id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); |
if (!id->id) { |
kfree(id); |
return; |
} |
strcpy(id->id, dev_id); |
list_add_tail(&id->list, &device->pnp.ids); |
} |
static void acpi_device_set_id(struct acpi_device *device) |
{ |
ACPI_STATUS status; |
ACPI_DEVICE_INFO *info; |
ACPI_DEVICE_ID_LIST *cid_list; |
int i; |
switch (device->device_type) |
{ |
case ACPI_BUS_TYPE_DEVICE: |
if (ACPI_IS_ROOT_DEVICE(device)) { |
acpi_add_id(device, ACPI_SYSTEM_HID); |
break; |
} |
status = AcpiGetObjectInfo(device->handle, &info); |
if (ACPI_FAILURE(status)) { |
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); |
return; |
} |
if (info->Valid & ACPI_VALID_HID) |
acpi_add_id(device, info->HardwareId.String); |
if (info->Valid & ACPI_VALID_CID) |
{ |
cid_list = &info->CompatibleIdList; |
for (i = 0; i < cid_list->Count; i++) |
acpi_add_id(device, cid_list->Ids[i].String); |
} |
if (info->Valid & ACPI_VALID_ADR) { |
device->pnp.bus_address = info->Address; |
device->flags.bus_address = 1; |
} |
kfree(info); |
/* |
* Some devices don't reliably have _HIDs & _CIDs, so add |
* synthetic HIDs to make sure drivers can find them. |
*/ |
if (acpi_is_video_device(device)) |
acpi_add_id(device, ACPI_VIDEO_HID); |
else if (ACPI_SUCCESS(acpi_bay_match(device))) |
acpi_add_id(device, ACPI_BAY_HID); |
else if (ACPI_SUCCESS(acpi_dock_match(device))) |
acpi_add_id(device, ACPI_DOCK_HID); |
else if (!acpi_device_hid(device) && |
ACPI_IS_ROOT_DEVICE(device->parent)) { |
acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ |
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); |
strcpy(device->pnp.device_class, ACPI_BUS_CLASS); |
} |
break; |
case ACPI_BUS_TYPE_POWER: |
acpi_add_id(device, ACPI_POWER_HID); |
break; |
case ACPI_BUS_TYPE_PROCESSOR: |
acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID); |
break; |
case ACPI_BUS_TYPE_THERMAL: |
acpi_add_id(device, ACPI_THERMAL_HID); |
break; |
case ACPI_BUS_TYPE_POWER_BUTTON: |
acpi_add_id(device, ACPI_BUTTON_HID_POWERF); |
break; |
case ACPI_BUS_TYPE_SLEEP_BUTTON: |
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); |
break; |
} |
/* |
* We build acpi_devices for some objects that don't have _HID or _CID, |
* e.g., PCI bridges and slots. Drivers can't bind to these objects, |
* but we do use them indirectly by traversing the acpi_device tree. |
* This generic ID isn't useful for driver binding, but it provides |
* the useful property that "every acpi_device has an ID." |
*/ |
if (list_empty(&device->pnp.ids)) |
acpi_add_id(device, "device"); |
} |
static int acpi_device_set_context(struct acpi_device *device) |
{ |
ACPI_STATUS status; |
/* |
* Context |
* ------- |
* Attach this 'struct acpi_device' to the ACPI object. This makes |
* resolutions from handle->device very efficient. Fixed hardware |
* devices have no handles, so we skip them. |
*/ |
if (!device->handle) |
return 0; |
status = AcpiAttachData(device->handle, |
acpi_bus_data_handler, device); |
if (ACPI_SUCCESS(status)) |
return 0; |
printk(KERN_ERR PREFIX "Error attaching device data\n"); |
return -ENODEV; |
} |
static int acpi_add_single_object(struct acpi_device **child, |
ACPI_HANDLE handle, int type, |
unsigned long long sta, |
struct acpi_bus_ops *ops) |
{ |
int result; |
struct acpi_device *device; |
ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); |
if (!device) { |
printk(KERN_ERR PREFIX "Memory allocation error\n"); |
return -ENOMEM; |
} |
INIT_LIST_HEAD(&device->pnp.ids); |
device->device_type = type; |
device->handle = handle; |
device->parent = acpi_bus_get_parent(handle); |
device->bus_ops = *ops; /* workround for not call .start */ |
STRUCT_TO_INT(device->status) = sta; |
acpi_device_get_busid(device); |
/* |
* Flags |
* ----- |
* Note that we only look for object handles -- cannot evaluate objects |
* until we know the device is present and properly initialized. |
*/ |
result = acpi_bus_get_flags(device); |
if (result) |
goto end; |
/* |
* Initialize Device |
* ----------------- |
* TBD: Synch with Core's enumeration/initialization process. |
*/ |
acpi_device_set_id(device); |
if ((result = acpi_device_set_context(device))) |
goto end; |
result = acpi_device_register(device); |
/* |
* Bind _ADR-Based Devices when hot add |
*/ |
// if (device->flags.bus_address) { |
// if (device->parent && device->parent->ops.bind) |
// device->parent->ops.bind(device); |
// } |
end: |
if (!result) { |
AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer); |
dbgprintf(PREFIX "Adding [%s]\n", (char *)buffer.Pointer); |
kfree(buffer.Pointer); |
*child = device; |
}; |
return result; |
} |
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
static int acpi_bus_type_and_status(ACPI_HANDLE handle, int *type, |
unsigned long long *sta) |
{ |
ACPI_STATUS status; |
ACPI_OBJECT_TYPE acpi_type; |
status = AcpiGetType(handle, &acpi_type); |
if (ACPI_FAILURE(status)) |
return -ENODEV; |
switch (acpi_type) |
{ |
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ |
case ACPI_TYPE_DEVICE: |
*type = ACPI_BUS_TYPE_DEVICE; |
status = acpi_bus_get_status_handle(handle, sta); |
if (ACPI_FAILURE(status)) |
return -ENODEV; |
break; |
case ACPI_TYPE_PROCESSOR: |
*type = ACPI_BUS_TYPE_PROCESSOR; |
status = acpi_bus_get_status_handle(handle, sta); |
if (ACPI_FAILURE(status)) |
return -ENODEV; |
break; |
case ACPI_TYPE_THERMAL: |
*type = ACPI_BUS_TYPE_THERMAL; |
*sta = ACPI_STA_DEFAULT; |
break; |
case ACPI_TYPE_POWER: |
*type = ACPI_BUS_TYPE_POWER; |
*sta = ACPI_STA_DEFAULT; |
break; |
default: |
return -ENODEV; |
} |
return 0; |
} |
static ACPI_STATUS acpi_bus_check_add(ACPI_HANDLE handle, u32 lvl, |
void *context, void **return_value) |
{ |
struct acpi_bus_ops *ops = context; |
int type; |
unsigned long long sta; |
struct acpi_device *device; |
ACPI_STATUS status; |
int result; |
result = acpi_bus_type_and_status(handle, &type, &sta); |
if (result) |
return AE_OK; |
if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) |
return AE_CTRL_DEPTH; |
/* |
* We may already have an acpi_device from a previous enumeration. If |
* so, we needn't add it again, but we may still have to start it. |
*/ |
device = NULL; |
acpi_bus_get_device(handle, &device); |
if (ops->acpi_op_add && !device) |
acpi_add_single_object(&device, handle, type, sta, ops); |
if (!device) |
return AE_CTRL_DEPTH; |
/* |
if (ops->acpi_op_start && !(ops->acpi_op_add)) { |
status = acpi_start_single_object(device); |
if (ACPI_FAILURE(status)) |
return AE_CTRL_DEPTH; |
} |
*/ |
if (!*return_value) |
*return_value = device; |
return AE_OK; |
} |
static int acpi_bus_scan(ACPI_HANDLE handle, struct acpi_bus_ops *ops, |
struct acpi_device **child) |
{ |
ACPI_STATUS status; |
void *device = NULL; |
status = acpi_bus_check_add(handle, 0, ops, &device); |
if (ACPI_SUCCESS(status)) |
AcpiWalkNamespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
acpi_bus_check_add, NULL, ops, &device); |
if (child) |
*child = device; |
if (device) |
return 0; |
else |
return -ENODEV; |
} |
int acpi_scan() |
{ |
int err; |
struct acpi_bus_ops ops; |
memset(&ops, 0, sizeof(ops)); |
ops.acpi_op_add = 1; |
ops.acpi_op_start = 1; |
err = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); |
return err; |
}; |
/drivers/include/ddk.h |
---|
11,6 → 11,9 |
#define MANUAL_DESTROY 0x80000000 |
#define ENTER() dbgprintf("enter %s\n",__FUNCTION__) |
#define LEAVE() dbgprintf("leave %s\n",__FUNCTION__) |
typedef struct |
{ |
u32_t code; |
/drivers/include/linux/pci.h |
---|
349,12 → 349,45 |
{ |
resource_size_t start; |
resource_size_t end; |
// const char *name; |
const char *name; |
unsigned long flags; |
// struct resource *parent, *sibling, *child; |
struct resource *parent, *sibling, *child; |
}; |
/* |
* For PCI devices, the region numbers are assigned this way: |
*/ |
enum { |
/* #0-5: standard PCI resources */ |
PCI_STD_RESOURCES, |
PCI_STD_RESOURCE_END = 5, |
/* #6: expansion ROM resource */ |
PCI_ROM_RESOURCE, |
/* device specific resources */ |
#ifdef CONFIG_PCI_IOV |
PCI_IOV_RESOURCES, |
PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1, |
#endif |
/* resources assigned to buses behind the bridge */ |
#define PCI_BRIDGE_RESOURCE_NUM 4 |
PCI_BRIDGE_RESOURCES, |
PCI_BRIDGE_RESOURCE_END = PCI_BRIDGE_RESOURCES + |
PCI_BRIDGE_RESOURCE_NUM - 1, |
/* total resources associated with a PCI device */ |
PCI_NUM_RESOURCES, |
/* preserve this for compatibility */ |
DEVICE_COUNT_RESOURCE |
}; |
/* |
* IO resources have these defined flags. |
*/ |
#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ |
549,6 → 582,71 |
struct pci_dev pci_dev; |
}pci_dev_t; |
typedef unsigned short __bitwise pci_bus_flags_t; |
enum pci_bus_flags { |
PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, |
PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2, |
}; |
struct pci_sysdata |
{ |
int domain; /* PCI domain */ |
int node; /* NUMA node */ |
#ifdef CONFIG_X86_64 |
void *iommu; /* IOMMU private data */ |
#endif |
}; |
struct pci_bus; |
struct pci_ops |
{ |
int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); |
int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); |
}; |
struct pci_bus { |
struct list_head node; /* node in list of buses */ |
struct pci_bus *parent; /* parent bus this bridge is on */ |
struct list_head children; /* list of child buses */ |
struct list_head devices; /* list of devices on this bus */ |
struct pci_dev *self; /* bridge device as seen by parent */ |
struct list_head slots; /* list of slots on this bus */ |
struct resource *resource[PCI_BRIDGE_RESOURCE_NUM]; |
struct list_head resources; /* address space routed to this bus */ |
struct pci_ops *ops; /* configuration access functions */ |
void *sysdata; /* hook for sys-specific extension */ |
unsigned char number; /* bus number */ |
unsigned char primary; /* number of primary bridge */ |
unsigned char secondary; /* number of secondary bridge */ |
unsigned char subordinate; /* max number of subordinate buses */ |
char name[48]; |
unsigned short bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */ |
pci_bus_flags_t bus_flags; /* Inherited by child busses */ |
// struct device *bridge; |
// struct device dev; |
// struct bin_attribute *legacy_io; /* legacy I/O for this bus */ |
// struct bin_attribute *legacy_mem; /* legacy mem */ |
unsigned int is_added:1; |
}; |
#define pci_bus_b(n) list_entry(n, struct pci_bus, node) |
#define to_pci_bus(n) container_of(n, struct pci_bus, dev) |
static inline int pci_domain_nr(struct pci_bus *bus) |
{ |
struct pci_sysdata *sd = bus->sysdata; |
return sd->domain; |
} |
int enum_pci_devices(void); |
struct pci_device_id* |
558,7 → 656,12 |
int pci_set_dma_mask(struct pci_dev *dev, u64 mask); |
struct pci_bus * pci_create_bus(int bus, struct pci_ops *ops, void *sysdata); |
struct pci_bus * pci_find_bus(int domain, int busnr); |
struct pci_bus * pci_find_next_bus(const struct pci_bus *from); |
#define pci_name(x) "radeon" |
#endif //__PCI__H__ |
/drivers/include/linux/types.h |
---|
330,11 → 330,6 |
#define ENTER() dbgprintf("enter %s\n",__FUNCTION__) |
#define LEAVE() dbgprintf("leave %s\n",__FUNCTION__) |
#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159 |
#endif /* _LINUX_TYPES_H */ |