diff --git a/drivers/ddk/Makefile b/drivers/ddk/Makefile index 694f40125a..0ddec9dcf0 100644 --- a/drivers/ddk/Makefile +++ b/drivers/ddk/Makefile @@ -29,20 +29,31 @@ NAME_SRCS:= \ stdio/vsprintf.c \ stdio/doprnt.c \ stdio/chartab.c \ - string/_memmove.S \ - string/_strncat.S \ - string/_strncmp.S \ - string/_strncpy.S \ - string/_strnlen.S \ - string/memcpy.S \ - string/memcmp.S \ - string/memset.S \ - string/strcat.S \ - string/strchr.S \ - string/strcpy.S \ - string/strncpy.S \ - string/strncmp.S \ - string/strlen.S + string/_memmove.S \ + string/_strncat.S \ + 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/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/strnlen.S \ + string/strrchr.S @@ -64,7 +75,7 @@ libcore.a: core.S Makefile $(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 $@ $< diff --git a/drivers/ddk/string/_memmove.S b/drivers/ddk/string/_memmove.S index 74b529b80e..cb3c410af6 100644 --- a/drivers/ddk/string/_memmove.S +++ b/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 - -.text - - .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 +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: - 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 + shrdl $2, %ecx, %eax /* Save low 2 bits of ecx in eax */ + shrl $2, %ecx + + rep movsl /* Copy longwords. */ + shldl $2, %eax, %ecx /* Restore excess count */ upword: - shr ecx, 1 - rep movsw # Copy words - adc ecx, ecx # One more byte? + shrl $1, %ecx + + 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 - ret - -# Handle bad overlap by copying downwards, don't bother to do word copies. + 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. */ downwards: - std # Set direction bit: downwards - lea esi, [esi+ecx-1] - lea edi, [edi+ecx-1] - rep movsb # Copy bytes - cld - jmp done + std /* Set direction bit: downwards */ + leal -1(%esi,%ecx,1), %esi + leal -1(%edi,%ecx,1), %edi + + rep movsb /* Copy bytes */ + cld + jmp done diff --git a/drivers/ddk/string/_strncat.S b/drivers/ddk/string/_strncat.S index e39667551e..653364b5df 100644 --- a/drivers/ddk/string/_strncat.S +++ b/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. -# - -.intel_syntax - -.global __strncat - - .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 - 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 - ret +/* _strncat() Author: Kees J. Bot */ +/* 1 Jan 1994 */ + +/* char *_strncat(char *s1, const char *s2, size_t edx) */ +/* Append string s2 to s1. */ +/* */ +#include "asm.h" + +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 + + 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 + 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 diff --git a/drivers/ddk/string/_strncmp.S b/drivers/ddk/string/_strncmp.S index c09237770f..e47cc68d82 100644 --- a/drivers/ddk/string/_strncmp.S +++ b/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? - je done - - mov esi, [ebp+8] # esi = string s1 - mov edi, [ebp+12] # edi = string s2 - cld +ENTRY(_strncmp) + push %ebp + movl %esp, %ebp + push %esi + push %edi + testl %ecx, %ecx /* Max length is zero? */ + je done + movl 8(%ebp), %esi /* esi = string s1 */ + movl 12(%ebp), %edi /* edi = string s2 */ + cld compare: - cmpsb # Compare two bytes - jne done - - cmpb [esi-1], 0 # End of string? - je done - - dec ecx # Length limit reached? - jne compare + cmpsb /* Compare two bytes */ + jne done + cmpb $0, -1(%esi) /* End of string? */ + je done + 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 - ret + 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 diff --git a/drivers/ddk/string/_strncpy.S b/drivers/ddk/string/_strncpy.S index 13d1e5f745..6830c2c0fa 100644 --- a/drivers/ddk/string/_strncpy.S +++ b/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 - -.text -.globl __strncpy -.align 16 - -__strncpy: - mov edi, [ebp+12] # edi = string s2 - xorb al, al # Look for a zero byte - mov edx, ecx # Save maximum count +ENTRY(_strncpy) + movl 12(%ebp), %edi /* edi = string s2 */ + xorb %al, %al /* Look for a zero byte */ + movl %ecx, %edx /* 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 + + 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 */ + + rep movsb /* Copy bytes */ ret diff --git a/drivers/ddk/string/_strnlen.S b/drivers/ddk/string/_strnlen.S index 3e28af0b42..d29f548331 100644 --- a/drivers/ddk/string/_strnlen.S +++ b/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 - jne no0 - inc ecx # Don't count zero byte + repne scasb /* Look for zero */ + jne no0 + incl %ecx /* Don't count zero byte */ no0: - mov eax, edx - sub eax, ecx # Compute bytes scanned - pop edi - pop ebp - ret + movl %edx, %eax + subl %ecx, %eax /* Compute bytes scanned */ + pop %edi + pop %ebp + ret diff --git a/drivers/ddk/string/asm.h b/drivers/ddk/string/asm.h new file mode 100644 index 0000000000..615955ccdc --- /dev/null +++ b/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_ */ diff --git a/drivers/ddk/string/bcmp.S b/drivers/ddk/string/bcmp.S new file mode 100644 index 0000000000..ae746619b6 --- /dev/null +++ b/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 diff --git a/drivers/ddk/string/bcopy.S b/drivers/ddk/string/bcopy.S new file mode 100644 index 0000000000..b0477abdf4 --- /dev/null +++ b/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 */ diff --git a/drivers/ddk/string/bzero.S b/drivers/ddk/string/bzero.S new file mode 100644 index 0000000000..779efae314 --- /dev/null +++ b/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 diff --git a/drivers/ddk/string/index.S b/drivers/ddk/string/index.S new file mode 100644 index 0000000000..80d0a9d0e3 --- /dev/null +++ b/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) diff --git a/drivers/ddk/string/memchr.S b/drivers/ddk/string/memchr.S new file mode 100644 index 0000000000..e1806d4c9d --- /dev/null +++ b/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 diff --git a/drivers/ddk/string/memcmp.S b/drivers/ddk/string/memcmp.S index 73a59c2460..a588656be6 100644 --- a/drivers/ddk/string/memcmp.S +++ b/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 - -.globl _memcmp - - .text - .align 16 -_memcmp: +ENTRY(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 + 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 + + 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: 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 +cword: + shrdl $1, %ecx, %eax /* Save low bit of ecx in eax */ + shrl $1, %ecx + + 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 diff --git a/drivers/ddk/string/memcpy.S b/drivers/ddk/string/memcpy.S index 95364123a3..be2e931ca8 100644 --- a/drivers/ddk/string/memcpy.S +++ b/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 */ diff --git a/drivers/ddk/string/memmove.S b/drivers/ddk/string/memmove.S new file mode 100644 index 0000000000..292d7e3e08 --- /dev/null +++ b/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 */ diff --git a/drivers/ddk/string/memset.S b/drivers/ddk/string/memset.S index 35f05234b1..f3568f87cc 100644 --- a/drivers/ddk/string/memset.S +++ b/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 - 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 +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 + 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 - 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 + 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 %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 - ret + movl 8(%ebp), %eax /* Return some value you have no need for */ + pop %edi + pop %ebp + ret diff --git a/drivers/ddk/string/rindex.S b/drivers/ddk/string/rindex.S new file mode 100644 index 0000000000..70c97e5101 --- /dev/null +++ b/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) diff --git a/drivers/ddk/string/strcat.S b/drivers/ddk/string/strcat.S index 856e7b8443..49f4a1b2d2 100644 --- a/drivers/ddk/string/strcat.S +++ b/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 */ diff --git a/drivers/ddk/string/strchr.S b/drivers/ddk/string/strchr.S index 70302d22c4..fbe2a382ba 100644 --- a/drivers/ddk/string/strchr.S +++ b/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 - cld - mov edi, [ebp+8] # edi = string - mov edx, 16 # Look at small chunks of the string +ENTRY(strchr) + push %ebp + movl %esp, %ebp + push %edi + cld + 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 - repne scasb + shll $1, %edx /* Chunks become bigger each time */ + movl %edx, %ecx + xorb %al, %al /* Look for the zero at the end */ - 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 + 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 */ - popf # Did we find the end of string earlier? - - jne next # No, try again - - xor eax, eax # Return NULL - pop edi - pop ebp - ret + repne scasb + je found + 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 - ret + pop %eax /* Get rid of those flags */ + leal -1(%edi), %eax /* Address of byte found */ + pop %edi + pop %ebp + ret diff --git a/drivers/ddk/string/strcmp.S b/drivers/ddk/string/strcmp.S new file mode 100644 index 0000000000..c6399559f6 --- /dev/null +++ b/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 */ diff --git a/drivers/ddk/string/strcpy.S b/drivers/ddk/string/strcpy.S index ba9a1e6d92..68b115013d 100644 --- a/drivers/ddk/string/strcpy.S +++ b/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 diff --git a/drivers/ddk/string/strlen.S b/drivers/ddk/string/strlen.S index 78fb383166..ffaff46a0e 100644 --- a/drivers/ddk/string/strlen.S +++ b/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 */ diff --git a/drivers/ddk/string/strncat.S b/drivers/ddk/string/strncat.S new file mode 100644 index 0000000000..72c03d8403 --- /dev/null +++ b/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 */ diff --git a/drivers/ddk/string/strncmp.S b/drivers/ddk/string/strncmp.S index bef4d07f99..c997f5b025 100644 --- a/drivers/ddk/string/strncmp.S +++ b/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 */ diff --git a/drivers/ddk/string/strncpy.S b/drivers/ddk/string/strncpy.S index 9ab79c37b3..804b29be50 100644 --- a/drivers/ddk/string/strncpy.S +++ b/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 diff --git a/drivers/ddk/string/strnlen.S b/drivers/ddk/string/strnlen.S new file mode 100644 index 0000000000..412f50e62e --- /dev/null +++ b/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 */ diff --git a/drivers/ddk/string/strrchr.S b/drivers/ddk/string/strrchr.S new file mode 100644 index 0000000000..61a52c4a79 --- /dev/null +++ b/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 diff --git a/drivers/devman/Makefile b/drivers/devman/Makefile index d49b95313a..897356ddf7 100644 --- a/drivers/devman/Makefile +++ b/drivers/devman/Makefile @@ -24,7 +24,10 @@ LIBS:= -lacpica -lgcc -lddk -lcore NAME= acpi -NAME_SRCS= acpi.c +NAME_SRCS= acpi.c \ + scan.c \ + pci_irq.c \ + pci/pci.c all: $(NAME).dll diff --git a/drivers/devman/acpi.c b/drivers/devman/acpi.c index 3b5837ae7e..6f08a82157 100644 --- a/drivers/devman/acpi.c +++ b/drivers/devman/acpi.c @@ -6,6 +6,9 @@ #include #include "acpi.h" +#include "acpi_bus.h" + +#define PREFIX "ACPI: " #define ACPI_BUS_CLASS "system_bus" #define ACPI_BUS_HID "KLBSYBUS" @@ -16,7 +19,7 @@ static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); -DEFINE_MUTEX(acpi_device_lock); + struct acpi_device_bus_id { @@ -44,39 +47,6 @@ enum acpi_bus_removal_type { 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,811 +66,10 @@ static ACPI_HANDLE pci_root_handle; #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_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_hardware_id { - struct list_head list; - char *id; -}; - -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 */ -}; - struct acpi_device *acpi_root; - -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; -} - - - -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 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 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; - } -} - - -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; -} - -/* - * 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); -} - -#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; -} - - -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 "%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; - - dbgprintf(KERN_ERR "Error attaching device data\n"); - return -ENODEV; -} - - -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) { - dbgprintf(KERN_ERR "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 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. - */ - 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("Adding [%s]\n", (char *)buffer.Pointer); - kfree(buffer.Pointer); - *child = device; - }; - return result; -} - - - - -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; - - ENTER(); - - 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; - - LEAVE(); - - 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; -}; - +extern struct resource iomem_resource; +extern struct resource ioport_resource; enum pic_mode { @@ -925,7 +94,7 @@ static void set_pic_mode(enum pic_mode mode) * provide us with correct information anyway */ if (ACPI_SUCCESS(as)) - dbgprintf("ACPI: machine set to %s mode\n", mode ? "APIC" : "PIC"); + dbgprintf(PREFIX "machine set to %s mode\n", mode ? "APIC" : "PIC"); } void print_device_tree(struct acpi_device *device) @@ -940,6 +109,478 @@ void print_device_tree(struct acpi_device *device) }; }; + +/* +int acpi_pci_bind_root(struct acpi_device *device) +{ + device->ops.bind = acpi_pci_bind; + device->ops.unbind = acpi_pci_unbind; + + return 0; +} +*/ + +static bool pci_use_crs = false; + +#define IORESOURCE_BUS 0x00001000 + +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 */ + +}; + +static LIST_HEAD(acpi_pci_roots); + +#define ACPI_PCI_ROOT_CLASS "pci_bridge" +#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" + +static ACPI_STATUS +get_root_bridge_busnr_callback(ACPI_RESOURCE *resource, void *data) +{ + struct resource *res = data; + ACPI_RESOURCE_ADDRESS64 address; + + if (resource->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && + resource->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && + resource->Type != ACPI_RESOURCE_TYPE_ADDRESS64) + return AE_OK; + + 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 AE_OK; +} + + + +static ACPI_STATUS try_get_root_bridge_busnr(ACPI_HANDLE handle, + struct resource *res) +{ + ACPI_STATUS status; + + res->start = -1; + status = + AcpiWalkResources(handle, METHOD_NAME__CRS, + get_root_bridge_busnr_callback, res); + if (ACPI_FAILURE(status)) + return status; + if (res->start == -1) + return AE_ERROR; + return AE_OK; +} + + +struct pci_root_info +{ + struct acpi_device *bridge; + char *name; + unsigned int res_num; + struct resource *res; + struct pci_bus *bus; + int busnum; +}; + + +static ACPI_STATUS +resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr) +{ + ACPI_STATUS status; + struct acpi_resource_memory24 *memory24; + struct acpi_resource_memory32 *memory32; + struct acpi_resource_fixed_memory32 *fixed_memory32; + + 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; + } + break; + } + return AE_ERROR; +} + + +static ACPI_STATUS +count_resource(ACPI_RESOURCE *acpi_res, void *data) +{ + struct pci_root_info *info = data; + ACPI_RESOURCE_ADDRESS64 addr; + ACPI_STATUS status; + + status = resource_to_addr(acpi_res, &addr); + if (ACPI_SUCCESS(status)) + info->res_num++; + return AE_OK; +} + + +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; + + status = resource_to_addr(acpi_res, &addr); + if (!ACPI_SUCCESS(status)) + return AE_OK; + + 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; + + start = addr.Minimum + addr.TranslationOffset; + end = addr.Maximum + addr.TranslationOffset; + + res = &info->res[info->res_num]; + res->name = info->name; + res->flags = flags; + res->start = start; + res->end = end; + res->child = NULL; + + if (!pci_use_crs) { + printk("host bridge window %pR (ignored)\n", res); + return AE_OK; + } + +#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); + } + return AE_OK; +#endif +} + + + +static void +get_current_resources(struct acpi_device *device, int busnum, + int domain, struct pci_bus *bus) +{ + struct pci_root_info info; + size_t size; + + char buf[64]; + +// if (pci_use_crs) +// pci_bus_remove_resources(bus); + + info.bridge = device; + info.bus = bus; + info.res_num = 0; + AcpiWalkResources(device->handle, METHOD_NAME__CRS, count_resource, + &info); + if (!info.res_num) + return; + + size = sizeof(*info.res) * info.res_num; + info.res = kmalloc(size, GFP_KERNEL); + if (!info.res) + goto res_alloc_fail; + + vsprintf(buf,"PCI Bus %04x:%02x", domain, busnum); + info.name = strdup(buf); + + if (!info.name) + goto name_alloc_fail; + + info.res_num = 0; + AcpiWalkResources(device->handle, METHOD_NAME__CRS, setup_resource, + &info); + + return; + +name_alloc_fail: + kfree(info.res); +res_alloc_fail: + return; +} + + + + +struct pci_ops pci_root_ops = { + .read = NULL, + .write = NULL, +}; + + +struct pci_bus* pci_acpi_scan_root(struct acpi_pci_root *root) +{ + 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; + + if (domain ) { + printk(KERN_WARNING "pci_bus %04x:%02x: " + "ignored (multiple domains not supported)\n", + domain, busnum); + return NULL; + } + + /* 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; + } + + 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 (!bus) + kfree(sd); + + if (bus && node != -1) { + printk("on NUMA node %d\n", node); + } + + return bus; +} + + + +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; + + root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); + if (!root) + return -ENOMEM; + + 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; + } + + /* 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)) + { + /* + * 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]. + */ + 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; + } + } + + 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; + + /* + * All supported architectures that use ACPI have support for + * PCI domains, so we indicate this in _OSC support capabilities. + */ +// flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; +// acpi_pci_osc_support(root, flags); + + /* + * TBD: Need PCI interface for enumeration/configuration of roots. + */ + + /* TBD: Locking */ + list_add_tail(&root->node, &acpi_pci_roots); + + printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", + acpi_device_name(device), acpi_device_bid(device), + root->segment, &root->secondary); + + /* + * 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). + */ + + 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; + } + + /* + * Attach ACPI-PCI Context + * ----------------------- + * Thus binding the ACPI and PCI devices. + */ +// result = acpi_pci_bind_root(device); +// if (result) +// goto end; + + /* + * PCI Routing Table + * ----------------- + * Evaluate and parse _PRT, if exists. + */ + status = AcpiGetHandle(device->handle, METHOD_NAME__PRT, &handle); + if (ACPI_SUCCESS(status)) + result = acpi_pci_irq_add_prt(device->handle, root->bus); + + /* + * Scan and bind all _ADR-Based Devices + */ +// list_for_each_entry(child, &device->children, node) +// acpi_pci_bridge_scan(child); + + return 0; + +end: + if (!list_empty(&root->node)) + list_del(&root->node); + kfree(root); + return result; +} + + +static const struct acpi_device_ids root_device_ids[] = +{ + {"PNP0A03", 0}, + {"", 0}, +}; + +void acpi_init_pci(struct acpi_device *device) +{ + struct acpi_device *child; + + if ( !acpi_match_device_ids(device, root_device_ids) ) + { + dbgprintf(PREFIX "PCI root %s\n", device->pnp.bus_id); + acpi_pci_root_add(device); + }; + + list_for_each_entry(child, &device->children, node) + { + acpi_init_pci(child); + }; + +}; + + u32_t drvEntry(int action, char *cmdline) { u32_t retval; @@ -1004,73 +645,11 @@ u32_t drvEntry(int action, char *cmdline) set_pic_mode(IO_APIC); -#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 - acpi_scan(); - print_device_tree(acpi_root); +// print_device_tree(acpi_root); + + acpi_init_pci(acpi_root); /* ACPI_HANDLE bus_handle; @@ -1182,6 +761,70 @@ err: }; +#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 @@ -1379,3 +1022,15 @@ static void scan_devices(void) } #endif + +char* strdup(const char *str) +{ + size_t len = strlen (str) + 1; + char *copy = malloc(len); + if (copy) + { + memcpy (copy, str, len); + } + return copy; +} + diff --git a/drivers/devman/acpi_bus.h b/drivers/devman/acpi_bus.h new file mode 100644 index 0000000000..4b866336ed --- /dev/null +++ b/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); diff --git a/drivers/devman/pci/pci.c b/drivers/devman/pci/pci.c new file mode 100644 index 0000000000..7c0e4bf0c6 --- /dev/null +++ b/drivers/devman/pci/pci.c @@ -0,0 +1,151 @@ + +#include +#include +#include +#include +#include + +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; +} + + diff --git a/drivers/devman/pci_irq.c b/drivers/devman/pci_irq.c new file mode 100644 index 0000000000..f4beba9a1b --- /dev/null +++ b/drivers/devman/pci_irq.c @@ -0,0 +1,131 @@ + +#include +#include +#include +#include +#include +#include + +#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; +} + diff --git a/drivers/devman/scan.c b/drivers/devman/scan.c new file mode 100644 index 0000000000..651c5442bf --- /dev/null +++ b/drivers/devman/scan.c @@ -0,0 +1,766 @@ + + +#include +#include +#include +#include +#include + +#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; +}; + diff --git a/drivers/include/ddk.h b/drivers/include/ddk.h index 1b331f010f..6381ca5dbc 100644 --- a/drivers/include/ddk.h +++ b/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; diff --git a/drivers/include/linux/pci.h b/drivers/include/linux/pci.h index b705ee1f4e..5b295409d0 100644 --- a/drivers/include/linux/pci.h +++ b/drivers/include/linux/pci.h @@ -349,11 +349,44 @@ struct resource { 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. */ @@ -549,6 +582,71 @@ typedef struct 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,6 +656,11 @@ find_pci_device(pci_dev_t* pdev, struct pci_device_id *idlist); 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" diff --git a/drivers/include/linux/types.h b/drivers/include/linux/types.h index 335c5fe80f..209d2118bf 100644 --- a/drivers/include/linux/types.h +++ b/drivers/include/linux/types.h @@ -330,11 +330,6 @@ struct drm_file; -#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 */