forked from KolibriOS/kolibrios
ddk: fix strcpy
devman: scan pci root bus git-svn-id: svn://kolibrios.org@1627 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
8c44a1652a
commit
49cb0f914d
@ -29,20 +29,31 @@ NAME_SRCS:= \
|
|||||||
stdio/vsprintf.c \
|
stdio/vsprintf.c \
|
||||||
stdio/doprnt.c \
|
stdio/doprnt.c \
|
||||||
stdio/chartab.c \
|
stdio/chartab.c \
|
||||||
string/_memmove.S \
|
string/_memmove.S \
|
||||||
string/_strncat.S \
|
string/_strncat.S \
|
||||||
string/_strncmp.S \
|
string/_strncmp.S \
|
||||||
string/_strncpy.S \
|
string/_strncpy.S \
|
||||||
string/_strnlen.S \
|
string/_strnlen.S \
|
||||||
string/memcpy.S \
|
string/bcmp.S \
|
||||||
string/memcmp.S \
|
string/bcopy.S \
|
||||||
string/memset.S \
|
string/bzero.S \
|
||||||
string/strcat.S \
|
string/index.S \
|
||||||
string/strchr.S \
|
string/memchr.S \
|
||||||
string/strcpy.S \
|
string/memcmp.S \
|
||||||
string/strncpy.S \
|
string/memcpy.S \
|
||||||
string/strncmp.S \
|
string/memmove.S \
|
||||||
string/strlen.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
|
$(LD) -shared -s --out-implib $@ --output-def core.def -o core.dll core.o
|
||||||
|
|
||||||
%.o: %.S Makefile
|
%.o: %.S Makefile
|
||||||
$(AS) -o $@ $<
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
%.o: %.c Makefile
|
%.o: %.c Makefile
|
||||||
$(CC) $(CFLAGS) -o $@ $<
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
@ -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)
|
/* void *_memmove(void *s1, const void *s2, size_t n) */
|
||||||
# Copy a chunk of memory. Handle overlap.
|
/* Copy a chunk of memory. Handle overlap. */
|
||||||
|
/* */
|
||||||
|
|
||||||
.intel_syntax
|
#include "asm.h"
|
||||||
|
|
||||||
.globl __memmove, __memcpy
|
ENTRY(_memmove)
|
||||||
|
push %ebp
|
||||||
.text
|
movl %esp, %ebp
|
||||||
|
push %esi
|
||||||
.align 16
|
push %edi
|
||||||
__memmove:
|
movl 8(%ebp), %edi /* String s1 */
|
||||||
push ebp
|
movl 12(%ebp), %esi /* String s2 */
|
||||||
mov ebp, esp
|
movl 16(%ebp), %ecx /* Length */
|
||||||
|
movl %edi, %eax
|
||||||
push esi
|
subl %esi, %eax
|
||||||
push edi
|
cmpl %ecx, %eax
|
||||||
|
jb downwards /* if (s2 - s1) < n then copy downwards */
|
||||||
mov edi, [ebp+8] # String s1
|
LABEL(_memcpy)
|
||||||
mov esi, [ebp+12] # String s2
|
cld /* Clear direction bit: upwards */
|
||||||
mov ecx, [ebp+16] # Length
|
cmpl $16, %ecx
|
||||||
|
jb upbyte /* Don't bother being smart with short arrays */
|
||||||
mov eax, edi
|
movl %esi, %eax
|
||||||
sub eax, esi
|
orl %edi, %eax
|
||||||
cmp eax, ecx
|
testb $1, %al
|
||||||
jb downwards # if (s2 - s1) < n then copy downwards
|
jne upbyte /* Bit 0 set, use byte copy */
|
||||||
__memcpy:
|
testb $2, %al
|
||||||
cld # Clear direction bit: upwards
|
jne upword /* Bit 1 set, use word copy */
|
||||||
cmp ecx, 16
|
|
||||||
jb upbyte # Don't bother being smart with short arrays
|
|
||||||
|
|
||||||
mov eax, esi
|
|
||||||
or eax, edi
|
|
||||||
testb al, 1
|
|
||||||
jnz upbyte # Bit 0 set, use byte copy
|
|
||||||
|
|
||||||
testb al, 2
|
|
||||||
|
|
||||||
jnz upword # Bit 1 set, use word copy
|
|
||||||
uplword:
|
uplword:
|
||||||
shrd eax, ecx, 2 # Save low 2 bits of ecx in eax
|
shrdl $2, %ecx, %eax /* Save low 2 bits of ecx in eax */
|
||||||
shr ecx, 2
|
shrl $2, %ecx
|
||||||
rep movsd # Copy longwords.
|
|
||||||
shld ecx, eax, 2 # Restore excess count
|
rep movsl /* Copy longwords. */
|
||||||
|
shldl $2, %eax, %ecx /* Restore excess count */
|
||||||
upword:
|
upword:
|
||||||
shr ecx, 1
|
shrl $1, %ecx
|
||||||
rep movsw # Copy words
|
|
||||||
adc ecx, ecx # One more byte?
|
rep movsw /* Copy words */
|
||||||
|
adcl %ecx, %ecx /* One more byte? */
|
||||||
upbyte:
|
upbyte:
|
||||||
rep movsb # Copy bytes
|
rep movsb /* Copy bytes */
|
||||||
done:
|
done:
|
||||||
mov eax, [ebp+8] # Absolutely noone cares about this value
|
movl 8(%ebp), %eax /* Absolutely noone cares about this value */
|
||||||
pop edi
|
pop %edi
|
||||||
pop esi
|
pop %esi
|
||||||
pop ebp
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# Handle bad overlap by copying downwards, don't bother to do word copies.
|
|
||||||
|
|
||||||
|
/* Handle bad overlap by copying downwards, don't bother to do word copies. */
|
||||||
downwards:
|
downwards:
|
||||||
std # Set direction bit: downwards
|
std /* Set direction bit: downwards */
|
||||||
lea esi, [esi+ecx-1]
|
leal -1(%esi,%ecx,1), %esi
|
||||||
lea edi, [edi+ecx-1]
|
leal -1(%edi,%ecx,1), %edi
|
||||||
rep movsb # Copy bytes
|
|
||||||
cld
|
rep movsb /* Copy bytes */
|
||||||
jmp done
|
cld
|
||||||
|
jmp done
|
||||||
|
@ -1,43 +1,40 @@
|
|||||||
# _strncat() Author: Kees J. Bot
|
/* _strncat() Author: Kees J. Bot */
|
||||||
# 1 Jan 1994
|
/* 1 Jan 1994 */
|
||||||
# char *_strncat(char *s1, const char *s2, size_t edx)
|
|
||||||
# Append string s2 to s1.
|
|
||||||
#
|
|
||||||
|
|
||||||
.intel_syntax
|
/* char *_strncat(char *s1, const char *s2, size_t edx) */
|
||||||
|
/* Append string s2 to s1. */
|
||||||
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.global __strncat
|
ENTRY(_strncat)
|
||||||
|
push %ebp
|
||||||
.text
|
movl %esp, %ebp
|
||||||
.align 16
|
push %esi
|
||||||
__strncat:
|
push %edi
|
||||||
push ebp
|
movl 8(%ebp), %edi /* String s1 */
|
||||||
mov ebp, esp
|
movl $-1, %ecx
|
||||||
push esi
|
xorb %al, %al /* Null byte */
|
||||||
push edi
|
|
||||||
mov edi, [ebp+8] # String s1
|
|
||||||
mov ecx, -1
|
|
||||||
xorb al, al # Null byte
|
|
||||||
cld
|
cld
|
||||||
repne
|
|
||||||
scasb # Look for the zero byte in s1
|
repne scasb /* Look for the zero byte in s1 */
|
||||||
dec edi # Back one up (and clear 'Z' flag)
|
decl %edi /* Back one up (and clear 'Z' flag) */
|
||||||
push edi # Save end of s1
|
push %edi /* Save end of s1 */
|
||||||
mov edi, [12+ebp] # edi = string s2
|
movl 12(%ebp), %edi /* edi = string s2 */
|
||||||
mov ecx, edx # Maximum count
|
movl %edx, %ecx /* Maximum count */
|
||||||
repne
|
|
||||||
scasb # Look for the end of s2
|
repne scasb /* Look for the end of s2 */
|
||||||
jne no0
|
jne no0
|
||||||
inc ecx # Exclude null byte
|
incl %ecx /* Exclude null byte */
|
||||||
no0: sub edx, ecx # Number of bytes in s2
|
no0:
|
||||||
mov ecx, edx
|
subl %ecx, %edx /* Number of bytes in s2 */
|
||||||
mov esi, [12+ebp] # esi = string s2
|
movl %edx, %ecx
|
||||||
pop edi # edi = end of string s1
|
movl 12(%ebp), %esi /* esi = string s2 */
|
||||||
rep
|
pop %edi /* edi = end of string s1 */
|
||||||
movsb # Copy bytes
|
|
||||||
stosb # Add a terminating null
|
rep movsb /* Copy bytes */
|
||||||
mov eax, [8+ebp] # Return s1
|
stosb /* Add a terminating null */
|
||||||
pop edi
|
movl 8(%ebp), %eax /* Return s1 */
|
||||||
pop esi
|
pop %edi
|
||||||
pop ebp
|
pop %esi
|
||||||
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
@ -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)
|
/* int strncmp(const char *s1, const char *s2, size_t ecx) */
|
||||||
# Compare two strings.
|
/* Compare two strings. */
|
||||||
#
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(_strncmp)
|
||||||
|
push %ebp
|
||||||
.globl __strncmp
|
movl %esp, %ebp
|
||||||
|
push %esi
|
||||||
.text
|
push %edi
|
||||||
.align 16
|
testl %ecx, %ecx /* Max length is zero? */
|
||||||
__strncmp:
|
je done
|
||||||
push ebp
|
movl 8(%ebp), %esi /* esi = string s1 */
|
||||||
mov ebp, esp
|
movl 12(%ebp), %edi /* edi = string s2 */
|
||||||
|
cld
|
||||||
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
|
|
||||||
compare:
|
compare:
|
||||||
cmpsb # Compare two bytes
|
cmpsb /* Compare two bytes */
|
||||||
jne done
|
jne done
|
||||||
|
cmpb $0, -1(%esi) /* End of string? */
|
||||||
cmpb [esi-1], 0 # End of string?
|
je done
|
||||||
je done
|
decl %ecx /* Length limit reached? */
|
||||||
|
jne compare
|
||||||
dec ecx # Length limit reached?
|
|
||||||
jne compare
|
|
||||||
done:
|
done:
|
||||||
seta al # al = (s1 > s2)
|
seta %al /* al = (s1 > s2) */
|
||||||
setb ah # ah = (s1 < s2)
|
setb %ah /* ah = (s1 < s2) */
|
||||||
subb al, ah
|
subb %ah, %al
|
||||||
movsx eax, al # eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1
|
movsbl %al, %eax /* eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1 */
|
||||||
|
pop %edi
|
||||||
pop edi
|
pop %esi
|
||||||
pop esi
|
pop %ebp
|
||||||
pop ebp
|
ret
|
||||||
ret
|
|
||||||
|
@ -1,27 +1,22 @@
|
|||||||
# _strncpy() Author: Kees J. Bot
|
/* _strncpy() Author: Kees J. Bot */
|
||||||
# 1 Jan 1994
|
/* 1 Jan 1994 */
|
||||||
|
|
||||||
# char *_strncpy(char *s1, const char *s2, size_t ecx)
|
/* char *_strncpy(char *s1, const char *s2, size_t ecx) */
|
||||||
# Copy string s2 to s1.
|
/* Copy string s2 to s1. */
|
||||||
#
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(_strncpy)
|
||||||
|
movl 12(%ebp), %edi /* edi = string s2 */
|
||||||
.text
|
xorb %al, %al /* Look for a zero byte */
|
||||||
.globl __strncpy
|
movl %ecx, %edx /* Save maximum count */
|
||||||
.align 16
|
|
||||||
|
|
||||||
__strncpy:
|
|
||||||
mov edi, [ebp+12] # edi = string s2
|
|
||||||
xorb al, al # Look for a zero byte
|
|
||||||
mov edx, ecx # Save maximum count
|
|
||||||
cld
|
cld
|
||||||
repne
|
|
||||||
scasb # Look for end of s2
|
repne scasb /* Look for end of s2 */
|
||||||
sub edx, ecx # Number of bytes in s2 including null
|
subl %ecx, %edx /* Number of bytes in s2 including null */
|
||||||
xchg ecx, edx
|
xchgl %edx, %ecx
|
||||||
mov esi, [ebp+12] # esi = string s2
|
movl 12(%ebp), %esi /* esi = string s2 */
|
||||||
mov edi, [ebp+8] # edi = string s1
|
movl 8(%ebp), %edi /* edi = string s1 */
|
||||||
rep
|
|
||||||
movsb # Copy bytes
|
rep movsb /* Copy bytes */
|
||||||
ret
|
ret
|
||||||
|
@ -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)
|
/* size_t _strnlen(const char *s, size_t ecx) */
|
||||||
# Return the length of a string.
|
/* 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
|
repne scasb /* Look for zero */
|
||||||
|
jne no0
|
||||||
.text
|
incl %ecx /* Don't count zero byte */
|
||||||
.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
|
|
||||||
no0:
|
no0:
|
||||||
mov eax, edx
|
movl %edx, %eax
|
||||||
sub eax, ecx # Compute bytes scanned
|
subl %ecx, %eax /* Compute bytes scanned */
|
||||||
pop edi
|
pop %edi
|
||||||
pop ebp
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
61
drivers/ddk/string/asm.h
Normal file
61
drivers/ddk/string/asm.h
Normal file
@ -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_ */
|
27
drivers/ddk/string/bcmp.S
Normal file
27
drivers/ddk/string/bcmp.S
Normal file
@ -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
|
14
drivers/ddk/string/bcopy.S
Normal file
14
drivers/ddk/string/bcopy.S
Normal file
@ -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 */
|
18
drivers/ddk/string/bzero.S
Normal file
18
drivers/ddk/string/bzero.S
Normal file
@ -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
|
11
drivers/ddk/string/index.S
Normal file
11
drivers/ddk/string/index.S
Normal file
@ -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)
|
29
drivers/ddk/string/memchr.S
Normal file
29
drivers/ddk/string/memchr.S
Normal file
@ -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
|
@ -1,59 +1,57 @@
|
|||||||
# memcmp() Author: Kees J. Bot
|
/* memcmp() Author: Kees J. Bot */
|
||||||
# 2 Jan 1994
|
/* 2 Jan 1994 */
|
||||||
|
|
||||||
# int memcmp(const void *s1, const void *s2, size_t n)
|
/* int memcmp(const void *s1, const void *s2, size_t n) */
|
||||||
# Compare two chunks of memory.
|
/* Compare two chunks of memory. */
|
||||||
#
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(memcmp)
|
||||||
|
|
||||||
.globl _memcmp
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 16
|
|
||||||
_memcmp:
|
|
||||||
cld
|
cld
|
||||||
push ebp
|
push %ebp
|
||||||
mov ebp, esp
|
movl %esp, %ebp
|
||||||
push esi
|
push %esi
|
||||||
push edi
|
push %edi
|
||||||
mov esi, [8+ebp] # String s1
|
movl 8(%ebp), %esi /* String s1 */
|
||||||
mov edi, [12+ebp] # String s2
|
movl 12(%ebp), %edi /* String s2 */
|
||||||
mov ecx, [16+ebp] # Length
|
movl 16(%ebp), %ecx /* Length */
|
||||||
cmp ecx, 16
|
cmpl $16, %ecx
|
||||||
jb cbyte # Don't bother being smart with short arrays
|
jb cbyte /* Don't bother being smart with short arrays */
|
||||||
mov eax, esi
|
movl %esi, %eax
|
||||||
or eax, edi
|
orl %edi, %eax
|
||||||
testb al, 1
|
testb $1, %al
|
||||||
jnz cbyte # Bit 0 set, use byte compare
|
jne cbyte /* Bit 0 set, use byte compare */
|
||||||
testb al, 2
|
testb $2, %al
|
||||||
jnz cword # Bit 1 set, use word compare
|
jne cword /* Bit 1 set, use word compare */
|
||||||
clword: shrd eax, ecx, 2 # Save low two bits of ecx in eax
|
clword:
|
||||||
shr ecx, 2
|
shrdl $2, %ecx, %eax /* Save low two bits of ecx in eax */
|
||||||
repe
|
shrl $2, %ecx
|
||||||
cmpsd # Compare longwords
|
|
||||||
sub esi, 4
|
repe cmpsl /* Compare longwords */
|
||||||
sub edi, 4
|
subl $4, %esi
|
||||||
inc ecx # Recompare the last longword
|
subl $4, %edi
|
||||||
shld ecx, eax, 2 # And any excess bytes
|
incl %ecx /* Recompare the last longword */
|
||||||
|
shldl $2, %eax, %ecx /* And any excess bytes */
|
||||||
jmp last
|
jmp last
|
||||||
cword: shrd eax, ecx, 1 # Save low bit of ecx in eax
|
cword:
|
||||||
shr ecx, 1
|
shrdl $1, %ecx, %eax /* Save low bit of ecx in eax */
|
||||||
repe
|
shrl $1, %ecx
|
||||||
cmpsw # Compare words
|
|
||||||
sub esi, 2
|
repe cmpsw /* Compare words */
|
||||||
sub edi, 2
|
subl $2, %esi
|
||||||
inc ecx # Recompare the last word
|
subl $2, %edi
|
||||||
shld ecx, eax, 1 # And one more byte?
|
incl %ecx /* Recompare the last word */
|
||||||
cbyte: test ecx, ecx # Set 'Z' flag if ecx = 0
|
shldl $1, %eax, %ecx /* And one more byte? */
|
||||||
last: repe
|
cbyte:
|
||||||
cmpsb # Look for the first differing byte
|
testl %ecx, %ecx /* Set 'Z' flag if ecx = 0 */
|
||||||
seta al # al = (s1 > s2)
|
last:
|
||||||
setb ah # ah = (s1 < s2)
|
repe cmpsb /* Look for the first differing byte */
|
||||||
subb al, ah
|
seta %al /* al = (s1 > s2) */
|
||||||
movsxb eax, al # eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1
|
setb %ah /* ah = (s1 < s2) */
|
||||||
mov edx, esi # For bcmp() to play with
|
subb %ah, %al
|
||||||
pop edi
|
movsbl %al, %eax /* eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1 */
|
||||||
pop esi
|
movl %esi, %edx /* For bcmp() to play with */
|
||||||
pop ebp
|
pop %edi
|
||||||
|
pop %esi
|
||||||
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
@ -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)
|
/* void *memcpy(void *s1, const void *s2, size_t n) */
|
||||||
# Copy a chunk of memory.
|
/* Copy a chunk of memory. */
|
||||||
# This routine need not handle overlap, so it does not handle overlap.
|
/* This routine need not handle overlap, so it does not handle overlap. */
|
||||||
# One could simply call __memmove, the cost of the overlap check is
|
/* One could simply call __memmove, the cost of the overlap check is */
|
||||||
# negligible, but you are dealing with a programmer who believes that
|
/* negligible, but you are dealing with a programmer who believes that if */
|
||||||
# if anything can go wrong, it should go wrong.
|
/* anything can go wrong, it should go wrong. */
|
||||||
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(memcpy)
|
||||||
|
push %ebp
|
||||||
.globl _memcpy
|
movl %esp, %ebp
|
||||||
|
push %esi
|
||||||
.text
|
push %edi
|
||||||
|
movl 8(%ebp), %edi /* String s1 */
|
||||||
.align 16
|
movl 12(%ebp), %esi /* String s2 */
|
||||||
_memcpy:
|
movl 16(%ebp), %ecx /* Length */
|
||||||
push ebp
|
/* No overlap check here */
|
||||||
mov ebp, esp
|
jmp _C_LABEL(_memcpy) /* Call the part of __memmove that copies up */
|
||||||
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
|
|
||||||
|
10
drivers/ddk/string/memmove.S
Normal file
10
drivers/ddk/string/memmove.S
Normal file
@ -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 */
|
@ -1,47 +1,45 @@
|
|||||||
# memset() Author: Kees J. Bot
|
/* memset() Author: Kees J. Bot */
|
||||||
# 2 Jan 1994
|
/* 2 Jan 1994 */
|
||||||
# void *memset(void *s, int c, size_t n)
|
|
||||||
# Set a chunk of memory to the same byte value.
|
|
||||||
#
|
|
||||||
|
|
||||||
.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
|
ENTRY(memset)
|
||||||
|
push %ebp
|
||||||
.text
|
movl %esp, %ebp
|
||||||
.align 16
|
push %edi
|
||||||
_memset:
|
movl 8(%ebp), %edi /* The string */
|
||||||
push ebp
|
movzbl 12(%ebp), %eax /* The fill byte */
|
||||||
mov ebp, esp
|
movl 16(%ebp), %ecx /* Length */
|
||||||
push edi
|
cld
|
||||||
mov edi, [8+ebp] # The string
|
cmpl $16, %ecx
|
||||||
movzx eax, byte ptr [12+ebp] # The fill byte
|
jb sbyte /* Don't bother being smart with short arrays */
|
||||||
mov ecx, [16+ebp] # Length
|
testl $1, %edi
|
||||||
cld
|
jne sbyte /* Bit 0 set, use byte store */
|
||||||
cmp ecx, 16
|
testl $2, %edi
|
||||||
jb sbyte # Don't bother being smart with short arrays
|
jne sword /* Bit 1 set, use word store */
|
||||||
test edi, 1
|
|
||||||
jnz sbyte # Bit 0 set, use byte store
|
|
||||||
test edi, 2
|
|
||||||
jnz sword # Bit 1 set, use word store
|
|
||||||
slword:
|
slword:
|
||||||
movb ah, al
|
movb %al, %ah
|
||||||
mov edx, eax
|
movl %eax, %edx
|
||||||
sal edx, 16
|
sall $16, %edx
|
||||||
or eax, edx # One byte to four bytes
|
orl %edx, %eax /* One byte to four bytes */
|
||||||
shrd edx, ecx, 2 # Save low two bits of ecx in edx
|
shrdl $2, %ecx, %edx /* Save low two bits of ecx in edx */
|
||||||
shr ecx, 2
|
shrl $2, %ecx
|
||||||
rep stosd # Store longwords.
|
|
||||||
shld ecx, edx, 2 # Restore low two bits
|
rep stosl /* Store longwords. */
|
||||||
sword:
|
shldl $2, %edx, %ecx /* Restore low two bits */
|
||||||
movb ah, al # One byte to two bytes
|
sword:
|
||||||
shr ecx, 1
|
movb %al, %ah /* One byte to two bytes */
|
||||||
rep stosw # Store words
|
shrl $1, %ecx
|
||||||
adc ecx, ecx # One more byte?
|
|
||||||
|
rep stosw /* Store words */
|
||||||
|
adcl %ecx, %ecx /* One more byte? */
|
||||||
sbyte:
|
sbyte:
|
||||||
rep stosb # Store bytes
|
rep stosb /* Store bytes */
|
||||||
done:
|
done:
|
||||||
mov eax, [8+ebp] # Return some value you have no need for
|
movl 8(%ebp), %eax /* Return some value you have no need for */
|
||||||
pop edi
|
pop %edi
|
||||||
pop ebp
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
11
drivers/ddk/string/rindex.S
Normal file
11
drivers/ddk/string/rindex.S
Normal file
@ -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)
|
@ -1,15 +1,11 @@
|
|||||||
# strcat() Author: Kees J. Bot
|
/* strcat() Author: Kees J. Bot */
|
||||||
# 1 Jan 1994
|
/* 1 Jan 1994 */
|
||||||
# char *strcat(char *s1, const char *s2)
|
|
||||||
# Append string s2 to s1.
|
|
||||||
#
|
|
||||||
|
|
||||||
.intel_syntax
|
/* char *strcat(char *s1, const char *s2) */
|
||||||
|
/* Append string s2 to s1. */
|
||||||
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.global _strcat
|
ENTRY(strcat)
|
||||||
|
movl $-1, %edx /* Unlimited length */
|
||||||
.text
|
jmp _C_LABEL(_strncat) /* Common code */
|
||||||
.align 16
|
|
||||||
_strcat:
|
|
||||||
mov edx, -1 # Unlimited length
|
|
||||||
jmp __strncat # Common code
|
|
||||||
|
@ -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)
|
/* char *strchr(const char *s, int c) */
|
||||||
# Look for a character in a string.
|
/* Look for a character in a string. */
|
||||||
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(strchr)
|
||||||
|
push %ebp
|
||||||
.globl _strchr
|
movl %esp, %ebp
|
||||||
|
push %edi
|
||||||
.text
|
cld
|
||||||
.align 16
|
movl 8(%ebp), %edi /* edi = string */
|
||||||
_strchr:
|
movl $16, %edx /* Look at small chunks of the string */
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
push edi
|
|
||||||
cld
|
|
||||||
mov edi, [ebp+8] # edi = string
|
|
||||||
mov edx, 16 # Look at small chunks of the string
|
|
||||||
next:
|
next:
|
||||||
shl edx, 1 # Chunks become bigger each time
|
shll $1, %edx /* Chunks become bigger each time */
|
||||||
mov ecx, edx
|
movl %edx, %ecx
|
||||||
xorb al, al # Look for the zero at the end
|
xorb %al, %al /* Look for the zero at the end */
|
||||||
repne scasb
|
|
||||||
|
|
||||||
pushf # Remember the flags
|
repne scasb
|
||||||
sub ecx, edx
|
pushf /* Remember the flags */
|
||||||
neg ecx # Some or all of the chunk
|
subl %edx, %ecx
|
||||||
sub edi, ecx # Step back
|
negl %ecx /* Some or all of the chunk */
|
||||||
movb al, [ebp+12] # The character to look for
|
subl %ecx, %edi /* Step back */
|
||||||
repne scasb
|
movb 12(%ebp), %al /* The character to look for */
|
||||||
je found
|
|
||||||
|
|
||||||
popf # Did we find the end of string earlier?
|
repne scasb
|
||||||
|
je found
|
||||||
jne next # No, try again
|
popf /* Did we find the end of string earlier? */
|
||||||
|
jne next /* No, try again */
|
||||||
xor eax, eax # Return NULL
|
xorl %eax, %eax /* Return NULL */
|
||||||
pop edi
|
pop %edi
|
||||||
pop ebp
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
found:
|
found:
|
||||||
pop eax # Get rid of those flags
|
pop %eax /* Get rid of those flags */
|
||||||
lea eax, [edi-1] # Address of byte found
|
leal -1(%edi), %eax /* Address of byte found */
|
||||||
pop edi
|
pop %edi
|
||||||
pop ebp
|
pop %ebp
|
||||||
ret
|
ret
|
||||||
|
11
drivers/ddk/string/strcmp.S
Normal file
11
drivers/ddk/string/strcmp.S
Normal file
@ -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 */
|
@ -1,24 +1,20 @@
|
|||||||
# strcpy() Author: Kees J. Bot
|
/* strcpy() Author: Kees J. Bot */
|
||||||
# 1 Jan 1994
|
/* 1 Jan 1994 */
|
||||||
# char *strcpy(char *s1, const char *s2)
|
|
||||||
# Copy string s2 to s1.
|
|
||||||
#
|
|
||||||
|
|
||||||
.intel_syntax
|
/* char *strcpy(char *s1, const char *s2) */
|
||||||
|
/* Copy string s2 to s1. */
|
||||||
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.global _strcpy
|
ENTRY(strcpy)
|
||||||
|
push %ebp
|
||||||
.text
|
movl %esp, %ebp
|
||||||
.align 16
|
push %esi
|
||||||
_strcpy:
|
push %edi
|
||||||
push ebp
|
movl $-1, %ecx /* Unlimited length */
|
||||||
mov ebp, esp
|
call _C_LABEL(_strncpy) /* Common code */
|
||||||
push esi
|
movl 8(%ebp), %eax /* Return s1 */
|
||||||
push edi
|
pop %edi
|
||||||
mov ecx, -1 # Unlimited length
|
pop %esi
|
||||||
call _strncpy # Common code
|
pop %ebp
|
||||||
mov eax, [8+ebp] # Return s1
|
|
||||||
pop edi
|
|
||||||
pop esi
|
|
||||||
pop ebp
|
|
||||||
ret
|
ret
|
||||||
|
@ -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)
|
/* size_t strlen(const char *s) */
|
||||||
# Return the length of a string.
|
/* Return the length of a string. */
|
||||||
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(strlen)
|
||||||
|
movl $-1, %ecx /* Unlimited length */
|
||||||
.globl _strlen
|
jmp _C_LABEL(_strnlen) /* Common code */
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_strlen:
|
|
||||||
mov ecx, -1 # Unlimited length
|
|
||||||
jmp __strnlen # Common code
|
|
||||||
|
11
drivers/ddk/string/strncat.S
Normal file
11
drivers/ddk/string/strncat.S
Normal file
@ -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 */
|
@ -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)
|
/* int strncmp(const char *s1, const char *s2, size_t n) */
|
||||||
# Compare two strings.
|
/* Compare two strings. */
|
||||||
#
|
/* */
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
.intel_syntax
|
ENTRY(strncmp)
|
||||||
|
movl 12(%esp), %ecx /* Maximum length */
|
||||||
.globl _strncmp
|
jmp _C_LABEL(_strncmp) /* Common code */
|
||||||
.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
|
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
# strncpy() Author: Kees J. Bot
|
/* strncpy() Author: Kees J. Bot */
|
||||||
# 1 Jan 1994
|
/* 1 Jan 1994 */
|
||||||
# char *strncpy(char *s1, const char *s2, size_t n)
|
|
||||||
# Copy string s2 to s1.
|
|
||||||
#
|
|
||||||
|
|
||||||
.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
|
rep stosb /* strncpy always copies n bytes by null padding */
|
||||||
|
movl 8(%ebp), %eax /* Return s1 */
|
||||||
.align 16
|
pop %edi
|
||||||
_strncpy:
|
pop %esi
|
||||||
push ebp
|
pop %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
|
|
||||||
ret
|
ret
|
||||||
|
11
drivers/ddk/string/strnlen.S
Normal file
11
drivers/ddk/string/strnlen.S
Normal file
@ -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 */
|
35
drivers/ddk/string/strrchr.S
Normal file
35
drivers/ddk/string/strrchr.S
Normal file
@ -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
|
@ -24,7 +24,10 @@ LIBS:= -lacpica -lgcc -lddk -lcore
|
|||||||
|
|
||||||
NAME= acpi
|
NAME= acpi
|
||||||
|
|
||||||
NAME_SRCS= acpi.c
|
NAME_SRCS= acpi.c \
|
||||||
|
scan.c \
|
||||||
|
pci_irq.c \
|
||||||
|
pci/pci.c
|
||||||
|
|
||||||
|
|
||||||
all: $(NAME).dll
|
all: $(NAME).dll
|
||||||
|
File diff suppressed because it is too large
Load Diff
128
drivers/devman/acpi_bus.h
Normal file
128
drivers/devman/acpi_bus.h
Normal file
@ -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);
|
151
drivers/devman/pci/pci.c
Normal file
151
drivers/devman/pci/pci.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
|
||||||
|
#include <ddk.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <mutex.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
LIST_HEAD(pci_root_buses);
|
||||||
|
|
||||||
|
#define IO_SPACE_LIMIT 0xffff
|
||||||
|
|
||||||
|
struct resource ioport_resource = {
|
||||||
|
.name = "PCI IO",
|
||||||
|
.start = 0,
|
||||||
|
.end = IO_SPACE_LIMIT,
|
||||||
|
.flags = IORESOURCE_IO,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct resource iomem_resource = {
|
||||||
|
.name = "PCI mem",
|
||||||
|
.start = 0,
|
||||||
|
.end = -1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static inline int pci_domain_nr(struct pci_bus *bus)
|
||||||
|
{
|
||||||
|
struct pci_sysdata *sd = bus->sysdata;
|
||||||
|
return sd->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pci_bus * pci_alloc_bus(void)
|
||||||
|
{
|
||||||
|
struct pci_bus *b;
|
||||||
|
|
||||||
|
b = kzalloc(sizeof(*b), GFP_KERNEL);
|
||||||
|
if (b) {
|
||||||
|
INIT_LIST_HEAD(&b->node);
|
||||||
|
INIT_LIST_HEAD(&b->children);
|
||||||
|
INIT_LIST_HEAD(&b->devices);
|
||||||
|
INIT_LIST_HEAD(&b->slots);
|
||||||
|
INIT_LIST_HEAD(&b->resources);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pci_bus * pci_create_bus(int bus, struct pci_ops *ops, void *sysdata)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct pci_bus *b, *b2;
|
||||||
|
|
||||||
|
b = pci_alloc_bus();
|
||||||
|
if (!b)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
b->sysdata = sysdata;
|
||||||
|
b->ops = ops;
|
||||||
|
|
||||||
|
b2 = pci_find_bus(pci_domain_nr(b), bus);
|
||||||
|
if (b2) {
|
||||||
|
/* If we already got to this bus through a different bridge, ignore it */
|
||||||
|
dbgprintf("bus already known\n");
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// down_write(&pci_bus_sem);
|
||||||
|
list_add_tail(&b->node, &pci_root_buses);
|
||||||
|
// up_write(&pci_bus_sem);
|
||||||
|
|
||||||
|
b->number = b->secondary = bus;
|
||||||
|
b->resource[0] = &ioport_resource;
|
||||||
|
b->resource[1] = &iomem_resource;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
kfree(b);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
|
||||||
|
{
|
||||||
|
struct pci_bus* child;
|
||||||
|
struct list_head *tmp;
|
||||||
|
|
||||||
|
if(bus->number == busnr)
|
||||||
|
return bus;
|
||||||
|
|
||||||
|
list_for_each(tmp, &bus->children) {
|
||||||
|
child = pci_do_find_bus(pci_bus_b(tmp), busnr);
|
||||||
|
if(child)
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_find_bus - locate PCI bus from a given domain and bus number
|
||||||
|
* @domain: number of PCI domain to search
|
||||||
|
* @busnr: number of desired PCI bus
|
||||||
|
*
|
||||||
|
* Given a PCI bus number and domain number, the desired PCI bus is located
|
||||||
|
* in the global list of PCI buses. If the bus is found, a pointer to its
|
||||||
|
* data structure is returned. If no bus is found, %NULL is returned.
|
||||||
|
*/
|
||||||
|
struct pci_bus * pci_find_bus(int domain, int busnr)
|
||||||
|
{
|
||||||
|
struct pci_bus *bus = NULL;
|
||||||
|
struct pci_bus *tmp_bus;
|
||||||
|
|
||||||
|
while ((bus = pci_find_next_bus(bus)) != NULL) {
|
||||||
|
if (pci_domain_nr(bus) != domain)
|
||||||
|
continue;
|
||||||
|
tmp_bus = pci_do_find_bus(bus, busnr);
|
||||||
|
if (tmp_bus)
|
||||||
|
return tmp_bus;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_find_next_bus - begin or continue searching for a PCI bus
|
||||||
|
* @from: Previous PCI bus found, or %NULL for new search.
|
||||||
|
*
|
||||||
|
* Iterates through the list of known PCI busses. A new search is
|
||||||
|
* initiated by passing %NULL as the @from argument. Otherwise if
|
||||||
|
* @from is not %NULL, searches continue from next device on the
|
||||||
|
* global list.
|
||||||
|
*/
|
||||||
|
struct pci_bus *
|
||||||
|
pci_find_next_bus(const struct pci_bus *from)
|
||||||
|
{
|
||||||
|
struct list_head *n;
|
||||||
|
struct pci_bus *b = NULL;
|
||||||
|
|
||||||
|
// WARN_ON(in_interrupt());
|
||||||
|
// down_read(&pci_bus_sem);
|
||||||
|
n = from ? from->node.next : pci_root_buses.next;
|
||||||
|
if (n != &pci_root_buses)
|
||||||
|
b = pci_bus_b(n);
|
||||||
|
// up_read(&pci_bus_sem);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
131
drivers/devman/pci_irq.c
Normal file
131
drivers/devman/pci_irq.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
|
||||||
|
#include <ddk.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <mutex.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
|
#include "acpi_bus.h"
|
||||||
|
|
||||||
|
#define PREFIX "ACPI: "
|
||||||
|
|
||||||
|
struct acpi_prt_entry
|
||||||
|
{
|
||||||
|
struct list_head list;
|
||||||
|
ACPI_PCI_ID id;
|
||||||
|
u8 pin;
|
||||||
|
ACPI_HANDLE link;
|
||||||
|
u32 index; /* GSI, or link _CRS index */
|
||||||
|
};
|
||||||
|
|
||||||
|
static LIST_HEAD(acpi_prt_list);
|
||||||
|
static DEFINE_SPINLOCK(acpi_prt_lock);
|
||||||
|
|
||||||
|
static inline char pin_name(int pin)
|
||||||
|
{
|
||||||
|
return 'A' + pin - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int acpi_pci_irq_add_entry(ACPI_HANDLE handle, struct pci_bus *bus,
|
||||||
|
struct acpi_pci_routing_table *prt)
|
||||||
|
{
|
||||||
|
struct acpi_prt_entry *entry;
|
||||||
|
|
||||||
|
entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
|
||||||
|
if (!entry)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses
|
||||||
|
* 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert
|
||||||
|
* it here.
|
||||||
|
*/
|
||||||
|
entry->id.Segment = pci_domain_nr(bus);
|
||||||
|
entry->id.Bus = bus->number;
|
||||||
|
entry->id.Device = (prt->Address >> 16) & 0xFFFF;
|
||||||
|
entry->pin = prt->Pin + 1;
|
||||||
|
|
||||||
|
// do_prt_fixups(entry, prt);
|
||||||
|
|
||||||
|
entry->index = prt->SourceIndex;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type 1: Dynamic
|
||||||
|
* ---------------
|
||||||
|
* The 'source' field specifies the PCI interrupt link device used to
|
||||||
|
* configure the IRQ assigned to this slot|dev|pin. The 'source_index'
|
||||||
|
* indicates which resource descriptor in the resource template (of
|
||||||
|
* the link device) this interrupt is allocated from.
|
||||||
|
*
|
||||||
|
* NOTE: Don't query the Link Device for IRQ information at this time
|
||||||
|
* because Link Device enumeration may not have occurred yet
|
||||||
|
* (e.g. exists somewhere 'below' this _PRT entry in the ACPI
|
||||||
|
* namespace).
|
||||||
|
*/
|
||||||
|
if (prt->Source[0])
|
||||||
|
AcpiGetHandle(handle, prt->Source, &entry->link);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type 2: Static
|
||||||
|
* --------------
|
||||||
|
* The 'source' field is NULL, and the 'source_index' field specifies
|
||||||
|
* the IRQ value, which is hardwired to specific interrupt inputs on
|
||||||
|
* the interrupt controller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dbgprintf(PREFIX " %04x:%02x:%02x[%c] -> %s[%d]\n",
|
||||||
|
entry->id.Segment, entry->id.Bus,
|
||||||
|
entry->id.Device, pin_name(entry->pin),
|
||||||
|
prt->Source, entry->index);
|
||||||
|
|
||||||
|
spin_lock(&acpi_prt_lock);
|
||||||
|
list_add_tail(&entry->list, &acpi_prt_list);
|
||||||
|
spin_unlock(&acpi_prt_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int acpi_pci_irq_add_prt(ACPI_HANDLE handle, struct pci_bus *bus)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
struct acpi_pci_routing_table *entry;
|
||||||
|
|
||||||
|
/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
|
||||||
|
status = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
|
||||||
|
(char *) buffer.Pointer);
|
||||||
|
|
||||||
|
kfree(buffer.Pointer);
|
||||||
|
|
||||||
|
buffer.Length = ACPI_ALLOCATE_BUFFER;
|
||||||
|
buffer.Pointer = NULL;
|
||||||
|
|
||||||
|
status = AcpiGetIrqRoutingTable(handle, &buffer);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
{
|
||||||
|
dbgprintf("AcpiGetIrqRoutingTable failed "
|
||||||
|
"evaluating _PRT [%s]\n",AcpiFormatException(status));
|
||||||
|
kfree(buffer.Pointer);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = buffer.Pointer;
|
||||||
|
while (entry && (entry->Length > 0)) {
|
||||||
|
acpi_pci_irq_add_entry(handle, bus, entry);
|
||||||
|
entry = (struct acpi_pci_routing_table *)
|
||||||
|
((unsigned long)entry + entry->Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(buffer.Pointer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
766
drivers/devman/scan.c
Normal file
766
drivers/devman/scan.c
Normal file
@ -0,0 +1,766 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <ddk.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <mutex.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
|
#include "acpi_bus.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define PREFIX "ACPI: "
|
||||||
|
|
||||||
|
#define ACPI_BUS_CLASS "system_bus"
|
||||||
|
#define ACPI_BUS_HID "KLBSYBUS"
|
||||||
|
#define ACPI_BUS_DEVICE_NAME "System Bus"
|
||||||
|
|
||||||
|
|
||||||
|
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
|
||||||
|
|
||||||
|
#define STRUCT_TO_INT(s) (*((int*)&s))
|
||||||
|
|
||||||
|
|
||||||
|
extern struct acpi_device *acpi_root;
|
||||||
|
|
||||||
|
static LIST_HEAD(acpi_device_list);
|
||||||
|
static LIST_HEAD(acpi_bus_id_list);
|
||||||
|
DEFINE_MUTEX(acpi_device_lock);
|
||||||
|
|
||||||
|
|
||||||
|
struct acpi_device_bus_id{
|
||||||
|
char bus_id[15];
|
||||||
|
unsigned int instance_no;
|
||||||
|
struct list_head node;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct acpi_hardware_id {
|
||||||
|
struct list_head list;
|
||||||
|
char *id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define acpi_device_name(d) ((d)->pnp.device_name)
|
||||||
|
#define acpi_device_class(d) ((d)->pnp.device_class)
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
acpi_util_eval_error(ACPI_HANDLE h, ACPI_STRING p, ACPI_STATUS s)
|
||||||
|
{
|
||||||
|
#ifdef ACPI_DEBUG_OUTPUT
|
||||||
|
char prefix[80] = {'\0'};
|
||||||
|
ACPI_BUFFER buffer = {sizeof(prefix), prefix};
|
||||||
|
AcpiGetName(h, ACPI_FULL_PATHNAME, &buffer);
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
|
||||||
|
(char *) prefix, p, AcpiFormatException(s)));
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ACPI_STATUS
|
||||||
|
acpi_evaluate_integer(ACPI_HANDLE handle, ACPI_STRING pathname,
|
||||||
|
ACPI_OBJECT_LIST *arguments, unsigned long long *data)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status = AE_OK;
|
||||||
|
ACPI_OBJECT element;
|
||||||
|
ACPI_BUFFER buffer = { 0, NULL };
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return AE_BAD_PARAMETER;
|
||||||
|
|
||||||
|
buffer.Length = sizeof(ACPI_OBJECT);
|
||||||
|
buffer.Pointer = &element;
|
||||||
|
status = AcpiEvaluateObject(handle, pathname, arguments, &buffer);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
acpi_util_eval_error(handle, pathname, status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.Type != ACPI_TYPE_INTEGER) {
|
||||||
|
acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
|
||||||
|
return AE_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = element.Integer.Value;
|
||||||
|
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
|
||||||
|
|
||||||
|
return AE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void acpi_bus_data_handler(ACPI_HANDLE handle, void *context)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* TBD */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int acpi_bus_get_device(ACPI_HANDLE handle, struct acpi_device **device)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status = AE_OK;
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TBD: Support fixed-feature devices */
|
||||||
|
|
||||||
|
status = AcpiGetData(handle, acpi_bus_data_handler, (void **)device);
|
||||||
|
if (ACPI_FAILURE(status) || !*device) {
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
|
||||||
|
handle));
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ACPI_STATUS acpi_bus_get_status_handle(ACPI_HANDLE handle,
|
||||||
|
unsigned long long *sta)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
|
||||||
|
status = acpi_evaluate_integer(handle, "_STA", NULL, sta);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
{
|
||||||
|
return AE_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (status == AE_NOT_FOUND)
|
||||||
|
{
|
||||||
|
*sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
|
||||||
|
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
|
||||||
|
return AE_OK;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
ACPI Bus operations
|
||||||
|
-------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
int acpi_match_device_ids(struct acpi_device *device,
|
||||||
|
const struct acpi_device_ids *ids)
|
||||||
|
{
|
||||||
|
const struct acpi_device_ids *id;
|
||||||
|
struct acpi_hardware_id *hwid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device is not present, it is unnecessary to load device
|
||||||
|
* driver for it.
|
||||||
|
*/
|
||||||
|
// if (!device->status.present)
|
||||||
|
// return -ENODEV;
|
||||||
|
|
||||||
|
for (id = ids; id->id[0]; id++)
|
||||||
|
list_for_each_entry(hwid, &device->pnp.ids, list)
|
||||||
|
if (!strcmp((char *) id->id, hwid->id))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int acpi_device_register(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linkage
|
||||||
|
* -------
|
||||||
|
* Link this device to its parent and siblings.
|
||||||
|
*/
|
||||||
|
INIT_LIST_HEAD(&device->children);
|
||||||
|
INIT_LIST_HEAD(&device->node);
|
||||||
|
|
||||||
|
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
|
||||||
|
if (!new_bus_id) {
|
||||||
|
printk(KERN_ERR PREFIX "Memory allocation error\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&acpi_device_lock);
|
||||||
|
/*
|
||||||
|
* Find suitable bus_id and instance number in acpi_bus_id_list
|
||||||
|
* If failed, create one and link it into acpi_bus_id_list
|
||||||
|
*/
|
||||||
|
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
|
||||||
|
{
|
||||||
|
if (!strcmp(acpi_device_bus_id->bus_id,
|
||||||
|
acpi_device_hid(device)))
|
||||||
|
{
|
||||||
|
acpi_device_bus_id->instance_no++;
|
||||||
|
found = 1;
|
||||||
|
kfree(new_bus_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
acpi_device_bus_id = new_bus_id;
|
||||||
|
strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
|
||||||
|
acpi_device_bus_id->instance_no = 0;
|
||||||
|
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
|
||||||
|
|
||||||
|
if (device->parent)
|
||||||
|
list_add_tail(&device->node, &device->parent->children);
|
||||||
|
|
||||||
|
mutex_unlock(&acpi_device_lock);
|
||||||
|
|
||||||
|
// device->dev.bus = &acpi_bus_type;
|
||||||
|
// device->dev.release = &acpi_device_release;
|
||||||
|
// result = device_register(&device->dev);
|
||||||
|
// if (result) {
|
||||||
|
// dev_err(&device->dev, "Error registering device\n");
|
||||||
|
// goto end;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
|
||||||
|
return 0;
|
||||||
|
end:
|
||||||
|
mutex_lock(&acpi_device_lock);
|
||||||
|
if (device->parent)
|
||||||
|
list_del(&device->node);
|
||||||
|
mutex_unlock(&acpi_device_lock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct acpi_device *acpi_bus_get_parent(ACPI_HANDLE handle)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
struct acpi_device *device;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fixed hardware devices do not appear in the namespace and do not
|
||||||
|
* have handles, but we fabricate acpi_devices for them, so we have
|
||||||
|
* to deal with them specially.
|
||||||
|
*/
|
||||||
|
if (handle == NULL)
|
||||||
|
return acpi_root;
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = AcpiGetParent(handle, &handle);
|
||||||
|
if (status == AE_NULL_ENTRY)
|
||||||
|
return NULL;
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return acpi_root;
|
||||||
|
|
||||||
|
ret = acpi_bus_get_device(handle, &device);
|
||||||
|
if (ret == 0)
|
||||||
|
return device;
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int acpi_bus_get_flags(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status = AE_OK;
|
||||||
|
ACPI_HANDLE temp = NULL;
|
||||||
|
|
||||||
|
/* Presence of _STA indicates 'dynamic_status' */
|
||||||
|
status = AcpiGetHandle(device->handle, "_STA", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.dynamic_status = 1;
|
||||||
|
|
||||||
|
/* Presence of _RMV indicates 'removable' */
|
||||||
|
status = AcpiGetHandle(device->handle, "_RMV", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.removable = 1;
|
||||||
|
|
||||||
|
/* Presence of _EJD|_EJ0 indicates 'ejectable' */
|
||||||
|
status = AcpiGetHandle(device->handle, "_EJD", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.ejectable = 1;
|
||||||
|
else {
|
||||||
|
status = AcpiGetHandle(device->handle, "_EJ0", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.ejectable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Presence of _LCK indicates 'lockable' */
|
||||||
|
status = AcpiGetHandle(device->handle, "_LCK", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.lockable = 1;
|
||||||
|
|
||||||
|
/* Presence of _PS0|_PR0 indicates 'power manageable' */
|
||||||
|
status = AcpiGetHandle(device->handle, "_PS0", &temp);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
status = AcpiGetHandle(device->handle, "_PR0", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.power_manageable = 1;
|
||||||
|
|
||||||
|
/* Presence of _PRW indicates wake capable */
|
||||||
|
status = AcpiGetHandle(device->handle, "_PRW", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device->flags.wake_capable = 1;
|
||||||
|
|
||||||
|
/* TBD: Performance management */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_device_get_busid(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
char bus_id[5] = { '?', 0 };
|
||||||
|
struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bus ID
|
||||||
|
* ------
|
||||||
|
* The device's Bus ID is simply the object name.
|
||||||
|
* TBD: Shouldn't this value be unique (within the ACPI namespace)?
|
||||||
|
*/
|
||||||
|
if (ACPI_IS_ROOT_DEVICE(device)) {
|
||||||
|
strcpy(device->pnp.bus_id, "ACPI");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (device->device_type)
|
||||||
|
{
|
||||||
|
case ACPI_BUS_TYPE_POWER_BUTTON:
|
||||||
|
strcpy(device->pnp.bus_id, "PWRF");
|
||||||
|
break;
|
||||||
|
case ACPI_BUS_TYPE_SLEEP_BUTTON:
|
||||||
|
strcpy(device->pnp.bus_id, "SLPF");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
AcpiGetName(device->handle, ACPI_SINGLE_NAME, &buffer);
|
||||||
|
/* Clean up trailing underscores (if any) */
|
||||||
|
for (i = 3; i > 1; i--) {
|
||||||
|
if (bus_id[i] == '_')
|
||||||
|
bus_id[i] = '\0';
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strcpy(device->pnp.bus_id, bus_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001
|
||||||
|
#define ACPI_VIDEO_DEVICE_POSTING 0x0002
|
||||||
|
#define ACPI_VIDEO_ROM_AVAILABLE 0x0004
|
||||||
|
#define ACPI_VIDEO_BACKLIGHT 0x0008
|
||||||
|
#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010
|
||||||
|
#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020
|
||||||
|
#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040
|
||||||
|
#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080
|
||||||
|
#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100
|
||||||
|
#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
|
||||||
|
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
|
||||||
|
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
|
||||||
|
|
||||||
|
|
||||||
|
long acpi_is_video_device(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
ACPI_HANDLE h_dummy;
|
||||||
|
long video_caps = 0;
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Is this device able to support video switching ? */
|
||||||
|
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOD", &h_dummy)) ||
|
||||||
|
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOS", &h_dummy)))
|
||||||
|
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
|
||||||
|
|
||||||
|
/* Is this device able to retrieve a video ROM ? */
|
||||||
|
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_ROM", &h_dummy)))
|
||||||
|
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
|
||||||
|
|
||||||
|
/* Is this device able to configure which video head to be POSTed ? */
|
||||||
|
if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_VPO", &h_dummy)) &&
|
||||||
|
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_GPD", &h_dummy)) &&
|
||||||
|
ACPI_SUCCESS(AcpiGetHandle(device->handle, "_SPD", &h_dummy)))
|
||||||
|
video_caps |= ACPI_VIDEO_DEVICE_POSTING;
|
||||||
|
|
||||||
|
return video_caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* acpi_bay_match - see if a device is an ejectable driver bay
|
||||||
|
*
|
||||||
|
* If an acpi object is ejectable and has one of the ACPI ATA methods defined,
|
||||||
|
* then we can safely call it an ejectable drive bay
|
||||||
|
*/
|
||||||
|
static int acpi_bay_match(struct acpi_device *device){
|
||||||
|
ACPI_STATUS status;
|
||||||
|
ACPI_HANDLE handle;
|
||||||
|
ACPI_HANDLE tmp;
|
||||||
|
ACPI_HANDLE phandle;
|
||||||
|
|
||||||
|
handle = device->handle;
|
||||||
|
|
||||||
|
status = AcpiGetHandle(handle, "_EJ0", &tmp);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if ((ACPI_SUCCESS(AcpiGetHandle(handle, "_GTF", &tmp))) ||
|
||||||
|
(ACPI_SUCCESS(AcpiGetHandle(handle, "_GTM", &tmp))) ||
|
||||||
|
(ACPI_SUCCESS(AcpiGetHandle(handle, "_STM", &tmp))) ||
|
||||||
|
(ACPI_SUCCESS(AcpiGetHandle(handle, "_SDD", &tmp))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (AcpiGetParent(handle, &phandle))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if ((ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTF", &tmp))) ||
|
||||||
|
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTM", &tmp))) ||
|
||||||
|
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_STM", &tmp))) ||
|
||||||
|
(ACPI_SUCCESS(AcpiGetHandle(phandle, "_SDD", &tmp))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* acpi_dock_match - see if a device has a _DCK method
|
||||||
|
*/
|
||||||
|
static int acpi_dock_match(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
ACPI_HANDLE tmp;
|
||||||
|
return AcpiGetHandle(device->handle, "_DCK", &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *acpi_device_hid(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
struct acpi_hardware_id *hid;
|
||||||
|
|
||||||
|
hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
|
||||||
|
return hid->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_add_id(struct acpi_device *device, const char *dev_id)
|
||||||
|
{
|
||||||
|
struct acpi_hardware_id *id;
|
||||||
|
|
||||||
|
id = kmalloc(sizeof(*id), GFP_KERNEL);
|
||||||
|
if (!id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&id->list);
|
||||||
|
|
||||||
|
id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
|
||||||
|
if (!id->id) {
|
||||||
|
kfree(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(id->id, dev_id);
|
||||||
|
list_add_tail(&id->list, &device->pnp.ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void acpi_device_set_id(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
ACPI_DEVICE_INFO *info;
|
||||||
|
ACPI_DEVICE_ID_LIST *cid_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch (device->device_type)
|
||||||
|
{
|
||||||
|
case ACPI_BUS_TYPE_DEVICE:
|
||||||
|
if (ACPI_IS_ROOT_DEVICE(device)) {
|
||||||
|
acpi_add_id(device, ACPI_SYSTEM_HID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = AcpiGetObjectInfo(device->handle, &info);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->Valid & ACPI_VALID_HID)
|
||||||
|
acpi_add_id(device, info->HardwareId.String);
|
||||||
|
if (info->Valid & ACPI_VALID_CID)
|
||||||
|
{
|
||||||
|
cid_list = &info->CompatibleIdList;
|
||||||
|
for (i = 0; i < cid_list->Count; i++)
|
||||||
|
acpi_add_id(device, cid_list->Ids[i].String);
|
||||||
|
}
|
||||||
|
if (info->Valid & ACPI_VALID_ADR) {
|
||||||
|
device->pnp.bus_address = info->Address;
|
||||||
|
device->flags.bus_address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some devices don't reliably have _HIDs & _CIDs, so add
|
||||||
|
* synthetic HIDs to make sure drivers can find them.
|
||||||
|
*/
|
||||||
|
if (acpi_is_video_device(device))
|
||||||
|
acpi_add_id(device, ACPI_VIDEO_HID);
|
||||||
|
else if (ACPI_SUCCESS(acpi_bay_match(device)))
|
||||||
|
acpi_add_id(device, ACPI_BAY_HID);
|
||||||
|
else if (ACPI_SUCCESS(acpi_dock_match(device)))
|
||||||
|
acpi_add_id(device, ACPI_DOCK_HID);
|
||||||
|
else if (!acpi_device_hid(device) &&
|
||||||
|
ACPI_IS_ROOT_DEVICE(device->parent)) {
|
||||||
|
acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
|
||||||
|
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
|
||||||
|
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ACPI_BUS_TYPE_POWER:
|
||||||
|
acpi_add_id(device, ACPI_POWER_HID);
|
||||||
|
break;
|
||||||
|
case ACPI_BUS_TYPE_PROCESSOR:
|
||||||
|
acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
|
||||||
|
break;
|
||||||
|
case ACPI_BUS_TYPE_THERMAL:
|
||||||
|
acpi_add_id(device, ACPI_THERMAL_HID);
|
||||||
|
break;
|
||||||
|
case ACPI_BUS_TYPE_POWER_BUTTON:
|
||||||
|
acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
|
||||||
|
break;
|
||||||
|
case ACPI_BUS_TYPE_SLEEP_BUTTON:
|
||||||
|
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We build acpi_devices for some objects that don't have _HID or _CID,
|
||||||
|
* e.g., PCI bridges and slots. Drivers can't bind to these objects,
|
||||||
|
* but we do use them indirectly by traversing the acpi_device tree.
|
||||||
|
* This generic ID isn't useful for driver binding, but it provides
|
||||||
|
* the useful property that "every acpi_device has an ID."
|
||||||
|
*/
|
||||||
|
if (list_empty(&device->pnp.ids))
|
||||||
|
acpi_add_id(device, "device");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int acpi_device_set_context(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Context
|
||||||
|
* -------
|
||||||
|
* Attach this 'struct acpi_device' to the ACPI object. This makes
|
||||||
|
* resolutions from handle->device very efficient. Fixed hardware
|
||||||
|
* devices have no handles, so we skip them.
|
||||||
|
*/
|
||||||
|
if (!device->handle)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
status = AcpiAttachData(device->handle,
|
||||||
|
acpi_bus_data_handler, device);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
printk(KERN_ERR PREFIX "Error attaching device data\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int acpi_add_single_object(struct acpi_device **child,
|
||||||
|
ACPI_HANDLE handle, int type,
|
||||||
|
unsigned long long sta,
|
||||||
|
struct acpi_bus_ops *ops)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
struct acpi_device *device;
|
||||||
|
ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
|
||||||
|
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
|
||||||
|
if (!device) {
|
||||||
|
printk(KERN_ERR PREFIX "Memory allocation error\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&device->pnp.ids);
|
||||||
|
device->device_type = type;
|
||||||
|
device->handle = handle;
|
||||||
|
device->parent = acpi_bus_get_parent(handle);
|
||||||
|
device->bus_ops = *ops; /* workround for not call .start */
|
||||||
|
STRUCT_TO_INT(device->status) = sta;
|
||||||
|
|
||||||
|
acpi_device_get_busid(device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags
|
||||||
|
* -----
|
||||||
|
* Note that we only look for object handles -- cannot evaluate objects
|
||||||
|
* until we know the device is present and properly initialized.
|
||||||
|
*/
|
||||||
|
result = acpi_bus_get_flags(device);
|
||||||
|
if (result)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize Device
|
||||||
|
* -----------------
|
||||||
|
* TBD: Synch with Core's enumeration/initialization process.
|
||||||
|
*/
|
||||||
|
acpi_device_set_id(device);
|
||||||
|
|
||||||
|
|
||||||
|
if ((result = acpi_device_set_context(device)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
result = acpi_device_register(device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bind _ADR-Based Devices when hot add
|
||||||
|
*/
|
||||||
|
// if (device->flags.bus_address) {
|
||||||
|
// if (device->parent && device->parent->ops.bind)
|
||||||
|
// device->parent->ops.bind(device);
|
||||||
|
// }
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (!result) {
|
||||||
|
AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||||
|
dbgprintf(PREFIX "Adding [%s]\n", (char *)buffer.Pointer);
|
||||||
|
kfree(buffer.Pointer);
|
||||||
|
*child = device;
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
|
||||||
|
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
|
||||||
|
|
||||||
|
static int acpi_bus_type_and_status(ACPI_HANDLE handle, int *type,
|
||||||
|
unsigned long long *sta)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
ACPI_OBJECT_TYPE acpi_type;
|
||||||
|
|
||||||
|
status = AcpiGetType(handle, &acpi_type);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
switch (acpi_type)
|
||||||
|
{
|
||||||
|
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
|
||||||
|
case ACPI_TYPE_DEVICE:
|
||||||
|
*type = ACPI_BUS_TYPE_DEVICE;
|
||||||
|
status = acpi_bus_get_status_handle(handle, sta);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return -ENODEV;
|
||||||
|
break;
|
||||||
|
case ACPI_TYPE_PROCESSOR:
|
||||||
|
*type = ACPI_BUS_TYPE_PROCESSOR;
|
||||||
|
status = acpi_bus_get_status_handle(handle, sta);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return -ENODEV;
|
||||||
|
break;
|
||||||
|
case ACPI_TYPE_THERMAL:
|
||||||
|
*type = ACPI_BUS_TYPE_THERMAL;
|
||||||
|
*sta = ACPI_STA_DEFAULT;
|
||||||
|
break;
|
||||||
|
case ACPI_TYPE_POWER:
|
||||||
|
*type = ACPI_BUS_TYPE_POWER;
|
||||||
|
*sta = ACPI_STA_DEFAULT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ACPI_STATUS acpi_bus_check_add(ACPI_HANDLE handle, u32 lvl,
|
||||||
|
void *context, void **return_value)
|
||||||
|
{
|
||||||
|
struct acpi_bus_ops *ops = context;
|
||||||
|
int type;
|
||||||
|
unsigned long long sta;
|
||||||
|
struct acpi_device *device;
|
||||||
|
ACPI_STATUS status;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = acpi_bus_type_and_status(handle, &type, &sta);
|
||||||
|
if (result)
|
||||||
|
return AE_OK;
|
||||||
|
|
||||||
|
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
|
||||||
|
!(sta & ACPI_STA_DEVICE_FUNCTIONING))
|
||||||
|
return AE_CTRL_DEPTH;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We may already have an acpi_device from a previous enumeration. If
|
||||||
|
* so, we needn't add it again, but we may still have to start it.
|
||||||
|
*/
|
||||||
|
device = NULL;
|
||||||
|
acpi_bus_get_device(handle, &device);
|
||||||
|
if (ops->acpi_op_add && !device)
|
||||||
|
acpi_add_single_object(&device, handle, type, sta, ops);
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
return AE_CTRL_DEPTH;
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (ops->acpi_op_start && !(ops->acpi_op_add)) {
|
||||||
|
status = acpi_start_single_object(device);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return AE_CTRL_DEPTH;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!*return_value)
|
||||||
|
*return_value = device;
|
||||||
|
return AE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int acpi_bus_scan(ACPI_HANDLE handle, struct acpi_bus_ops *ops,
|
||||||
|
struct acpi_device **child)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
void *device = NULL;
|
||||||
|
|
||||||
|
status = acpi_bus_check_add(handle, 0, ops, &device);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
AcpiWalkNamespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
|
||||||
|
acpi_bus_check_add, NULL, ops, &device);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
*child = device;
|
||||||
|
|
||||||
|
if (device)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int acpi_scan()
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct acpi_bus_ops ops;
|
||||||
|
|
||||||
|
memset(&ops, 0, sizeof(ops));
|
||||||
|
ops.acpi_op_add = 1;
|
||||||
|
ops.acpi_op_start = 1;
|
||||||
|
|
||||||
|
err = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
#define MANUAL_DESTROY 0x80000000
|
#define MANUAL_DESTROY 0x80000000
|
||||||
|
|
||||||
|
#define ENTER() dbgprintf("enter %s\n",__FUNCTION__)
|
||||||
|
#define LEAVE() dbgprintf("leave %s\n",__FUNCTION__)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u32_t code;
|
u32_t code;
|
||||||
|
@ -349,11 +349,44 @@ struct resource
|
|||||||
{
|
{
|
||||||
resource_size_t start;
|
resource_size_t start;
|
||||||
resource_size_t end;
|
resource_size_t end;
|
||||||
// const char *name;
|
const char *name;
|
||||||
unsigned long flags;
|
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.
|
* IO resources have these defined flags.
|
||||||
*/
|
*/
|
||||||
@ -549,6 +582,71 @@ typedef struct
|
|||||||
struct pci_dev pci_dev;
|
struct pci_dev pci_dev;
|
||||||
}pci_dev_t;
|
}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);
|
int enum_pci_devices(void);
|
||||||
|
|
||||||
struct pci_device_id*
|
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);
|
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"
|
#define pci_name(x) "radeon"
|
||||||
|
|
||||||
|
@ -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
|
#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
|
||||||
|
|
||||||
#endif /* _LINUX_TYPES_H */
|
#endif /* _LINUX_TYPES_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user