diff options
Diffstat (limited to 'drivers')
237 files changed, 12132 insertions, 4450 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 307cb08ad..e1e0745a4 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -4,7 +4,7 @@ O_TARGET := acpi.o -export-objs := ksyms.o +export-objs := acpi_ksyms.o export ACPI_CFLAGS ACPI_CFLAGS := -D_LINUX @@ -20,18 +20,26 @@ EXTRA_CFLAGS += -I./include EXTRA_CFLAGS += $(ACPI_CFLAGS) +# genksyms only reads $(CFLAGS), it should really read $(EXTRA_CFLAGS) as well. +# Without EXTRA_CFLAGS the gcc pass for genksyms fails, resulting in an empty +# include/linux/modules/acpi_ksyms.ver. Changing genkyms to use EXTRA_CFLAGS +# will hit everything, too risky in 2.4.0-prerelease. Bandaid by tweaking +# CFLAGS only for .ver targets. Review after 2.4.0 release. KAO + +$(MODINCL)/%.ver: CFLAGS := -I./include $(CFLAGS) + acpi-subdirs := common dispatcher events hardware \ interpreter namespace parser resources tables subdir-$(CONFIG_ACPI) += $(acpi-subdirs) obj-$(CONFIG_ACPI) := $(patsubst %,%.o,$(acpi-subdirs)) -obj-$(CONFIG_ACPI) += os.o ksyms.o +obj-$(CONFIG_ACPI) += os.o acpi_ksyms.o ifdef CONFIG_ACPI_KERNEL_CONFIG obj-$(CONFIG_ACPI) += acpiconf.o osconf.o else - obj-$(CONFIG_ACPI) += driver.o cmbatt.o cpu.o ec.o ksyms.o sys.o table.o power.o + obj-$(CONFIG_ACPI) += driver.o cmbatt.o cpu.o ec.o acpi_ksyms.o sys.o table.o power.o endif include $(TOPDIR)/Rules.make diff --git a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c new file mode 100644 index 000000000..8e1774c9a --- /dev/null +++ b/drivers/acpi/acpi_ksyms.c @@ -0,0 +1,83 @@ +/* + * ksyms.c - ACPI exported symbols + * + * Copyright (C) 2000 Andrew Grover + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/acpi.h> +#include "acpi.h" +#include "acdebug.h" + +extern int acpi_in_debugger; + +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("symbols") + +#ifdef ENABLE_DEBUGGER +EXPORT_SYMBOL(acpi_in_debugger); +EXPORT_SYMBOL(acpi_db_user_commands); +#endif + +EXPORT_SYMBOL(acpi_os_free); +EXPORT_SYMBOL(acpi_os_breakpoint); +EXPORT_SYMBOL(acpi_os_printf); +EXPORT_SYMBOL(acpi_os_callocate); +EXPORT_SYMBOL(acpi_os_sleep); +EXPORT_SYMBOL(acpi_os_sleep_usec); +EXPORT_SYMBOL(acpi_os_in8); +EXPORT_SYMBOL(acpi_os_out8); +EXPORT_SYMBOL(acpi_os_queue_for_execution); + +EXPORT_SYMBOL(acpi_dbg_layer); +EXPORT_SYMBOL(acpi_dbg_level); +EXPORT_SYMBOL(function_exit); +EXPORT_SYMBOL(function_trace); +EXPORT_SYMBOL(function_status_exit); +EXPORT_SYMBOL(function_value_exit); +EXPORT_SYMBOL(debug_print_raw); +EXPORT_SYMBOL(debug_print_prefix); + +EXPORT_SYMBOL(acpi_cm_strncmp); +EXPORT_SYMBOL(acpi_cm_memcpy); +EXPORT_SYMBOL(acpi_cm_memset); + +EXPORT_SYMBOL(acpi_get_handle); +EXPORT_SYMBOL(acpi_get_parent); +EXPORT_SYMBOL(acpi_get_type); +EXPORT_SYMBOL(acpi_get_name); +EXPORT_SYMBOL(acpi_get_object_info); +EXPORT_SYMBOL(acpi_get_next_object); +EXPORT_SYMBOL(acpi_evaluate_object); + +EXPORT_SYMBOL(acpi_install_notify_handler); +EXPORT_SYMBOL(acpi_remove_notify_handler); +EXPORT_SYMBOL(acpi_install_gpe_handler); +EXPORT_SYMBOL(acpi_remove_gpe_handler); +EXPORT_SYMBOL(acpi_install_address_space_handler); +EXPORT_SYMBOL(acpi_remove_address_space_handler); + +EXPORT_SYMBOL(acpi_get_current_resources); +EXPORT_SYMBOL(acpi_get_possible_resources); +EXPORT_SYMBOL(acpi_set_current_resources); + +EXPORT_SYMBOL(acpi_enable_event); +EXPORT_SYMBOL(acpi_disable_event); +EXPORT_SYMBOL(acpi_clear_event); diff --git a/drivers/acpi/cmbatt.c b/drivers/acpi/cmbatt.c index c45aa810c..d5dc5977a 100644 --- a/drivers/acpi/cmbatt.c +++ b/drivers/acpi/cmbatt.c @@ -113,10 +113,10 @@ acpi_get_battery_status(ACPI_HANDLE handle, struct cmbatt_status *result) obj = (ACPI_OBJECT *) buf.pointer; objs = obj->package.elements; - result->state = objs[0].number.value; - result->present_rate = objs[1].number.value; - result->remaining_capacity = objs[2].number.value; - result->present_voltage = objs[3].number.value; + result->state = objs[0].integer.value; + result->present_rate = objs[1].integer.value; + result->remaining_capacity = objs[2].integer.value; + result->present_voltage = objs[3].integer.value; kfree(buf.pointer); @@ -153,15 +153,15 @@ acpi_get_battery_info(ACPI_HANDLE handle, struct cmbatt_info *result) obj = (ACPI_OBJECT *) buf.pointer; objs = obj->package.elements; - result->power_unit=objs[0].number.value; - result->design_capacity=objs[1].number.value; - result->last_full_capacity=objs[2].number.value; - result->battery_technology=objs[3].number.value; - result->design_voltage=objs[4].number.value; - result->design_capacity_warning=objs[5].number.value; - result->design_capacity_low=objs[6].number.value; - result->battery_capacity_granularity_1=objs[7].number.value; - result->battery_capacity_granularity_2=objs[8].number.value; + result->power_unit=objs[0].integer.value; + result->design_capacity=objs[1].integer.value; + result->last_full_capacity=objs[2].integer.value; + result->battery_technology=objs[3].integer.value; + result->design_voltage=objs[4].integer.value; + result->design_capacity_warning=objs[5].integer.value; + result->design_capacity_low=objs[6].integer.value; + result->battery_capacity_granularity_1=objs[7].integer.value; + result->battery_capacity_granularity_2=objs[8].integer.value; /* BUG: trailing NULL issue */ strncpy(result->model_number, objs[9].string.pointer, MAX_BATT_STRLEN-1); diff --git a/drivers/acpi/common/cmalloc.c b/drivers/acpi/common/cmalloc.c index b7a64e5b6..d8514698f 100644 --- a/drivers/acpi/common/cmalloc.c +++ b/drivers/acpi/common/cmalloc.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmalloc - local memory allocation routines - * $Revision: 79 $ + * $Revision: 84 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,8 +57,6 @@ _cm_allocate ( u32 line) { void *address = NULL; - DEBUG_ONLY_MEMBERS (\ - ACPI_STATUS status) /* Check for an inadvertent size of zero bytes */ @@ -107,8 +105,6 @@ _cm_callocate ( u32 line) { void *address = NULL; - DEBUG_ONLY_MEMBERS (\ - ACPI_STATUS status) /* Check for an inadvertent size of zero bytes */ diff --git a/drivers/acpi/common/cmclib.c b/drivers/acpi/common/cmclib.c index 5146b09c5..88e92d17f 100644 --- a/drivers/acpi/common/cmclib.c +++ b/drivers/acpi/common/cmclib.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmclib - Local implementation of C library functions - * $Revision: 28 $ + * $Revision: 32 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -347,7 +347,7 @@ acpi_cm_memcpy ( void * acpi_cm_memset ( void *dest, - u32 value, + NATIVE_UINT value, NATIVE_UINT count) { NATIVE_CHAR *new = (NATIVE_CHAR *) dest; @@ -522,6 +522,7 @@ static const u8 _acpi_ctype[257] = { #define IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) #define IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) #define IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) +#define IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) /******************************************************************************* @@ -658,7 +659,7 @@ u32 acpi_cm_strtoul ( const NATIVE_CHAR *string, NATIVE_CHAR **terminator, - u32 base) + NATIVE_UINT base) { u32 converted = 0; u32 index; diff --git a/drivers/acpi/common/cmcopy.c b/drivers/acpi/common/cmcopy.c index 68b7bda01..da3851c17 100644 --- a/drivers/acpi/common/cmcopy.c +++ b/drivers/acpi/common/cmcopy.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmcopy - Internal to external object translation utilities - * $Revision: 61 $ + * $Revision: 62 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -118,9 +118,9 @@ acpi_cm_build_external_simple_object ( break; - case ACPI_TYPE_NUMBER: + case ACPI_TYPE_INTEGER: - external_obj->number.value= internal_obj->number.value; + external_obj->integer.value= internal_obj->integer.value; break; @@ -469,11 +469,11 @@ acpi_cm_build_internal_simple_object ( break; - case ACPI_TYPE_NUMBER: + case ACPI_TYPE_INTEGER: /* * Number is included in the object itself */ - internal_obj->number.value = external_obj->number.value; + internal_obj->integer.value = external_obj->integer.value; break; diff --git a/drivers/acpi/common/cmdebug.c b/drivers/acpi/common/cmdebug.c index a55372d5c..2d0022ac3 100644 --- a/drivers/acpi/common/cmdebug.c +++ b/drivers/acpi/common/cmdebug.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmdebug - Debug print routines - * $Revision: 61 $ + * $Revision: 64 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -281,7 +281,7 @@ function_value_exit ( u32 line_number, u32 component_id, NATIVE_CHAR *function_name, - NATIVE_UINT value) + ACPI_INTEGER value) { debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, diff --git a/drivers/acpi/common/cmdelete.c b/drivers/acpi/common/cmdelete.c index a6e74c12f..b516b691c 100644 --- a/drivers/acpi/common/cmdelete.c +++ b/drivers/acpi/common/cmdelete.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: cmdelete - object deletion and reference count utilities - * $Revision: 60 $ + * $Revision: 62 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/common/cmeval.c b/drivers/acpi/common/cmeval.c index 29a5cefa6..653e26a47 100644 --- a/drivers/acpi/common/cmeval.c +++ b/drivers/acpi/common/cmeval.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmeval - Object evaluation - * $Revision: 19 $ + * $Revision: 21 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -77,7 +77,7 @@ acpi_cm_evaluate_numeric_object ( /* Is the return object of the correct type? */ - if (obj_desc->common.type != ACPI_TYPE_NUMBER) { + if (obj_desc->common.type != ACPI_TYPE_INTEGER) { status = AE_TYPE; } else { @@ -85,7 +85,7 @@ acpi_cm_evaluate_numeric_object ( * Since the structure is a union, setting any field will set all * of the variables in the union */ - *address = obj_desc->number.value; + *address = obj_desc->integer.value; } /* On exit, we must delete the return object */ @@ -142,17 +142,17 @@ acpi_cm_execute_HID ( * a string */ - if ((obj_desc->common.type != ACPI_TYPE_NUMBER) && + if ((obj_desc->common.type != ACPI_TYPE_INTEGER) && (obj_desc->common.type != ACPI_TYPE_STRING)) { status = AE_TYPE; } else { - if (obj_desc->common.type == ACPI_TYPE_NUMBER) { + if (obj_desc->common.type == ACPI_TYPE_INTEGER) { /* Convert the Numeric HID to string */ - acpi_aml_eisa_id_to_string ((u32) obj_desc->number.value, hid->buffer); + acpi_aml_eisa_id_to_string ((u32) obj_desc->integer.value, hid->buffer); } else { @@ -217,17 +217,17 @@ acpi_cm_execute_UID ( * a string */ - if ((obj_desc->common.type != ACPI_TYPE_NUMBER) && + if ((obj_desc->common.type != ACPI_TYPE_INTEGER) && (obj_desc->common.type != ACPI_TYPE_STRING)) { status = AE_TYPE; } else { - if (obj_desc->common.type == ACPI_TYPE_NUMBER) { + if (obj_desc->common.type == ACPI_TYPE_INTEGER) { /* Convert the Numeric UID to string */ - acpi_aml_unsigned_integer_to_string (obj_desc->number.value, uid->buffer); + acpi_aml_unsigned_integer_to_string (obj_desc->integer.value, uid->buffer); } else { @@ -289,14 +289,14 @@ acpi_cm_execute_STA ( /* Is the return object of the correct type? */ - if (obj_desc->common.type != ACPI_TYPE_NUMBER) { + if (obj_desc->common.type != ACPI_TYPE_INTEGER) { status = AE_TYPE; } else { /* Extract the status flags */ - *flags = (u32) obj_desc->number.value; + *flags = (u32) obj_desc->integer.value; } /* On exit, we must delete the return object */ diff --git a/drivers/acpi/common/cmglobal.c b/drivers/acpi/common/cmglobal.c index 4b4460f46..a388907f3 100644 --- a/drivers/acpi/common/cmglobal.c +++ b/drivers/acpi/common/cmglobal.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmglobal - Global variables for the ACPI subsystem - * $Revision: 112 $ + * $Revision: 116 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,7 +95,7 @@ PREDEFINED_NAMES acpi_gbl_pre_defined_names[] = {"_SB_", INTERNAL_TYPE_DEF_ANY}, {"_SI_", INTERNAL_TYPE_DEF_ANY}, {"_TZ_", INTERNAL_TYPE_DEF_ANY}, - {"_REV", ACPI_TYPE_NUMBER, "2"}, + {"_REV", ACPI_TYPE_INTEGER, "2"}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, @@ -152,6 +152,13 @@ u8 acpi_gbl_ns_properties[] = }; +/* Hex to ASCII conversion table */ + +NATIVE_CHAR acpi_gbl_hex_to_ascii[] = + {'0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F'}; + + /****************************************************************************** * * Table globals diff --git a/drivers/acpi/common/cminit.c b/drivers/acpi/common/cminit.c index e6cfb7655..0952720f1 100644 --- a/drivers/acpi/common/cminit.c +++ b/drivers/acpi/common/cminit.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cminit - Common ACPI subsystem initialization - * $Revision: 91 $ + * $Revision: 93 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +35,9 @@ MODULE_NAME ("cminit") +#define ACPI_OFFSET(d,o) ((u32) &(((d *)0)->o)) +#define ACPI_FADT_OFFSET(o) ACPI_OFFSET (FADT_DESCRIPTOR, o) + /******************************************************************************* * * FUNCTION: Acpi_cm_fadt_register_error @@ -53,12 +56,13 @@ static ACPI_STATUS acpi_cm_fadt_register_error ( NATIVE_CHAR *register_name, - u32 value) + u32 value, + u32 offset) { REPORT_ERROR ( - ("Invalid FADT register value, %s=%X (FADT=%p)\n", - register_name, value, acpi_gbl_FADT)); + ("Invalid FADT value %s=%lX at offset %lX FADT=%p\n", + register_name, value, offset, acpi_gbl_FADT)); return (AE_BAD_VALUE); @@ -91,39 +95,42 @@ acpi_cm_validate_fadt ( if (acpi_gbl_FADT->pm1_evt_len < 4) { status = acpi_cm_fadt_register_error ("PM1_EVT_LEN", - (u32) acpi_gbl_FADT->pm1_evt_len); + (u32) acpi_gbl_FADT->pm1_evt_len, + ACPI_FADT_OFFSET (pm1_evt_len)); } if (!acpi_gbl_FADT->pm1_cnt_len) { - status = acpi_cm_fadt_register_error ("PM1_CNT_LEN", - 0); + status = acpi_cm_fadt_register_error ("PM1_CNT_LEN", 0, + ACPI_FADT_OFFSET (pm1_cnt_len)); } if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_evt_blk.address)) { - status = acpi_cm_fadt_register_error ("PM1a_EVT_BLK", - 0); + status = acpi_cm_fadt_register_error ("X_PM1a_EVT_BLK", 0, + ACPI_FADT_OFFSET (Xpm1a_evt_blk.address)); } if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_cnt_blk.address)) { - status = acpi_cm_fadt_register_error ("PM1a_CNT_BLK", - 0); + status = acpi_cm_fadt_register_error ("X_PM1a_CNT_BLK", 0, + ACPI_FADT_OFFSET (Xpm1a_cnt_blk.address)); } if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address)) { - status = acpi_cm_fadt_register_error ("PM_TMR_BLK", - 0); + status = acpi_cm_fadt_register_error ("X_PM_TMR_BLK", 0, + ACPI_FADT_OFFSET (Xpm_tmr_blk.address)); } if ((ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address) && !acpi_gbl_FADT->pm2_cnt_len)) { status = acpi_cm_fadt_register_error ("PM2_CNT_LEN", - (u32) acpi_gbl_FADT->pm2_cnt_len); + (u32) acpi_gbl_FADT->pm2_cnt_len, + ACPI_FADT_OFFSET (pm2_cnt_len)); } if (acpi_gbl_FADT->pm_tm_len < 4) { status = acpi_cm_fadt_register_error ("PM_TM_LEN", - (u32) acpi_gbl_FADT->pm_tm_len); + (u32) acpi_gbl_FADT->pm_tm_len, + ACPI_FADT_OFFSET (pm_tm_len)); } /* length of GPE blocks must be a multiple of 2 */ @@ -132,15 +139,17 @@ acpi_cm_validate_fadt ( if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) && (acpi_gbl_FADT->gpe0blk_len & 1)) { - status = acpi_cm_fadt_register_error ("GPE0_BLK_LEN", - (u32) acpi_gbl_FADT->gpe0blk_len); + status = acpi_cm_fadt_register_error ("(x)GPE0_BLK_LEN", + (u32) acpi_gbl_FADT->gpe0blk_len, + ACPI_FADT_OFFSET (gpe0blk_len)); } if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) && (acpi_gbl_FADT->gpe1_blk_len & 1)) { - status = acpi_cm_fadt_register_error ("GPE1_BLK_LEN", - (u32) acpi_gbl_FADT->gpe1_blk_len); + status = acpi_cm_fadt_register_error ("(x)GPE1_BLK_LEN", + (u32) acpi_gbl_FADT->gpe1_blk_len, + ACPI_FADT_OFFSET (gpe1_blk_len)); } return (status); diff --git a/drivers/acpi/common/cmobject.c b/drivers/acpi/common/cmobject.c index 95e70fb14..5f73abaaf 100644 --- a/drivers/acpi/common/cmobject.c +++ b/drivers/acpi/common/cmobject.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmobject - ACPI object create/delete/size/cache routines - * $Revision: 34 $ + * $Revision: 35 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -434,7 +434,7 @@ acpi_cm_get_simple_object_size ( break; - case ACPI_TYPE_NUMBER: + case ACPI_TYPE_INTEGER: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_POWER: diff --git a/drivers/acpi/common/cmutils.c b/drivers/acpi/common/cmutils.c index cb3d959c8..b0ee8b4d9 100644 --- a/drivers/acpi/common/cmutils.c +++ b/drivers/acpi/common/cmutils.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: cmutils - common utility procedures - * $Revision: 21 $ + * $Revision: 23 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -647,16 +647,16 @@ acpi_cm_resolve_package_references ( if (sub_object->common.type == INTERNAL_TYPE_REFERENCE) { if (sub_object->reference.op_code == AML_ZERO_OP) { - sub_object->common.type = ACPI_TYPE_NUMBER; - sub_object->number.value = 0; + sub_object->common.type = ACPI_TYPE_INTEGER; + sub_object->integer.value = 0; } else if (sub_object->reference.op_code == AML_ONE_OP) { - sub_object->common.type = ACPI_TYPE_NUMBER; - sub_object->number.value = 1; + sub_object->common.type = ACPI_TYPE_INTEGER; + sub_object->integer.value = 1; } else if (sub_object->reference.op_code == AML_ONES_OP) { - sub_object->common.type = ACPI_TYPE_NUMBER; - sub_object->number.value = ACPI_INTEGER_MAX; + sub_object->common.type = ACPI_TYPE_INTEGER; + sub_object->integer.value = ACPI_INTEGER_MAX; } } } diff --git a/drivers/acpi/common/cmxface.c b/drivers/acpi/common/cmxface.c index fc063850c..ce87b50d2 100644 --- a/drivers/acpi/common/cmxface.c +++ b/drivers/acpi/common/cmxface.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: cmxface - External interfaces for "global" ACPI functions - * $Revision: 55 $ + * $Revision: 62 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -304,16 +304,22 @@ acpi_get_system_info ( out_buffer->length = sizeof (ACPI_SYSTEM_INFO); info_ptr = (ACPI_SYSTEM_INFO *) out_buffer->pointer; - /* TBD [Future]: need a version number, or use the version string */ - info_ptr->acpi_ca_version = 0x1234; + info_ptr->acpi_ca_version = ACPI_CA_VERSION; /* System flags (ACPI capabilities) */ info_ptr->flags = acpi_gbl_system_flags; /* Timer resolution - 24 or 32 bits */ - - info_ptr->timer_resolution = acpi_hw_pmt_resolution (); + if (!acpi_gbl_FADT) { + info_ptr->timer_resolution = 0; + } + else if (acpi_gbl_FADT->tmr_val_ext == 0) { + info_ptr->timer_resolution = 24; + } + else { + info_ptr->timer_resolution = 32; + } /* Clear the reserved fields */ diff --git a/drivers/acpi/cpu.c b/drivers/acpi/cpu.c index 00ec59da5..3e4adcee2 100644 --- a/drivers/acpi/cpu.c +++ b/drivers/acpi/cpu.c @@ -39,6 +39,9 @@ static int acpi_c3_tested = 0; static int acpi_max_c_state = 1; static int acpi_pm_tmr_len; +#define MAX_C2_LATENCY 100 +#define MAX_C3_LATENCY 1000 + /* * Clear busmaster activity flag */ @@ -251,10 +254,7 @@ static ACPI_STATUS acpi_found_cpu(ACPI_HANDLE handle, u32 level, void *ctx, void **value) { ACPI_OBJECT obj; - ACPI_CX_STATE lat[4]; - ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE]; ACPI_BUFFER buf; - int i, count; buf.length = sizeof(obj); buf.pointer = &obj; @@ -273,41 +273,28 @@ acpi_found_cpu(ACPI_HANDLE handle, u32 level, void *ctx, void **value) acpi_pblk = obj.processor.pblk_address; - buf.length = sizeof(lat); - buf.pointer = lat; - if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf))) - return AE_OK; + if (acpi_fadt.plvl2_lat + && acpi_fadt.plvl2_lat <= MAX_C2_LATENCY) { + acpi_c2_exit_latency + = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl2_lat); + acpi_c2_enter_latency + = ACPI_MICROSEC_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); + acpi_max_c_state = 2; - if (lat[2].latency < MAX_CX_STATE_LATENCY) { printk(KERN_INFO "ACPI: System firmware supports: C2"); - acpi_c2_exit_latency = lat[2].latency; - acpi_max_c_state = 2; - if (lat[3].latency < MAX_CX_STATE_LATENCY) { - printk(" C3"); - acpi_c3_exit_latency = lat[3].latency; + if (acpi_fadt.plvl3_lat + && acpi_fadt.plvl3_lat <= MAX_C3_LATENCY) { + acpi_c3_exit_latency + = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl3_lat); + acpi_c3_enter_latency + = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl3_lat * 5); acpi_max_c_state = 3; - } - printk("\n"); - } - memset(throttle, 0, sizeof(throttle)); - buf.length = sizeof(throttle); - buf.pointer = throttle; - - if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf))) - return AE_OK; - - for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) { - if (throttle[i].percent_of_clock) - count++; - } - - /* 0% throttled really doesn't count */ - count--; + printk(" C3"); + } - if (count > 0) { - DEBUG_PRINT(ACPI_INFO, ("%d throttling states\n", count)); + printk("\n"); } return AE_OK; diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index 1ce75dbdb..897324547 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dsfield - Dispatcher field routines - * $Revision: 29 $ + * $Revision: 31 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index d9d73ccea..4834f47ec 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dsmethod - Parser/Interpreter interface - control method parsing - * $Revision: 53 $ + * $Revision: 56 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index e6913fabf..dfaa2a103 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dsmthdat - control method arguments and local variables - * $Revision: 36 $ + * $Revision: 39 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +40,7 @@ * * FUNCTION: Acpi_ds_method_data_init * - * PARAMETERS: *Obj_desc + * PARAMETERS: Walk_state - Current walk state object * * RETURN: Status * @@ -97,7 +97,7 @@ acpi_ds_method_data_init ( * * FUNCTION: Acpi_ds_method_data_delete_all * - * PARAMETERS: None + * PARAMETERS: Walk_state - Current walk state object * * RETURN: Status * @@ -153,7 +153,9 @@ acpi_ds_method_data_delete_all ( * * FUNCTION: Acpi_ds_method_data_init_args * - * PARAMETERS: None + * PARAMETERS: *Params - Pointer to a parameter list for the method + * Max_param_count - The arg count for this method + * Walk_state - Current walk state object * * RETURN: Status * @@ -214,6 +216,7 @@ acpi_ds_method_data_init_args ( * Index - Which local_var or argument to get * Entry - Pointer to where a pointer to the stack * entry is returned. + * Walk_state - Current walk state object * * RETURN: Status * @@ -276,6 +279,7 @@ acpi_ds_method_data_get_entry ( * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG * Index - Which local_var or argument to get * Object - Object to be inserted into the stack entry + * Walk_state - Current walk state object * * RETURN: Status * @@ -320,6 +324,7 @@ acpi_ds_method_data_set_entry ( * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG * Index - Which local_var or argument whose type * to get + * Walk_state - Current walk state object * * RETURN: Data type of selected Arg or Local * Used only in Exec_monadic2()/Type_op. @@ -366,6 +371,7 @@ acpi_ds_method_data_get_type ( * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG * Index - Which local_var or argument whose type * to get + * Walk_state - Current walk state object * * RETURN: Get the Node associated with a local or arg. * @@ -418,7 +424,8 @@ acpi_ds_method_data_get_nte ( * * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG * Index - Which local_var or argument to get - * *Dest_desc - Descriptor into which selected Arg + * Walk_state - Current walk state object + * *Dest_desc - Ptr to Descriptor into which selected Arg * or Local value should be copied * * RETURN: Status @@ -474,10 +481,12 @@ acpi_ds_method_data_get_value ( switch (type) { case MTH_TYPE_ARG: + return (AE_AML_UNINITIALIZED_ARG); break; case MTH_TYPE_LOCAL: + return (AE_AML_UNINITIALIZED_LOCAL); break; } @@ -502,6 +511,7 @@ acpi_ds_method_data_get_value ( * * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG * Index - Which local_var or argument to delete + * Walk_state - Current walk state object * * RETURN: Status * @@ -548,7 +558,6 @@ acpi_ds_method_data_delete_value ( * Decrement the reference count by one to balance the * increment when the object was stored in the slot. */ - acpi_cm_remove_reference (object); } @@ -563,18 +572,14 @@ acpi_ds_method_data_delete_value ( * * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG * Index - Which local_var or argument to set - * *Src_desc - Value to be stored - * *Dest_desc - Descriptor into which *Src_desc - * can be copied, or NULL if one must - * be allocated for the purpose. If - * provided, this descriptor will be - * used for the new value. + * Src_desc - Value to be stored + * Walk_state - Current walk state * * RETURN: Status * * DESCRIPTION: Store a value in an Arg or Local. The Src_desc is installed * as the new value for the Arg or Local and the reference count - * is incremented. + * for Src_desc is incremented. * ******************************************************************************/ @@ -644,7 +649,6 @@ acpi_ds_method_data_set_value ( * Store this object into the Node * (do the indirect store) */ - status = acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) *entry, src_desc, src_desc->common.type); return (status); @@ -652,10 +656,18 @@ acpi_ds_method_data_set_value ( /* - * Otherwise, just delete the existing object - * before storing the new one + * Perform "Implicit conversion" of the new object to the type of the + * existing object */ + status = acpi_aml_convert_to_target_type ((*entry)->common.type, &src_desc, walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + /* + * Delete the existing object + * before storing the new one + */ acpi_ds_method_data_delete_value (type, index, walk_state); } @@ -666,7 +678,6 @@ acpi_ds_method_data_set_value ( * Install the new object in the stack entry * (increments the object reference count by one) */ - status = acpi_ds_method_data_set_entry (type, index, src_desc, walk_state); if (ACPI_FAILURE (status)) { goto cleanup; diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 042cc4a80..0a6c88b4d 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dsobject - Dispatcher object management routines - * $Revision: 53 $ + * $Revision: 56 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -241,14 +241,14 @@ acpi_ds_init_object_from_op ( /* We are expecting a number */ - if (arg_desc->common.type != ACPI_TYPE_NUMBER) { + if (arg_desc->common.type != ACPI_TYPE_INTEGER) { acpi_cm_remove_reference (arg_desc); return (AE_TYPE); } /* Get the value, delete the internal object */ - (*obj_desc)->buffer.length = (u32) arg_desc->number.value; + (*obj_desc)->buffer.length = (u32) arg_desc->integer.value; acpi_cm_remove_reference (arg_desc); /* Allocate the buffer */ @@ -304,8 +304,8 @@ acpi_ds_init_object_from_op ( status = acpi_ds_build_internal_object (walk_state, op, obj_desc); break; - case ACPI_TYPE_NUMBER: - (*obj_desc)->number.value = op->value.integer; + case ACPI_TYPE_INTEGER: + (*obj_desc)->integer.value = op->value.integer; break; @@ -411,18 +411,20 @@ acpi_ds_build_internal_simple_obj ( acpi_ns_externalize_name (ACPI_UINT32_MAX, op->value.string, &length, &name); if (name) { - REPORT_WARNING (("Reference %s AML %X not found\n", + REPORT_WARNING (("Reference %s at AML %X not found\n", name, op->aml_offset)); acpi_cm_free (name); } else { - REPORT_WARNING (("Reference %s AML %X not found\n", + REPORT_WARNING (("Reference %s at AML %X not found\n", op->value.string, op->aml_offset)); } *obj_desc_ptr = NULL; } - return (status); + else { + return (status); + } } } diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 21e15bc26..ba06cf4db 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -2,12 +2,12 @@ * * Module Name: dsopcode - Dispatcher Op Region support and handling of * "control" opcodes - * $Revision: 28 $ + * $Revision: 30 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -355,7 +355,7 @@ acpi_ds_eval_field_unit_operands ( } - offset = (u32) off_desc->number.value; + offset = (u32) off_desc->integer.value; /* @@ -427,7 +427,7 @@ acpi_ds_eval_field_unit_operands ( /* Offset is in bits, count is in bits */ bit_offset = offset; - bit_count = (u16) cnt_desc->number.value; + bit_count = (u16) cnt_desc->integer.value; break; @@ -586,7 +586,7 @@ acpi_ds_eval_region_operands ( */ operand_desc = walk_state->operands[walk_state->num_operands - 1]; - obj_desc->region.length = (u32) operand_desc->number.value; + obj_desc->region.length = (u32) operand_desc->integer.value; acpi_cm_remove_reference (operand_desc); /* @@ -595,7 +595,7 @@ acpi_ds_eval_region_operands ( */ operand_desc = walk_state->operands[walk_state->num_operands - 2]; - obj_desc->region.address = (ACPI_PHYSICAL_ADDRESS) operand_desc->number.value; + obj_desc->region.address = (ACPI_PHYSICAL_ADDRESS) operand_desc->integer.value; acpi_cm_remove_reference (operand_desc); diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 2efa43e51..d31464840 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dsutils - Dispatcher utilities - * $Revision: 50 $ + * $Revision: 52 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -566,7 +566,7 @@ acpi_ds_map_opcode_to_data_type ( case AML_WORD_OP: case AML_DWORD_OP: - data_type = ACPI_TYPE_NUMBER; + data_type = ACPI_TYPE_INTEGER; break; diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 1f7e329ad..a2e1b73d3 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -2,12 +2,12 @@ * * Module Name: dswexec - Dispatcher method execution callbacks; * dispatch to interpreter. - * $Revision: 50 $ + * $Revision: 55 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,7 +46,7 @@ * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Get the result of a predicate evaluation * ****************************************************************************/ @@ -93,22 +93,22 @@ acpi_ds_get_predicate_value ( * be a number */ - if (obj_desc->common.type != ACPI_TYPE_NUMBER) { + if (obj_desc->common.type != ACPI_TYPE_INTEGER) { status = AE_AML_OPERAND_TYPE; goto cleanup; } - /* TBD: 64/32-bit */ + /* Truncate the predicate to 32-bits if necessary */ - obj_desc->number.value &= (UINT64) 0x00000000FFFFFFFF; + acpi_aml_truncate_for32bit_table (obj_desc, walk_state); /* * Save the result of the predicate evaluation on * the control stack */ - if (obj_desc->number.value) { + if (obj_desc->integer.value) { walk_state->control_state->common.value = TRUE; } @@ -330,6 +330,8 @@ acpi_ds_exec_end_op ( walk_state->num_operands = 0; walk_state->return_desc = NULL; + walk_state->op_info = op_info; + walk_state->opcode = opcode; /* Call debugger for single step support (DEBUG build only) */ diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index b3f1dc062..300d02b7f 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dswload - Dispatcher namespace load callbacks - * $Revision: 24 $ + * $Revision: 26 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index 11b6a6cb9..332ab4ffd 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dswscope - Scope stack manipulation - * $Revision: 40 $ + * $Revision: 42 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index a15a6f5f7..a436945df 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dswstate - Dispatcher parse tree walk management routines - * $Revision: 36 $ + * $Revision: 38 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,31 +37,6 @@ /******************************************************************************* * - * FUNCTION: Acpi_ds_result_stack_clear - * - * PARAMETERS: Walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Reset this walk's result stack pointers to zero, thus setting - * the stack to zero. - * - ******************************************************************************/ - -ACPI_STATUS -xxx_acpi_ds_result_stack_clear ( - ACPI_WALK_STATE *walk_state) -{ -/* - Walk_state->Num_results = 0; - Walk_state->Current_result = 0; -*/ - return (AE_OK); -} - - -/******************************************************************************* - * * FUNCTION: Acpi_ds_result_insert * * PARAMETERS: Object - Object to push @@ -135,7 +110,7 @@ acpi_ds_result_remove ( /* Check for a valid result object */ if (!state->results.obj_desc [index]) { - return (AE_AML_NO_OPERAND); + return (AE_AML_NO_RETURN_VALUE); } /* Remove the object */ @@ -179,7 +154,7 @@ acpi_ds_result_pop ( if (!state->results.num_results) { - return (AE_STACK_UNDERFLOW); + return (AE_AML_NO_RETURN_VALUE); } /* Remove top element */ @@ -198,12 +173,12 @@ acpi_ds_result_pop ( } - return (AE_STACK_UNDERFLOW); + return (AE_AML_NO_RETURN_VALUE); } /******************************************************************************* * - * FUNCTION: Acpi_ds_result_pop + * FUNCTION: Acpi_ds_result_pop_from_bottom * * PARAMETERS: Object - Where to return the popped object * Walk_state - Current Walk state @@ -231,7 +206,7 @@ acpi_ds_result_pop_from_bottom ( if (!state->results.num_results) { - return (AE_STACK_UNDERFLOW); + return (AE_AML_NO_RETURN_VALUE); } /* Remove Bottom element */ @@ -250,7 +225,7 @@ acpi_ds_result_pop_from_bottom ( /* Check for a valid result object */ if (!*object) { - return (AE_AML_NO_OPERAND); + return (AE_AML_NO_RETURN_VALUE); } @@ -260,15 +235,14 @@ acpi_ds_result_pop_from_bottom ( /******************************************************************************* * - * FUNCTION: Acpi_ds_result_pop + * FUNCTION: Acpi_ds_result_push * * PARAMETERS: Object - Where to return the popped object * Walk_state - Current Walk state * * RETURN: Status * - * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In - * other words, this is a FIFO. + * DESCRIPTION: Push an object onto the current result stack * ******************************************************************************/ @@ -282,7 +256,7 @@ acpi_ds_result_push ( state = walk_state->results; if (!state) { - return (AE_OK); + return (AE_AML_INTERNAL); } if (state->results.num_results == OBJ_NUM_OPERANDS) { @@ -719,6 +693,7 @@ acpi_ds_create_walk_state ( ACPI_WALK_LIST *walk_list) { ACPI_WALK_STATE *walk_state; + ACPI_STATUS status; acpi_cm_acquire_mutex (ACPI_MTX_CACHES); @@ -736,7 +711,7 @@ acpi_ds_create_walk_state ( acpi_gbl_walk_state_cache_depth--; acpi_cm_release_mutex (ACPI_MTX_CACHES); - } + } else { /* The cache is empty, create a new object */ @@ -762,6 +737,14 @@ acpi_ds_create_walk_state ( acpi_ds_method_data_init (walk_state); #endif + /* Create an initial result stack entry */ + + status = acpi_ds_result_stack_push (walk_state); + if (ACPI_FAILURE (status)) { + return (NULL); + } + + /* Put the new state at the head of the walk list */ acpi_ds_push_walk_state (walk_state, walk_list); diff --git a/drivers/acpi/driver.c b/drivers/acpi/driver.c index 222598120..241528fc6 100644 --- a/drivers/acpi/driver.c +++ b/drivers/acpi/driver.c @@ -55,7 +55,7 @@ struct acpi_run_entry static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; static volatile u32 acpi_event_status = 0; -static volatile acpi_sstate_t acpi_event_state = ACPI_S0; +static volatile acpi_sstate_t acpi_event_state = ACPI_STATE_S0; static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); static volatile int acpi_thread_pid = -1; @@ -243,7 +243,7 @@ acpi_do_event(ctl_table * ctl, /* * Enter system sleep state */ -static int +/*static int acpi_do_sleep(ctl_table * ctl, int write, struct file *file, @@ -257,13 +257,13 @@ acpi_do_sleep(ctl_table * ctl, } } else { - int status = acpi_enter_sx(ACPI_S1); + int status = acpi_enter_sx(ACPI_STATE_S1); if (status) return status; } file->f_pos += *len; return 0; -} +}*/ /* @@ -382,7 +382,8 @@ static struct ctl_table acpi_table[] = &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency), 0644, NULL, &acpi_do_ulong}, - {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep}, +/* until it actually works */ +/* {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},*/ {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, @@ -415,7 +416,9 @@ static struct ctl_table acpi_dir_table[] = static int acpi_thread(void *context) { - ACPI_PHYSICAL_ADDRESS rsdp_phys; + ACPI_PHYSICAL_ADDRESS rsdp_phys; + ACPI_BUFFER buffer; + ACPI_SYSTEM_INFO sys_info; /* * initialize @@ -437,8 +440,6 @@ acpi_thread(void *context) rsdp_phys = efi.acpi; #endif - printk(KERN_ERR "ACPI: System description tables found\n"); - if (!ACPI_SUCCESS(acpi_find_and_load_tables(rsdp_phys))) return -ENODEV; @@ -448,6 +449,17 @@ acpi_thread(void *context) return -ENODEV; } + buffer.length = sizeof(sys_info); + buffer.pointer = &sys_info; + + if (!ACPI_SUCCESS (acpi_get_system_info(&buffer))) { + printk(KERN_ERR "ACPI: Could not get system info\n"); + acpi_terminate(); + return -ENODEV; + } + + printk(KERN_INFO "ACPI: Core Subsystem version [%x]\n", sys_info.acpi_ca_version); + if (!ACPI_SUCCESS(acpi_enable_subsystem(ACPI_FULL_INITIALIZATION))) { printk(KERN_ERR "ACPI: Subsystem enable failed\n"); acpi_terminate(); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 8f6f61e36..5e42683c6 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -270,25 +270,6 @@ ec_transaction ( return_ACPI_STATUS(status); } -static ACPI_STATUS -ec_space_setup ( - ACPI_HANDLE region_handle, - UINT32 function, - void *handler_context, - void **return_context) -{ - // TODO: What is this function for? - /* - * The ec object is in the handler context and is needed - * when calling the ec_space_handler. - */ - *return_context = handler_context; - - return AE_OK; -} - - - static void ec_query_handler ( @@ -419,8 +400,6 @@ ec_region_setup ( { FUNCTION_TRACE("acpi_ec_region_setup"); - printk("acpi_ec_region_setup\n"); - if (function == ACPI_REGION_DEACTIVATE) { if (*region_context) @@ -556,10 +535,10 @@ found_ec( buf.length = sizeof(obj); buf.pointer = &obj; if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf)) - || obj.type != ACPI_TYPE_NUMBER) + || obj.type != ACPI_TYPE_INTEGER) return AE_OK; - ec_cxt->gpe_bit = obj.number.value; + ec_cxt->gpe_bit = obj.integer.value; /* determine if we need the Global Lock when accessing */ buf.length = sizeof(obj); @@ -568,12 +547,12 @@ found_ec( status = acpi_evaluate_object(handle, "_GLK", NULL, &buf); if (status == AE_NOT_FOUND) ec_cxt->need_global_lock = 0; - else if (!ACPI_SUCCESS(status) || obj.type != ACPI_TYPE_NUMBER) { + else if (!ACPI_SUCCESS(status) || obj.type != ACPI_TYPE_INTEGER) { DEBUG_PRINT(ACPI_ERROR, ("_GLK failed\n")); return AE_OK; } - ec_cxt->need_global_lock = obj.number.value; + ec_cxt->need_global_lock = obj.integer.value; printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,gpe %d GL %d)\n", ec_cxt->data_port, ec_cxt->status_port, ec_cxt->gpe_bit, diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index d5ce143a8..afdd477db 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -2,12 +2,12 @@ * * Module Name: evevent - Fixed and General Purpose Acpi_event * handling and dispatch - * $Revision: 32 $ + * $Revision: 33 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index a52f2dc3d..cae4a44b2 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -2,12 +2,12 @@ * * Module Name: evmisc - ACPI device notification handler dispatch * and ACPI Global Lock support - * $Revision: 20 $ + * $Revision: 22 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 53cae6392..071639a27 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch - * $Revision: 93 $ + * $Revision: 94 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -122,8 +122,8 @@ acpi_ev_execute_reg_method ( u32 function) { ACPI_OPERAND_OBJECT *params[3]; - ACPI_OPERAND_OBJECT space_iD_obj; - ACPI_OPERAND_OBJECT function_obj; + ACPI_OPERAND_OBJECT space_id_desc; + ACPI_OPERAND_OBJECT function_desc; ACPI_STATUS status; @@ -141,24 +141,24 @@ acpi_ev_execute_reg_method ( * Passed as a parameter */ - acpi_cm_init_static_object (&space_iD_obj); - acpi_cm_init_static_object (&function_obj); + acpi_cm_init_static_object (&space_id_desc); + acpi_cm_init_static_object (&function_desc); /* * Method requires two parameters. */ - params [0] = &space_iD_obj; - params [1] = &function_obj; + params [0] = &space_id_desc; + params [1] = &function_desc; params [2] = NULL; /* * Set up the parameter objects */ - space_iD_obj.common.type = ACPI_TYPE_NUMBER; - space_iD_obj.number.value = region_obj->region.space_id; + space_id_desc.common.type = ACPI_TYPE_INTEGER; + space_id_desc.integer.value = region_obj->region.space_id; - function_obj.common.type = ACPI_TYPE_NUMBER; - function_obj.number.value = function; + function_desc.common.type = ACPI_TYPE_INTEGER; + function_desc.integer.value = function; /* * Execute the method, no return value diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 92e5f198f..eb5e2033e 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evrgnini- ACPI Address_space (Op_region) init - * $Revision: 31 $ + * $Revision: 33 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 02320e93c..369d2f184 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -2,12 +2,12 @@ * * Module Name: evsci - System Control Interrupt configuration and * legacy to ACPI mode state transition functions - * $Revision: 67 $ + * $Revision: 69 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index c3bbad0ff..f0e62934f 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evxface - External interfaces for ACPI events - * $Revision: 97 $ + * $Revision: 101 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -187,26 +187,25 @@ acpi_install_notify_handler ( return (AE_BAD_PARAMETER); } - /* Convert and validate the device handle */ - acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + /* Convert and validate the device handle */ + device_node = acpi_ns_convert_handle_to_entry (device); if (!device_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } - /* - * Support for global notify handlers. These handlers are invoked for - * every notifiy of the type specifiec + * Root Object: + * ------------ + * Registering a notify handler on the root object indicates that the + * caller wishes to receive notifications for all objects. Note that + * only one <external> global handler can be regsitered (per notify type). */ - if (device == ACPI_ROOT_OBJECT) { - /* - * Make sure the handler is not already installed. - */ + /* Make sure the handler is not already installed */ if (((handler_type == ACPI_SYSTEM_NOTIFY) && acpi_gbl_sys_notify.handler) || @@ -222,94 +221,89 @@ acpi_install_notify_handler ( acpi_gbl_sys_notify.handler = handler; acpi_gbl_sys_notify.context = context; } - - else { + else /* ACPI_DEVICE_NOTIFY */ { acpi_gbl_drv_notify.node = device_node; acpi_gbl_drv_notify.handler = handler; acpi_gbl_drv_notify.context = context; } - /* Global notify handler installed */ - - goto unlock_and_exit; } - /* - * These are the ONLY objects that can receive ACPI notifications + * Other Objects: + * -------------- + * Caller will only receive notifications specific to the target object. + * Note that only certain object types can receive notifications. */ - - if ((device_node->type != ACPI_TYPE_DEVICE) && - (device_node->type != ACPI_TYPE_PROCESSOR) && - (device_node->type != ACPI_TYPE_POWER) && - (device_node->type != ACPI_TYPE_THERMAL)) - { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - /* Check for an existing internal object */ - - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); - if (obj_desc) { + else { /* - * The object exists. - * Make sure the handler is not already installed. + * These are the ONLY objects that can receive ACPI notifications */ - - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - obj_desc->device.sys_handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && - obj_desc->device.drv_handler)) + if ((device_node->type != ACPI_TYPE_DEVICE) && + (device_node->type != ACPI_TYPE_PROCESSOR) && + (device_node->type != ACPI_TYPE_POWER) && + (device_node->type != ACPI_TYPE_THERMAL)) { - status = AE_EXIST; + status = AE_BAD_PARAMETER; goto unlock_and_exit; } - } - else { - /* Create a new object */ + /* Check for an existing internal object */ - obj_desc = acpi_cm_create_internal_object (device_node->type); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); + if (obj_desc) { + + /* Object exists - make sure there's no handler */ + + if (((handler_type == ACPI_SYSTEM_NOTIFY) && + obj_desc->device.sys_handler) || + ((handler_type == ACPI_DEVICE_NOTIFY) && + obj_desc->device.drv_handler)) + { + status = AE_EXIST; + goto unlock_and_exit; + } } - /* Attach new object to the Node */ + else { + /* Create a new object */ - status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type); + obj_desc = acpi_cm_create_internal_object (device_node->type); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } + /* Attach new object to the Node */ + status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type); - /* - * If we get here, we know that there is no handler installed - * so let's party - */ - notify_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_NOTIFY); - if (!notify_obj) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + } - notify_obj->notify_handler.node = device_node; - notify_obj->notify_handler.handler = handler; - notify_obj->notify_handler.context = context; + /* Install the handler */ + notify_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_NOTIFY); + if (!notify_obj) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } - if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->device.sys_handler = notify_obj; - } + notify_obj->notify_handler.node = device_node; + notify_obj->notify_handler.handler = handler; + notify_obj->notify_handler.context = context; - else { - obj_desc->device.drv_handler = notify_obj; - } + if (handler_type == ACPI_SYSTEM_NOTIFY) { + obj_desc->device.sys_handler = notify_obj; + } + else /* ACPI_DEVICE_NOTIFY */ { + obj_desc->device.drv_handler = notify_obj; + } + } unlock_and_exit: acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); @@ -343,7 +337,6 @@ acpi_remove_notify_handler ( ACPI_NAMESPACE_NODE *device_node; ACPI_STATUS status = AE_OK; - /* Parameter validation */ if ((!handler) || @@ -363,63 +356,92 @@ acpi_remove_notify_handler ( } /* - * These are the ONLY objects that can receive ACPI notifications + * Root Object: + * ------------ */ + if (device == ACPI_ROOT_OBJECT) { - if ((device_node->type != ACPI_TYPE_DEVICE) && - (device_node->type != ACPI_TYPE_PROCESSOR) && - (device_node->type != ACPI_TYPE_POWER) && - (device_node->type != ACPI_TYPE_THERMAL)) - { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - /* Check for an existing internal object */ + if (((handler_type == ACPI_SYSTEM_NOTIFY) && + !acpi_gbl_sys_notify.handler) || + ((handler_type == ACPI_DEVICE_NOTIFY) && + !acpi_gbl_drv_notify.handler)) + { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); - if (!obj_desc) { - status = AE_NOT_EXIST; - goto unlock_and_exit; + if (handler_type == ACPI_SYSTEM_NOTIFY) { + acpi_gbl_sys_notify.node = NULL; + acpi_gbl_sys_notify.handler = NULL; + acpi_gbl_sys_notify.context = NULL; + } + else { + acpi_gbl_drv_notify.node = NULL; + acpi_gbl_drv_notify.handler = NULL; + acpi_gbl_drv_notify.context = NULL; + } } /* - * The object exists. - * - * Make sure the handler is installed. + * Other Objects: + * -------------- */ - - if (handler_type == ACPI_SYSTEM_NOTIFY) { - notify_obj = obj_desc->device.sys_handler; - } else { - notify_obj = obj_desc->device.drv_handler; - } + /* + * These are the ONLY objects that can receive ACPI notifications + */ + if ((device_node->type != ACPI_TYPE_DEVICE) && + (device_node->type != ACPI_TYPE_PROCESSOR) && + (device_node->type != ACPI_TYPE_POWER) && + (device_node->type != ACPI_TYPE_THERMAL)) + { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } - if ((!notify_obj) || - (notify_obj->notify_handler.handler != handler)) - { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } + /* Check for an existing internal object */ - /* - * Now we can remove the handler - */ - if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->device.sys_handler = NULL; - } - else { - obj_desc->device.drv_handler = NULL; + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); + if (!obj_desc) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + /* Object exists - make sure there's an existing handler */ + + if (handler_type == ACPI_SYSTEM_NOTIFY) { + notify_obj = obj_desc->device.sys_handler; + } + else { + notify_obj = obj_desc->device.drv_handler; + } + + if ((!notify_obj) || + (notify_obj->notify_handler.handler != handler)) + { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Remove the handler */ + + if (handler_type == ACPI_SYSTEM_NOTIFY) { + obj_desc->device.sys_handler = NULL; + } + else { + obj_desc->device.drv_handler = NULL; + } + + acpi_cm_remove_reference (notify_obj); } - acpi_cm_remove_reference (notify_obj); unlock_and_exit: acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); return (status); } + /****************************************************************************** * * FUNCTION: Acpi_install_gpe_handler diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 5b7652e52..9864301a3 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable - * $Revision: 26 $ + * $Revision: 28 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 71116cfc8..e54bbab24 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -2,12 +2,12 @@ * * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and * Address Spaces. - * $Revision: 26 $ + * $Revision: 27 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index d2154a1a2..304d3dec6 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -1,12 +1,13 @@ + /****************************************************************************** * - * Module Name: hwacpi - ACPI hardware functions - mode and timer - * $Revision: 34 $ + * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface + * $Revision: 36 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -304,48 +305,3 @@ acpi_hw_get_mode_capabilities (void) } -/****************************************************************************** - * - * FUNCTION: Acpi_hw_pmt_ticks - * - * PARAMETERS: none - * - * RETURN: Current value of the ACPI PMT (timer) - * - * DESCRIPTION: Obtains current value of ACPI PMT - * - ******************************************************************************/ - -u32 -acpi_hw_pmt_ticks (void) -{ - u32 ticks; - - ticks = acpi_os_in32 ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address)); - - return (ticks); -} - - -/****************************************************************************** - * - * FUNCTION: Acpi_hw_pmt_resolution - * - * PARAMETERS: none - * - * RETURN: Number of bits of resolution in the PMT (either 24 or 32) - * - * DESCRIPTION: Obtains resolution of the ACPI PMT (either 24bit or 32bit) - * - ******************************************************************************/ - -u32 -acpi_hw_pmt_resolution (void) -{ - if (0 == acpi_gbl_FADT->tmr_val_ext) { - return (24); - } - - return (32); -} - diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 2b413fac8..b7b777df6 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -1,12 +1,13 @@ + /****************************************************************************** * * Module Name: hwgpe - Low level GPE enable/disable/clear functions - * $Revision: 25 $ + * $Revision: 28 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 77b6a1c8c..fc96c51fb 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -3,12 +3,12 @@ * * Module Name: hwregs - Read/write access functions for the various ACPI * control and status registers. - * $Revision: 86 $ + * $Revision: 88 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ /* This matches the #defines in actypes.h. */ NATIVE_CHAR *sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_","\\_S3_", - "\\_S4_","\\_S4_b","\\_S5_"}; + "\\_S4_","\\_S5_","\\_S4_b"}; /******************************************************************************* @@ -53,7 +53,7 @@ NATIVE_CHAR *sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_"," * ******************************************************************************/ -static u32 +u32 acpi_hw_get_bit_shift ( u32 mask) { @@ -185,9 +185,9 @@ acpi_hw_obtain_sleep_type_register_data ( } else if (((obj_desc->package.elements[0])->common.type != - ACPI_TYPE_NUMBER) || + ACPI_TYPE_INTEGER) || ((obj_desc->package.elements[1])->common.type != - ACPI_TYPE_NUMBER)) + ACPI_TYPE_INTEGER)) { /* Must have two */ @@ -199,9 +199,9 @@ acpi_hw_obtain_sleep_type_register_data ( /* * Valid _Sx_ package size, type, and value */ - *slp_typ_a = (u8) (obj_desc->package.elements[0])->number.value; + *slp_typ_a = (u8) (obj_desc->package.elements[0])->integer.value; - *slp_typ_b = (u8) (obj_desc->package.elements[1])->number.value; + *slp_typ_b = (u8) (obj_desc->package.elements[1])->integer.value; } @@ -581,13 +581,8 @@ acpi_hw_register_read ( case PM1_CONTROL: /* 16-bit access */ - if (register_id != SLP_TYPE_B) { - value |= acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); - } - - if (register_id != SLP_TYPE_A) { - value |= acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); - } + value = acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); + value |= acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); break; @@ -696,30 +691,20 @@ acpi_hw_register_write ( case PM1_CONTROL: /* 16-bit access */ - /* - * If SLP_TYP_A or SLP_TYP_B, only write to one reg block. - * Otherwise, write to both. - */ - if (register_id == SLP_TYPE_A) { - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); - } - else if (register_id == SLP_TYPE_B) { - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); - } - else { - /* disable/re-enable interrupts if sleeping */ - if (register_id == SLP_EN) { - disable(); - } + acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); + acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); + break; - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); - if (register_id == SLP_EN) { - enable(); - } - } + case PM1_a_CONTROL: /* 16-bit access */ + + acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); + break; + + + case PM1_b_CONTROL: /* 16-bit access */ + acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); break; diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c new file mode 100644 index 000000000..892c721c6 --- /dev/null +++ b/drivers/acpi/hardware/hwsleep.c @@ -0,0 +1,189 @@ + +/****************************************************************************** + * + * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface + * $Revision: 5 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000, 2001 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "acpi.h" +#include "acnamesp.h" +#include "achware.h" + +#define _COMPONENT HARDWARE + MODULE_NAME ("hwsleep") + + +/****************************************************************************** + * + * FUNCTION: Acpi_set_firmware_waking_vector + * + * PARAMETERS: Physical_address - Physical address of ACPI real mode + * entry point. + * + * RETURN: AE_OK or AE_ERROR + * + * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS + * + ******************************************************************************/ + +ACPI_STATUS +acpi_set_firmware_waking_vector ( + ACPI_PHYSICAL_ADDRESS physical_address) +{ + + + /* Make sure that we have an FACS */ + + if (!acpi_gbl_FACS) { + return (AE_NO_ACPI_TABLES); + } + + /* Set the vector */ + + if (acpi_gbl_FACS->vector_width == 32) { + * (u32 *) acpi_gbl_FACS->firmware_waking_vector = (u32) physical_address; + } + else { + *acpi_gbl_FACS->firmware_waking_vector = physical_address; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_get_firmware_waking_vector + * + * PARAMETERS: *Physical_address - Output buffer where contents of + * the Firmware_waking_vector field of + * the FACS will be stored. + * + * RETURN: Status + * + * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_firmware_waking_vector ( + ACPI_PHYSICAL_ADDRESS *physical_address) +{ + + + if (!physical_address) { + return (AE_BAD_PARAMETER); + } + + /* Make sure that we have an FACS */ + + if (!acpi_gbl_FACS) { + return (AE_NO_ACPI_TABLES); + } + + /* Get the vector */ + + if (acpi_gbl_FACS->vector_width == 32) { + *physical_address = * (u32 *) acpi_gbl_FACS->firmware_waking_vector; + } + else { + *physical_address = *acpi_gbl_FACS->firmware_waking_vector; + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: Acpi_enter_sleep_state + * + * PARAMETERS: Sleep_state - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) + * + ******************************************************************************/ + +ACPI_STATUS +acpi_enter_sleep_state ( + u8 sleep_state) +{ + ACPI_STATUS status; + ACPI_OBJECT_LIST arg_list; + ACPI_OBJECT arg; + u8 type_a; + u8 type_b; + u16 PM1_acontrol; + u16 PM1_bcontrol; + + /* + * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. + */ + + status = acpi_hw_obtain_sleep_type_register_data(sleep_state, &type_a, &type_b); + + if (!ACPI_SUCCESS(status)) { + return status; + } + + /* run the _PTS and _GTS methods */ + MEMSET(&arg_list, 0, sizeof(arg_list)); + arg_list.count = 1; + arg_list.pointer = &arg; + + MEMSET(&arg, 0, sizeof(arg)); + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = sleep_state; + + acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL); + acpi_evaluate_object(NULL, "\\_GTS", &arg_list, NULL); + + /* clear wake status */ + acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, WAK_STS, 1); + + PM1_acontrol = (u16) acpi_hw_register_read(ACPI_MTX_LOCK, PM1_CONTROL); + + /* mask off SLP_EN and SLP_TYP fields */ + PM1_acontrol &= 0xC3FF; + + /* mask in SLP_EN */ + PM1_acontrol |= (1 << acpi_hw_get_bit_shift (SLP_EN_MASK)); + + PM1_bcontrol = PM1_acontrol; + + /* mask in SLP_TYP */ + PM1_acontrol |= (type_a << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK)); + PM1_bcontrol |= (type_b << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK)); + + /* the old version was disabling interrupts. let's try it without + * and see how that works + */ + /*disable();*/ + + acpi_hw_register_write(ACPI_MTX_LOCK, PM1_a_CONTROL, PM1_acontrol); + acpi_hw_register_write(ACPI_MTX_LOCK, PM1_b_CONTROL, PM1_bcontrol); + + /*enable();*/ + + return (AE_OK); +} diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c new file mode 100644 index 000000000..b7f529ccf --- /dev/null +++ b/drivers/acpi/hardware/hwtimer.c @@ -0,0 +1,196 @@ + +/****************************************************************************** + * + * Name: hwtimer.c - ACPI Power Management Timer Interface + * $Revision: 4 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000, 2001 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "acpi.h" +#include "achware.h" + +#define _COMPONENT HARDWARE + MODULE_NAME ("hwtimer") + + +/****************************************************************************** + * + * FUNCTION: Acpi_get_timer_resolution + * + * PARAMETERS: none + * + * RETURN: Number of bits of resolution in the PM Timer (24 or 32). + * + * DESCRIPTION: Obtains resolution of the ACPI PM Timer. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_timer_resolution ( + u32 *resolution) +{ + if (!resolution) { + return (AE_BAD_PARAMETER); + } + + if (0 == acpi_gbl_FADT->tmr_val_ext) { + *resolution = 24; + } + else { + *resolution = 32; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_get_timer + * + * PARAMETERS: none + * + * RETURN: Current value of the ACPI PM Timer (in ticks). + * + * DESCRIPTION: Obtains current value of ACPI PM Timer. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_timer ( + u32 *ticks) +{ + if (!ticks) { + return (AE_BAD_PARAMETER); + } + + *ticks = acpi_os_in32 ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address)); + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_get_timer_duration + * + * PARAMETERS: Start_ticks + * End_ticks + * Time_elapsed + * + * RETURN: Time_elapsed + * + * DESCRIPTION: Computes the time elapsed (in microseconds) between two + * PM Timer time stamps, taking into account the possibility of + * rollovers, the timer resolution, and timer frequency. + * + * The PM Timer's clock ticks at roughly 3.6 times per + * _microsecond_, and its clock continues through Cx state + * transitions (unlike many CPU timestamp counters) -- making it + * a versatile and accurate timer. + * + * Note that this function accomodates only a single timer + * rollover. Thus for 24-bit timers, this function should only + * be used for calculating durations less than ~4.6 seconds + * (~20 hours for 32-bit timers). + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_timer_duration ( + u32 start_ticks, + u32 end_ticks, + u32 *time_elapsed) +{ + u32 delta_ticks = 0; + u32 seconds = 0; + u32 milliseconds = 0; + u32 microseconds = 0; + u32 remainder = 0; + + if (!time_elapsed) { + return (AE_BAD_PARAMETER); + } + + /* + * Compute Tick Delta: + * ------------------- + * Handle timer rollovers on 24- versus 32-bit timers. + */ + if (start_ticks < end_ticks) { + delta_ticks = end_ticks - start_ticks; + } + else if (start_ticks > end_ticks) { + /* 24-bit Timer */ + if (0 == acpi_gbl_FADT->tmr_val_ext) { + delta_ticks = (0x00FFFFFF - start_ticks) + end_ticks; + } + /* 32-bit Timer */ + else { + delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; + } + } + + /* + * Compute Duration: + * ----------------- + * Since certain compilers (gcc/Linux, argh!) don't support 64-bit + * divides in kernel-space we have to do some trickery to preserve + * accuracy while using 32-bit math. + * + * TODO: Change to use 64-bit math when supported. + * + * The process is as follows: + * 1. Compute the number of seconds by dividing Delta Ticks by + * the timer frequency. + * 2. Compute the number of milliseconds in the remainder from step #1 + * by multiplying by 1000 and then dividing by the timer frequency. + * 3. Compute the number of microseconds in the remainder from step #2 + * by multiplying by 1000 and then dividing by the timer frequency. + * 4. Add the results from steps 1, 2, and 3 to get the total duration. + * + * Example: The time elapsed for Delta_ticks = 0xFFFFFFFF should be + * 1199864031 microseconds. This is computed as follows: + * Step #1: Seconds = 1199; Remainder = 3092840 + * Step #2: Milliseconds = 864; Remainder = 113120 + * Step #3: Microseconds = 31; Remainder = <don't care!> + */ + + /* Step #1 */ + seconds = delta_ticks / PM_TIMER_FREQUENCY; + remainder = delta_ticks % PM_TIMER_FREQUENCY; + + /* Step #2 */ + milliseconds = (remainder * 1000) / PM_TIMER_FREQUENCY; + remainder = (remainder * 1000) % PM_TIMER_FREQUENCY; + + /* Step #3 */ + microseconds = (remainder * 1000) / PM_TIMER_FREQUENCY; + + /* Step #4 */ + *time_elapsed = seconds * 1000000; + *time_elapsed += milliseconds * 1000; + *time_elapsed += microseconds; + + return (AE_OK); +} + + diff --git a/drivers/acpi/include/accommon.h b/drivers/acpi/include/accommon.h index 37e13b228..61d54a220 100644 --- a/drivers/acpi/include/accommon.h +++ b/drivers/acpi/include/accommon.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: accommon.h -- prototypes for the common (subsystem-wide) procedures - * $Revision: 82 $ + * $Revision: 87 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -100,6 +100,8 @@ acpi_cm_allocate_owner_id ( * Cm_clib - Local implementations of C library functions */ +#ifndef ACPI_USE_SYSTEM_CLIBRARY + NATIVE_UINT acpi_cm_strlen ( const NATIVE_CHAR *string); @@ -141,7 +143,7 @@ u32 acpi_cm_strtoul ( const NATIVE_CHAR *string, NATIVE_CHAR **terminator, - u32 base); + NATIVE_UINT base); NATIVE_CHAR * acpi_cm_strstr ( @@ -161,7 +163,7 @@ acpi_cm_memcpy ( void * acpi_cm_memset ( void *dest, - u32 value, + NATIVE_UINT value, NATIVE_UINT count); u32 @@ -172,6 +174,7 @@ u32 acpi_cm_to_lower ( u32 c); +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ /* * Cm_copy - Object construction and conversion interfaces @@ -297,7 +300,7 @@ function_value_exit ( u32 line_number, u32 component_id, NATIVE_CHAR *function_name, - NATIVE_UINT value); + ACPI_INTEGER value); void function_ptr_exit ( @@ -596,7 +599,7 @@ acpi_cm_init_static_object ( #define acpi_cm_callocate(a) _cm_callocate(a, _COMPONENT,_THIS_MODULE,__LINE__) #define acpi_cm_free(a) _cm_free(a,_COMPONENT,_THIS_MODULE,__LINE__) -#ifndef ACPI_DEBUG +#ifndef ACPI_DEBUG_TRACK_ALLOCATIONS #define acpi_cm_add_element_to_alloc_list(a,b,c,d,e,f) #define acpi_cm_delete_element_from_alloc_list(a,b,c,d) diff --git a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h index 2b210339b..ea9be649d 100644 --- a/drivers/acpi/include/acconfig.h +++ b/drivers/acpi/include/acconfig.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 48 $ + * $Revision: 53 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ /* Version string */ -#define ACPI_CA_VERSION __DATE__ +#define ACPI_CA_VERSION 0x20010125 /* Maximum objects in the various object caches */ @@ -122,6 +122,10 @@ #define MTH_NUM_ARGS 7 #define MTH_MAX_ARG 6 +/* Maximum length of resulting string when converting from a buffer */ + +#define ACPI_MAX_STRING_CONVERSION 200 + /* * Operand Stack (in WALK_STATE), Must be large enough to contain MTH_MAX_ARG */ diff --git a/drivers/acpi/include/acdebug.h b/drivers/acpi/include/acdebug.h index 2bc9e7165..f1fa7094e 100644 --- a/drivers/acpi/include/acdebug.h +++ b/drivers/acpi/include/acdebug.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acdebug.h - ACPI/AML debugger - * $Revision: 37 $ + * $Revision: 39 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acdispat.h b/drivers/acpi/include/acdispat.h index 599e46c36..f5d52cc41 100644 --- a/drivers/acpi/include/acdispat.h +++ b/drivers/acpi/include/acdispat.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acdispat.h - dispatcher (parser to interpreter interface) - * $Revision: 33 $ + * $Revision: 35 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acenv.h b/drivers/acpi/include/acenv.h index f867a348f..9e4e62339 100644 --- a/drivers/acpi/include/acenv.h +++ b/drivers/acpi/include/acenv.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acenv.h - Generation environment specific items - * $Revision: 65 $ + * $Revision: 70 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ /* - * Configuration for ACPI Utilities + * Configuration for ACPI tools and utilities */ #ifdef _ACPI_DUMP_APP @@ -55,6 +55,16 @@ #define ACPI_USE_SYSTEM_CLIBRARY #endif +/* + * Memory allocation tracking. Used only if + * 1) This is the debug version + * 2) This is NOT a 16-bit version of the code (not enough real-mode memory) + */ +#ifdef ACPI_DEBUG +#ifndef _IA16 +#define ACPI_DEBUG_TRACK_ALLOCATIONS +#endif +#endif /* * Environment configuration. The purpose of this file is to interface to the @@ -154,17 +164,17 @@ #define STRUPR(s) strupr((s)) #define STRLEN(s) strlen((s)) #define STRCPY(d,s) strcpy((d), (s)) -#define STRNCPY(d,s,n) strncpy((d), (s), (n)) -#define STRNCMP(d,s,n) strncmp((d), (s), (n)) +#define STRNCPY(d,s,n) strncpy((d), (s), (NATIVE_INT)(n)) +#define STRNCMP(d,s,n) strncmp((d), (s), (NATIVE_INT)(n)) #define STRCMP(d,s) strcmp((d), (s)) #define STRCAT(d,s) strcat((d), (s)) -#define STRNCAT(d,s,n) strncat((d), (s), (n)) -#define STRTOUL(d,s,n) strtoul((d), (s), (n)) -#define MEMCPY(d,s,n) memcpy((d), (s), (n)) -#define MEMSET(d,s,n) memset((d), (s), (n)) +#define STRNCAT(d,s,n) strncat((d), (s), (NATIVE_INT)(n)) +#define STRTOUL(d,s,n) strtoul((d), (s), (NATIVE_INT)(n)) +#define MEMCPY(d,s,n) memcpy((d), (s), (NATIVE_INT)(n)) +#define MEMSET(d,s,n) memset((d), (s), (NATIVE_INT)(n)) #define TOUPPER toupper #define TOLOWER tolower - +#define IS_XDIGIT isxdigit /****************************************************************************** * diff --git a/drivers/acpi/include/acevents.h b/drivers/acpi/include/acevents.h index 3e76370bf..b7d335451 100644 --- a/drivers/acpi/include/acevents.h +++ b/drivers/acpi/include/acevents.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acevents.h - Event subcomponent prototypes and defines - * $Revision: 62 $ + * $Revision: 63 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acexcep.h b/drivers/acpi/include/acexcep.h index 1629a0934..8fb267585 100644 --- a/drivers/acpi/include/acexcep.h +++ b/drivers/acpi/include/acexcep.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acexcep.h - Exception codes returned by the ACPI subsystem - * $Revision: 37 $ + * $Revision: 41 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -116,8 +116,10 @@ #define AE_AML_NAME_NOT_FOUND (ACPI_STATUS) (0x0010 | AE_CODE_AML) #define AE_AML_INTERNAL (ACPI_STATUS) (0x0011 | AE_CODE_AML) #define AE_AML_INVALID_SPACE_ID (ACPI_STATUS) (0x0012 | AE_CODE_AML) +#define AE_AML_STRING_LIMIT (ACPI_STATUS) (0x0013 | AE_CODE_AML) +#define AE_AML_NO_RETURN_VALUE (ACPI_STATUS) (0x0014 | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x0012 +#define AE_CODE_AML_MAX 0x0014 /* * Internal exceptions used for control @@ -202,6 +204,8 @@ static NATIVE_CHAR *acpi_gbl_exception_names_aml[] = "AE_AML_NAME_NOT_FOUND", "AE_AML_INTERNAL", "AE_AML_INVALID_SPACE_ID", + "AE_AML_STRING_LIMIT", + "AE_AML_NO_RETURN_VALUE", }; static NATIVE_CHAR *acpi_gbl_exception_names_ctrl[] = diff --git a/drivers/acpi/include/acgcc.h b/drivers/acpi/include/acgcc.h index 5992f493d..82b1e5139 100644 --- a/drivers/acpi/include/acgcc.h +++ b/drivers/acpi/include/acgcc.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acgcc.h - GCC specific defines, etc. - * $Revision: 2 $ + * $Revision: 4 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acglobal.h b/drivers/acpi/include/acglobal.h index 248f72c9d..36444038c 100644 --- a/drivers/acpi/include/acglobal.h +++ b/drivers/acpi/include/acglobal.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acglobal.h - Declarations for global variables - * $Revision: 92 $ + * $Revision: 96 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -154,7 +154,6 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_set; /* TBD: [Restr ACPI_EXTERN u8 acpi_gbl_step_to_next_call; ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; - ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_drv_notify; ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify; @@ -162,7 +161,8 @@ ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_system_flags; extern u32 acpi_gbl_startup_flags; -extern u8 acpi_gbl_decode_to8bit[]; +extern u8 acpi_gbl_decode_to8bit[8]; +extern NATIVE_CHAR acpi_gbl_hex_to_ascii[]; /***************************************************************************** diff --git a/drivers/acpi/include/achware.h b/drivers/acpi/include/achware.h index 1a206e8d2..efb97bd2f 100644 --- a/drivers/acpi/include/achware.h +++ b/drivers/acpi/include/achware.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: achware.h -- hardware specific interfaces - * $Revision: 48 $ + * $Revision: 53 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,10 @@ #define __ACHWARE_H__ +/* PM Timer ticks per second (HZ) */ +#define PM_TIMER_FREQUENCY 3579545 + + /* Prototypes */ @@ -92,6 +96,10 @@ void acpi_hw_clear_acpi_status ( void); +u32 +acpi_hw_get_bit_shift ( + u32 mask); + /* GPE support */ @@ -121,89 +129,21 @@ acpi_hw_obtain_sleep_type_register_data ( u8 *slp_typ_b); -/* Cx State Prototypes */ - -ACPI_STATUS -acpi_hw_enter_c1( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_enter_c2( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_enter_c3( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_enter_cx ( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_set_cx ( - u32 cx_state); - -ACPI_STATUS -acpi_hw_get_cx_info ( - u32 cx_states[]); +/* ACPI Timer prototypes */ ACPI_STATUS -acpi_hw_get_cx_handler ( - u32 cx_state, - ACPI_C_STATE_HANDLER *handler); +acpi_get_timer_resolution ( + u32 *resolution); ACPI_STATUS -acpi_hw_set_cx_handler ( - u32 cx_state, - ACPI_C_STATE_HANDLER handler); - - -/* Throttling Prototypes */ - -void -acpi_hw_enable_throttling ( - ACPI_IO_ADDRESS pblk_address); - -void -acpi_hw_disable_throttling ( - ACPI_IO_ADDRESS pblk_address); - -u32 -acpi_hw_get_duty_cycle ( - u8 duty_offset, - ACPI_IO_ADDRESS pblk_address, - u32 num_throttle_states); - -void -acpi_hw_program_duty_cycle ( - u8 duty_offset, - u32 duty_cycle, - ACPI_IO_ADDRESS pblk_address, - u32 num_throttle_states); - -NATIVE_UINT -acpi_hw_local_pow ( - NATIVE_UINT x, - NATIVE_UINT y); - - -/* ACPI Timer prototypes */ - -u32 -acpi_hw_pmt_ticks ( - void); - -u32 -acpi_hw_pmt_resolution ( - void); +acpi_get_timer ( + u32 *ticks); ACPI_STATUS -acpi_get_timer ( - u32 *out_ticks); +acpi_get_timer_duration ( + u32 start_ticks, + u32 end_ticks, + u32 *time_elapsed); #endif /* __ACHWARE_H__ */ diff --git a/drivers/acpi/include/acinterp.h b/drivers/acpi/include/acinterp.h index c8c967492..6eb571e5f 100644 --- a/drivers/acpi/include/acinterp.h +++ b/drivers/acpi/include/acinterp.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acinterp.h - Interpreter subcomponent prototypes and defines - * $Revision: 86 $ + * $Revision: 91 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,9 +70,34 @@ acpi_aml_execute_method ( /* - * amfield - ACPI AML (p-code) execution - field manipulation + * amconvrt - object conversion */ +ACPI_STATUS +acpi_aml_convert_to_integer ( + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_convert_to_buffer ( + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_convert_to_string ( + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_convert_to_target_type ( + OBJECT_TYPE_INTERNAL destination_type, + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state); + + +/* + * amfield - ACPI AML (p-code) execution - field manipulation + */ ACPI_STATUS acpi_aml_read_field ( @@ -419,17 +444,75 @@ acpi_aml_exec_store ( ACPI_WALK_STATE *walk_state); ACPI_STATUS -acpi_aml_store_object_to_object ( +acpi_aml_store_object_to_index ( ACPI_OPERAND_OBJECT *val_desc, ACPI_OPERAND_OBJECT *dest_desc, ACPI_WALK_STATE *walk_state); ACPI_STATUS acpi_aml_store_object_to_node ( - ACPI_OPERAND_OBJECT *val_desc, + ACPI_OPERAND_OBJECT *source_desc, ACPI_NAMESPACE_NODE *node, ACPI_WALK_STATE *walk_state); +ACPI_STATUS +acpi_aml_store_object_to_object ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state); + + +/* + * + */ + +ACPI_STATUS +acpi_aml_resolve_object ( + ACPI_OPERAND_OBJECT **source_desc_ptr, + OBJECT_TYPE_INTERNAL target_type, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_store_object ( + ACPI_OPERAND_OBJECT *source_desc, + OBJECT_TYPE_INTERNAL target_type, + ACPI_OPERAND_OBJECT **target_desc_ptr, + ACPI_WALK_STATE *walk_state); + + +/* + * amcopy - object copy + */ + +ACPI_STATUS +acpi_aml_copy_buffer_to_buffer ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc); + +ACPI_STATUS +acpi_aml_copy_string_to_string ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc); + +ACPI_STATUS +acpi_aml_copy_integer_to_index_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc); + +ACPI_STATUS +acpi_aml_copy_integer_to_bank_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc); + +ACPI_STATUS +acpi_aml_copy_data_to_named_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_NAMESPACE_NODE *node); + +ACPI_STATUS +acpi_aml_copy_integer_to_field_unit ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc); /* * amutils - interpreter/scanner utilities diff --git a/drivers/acpi/include/aclinux.h b/drivers/acpi/include/aclinux.h index 673d5f96b..0cf0e2845 100644 --- a/drivers/acpi/include/aclinux.h +++ b/drivers/acpi/include/aclinux.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: aclinux.h - OS specific defines, etc. - * $Revision: 6 $ + * $Revision: 7 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/aclocal.h b/drivers/acpi/include/aclocal.h index a647026f1..2d931387e 100644 --- a/drivers/acpi/include/aclocal.h +++ b/drivers/acpi/include/aclocal.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: aclocal.h - Internal data types used across the ACPI subsystem - * $Revision: 95 $ + * $Revision: 100 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,7 +74,7 @@ typedef u32 ACPI_MUTEX_HANDLE; #define NUM_MTX MAX_MTX+1 -#ifdef ACPI_DEBUG +#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) #ifdef DEFINE_ACPI_GLOBALS /* Names for the mutexes used in the subsystem */ @@ -476,7 +476,9 @@ typedef struct acpi_opcode_info u32 parse_args; /* Grammar/Parse time arguments */ u32 runtime_args; /* Interpret time arguments */ - DEBUG_ONLY_MEMBERS (NATIVE_CHAR *name) /* op name (debug only) */ +#ifdef _OPCODE_NAMES + NATIVE_CHAR *name; /* op name (debug only) */ +#endif } ACPI_OPCODE_INFO; @@ -591,6 +593,7 @@ typedef struct acpi_walk_state ACPI_GENERIC_STATE *scope_info; /* Stack of nested scopes */ ACPI_PARSE_STATE *parser_state; /* Current state of parser */ u8 *aml_last_while; + ACPI_OPCODE_INFO *op_info; /* Info on current opcode */ ACPI_PARSE_DOWNWARDS descending_callback; ACPI_PARSE_UPWARDS ascending_callback; @@ -605,6 +608,7 @@ typedef struct acpi_walk_state u32 parse_flags; u8 walk_type; u8 return_used; + u16 opcode; /* Current AML opcode */ u32 prev_arg_types; /* Debug support */ @@ -728,14 +732,16 @@ typedef struct acpi_get_devices_info #define PM1_STS 0x0100 #define PM1_EN 0x0200 #define PM1_CONTROL 0x0300 -#define PM2_CONTROL 0x0400 -#define PM_TIMER 0x0500 -#define PROCESSOR_BLOCK 0x0600 -#define GPE0_STS_BLOCK 0x0700 -#define GPE0_EN_BLOCK 0x0800 -#define GPE1_STS_BLOCK 0x0900 -#define GPE1_EN_BLOCK 0x0A00 -#define SMI_CMD_BLOCK 0x0B00 +#define PM1_a_CONTROL 0x0400 +#define PM1_b_CONTROL 0x0500 +#define PM2_CONTROL 0x0600 +#define PM_TIMER 0x0700 +#define PROCESSOR_BLOCK 0x0800 +#define GPE0_STS_BLOCK 0x0900 +#define GPE0_EN_BLOCK 0x0A00 +#define GPE1_STS_BLOCK 0x0B00 +#define GPE1_EN_BLOCK 0x0C00 +#define SMI_CMD_BLOCK 0x0D00 /* * Address space bitmasks for mmio or io spaces @@ -751,66 +757,66 @@ typedef struct acpi_get_devices_info /* * Control bit definitions */ -#define TMR_STS (PM1_STS | 0x01) -#define BM_STS (PM1_STS | 0x02) -#define GBL_STS (PM1_STS | 0x03) -#define PWRBTN_STS (PM1_STS | 0x04) -#define SLPBTN_STS (PM1_STS | 0x05) -#define RTC_STS (PM1_STS | 0x06) -#define WAK_STS (PM1_STS | 0x07) - -#define TMR_EN (PM1_EN | 0x01) +#define TMR_STS (PM1_STS | 0x01) +#define BM_STS (PM1_STS | 0x02) +#define GBL_STS (PM1_STS | 0x03) +#define PWRBTN_STS (PM1_STS | 0x04) +#define SLPBTN_STS (PM1_STS | 0x05) +#define RTC_STS (PM1_STS | 0x06) +#define WAK_STS (PM1_STS | 0x07) + +#define TMR_EN (PM1_EN | 0x01) /* no BM_EN */ -#define GBL_EN (PM1_EN | 0x03) -#define PWRBTN_EN (PM1_EN | 0x04) -#define SLPBTN_EN (PM1_EN | 0x05) -#define RTC_EN (PM1_EN | 0x06) -#define WAK_EN (PM1_EN | 0x07) +#define GBL_EN (PM1_EN | 0x03) +#define PWRBTN_EN (PM1_EN | 0x04) +#define SLPBTN_EN (PM1_EN | 0x05) +#define RTC_EN (PM1_EN | 0x06) +#define WAK_EN (PM1_EN | 0x07) -#define SCI_EN (PM1_CONTROL | 0x01) -#define BM_RLD (PM1_CONTROL | 0x02) -#define GBL_RLS (PM1_CONTROL | 0x03) -#define SLP_TYPE_A (PM1_CONTROL | 0x04) -#define SLP_TYPE_B (PM1_CONTROL | 0x05) -#define SLP_EN (PM1_CONTROL | 0x06) +#define SCI_EN (PM1_CONTROL | 0x01) +#define BM_RLD (PM1_CONTROL | 0x02) +#define GBL_RLS (PM1_CONTROL | 0x03) +#define SLP_TYPE_A (PM1_CONTROL | 0x04) +#define SLP_TYPE_B (PM1_CONTROL | 0x05) +#define SLP_EN (PM1_CONTROL | 0x06) -#define ARB_DIS (PM2_CONTROL | 0x01) +#define ARB_DIS (PM2_CONTROL | 0x01) -#define TMR_VAL (PM_TIMER | 0x01) +#define TMR_VAL (PM_TIMER | 0x01) -#define GPE0_STS (GPE0_STS_BLOCK | 0x01) -#define GPE0_EN (GPE0_EN_BLOCK | 0x01) +#define GPE0_STS (GPE0_STS_BLOCK | 0x01) +#define GPE0_EN (GPE0_EN_BLOCK | 0x01) -#define GPE1_STS (GPE1_STS_BLOCK | 0x01) -#define GPE1_EN (GPE1_EN_BLOCK | 0x01) +#define GPE1_STS (GPE1_STS_BLOCK | 0x01) +#define GPE1_EN (GPE1_EN_BLOCK | 0x01) -#define TMR_STS_MASK 0x0001 -#define BM_STS_MASK 0x0010 -#define GBL_STS_MASK 0x0020 -#define PWRBTN_STS_MASK 0x0100 -#define SLPBTN_STS_MASK 0x0200 -#define RTC_STS_MASK 0x0400 -#define WAK_STS_MASK 0x8000 +#define TMR_STS_MASK 0x0001 +#define BM_STS_MASK 0x0010 +#define GBL_STS_MASK 0x0020 +#define PWRBTN_STS_MASK 0x0100 +#define SLPBTN_STS_MASK 0x0200 +#define RTC_STS_MASK 0x0400 +#define WAK_STS_MASK 0x8000 -#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK \ - | PWRBTN_STS_MASK | SLPBTN_STS_MASK \ - | RTC_STS_MASK | WAK_STS_MASK) +#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK \ + | PWRBTN_STS_MASK | SLPBTN_STS_MASK \ + | RTC_STS_MASK | WAK_STS_MASK) -#define TMR_EN_MASK 0x0001 -#define GBL_EN_MASK 0x0020 -#define PWRBTN_EN_MASK 0x0100 -#define SLPBTN_EN_MASK 0x0200 -#define RTC_EN_MASK 0x0400 +#define TMR_EN_MASK 0x0001 +#define GBL_EN_MASK 0x0020 +#define PWRBTN_EN_MASK 0x0100 +#define SLPBTN_EN_MASK 0x0200 +#define RTC_EN_MASK 0x0400 -#define SCI_EN_MASK 0x0001 -#define BM_RLD_MASK 0x0002 -#define GBL_RLS_MASK 0x0004 -#define SLP_TYPE_X_MASK 0x1C00 -#define SLP_EN_MASK 0x2000 +#define SCI_EN_MASK 0x0001 +#define BM_RLD_MASK 0x0002 +#define GBL_RLS_MASK 0x0004 +#define SLP_TYPE_X_MASK 0x1C00 +#define SLP_EN_MASK 0x2000 -#define ARB_DIS_MASK 0x0001 -#define TMR_VAL_MASK 0xFFFFFFFF +#define ARB_DIS_MASK 0x0001 +#define TMR_VAL_MASK 0xFFFFFFFF #define GPE0_STS_MASK #define GPE0_EN_MASK @@ -819,8 +825,8 @@ typedef struct acpi_get_devices_info #define GPE1_EN_MASK -#define ACPI_READ 1 -#define ACPI_WRITE 2 +#define ACPI_READ 1 +#define ACPI_WRITE 2 /* Plug and play */ diff --git a/drivers/acpi/include/acmacros.h b/drivers/acpi/include/acmacros.h index 19cfa0591..7bed83ddd 100644 --- a/drivers/acpi/include/acmacros.h +++ b/drivers/acpi/include/acmacros.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acmacros.h - C macros for the entire subsystem. - * $Revision: 59 $ + * $Revision: 62 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,14 @@ * Data manipulation macros */ +#ifndef LODWORD +#define LODWORD(l) ((u32)(UINT64)(l)) +#endif + +#ifndef HIDWORD +#define HIDWORD(l) ((u32)((((UINT64)(l)) >> 32) & 0xFFFFFFFF)) +#endif + #ifndef LOWORD #define LOWORD(l) ((u16)(NATIVE_UINT)(l)) #endif @@ -64,10 +72,18 @@ #ifdef _IA16 +/* + * For 16-bit addresses, we have to assume that the upper 32 bits + * are zero. + */ #define ACPI_GET_ADDRESS(a) ((a).lo) #define ACPI_STORE_ADDRESS(a,b) {(a).hi=0;(a).lo=(b);} -#define ACPI_VALID_ADDRESS(a) ((a).hi && (a).lo) +#define ACPI_VALID_ADDRESS(a) ((a).hi | (a).lo) + #else +/* + * Full 64-bit address on 32-bit and 64-bit platforms + */ #define ACPI_GET_ADDRESS(a) (a) #define ACPI_STORE_ADDRESS(a,b) ((a)=(b)) #define ACPI_VALID_ADDRESS(a) (a) @@ -335,7 +351,7 @@ */ #define return_VOID {function_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name);return;} #define return_ACPI_STATUS(s) {function_status_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,s);return(s);} -#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(NATIVE_UINT)s);return(s);} +#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(ACPI_INTEGER)s);return(s);} #define return_PTR(s) {function_ptr_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(u8 *)s);return(s);} @@ -346,6 +362,8 @@ #define DEBUG_DEFINE(a) a; #define DEBUG_ONLY_MEMBERS(a) a; +#define _OPCODE_NAMES +#define _VERBOSE_STRUCTURES /* Stack and buffer dumping */ @@ -458,9 +476,8 @@ */ #ifdef _IA16 #undef DEBUG_ONLY_MEMBERS +#undef _VERBOSE_STRUCTURES #define DEBUG_ONLY_MEMBERS(a) -#undef OP_INFO_ENTRY -#define OP_INFO_ENTRY(flags,name,Pargs,Iargs) {flags,Pargs,Iargs} #endif diff --git a/drivers/acpi/include/acnamesp.h b/drivers/acpi/include/acnamesp.h index e010a8118..d6acb8444 100644 --- a/drivers/acpi/include/acnamesp.h +++ b/drivers/acpi/include/acnamesp.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acnamesp.h - Namespace subcomponent prototypes and defines - * $Revision: 100 $ + * $Revision: 101 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acobject.h b/drivers/acpi/include/acobject.h index c801ff117..9394b470a 100644 --- a/drivers/acpi/include/acobject.h +++ b/drivers/acpi/include/acobject.h @@ -2,12 +2,12 @@ /****************************************************************************** * * Name: acobject.h - Definition of ACPI_OPERAND_OBJECT (Internal object only) - * $Revision: 75 $ + * $Revision: 78 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -113,10 +113,10 @@ typedef struct /* NUMBER - has value */ ACPI_INTEGER value; -} ACPI_OBJECT_NUMBER; +} ACPI_OBJECT_INTEGER; -typedef struct /* STRING - has length and pointer */ +typedef struct /* STRING - has length and pointer - Null terminated, ASCII characters only */ { ACPI_OBJECT_COMMON_HEADER @@ -126,13 +126,11 @@ typedef struct /* STRING - has length and pointer */ } ACPI_OBJECT_STRING; -typedef struct /* BUFFER - has length, sequence, and pointer */ +typedef struct /* BUFFER - has length and pointer - not null terminated */ { ACPI_OBJECT_COMMON_HEADER u32 length; - u32 sequence; /* Sequential count of buffers created */ - u8 *pointer; /* points to the buffer in allocated space */ } ACPI_OBJECT_BUFFER; @@ -398,7 +396,7 @@ typedef union acpi_operand_obj { ACPI_OBJECT_COMMON common; ACPI_OBJECT_CACHE_LIST cache; - ACPI_OBJECT_NUMBER number; + ACPI_OBJECT_INTEGER integer; ACPI_OBJECT_STRING string; ACPI_OBJECT_BUFFER buffer; ACPI_OBJECT_PACKAGE package; diff --git a/drivers/acpi/include/acoutput.h b/drivers/acpi/include/acoutput.h index 664a5f8a8..5c20943cb 100644 --- a/drivers/acpi/include/acoutput.h +++ b/drivers/acpi/include/acoutput.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acoutput.h -- debug output - * $Revision: 66 $ + * $Revision: 69 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,6 +58,7 @@ #define BATTERY 0x00040000 #define DEBUGGER 0x00100000 +#define COMPILER 0x00200000 #define ALL_COMPONENTS 0x001FFFFF #define COMPONENT_DEFAULT (ALL_COMPONENTS) diff --git a/drivers/acpi/include/acparser.h b/drivers/acpi/include/acparser.h index d657749da..9b4bfabea 100644 --- a/drivers/acpi/include/acparser.h +++ b/drivers/acpi/include/acparser.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: acparser.h - AML Parser subcomponent prototypes and defines - * $Revision: 47 $ + * $Revision: 49 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acpi.h b/drivers/acpi/include/acpi.h index 4896c4a7f..344b01a77 100644 --- a/drivers/acpi/include/acpi.h +++ b/drivers/acpi/include/acpi.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acpi.h - Master include file, Publics and external data. - * $Revision: 48 $ + * $Revision: 50 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/acpiosxf.h b/drivers/acpi/include/acpiosxf.h index 2f9eb4c13..ee289f33e 100644 --- a/drivers/acpi/include/acpiosxf.h +++ b/drivers/acpi/include/acpiosxf.h @@ -9,7 +9,7 @@ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -121,6 +121,10 @@ acpi_os_unmap_memory ( void *logical_address, u32 length); +ACPI_STATUS +acpi_os_get_physical_address ( + void *logical_address, + ACPI_PHYSICAL_ADDRESS *physical_address); /* * Interrupt handlers diff --git a/drivers/acpi/include/acpixf.h b/drivers/acpi/include/acpixf.h index d70fa75a7..8d293818f 100644 --- a/drivers/acpi/include/acpixf.h +++ b/drivers/acpi/include/acpixf.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -285,6 +285,10 @@ acpi_get_firmware_waking_vector ( ACPI_PHYSICAL_ADDRESS *physical_address); ACPI_STATUS +acpi_enter_sleep_state ( + u8 sleep_state); + +ACPI_STATUS acpi_get_processor_throttling_info ( ACPI_HANDLE processor_handle, ACPI_BUFFER *user_buffer); diff --git a/drivers/acpi/include/acresrc.h b/drivers/acpi/include/acresrc.h index 3bb19490d..0852367d2 100644 --- a/drivers/acpi/include/acresrc.h +++ b/drivers/acpi/include/acresrc.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acresrc.h - Resource Manager function prototypes - * $Revision: 20 $ + * $Revision: 22 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/actables.h b/drivers/acpi/include/actables.h index 4dd724517..be8b5e3b0 100644 --- a/drivers/acpi/include/actables.h +++ b/drivers/acpi/include/actables.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actables.h - ACPI table management - * $Revision: 27 $ + * $Revision: 29 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/actbl.h b/drivers/acpi/include/actbl.h index 34631e820..7a41842d2 100644 --- a/drivers/acpi/include/actbl.h +++ b/drivers/acpi/include/actbl.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actbl.h - Table data structures defined in ACPI specification - * $Revision: 43 $ + * $Revision: 45 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/actbl1.h b/drivers/acpi/include/actbl1.h index 019ba1680..5c68ca050 100644 --- a/drivers/acpi/include/actbl1.h +++ b/drivers/acpi/include/actbl1.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actbl1.h - ACPI 1.0 tables - * $Revision: 15 $ + * $Revision: 17 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/actbl2.h b/drivers/acpi/include/actbl2.h index e3ccf2188..0a05efa1c 100644 --- a/drivers/acpi/include/actbl2.h +++ b/drivers/acpi/include/actbl2.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actbl2.h - ACPI Specification Revision 2.0 Tables - * $Revision: 19 $ + * $Revision: 21 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -142,8 +142,8 @@ typedef struct u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ u16 flush_size; /* number of flush strides that need to be read */ u16 flush_stride; /* Processor's memory cache line width, in bytes */ - u8 duty_offset; /* Processor’s duty cycle index in processor's P_CNT reg*/ - u8 duty_width; /* Processor’s duty cycle value bit width in P_CNT register.*/ + u8 duty_offset; /* Processor_’s duty cycle index in processor's P_CNT reg*/ + u8 duty_width; /* Processor_’s duty cycle value bit width in P_CNT register.*/ u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ u8 century; /* index to century in RTC CMOS RAM */ diff --git a/drivers/acpi/include/actbl71.h b/drivers/acpi/include/actbl71.h index 408ec402e..095806ccb 100644 --- a/drivers/acpi/include/actbl71.h +++ b/drivers/acpi/include/actbl71.h @@ -3,12 +3,12 @@ * Name: actbl71.h - IA-64 Extensions to the ACPI Spec Rev. 0.71 * This file includes tables specific to this * specification revision. - * $Revision: 7 $ + * $Revision: 9 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/include/actypes.h b/drivers/acpi/include/actypes.h index dfa28a9d9..826fc8901 100644 --- a/drivers/acpi/include/actypes.h +++ b/drivers/acpi/include/actypes.h @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actypes.h - Common data types for the entire ACPI subsystem - * $Revision: 159 $ + * $Revision: 163 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -97,7 +97,7 @@ typedef INT16 NATIVE_INT; typedef UINT32 ACPI_TBLPTR; typedef UINT32 ACPI_IO_ADDRESS; -typedef void *ACPI_PHYSICAL_ADDRESS; +typedef char *ACPI_PHYSICAL_ADDRESS; #define ALIGNED_ADDRESS_BOUNDARY 0x00000002 #define _HW_ALIGNMENT_SUPPORT @@ -249,8 +249,9 @@ typedef UINT64 ACPI_INTEGER; #define ACPI_STATE_S2 (u8) 2 #define ACPI_STATE_S3 (u8) 3 #define ACPI_STATE_S4 (u8) 4 -#define ACPI_STATE_S4_bIOS (u8) 5 -#define ACPI_STATE_S5 (u8) 6 +#define ACPI_STATE_S5 (u8) 5 +/* let's pretend S4_bIOS didn't exist for now. ASG */ +#define ACPI_STATE_S4_bIOS (u8) 6 #define ACPI_S_STATES_MAX ACPI_STATE_S5 @@ -284,8 +285,37 @@ typedef u32 ACPI_TABLE_TYPE; typedef u32 ACPI_OBJECT_TYPE; typedef u8 OBJECT_TYPE_INTERNAL; +#define ACPI_BTYPE_ANY 0x00000000 +#define ACPI_BTYPE_INTEGER 0x00000001 +#define ACPI_BTYPE_STRING 0x00000002 +#define ACPI_BTYPE_BUFFER 0x00000004 +#define ACPI_BTYPE_PACKAGE 0x00000008 +#define ACPI_BTYPE_FIELD_UNIT 0x00000010 +#define ACPI_BTYPE_DEVICE 0x00000020 +#define ACPI_BTYPE_EVENT 0x00000040 +#define ACPI_BTYPE_METHOD 0x00000080 +#define ACPI_BTYPE_MUTEX 0x00000100 +#define ACPI_BTYPE_REGION 0x00000200 +#define ACPI_BTYPE_POWER 0x00000400 +#define ACPI_BTYPE_PROCESSOR 0x00000800 +#define ACPI_BTYPE_THERMAL 0x00001000 +#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 +#define ACPI_BTYPE_DDB_HANDLE 0x00004000 +#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 +#define ACPI_BTYPE_REFERENCE 0x00010000 +#define ACPI_BTYPE_RESOURCE 0x00020000 + +#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) + +#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) +#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE) +#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) +#define ACPI_BTYPE_OBJECTS_AND_REFS 0x00017FFF /* ARG or LOCAL */ +#define ACPI_BTYPE_ALL_OBJECTS 0x00007FFF + + #define ACPI_TYPE_ANY 0 /* 0x00 */ -#define ACPI_TYPE_NUMBER 1 /* 0x01 Byte/Word/Dword/Zero/One/Ones */ +#define ACPI_TYPE_INTEGER 1 /* 0x01 Byte/Word/Dword/Zero/One/Ones */ #define ACPI_TYPE_STRING 2 /* 0x02 */ #define ACPI_TYPE_BUFFER 3 /* 0x03 */ #define ACPI_TYPE_PACKAGE 4 /* 0x04 Byte_const, multiple Data_term/Constant/Super_name */ @@ -432,7 +462,7 @@ typedef union acpi_obj { ACPI_OBJECT_TYPE type; ACPI_INTEGER value; /* The actual number */ - } number; + } integer; struct { diff --git a/drivers/acpi/include/amlcode.h b/drivers/acpi/include/amlcode.h index 9a5cb2c52..707e7535d 100644 --- a/drivers/acpi/include/amlcode.h +++ b/drivers/acpi/include/amlcode.h @@ -3,12 +3,12 @@ * Name: amlcode.h - Definitions for AML, as included in "definition blocks" * Declarations and definitions contained herein are derived * directly from the ACPI specification. - * $Revision: 42 $ + * $Revision: 46 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -211,27 +211,42 @@ #define ARGP_TERMARG 0x0E #define ARGP_TERMLIST 0x0F #define ARGP_WORDDATA 0x10 +#define ARGP_QWORDDATA 0x11 +#define ARGP_SIMPLENAME 0x12 /* * Resolved argument types for the AML Interpreter * Each field in the Arg_types u32 is 5 bits, allowing for a maximum of 6 arguments. - * There can be up to 31 unique argument types + * There can be up to 31 unique argument types (0 is end-of-arg-list indicator) */ -#define ARGI_ANYTYPE 0x01 -#define ARGI_TARGETREF 0x02 -#define ARGI_REFERENCE 0x03 -#define ARGI_IF 0x04 -#define ARGI_NUMBER 0x05 -#define ARGI_STRING 0x06 -#define ARGI_BUFFER 0x07 -#define ARGI_PACKAGE 0x08 -#define ARGI_DATAOBJECT 0x09 /* Buffer, string, package or reference to a Node - Used only by Size_of operator*/ -#define ARGI_COMPLEXOBJ 0x0A /* Buffer or package */ -#define ARGI_MUTEX 0x0B -#define ARGI_EVENT 0x0C -#define ARGI_REGION 0x0D -#define ARGI_DDBHANDLE 0x0E +/* "Standard" ACPI types are 1-15 (0x0F) */ + +#define ARGI_INTEGER ACPI_TYPE_INTEGER /* 1 */ +#define ARGI_STRING ACPI_TYPE_STRING /* 2 */ +#define ARGI_BUFFER ACPI_TYPE_BUFFER /* 3 */ +#define ARGI_PACKAGE ACPI_TYPE_PACKAGE /* 4 */ +#define ARGI_EVENT ACPI_TYPE_EVENT +#define ARGI_MUTEX ACPI_TYPE_MUTEX +#define ARGI_REGION ACPI_TYPE_REGION +#define ARGI_DDBHANDLE ACPI_TYPE_DDB_HANDLE + +/* Custom types are 0x10 through 0x1F */ + +#define ARGI_IF 0x10 +#define ARGI_ANYOBJECT 0x11 +#define ARGI_ANYTYPE 0x12 +#define ARGI_COMPUTEDATA 0x13 /* Buffer, String, or Integer */ +#define ARGI_DATAOBJECT 0x14 /* Buffer, string, package or reference to a Node - Used only by Size_of operator*/ +#define ARGI_COMPLEXOBJ 0x15 /* Buffer or package */ +#define ARGI_INTEGER_REF 0x16 +#define ARGI_OBJECT_REF 0x17 +#define ARGI_DEVICE_REF 0x18 +#define ARGI_REFERENCE 0x19 +#define ARGI_TARGETREF 0x1A /* Target, subject to implicit conversion */ +#define ARGI_FIXED_TARGET 0x1B /* Target, no implicit conversion */ +#define ARGI_SIMPLE_TARGET 0x1C /* Name, Local, Arg -- no implicit conversion */ +#define ARGI_BUFFERSTRING 0x1D #define ARGI_INVALID_OPCODE 0xFFFFFFFF diff --git a/drivers/acpi/interpreter/amconfig.c b/drivers/acpi/interpreter/amconfig.c index 55e5b0510..497f35375 100644 --- a/drivers/acpi/interpreter/amconfig.c +++ b/drivers/acpi/interpreter/amconfig.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: amconfig - Namespace reconfiguration (Load/Unload opcodes) - * $Revision: 26 $ + * $Revision: 29 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,7 +73,8 @@ acpi_aml_exec_load_table ( table_header.length = 0; for (i = 0; i < sizeof (ACPI_TABLE_HEADER); i++) { status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, - i, 8, (u32 *) ((u8 *) &table_header + i)); + (ACPI_PHYSICAL_ADDRESS) i, 8, + (u32 *) ((u8 *) &table_header + i)); if (ACPI_FAILURE (status)) { return (status); } @@ -96,7 +97,8 @@ acpi_aml_exec_load_table ( for (i = 0; i < table_header.length; i++) { status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, - i, 8, (u32 *) (table_data_ptr + i)); + (ACPI_PHYSICAL_ADDRESS)i, 8, + (u32 *) (table_data_ptr + i)); if (ACPI_FAILURE (status)) { goto cleanup; } diff --git a/drivers/acpi/interpreter/amconvrt.c b/drivers/acpi/interpreter/amconvrt.c new file mode 100644 index 000000000..4c895c7ed --- /dev/null +++ b/drivers/acpi/interpreter/amconvrt.c @@ -0,0 +1,525 @@ +/****************************************************************************** + * + * Module Name: amconvrt - Object conversion routines + * $Revision: 3 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000, 2001 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acparser.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "acevents.h" +#include "amlcode.h" +#include "acdispat.h" + + +#define _COMPONENT INTERPRETER + MODULE_NAME ("amconvrt") + + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_convert_to_target_type + * + * PARAMETERS: *Obj_desc - Object to be converted. + * Walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_convert_to_target_type ( + OBJECT_TYPE_INTERNAL destination_type, + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state) +{ + ACPI_STATUS status = AE_OK; + + + /* + * If required by the target, + * perform implicit conversion on the source before we store it. + */ + + switch (GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)) + { + case ARGI_SIMPLE_TARGET: + case ARGI_FIXED_TARGET: + case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ + + switch (destination_type) + { + case INTERNAL_TYPE_DEF_FIELD: + /* + * Named field can always handle conversions + */ + break; + + default: + /* No conversion allowed for these types */ + + if (destination_type != (*obj_desc)->common.type) { + status = AE_TYPE; + } + } + break; + + + case ARGI_TARGETREF: + + switch (destination_type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_FIELD_UNIT: + case INTERNAL_TYPE_BANK_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: + /* + * These types require an Integer operand. We can convert + * a Buffer or a String to an Integer if necessary. + */ + status = acpi_aml_convert_to_integer (obj_desc, walk_state); + break; + + + case ACPI_TYPE_STRING: + + /* + * The operand must be a String. We can convert an + * Integer or Buffer if necessary + */ + status = acpi_aml_convert_to_string (obj_desc, walk_state); + break; + + + case ACPI_TYPE_BUFFER: + + /* + * The operand must be a String. We can convert an + * Integer or Buffer if necessary + */ + status = acpi_aml_convert_to_buffer (obj_desc, walk_state); + break; + } + break; + + + case ARGI_REFERENCE: + /* + * Create_xxxx_field cases - we are storing the field object into the name + */ + break; + + + default: + status = AE_AML_INTERNAL; + } + + + /* + * Source-to-Target conversion semantics: + * + * If conversion to the target type cannot be performed, then simply + * overwrite the target with the new object and type. + */ + if (status == AE_TYPE) { + status = AE_OK; + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_convert_to_integer + * + * PARAMETERS: *Obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * Walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to an integer. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_convert_to_integer ( + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state) +{ + u32 i; + ACPI_OPERAND_OBJECT *ret_desc; + u32 count; + char *pointer; + ACPI_INTEGER result; + u32 integer_size = sizeof (ACPI_INTEGER); + + + switch ((*obj_desc)->common.type) + { + case ACPI_TYPE_INTEGER: + return (AE_OK); + + case ACPI_TYPE_STRING: + pointer = (*obj_desc)->string.pointer; + count = (*obj_desc)->string.length; + break; + + case ACPI_TYPE_BUFFER: + pointer = (char *) (*obj_desc)->buffer.pointer; + count = (*obj_desc)->buffer.length; + break; + + default: + return (AE_TYPE); + } + + /* + * Create a new integer + */ + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + + /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ + + if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { + /* + * We are running a method that exists in a 32-bit ACPI table. + * Truncate the value to 32 bits by zeroing out the upper 32-bit field + */ + integer_size = sizeof (u32); + } + + + /* + * Convert the buffer/string to an integer. Note that both buffers and + * strings are treated as raw data - we don't convert ascii to hex for + * strings. + * + * There are two terminating conditions for the loop: + * 1) The size of an integer has been reached, or + * 2) The end of the buffer or string has been reached + */ + result = 0; + + /* Transfer no more than an integer's worth of data */ + + if (count > integer_size) { + count = integer_size; + } + + /* + * String conversion is different than Buffer conversion + */ + switch ((*obj_desc)->common.type) + { + case ACPI_TYPE_STRING: + + /* TBD: Need to use 64-bit STRTOUL */ + + /* + * Convert string to an integer + * String must be hexadecimal as per the ACPI specification + */ + + result = STRTOUL (pointer, NULL, 16); + break; + + + case ACPI_TYPE_BUFFER: + + /* + * Buffer conversion - we simply grab enough raw data from the + * buffer to fill an integer + */ + for (i = 0; i < count; i++) { + /* + * Get next byte and shift it into the Result. + * Little endian is used, meaning that the first byte of the buffer + * is the LSB of the integer + */ + result |= (((ACPI_INTEGER) pointer[i]) << (i * 8)); + } + + break; + } + + /* Save the Result, delete original descriptor, store new descriptor */ + + ret_desc->integer.value = result; + + if (walk_state->opcode != AML_STORE_OP) { + acpi_cm_remove_reference (*obj_desc); + } + + *obj_desc = ret_desc; + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_convert_to_buffer + * + * PARAMETERS: *Obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * Walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to an Buffer + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_convert_to_buffer ( + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state) +{ + ACPI_OPERAND_OBJECT *ret_desc; + u32 i; + u32 integer_size = sizeof (ACPI_INTEGER); + u8 *new_buf; + + + switch ((*obj_desc)->common.type) + { + case ACPI_TYPE_INTEGER: + + /* + * Create a new Buffer + */ + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ + + if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { + /* + * We are running a method that exists in a 32-bit ACPI table. + * Truncate the value to 32 bits by zeroing out the upper + * 32-bit field + */ + integer_size = sizeof (u32); + } + + /* Need enough space for one integers */ + + ret_desc->buffer.length = integer_size; + new_buf = acpi_cm_callocate (integer_size); + if (!new_buf) { + REPORT_ERROR + (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); + acpi_cm_remove_reference (ret_desc); + return (AE_NO_MEMORY); + } + + /* Copy the integer to the buffer */ + + for (i = 0; i < integer_size; i++) { + new_buf[i] = (u8) ((*obj_desc)->integer.value >> (i * 8)); + } + ret_desc->buffer.pointer = new_buf; + + /* Return the new buffer descriptor */ + + if (walk_state->opcode != AML_STORE_OP) { + acpi_cm_remove_reference (*obj_desc); + } + *obj_desc = ret_desc; + break; + + + case ACPI_TYPE_STRING: + break; + + + case ACPI_TYPE_BUFFER: + break; + + + default: + return (AE_TYPE); + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_convert_to_string + * + * PARAMETERS: *Obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * Walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to a string + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_convert_to_string ( + ACPI_OPERAND_OBJECT **obj_desc, + ACPI_WALK_STATE *walk_state) +{ + ACPI_OPERAND_OBJECT *ret_desc; + u32 i; + u32 index; + u32 integer_size = sizeof (ACPI_INTEGER); + u8 *new_buf; + u8 *pointer; + + + switch ((*obj_desc)->common.type) + { + case ACPI_TYPE_INTEGER: + + /* + * Create a new String + */ + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ + + if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { + /* + * We are running a method that exists in a 32-bit ACPI table. + * Truncate the value to 32 bits by zeroing out the upper + * 32-bit field + */ + integer_size = sizeof (u32); + } + + /* Need enough space for one ASCII integer plus null terminator */ + + ret_desc->string.length = (integer_size * 2) + 1; + new_buf = acpi_cm_callocate (ret_desc->string.length); + if (!new_buf) { + REPORT_ERROR + (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); + acpi_cm_remove_reference (ret_desc); + return (AE_NO_MEMORY); + } + + /* Copy the integer to the buffer */ + + for (i = 0; i < (integer_size * 2); i++) { + new_buf[i] = acpi_gbl_hex_to_ascii [((*obj_desc)->integer.value >> (i * 4)) & 0xF]; + } + + /* Null terminate */ + + new_buf [i] = 0; + ret_desc->buffer.pointer = new_buf; + + /* Return the new buffer descriptor */ + + if (walk_state->opcode != AML_STORE_OP) { + acpi_cm_remove_reference (*obj_desc); + } + *obj_desc = ret_desc; + + return (AE_OK); + + + case ACPI_TYPE_BUFFER: + + if (((*obj_desc)->buffer.length * 3) > ACPI_MAX_STRING_CONVERSION) { + return (AE_AML_STRING_LIMIT); + } + + /* + * Create a new String + */ + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + /* Need enough space for one ASCII integer plus null terminator */ + + ret_desc->string.length = (*obj_desc)->buffer.length * 3; + new_buf = acpi_cm_callocate (ret_desc->string.length + 1); + if (!new_buf) { + REPORT_ERROR + (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); + acpi_cm_remove_reference (ret_desc); + return (AE_NO_MEMORY); + } + + /* + * Convert each byte of the buffer to two ASCII characters plus a space. + */ + pointer = (*obj_desc)->buffer.pointer; + index = 0; + for (i = 0; i < (*obj_desc)->buffer.length; i++) { + new_buf[index + 0] = acpi_gbl_hex_to_ascii [pointer[i] & 0x0F]; + new_buf[index + 1] = acpi_gbl_hex_to_ascii [(pointer[i] >> 4) & 0x0F]; + new_buf[index + 2] = ' '; + index += 3; + } + + /* Null terminate */ + + new_buf [index] = 0; + ret_desc->buffer.pointer = new_buf; + + /* Return the new buffer descriptor */ + + if (walk_state->opcode != AML_STORE_OP) { + acpi_cm_remove_reference (*obj_desc); + } + *obj_desc = ret_desc; + break; + + + case ACPI_TYPE_STRING: + break; + + + default: + return (AE_TYPE); + break; + } + + return (AE_OK); +} + + diff --git a/drivers/acpi/interpreter/amcreate.c b/drivers/acpi/interpreter/amcreate.c index 02d7933e1..f19c422ce 100644 --- a/drivers/acpi/interpreter/amcreate.c +++ b/drivers/acpi/interpreter/amcreate.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: amcreate - Named object creation - * $Revision: 51 $ + * $Revision: 53 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -353,7 +353,7 @@ acpi_aml_exec_create_mutex ( goto cleanup; } - obj_desc->mutex.sync_level = (u8) sync_desc->number.value; + obj_desc->mutex.sync_level = (u8) sync_desc->integer.value; /* Obj_desc was on the stack top, and the name is below it */ diff --git a/drivers/acpi/interpreter/amdyadic.c b/drivers/acpi/interpreter/amdyadic.c index ba67b062a..a02173f29 100644 --- a/drivers/acpi/interpreter/amdyadic.c +++ b/drivers/acpi/interpreter/amdyadic.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: amdyadic - ACPI AML (p-code) execution for dyadic operators - * $Revision: 68 $ + * $Revision: 71 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,174 @@ MODULE_NAME ("amdyadic") -/***************************************************************************** +/******************************************************************************* + * + * FUNCTION: Acpi_aml_do_concatenate + * + * PARAMETERS: *Obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * + * RETURN: Status + * + * DESCRIPTION: Concatenate two objects OF THE SAME TYPE. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_do_concatenate ( + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc2, + ACPI_OPERAND_OBJECT **actual_ret_desc, + ACPI_WALK_STATE *walk_state) +{ + ACPI_STATUS status; + u32 i; + ACPI_INTEGER this_integer; + ACPI_OPERAND_OBJECT *ret_desc; + NATIVE_CHAR *new_buf; + u32 integer_size = sizeof (ACPI_INTEGER); + + + /* + * There are three cases to handle: + * 1) Two Integers concatenated to produce a buffer + * 2) Two Strings concatenated to produce a string + * 3) Two Buffers concatenated to produce a buffer + */ + switch (obj_desc->common.type) + { + case ACPI_TYPE_INTEGER: + + /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ + + if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { + /* + * We are running a method that exists in a 32-bit ACPI table. + * Truncate the value to 32 bits by zeroing out the upper + * 32-bit field + */ + integer_size = sizeof (u32); + } + + /* Result of two integers is a buffer */ + + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + /* Need enough space for two integers */ + + ret_desc->buffer.length = integer_size * 2; + new_buf = acpi_cm_callocate (ret_desc->buffer.length); + if (!new_buf) { + REPORT_ERROR + (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); + status = AE_NO_MEMORY; + goto cleanup; + } + + ret_desc->buffer.pointer = (u8 *) new_buf; + + /* Convert the first integer */ + + this_integer = obj_desc->integer.value; + for (i = 0; i < integer_size; i++) { + new_buf[i] = (u8) this_integer; + this_integer >>= 8; + } + + /* Convert the second integer */ + + this_integer = obj_desc2->integer.value; + for (; i < (integer_size * 2); i++) { + new_buf[i] = (u8) this_integer; + this_integer >>= 8; + } + + break; + + + case ACPI_TYPE_STRING: + + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + /* Operand1 is string */ + + new_buf = acpi_cm_allocate (obj_desc->string.length + + obj_desc2->string.length + 1); + if (!new_buf) { + REPORT_ERROR + (("Aml_exec_dyadic2_r/Concat_op: String allocation failure\n")); + status = AE_NO_MEMORY; + goto cleanup; + } + + STRCPY (new_buf, obj_desc->string.pointer); + STRCPY (new_buf + obj_desc->string.length, + obj_desc2->string.pointer); + + /* Point the return object to the new string */ + + ret_desc->string.pointer = new_buf; + ret_desc->string.length = obj_desc->string.length += + obj_desc2->string.length; + break; + + + case ACPI_TYPE_BUFFER: + + /* Operand1 is a buffer */ + + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); + if (!ret_desc) { + return (AE_NO_MEMORY); + } + + new_buf = acpi_cm_allocate (obj_desc->buffer.length + + obj_desc2->buffer.length); + if (!new_buf) { + REPORT_ERROR + (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); + status = AE_NO_MEMORY; + goto cleanup; + } + + MEMCPY (new_buf, obj_desc->buffer.pointer, + obj_desc->buffer.length); + MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer, + obj_desc2->buffer.length); + + /* + * Point the return object to the new buffer + */ + + ret_desc->buffer.pointer = (u8 *) new_buf; + ret_desc->buffer.length = obj_desc->buffer.length + + obj_desc2->buffer.length; + break; + + default: + status = AE_AML_INTERNAL; + ret_desc = NULL; + } + + + *actual_ret_desc = ret_desc; + return (AE_OK); + + +cleanup: + + acpi_cm_remove_reference (ret_desc); + return (status); +} + + +/******************************************************************************* * * FUNCTION: Acpi_aml_exec_dyadic1 * @@ -50,7 +217,7 @@ * * ALLOCATION: Deletes both operands * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_aml_exec_dyadic1 ( @@ -106,7 +273,7 @@ acpi_aml_exec_dyadic1 ( /* Dispatch the notify to the appropriate handler */ - acpi_ev_notify_dispatch (node, (u32) val_desc->number.value); + acpi_ev_notify_dispatch (node, (u32) val_desc->integer.value); break; default: @@ -135,7 +302,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_aml_exec_dyadic2_r * @@ -148,7 +315,7 @@ cleanup: * * ALLOCATION: Deletes one operand descriptor -- other remains on stack * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_aml_exec_dyadic2_r ( @@ -164,7 +331,6 @@ acpi_aml_exec_dyadic2_r ( ACPI_OPERAND_OBJECT *ret_desc2 = NULL; ACPI_STATUS status = AE_OK; u32 num_operands = 3; - NATIVE_CHAR *new_buf; /* Resolve all operands */ @@ -201,7 +367,7 @@ acpi_aml_exec_dyadic2_r ( case AML_SHIFT_RIGHT_OP: case AML_SUBTRACT_OP: - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -222,8 +388,8 @@ acpi_aml_exec_dyadic2_r ( case AML_ADD_OP: - ret_desc->number.value = obj_desc->number.value + - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value + + obj_desc2->integer.value; break; @@ -231,8 +397,8 @@ acpi_aml_exec_dyadic2_r ( case AML_BIT_AND_OP: - ret_desc->number.value = obj_desc->number.value & - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value & + obj_desc2->integer.value; break; @@ -240,8 +406,8 @@ acpi_aml_exec_dyadic2_r ( case AML_BIT_NAND_OP: - ret_desc->number.value = ~(obj_desc->number.value & - obj_desc2->number.value); + ret_desc->integer.value = ~(obj_desc->integer.value & + obj_desc2->integer.value); break; @@ -249,8 +415,8 @@ acpi_aml_exec_dyadic2_r ( case AML_BIT_OR_OP: - ret_desc->number.value = obj_desc->number.value | - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value | + obj_desc2->integer.value; break; @@ -258,8 +424,8 @@ acpi_aml_exec_dyadic2_r ( case AML_BIT_NOR_OP: - ret_desc->number.value = ~(obj_desc->number.value | - obj_desc2->number.value); + ret_desc->integer.value = ~(obj_desc->integer.value | + obj_desc2->integer.value); break; @@ -267,16 +433,16 @@ acpi_aml_exec_dyadic2_r ( case AML_BIT_XOR_OP: - ret_desc->number.value = obj_desc->number.value ^ - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value ^ + obj_desc2->integer.value; break; - /* Def_divide := Divide_op Dividend Divisor Remainder Quotient */ + /* Def_divide := Divide_op Dividend Divisor Remainder Quotient */ case AML_DIVIDE_OP: - if (!obj_desc2->number.value) { + if (!obj_desc2->integer.value) { REPORT_ERROR (("Aml_exec_dyadic2_r/Divide_op: Divide by zero\n")); @@ -284,7 +450,7 @@ acpi_aml_exec_dyadic2_r ( goto cleanup; } - ret_desc2 = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc2 = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc2) { status = AE_NO_MEMORY; goto cleanup; @@ -292,13 +458,13 @@ acpi_aml_exec_dyadic2_r ( /* Remainder (modulo) */ - ret_desc->number.value = ACPI_MODULO (obj_desc->number.value, - obj_desc2->number.value); + ret_desc->integer.value = ACPI_MODULO (obj_desc->integer.value, + obj_desc2->integer.value); /* Result (what we used to call the quotient) */ - ret_desc2->number.value = ACPI_DIVIDE (obj_desc->number.value, - obj_desc2->number.value); + ret_desc2->integer.value = ACPI_DIVIDE (obj_desc->integer.value, + obj_desc2->integer.value); break; @@ -306,8 +472,8 @@ acpi_aml_exec_dyadic2_r ( case AML_MULTIPLY_OP: - ret_desc->number.value = obj_desc->number.value * - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value * + obj_desc2->integer.value; break; @@ -315,8 +481,8 @@ acpi_aml_exec_dyadic2_r ( case AML_SHIFT_LEFT_OP: - ret_desc->number.value = obj_desc->number.value << - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value << + obj_desc2->integer.value; break; @@ -324,8 +490,8 @@ acpi_aml_exec_dyadic2_r ( case AML_SHIFT_RIGHT_OP: - ret_desc->number.value = obj_desc->number.value >> - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value >> + obj_desc2->integer.value; break; @@ -333,8 +499,8 @@ acpi_aml_exec_dyadic2_r ( case AML_SUBTRACT_OP: - ret_desc->number.value = obj_desc->number.value - - obj_desc2->number.value; + ret_desc->integer.value = obj_desc->integer.value - + obj_desc2->integer.value; break; @@ -342,79 +508,54 @@ acpi_aml_exec_dyadic2_r ( case AML_CONCAT_OP: - if (obj_desc2->common.type != obj_desc->common.type) { - status = AE_AML_OPERAND_TYPE; - goto cleanup; - } - /* Both operands are now known to be the same */ - - if (ACPI_TYPE_STRING == obj_desc->common.type) { - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING); - if (!ret_desc) { - status = AE_NO_MEMORY; - goto cleanup; - } + /* + * Convert the second operand if necessary. The first operand + * determines the type of the second operand, (See the Data Types + * section of the ACPI specification.) Both object types are + * guaranteed to be either Integer/String/Buffer by the operand + * resolution mechanism above. + */ - /* Operand1 is string */ + switch (obj_desc->common.type) + { + case ACPI_TYPE_INTEGER: + status = acpi_aml_convert_to_integer (&obj_desc2, walk_state); + break; - new_buf = acpi_cm_allocate (obj_desc->string.length + - obj_desc2->string.length + 1); - if (!new_buf) { - REPORT_ERROR - (("Aml_exec_dyadic2_r/Concat_op: String allocation failure\n")); - status = AE_NO_MEMORY; - goto cleanup; - } + case ACPI_TYPE_STRING: + status = acpi_aml_convert_to_string (&obj_desc2, walk_state); + break; - STRCPY (new_buf, obj_desc->string.pointer); - STRCPY (new_buf + obj_desc->string.length, - obj_desc2->string.pointer); + case ACPI_TYPE_BUFFER: + status = acpi_aml_convert_to_buffer (&obj_desc2, walk_state); + break; - /* Point the return object to the new string */ - - ret_desc->string.pointer = new_buf; - ret_desc->string.length = obj_desc->string.length += - obj_desc2->string.length; + default: + status = AE_AML_INTERNAL; } - else { - /* Operand1 is not a string ==> must be a buffer */ - - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER); - if (!ret_desc) { - status = AE_NO_MEMORY; - goto cleanup; - } - - new_buf = acpi_cm_allocate (obj_desc->buffer.length + - obj_desc2->buffer.length); - if (!new_buf) { - REPORT_ERROR - (("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure\n")); - status = AE_NO_MEMORY; - goto cleanup; - } - - MEMCPY (new_buf, obj_desc->buffer.pointer, - obj_desc->buffer.length); - MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer, - obj_desc2->buffer.length); + if (ACPI_FAILURE (status)) { + goto cleanup; + } - /* - * Point the return object to the new buffer - */ - ret_desc->buffer.pointer = (u8 *) new_buf; - ret_desc->buffer.length = obj_desc->buffer.length + - obj_desc2->buffer.length; + /* + * Both operands are now known to be the same object type + * (Both are Integer, String, or Buffer), and we can now perform the + * concatenation. + */ + status = acpi_aml_do_concatenate (obj_desc, obj_desc2, &ret_desc, walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; } break; default: - REPORT_ERROR (("Acpi_aml_exec_dyadic2_r: Unknown dyadic opcode %X\n", opcode)); + REPORT_ERROR (("Acpi_aml_exec_dyadic2_r: Unknown dyadic opcode %X\n", + opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } @@ -474,7 +615,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_aml_exec_dyadic2_s * @@ -486,7 +627,7 @@ cleanup: * * ALLOCATION: Deletes one operand descriptor -- other remains on stack * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_aml_exec_dyadic2_s ( @@ -516,7 +657,7 @@ acpi_aml_exec_dyadic2_s ( /* Create the internal return object */ - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -524,7 +665,7 @@ acpi_aml_exec_dyadic2_s ( /* Default return value is FALSE, operation did not time out */ - ret_desc->number.value = 0; + ret_desc->integer.value = 0; /* Examine the opcode */ @@ -562,7 +703,7 @@ acpi_aml_exec_dyadic2_s ( */ if (status == AE_TIME) { - ret_desc->number.value = ACPI_INTEGER_MAX; /* TRUE, op timed out */ + ret_desc->integer.value = ACPI_INTEGER_MAX; /* TRUE, op timed out */ status = AE_OK; } @@ -591,7 +732,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_aml_exec_dyadic2 * @@ -605,7 +746,7 @@ cleanup: * ALLOCATION: Deletes one operand descriptor -- other remains on stack * containing result value * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_aml_exec_dyadic2 ( @@ -636,7 +777,7 @@ acpi_aml_exec_dyadic2 ( /* Create the internal return object */ - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -654,8 +795,8 @@ acpi_aml_exec_dyadic2 ( case AML_LAND_OP: - lboolean = (u8) (obj_desc->number.value && - obj_desc2->number.value); + lboolean = (u8) (obj_desc->integer.value && + obj_desc2->integer.value); break; @@ -663,8 +804,8 @@ acpi_aml_exec_dyadic2 ( case AML_LEQUAL_OP: - lboolean = (u8) (obj_desc->number.value == - obj_desc2->number.value); + lboolean = (u8) (obj_desc->integer.value == + obj_desc2->integer.value); break; @@ -672,8 +813,8 @@ acpi_aml_exec_dyadic2 ( case AML_LGREATER_OP: - lboolean = (u8) (obj_desc->number.value > - obj_desc2->number.value); + lboolean = (u8) (obj_desc->integer.value > + obj_desc2->integer.value); break; @@ -681,8 +822,8 @@ acpi_aml_exec_dyadic2 ( case AML_LLESS_OP: - lboolean = (u8) (obj_desc->number.value < - obj_desc2->number.value); + lboolean = (u8) (obj_desc->integer.value < + obj_desc2->integer.value); break; @@ -690,8 +831,8 @@ acpi_aml_exec_dyadic2 ( case AML_LOR_OP: - lboolean = (u8) (obj_desc->number.value || - obj_desc2->number.value); + lboolean = (u8) (obj_desc->integer.value || + obj_desc2->integer.value); break; @@ -707,10 +848,10 @@ acpi_aml_exec_dyadic2 ( /* Set return value to logical TRUE (all ones) or FALSE (zero) */ if (lboolean) { - ret_desc->number.value = ACPI_INTEGER_MAX; + ret_desc->integer.value = ACPI_INTEGER_MAX; } else { - ret_desc->number.value = 0; + ret_desc->integer.value = 0; } diff --git a/drivers/acpi/interpreter/amfield.c b/drivers/acpi/interpreter/amfield.c index 356be14c2..3ed442c95 100644 --- a/drivers/acpi/interpreter/amfield.c +++ b/drivers/acpi/interpreter/amfield.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: amfield - ACPI AML (p-code) execution - field manipulation - * $Revision: 74 $ + * $Revision: 77 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -174,7 +174,8 @@ acpi_aml_access_named_field ( u32 byte_field_length; - /* Basic data checking */ + /* Parameter validation */ + if ((!named_field) || (ACPI_READ == mode && !buffer)) { return (AE_AML_INTERNAL); } @@ -227,7 +228,7 @@ acpi_aml_access_named_field ( /* TBD: should these round down to a power of 2? */ - if (DIV_8(bit_granularity) > byte_field_length) { + if (DIV_8 (bit_granularity) > byte_field_length) { bit_granularity = MUL_8(byte_field_length); } diff --git a/drivers/acpi/interpreter/amfldio.c b/drivers/acpi/interpreter/amfldio.c index ce877c982..d16cd3d9b 100644 --- a/drivers/acpi/interpreter/amfldio.c +++ b/drivers/acpi/interpreter/amfldio.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: amfldio - Aml Field I/O - * $Revision: 32 $ + * $Revision: 37 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -132,7 +132,7 @@ acpi_aml_read_field ( u32 this_field_byte_offset; u32 this_field_datum_offset; u32 previous_raw_datum; - u32 this_raw_datum; + u32 this_raw_datum = 0; u32 valid_field_bits; u32 mask; u32 merged_datum = 0; @@ -203,32 +203,46 @@ acpi_aml_read_field ( while (this_field_datum_offset < datum_length) { /* - * Get the next raw datum, it contains bits of the current - * field datum + * If the field is aligned on a byte boundary, we don't want + * to perform a final read, since this would potentially read + * past the end of the region. + * + * TBD: [Investigate] It may make more sense to just split the aligned + * and non-aligned cases since the aligned case is so very simple, */ - - status = acpi_aml_read_field_data (obj_desc, - this_field_byte_offset + byte_granularity, - bit_granularity, &this_raw_datum); - if (ACPI_FAILURE (status)) { - goto cleanup; - } - - /* Before merging the data, make sure the unused bits are clear */ - - switch (byte_granularity) + if ((obj_desc->field.bit_offset != 0) || + ((obj_desc->field.bit_offset == 0) && + (this_field_datum_offset < (datum_length -1)))) { - case 1: - this_raw_datum &= 0x000000FF; - previous_raw_datum &= 0x000000FF; - break; - - case 2: - this_raw_datum &= 0x0000FFFF; - previous_raw_datum &= 0x0000FFFF; - break; + /* + * Get the next raw datum, it contains some or all bits + * of the current field datum + */ + + status = acpi_aml_read_field_data (obj_desc, + this_field_byte_offset + byte_granularity, + bit_granularity, &this_raw_datum); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Before merging the data, make sure the unused bits are clear */ + + switch (byte_granularity) + { + case 1: + this_raw_datum &= 0x000000FF; + previous_raw_datum &= 0x000000FF; + break; + + case 2: + this_raw_datum &= 0x0000FFFF; + previous_raw_datum &= 0x0000FFFF; + break; + } } + /* * Put together bits of the two raw data to make a complete * field datum @@ -391,8 +405,6 @@ acpi_aml_write_field_data_with_update_rule ( merged_value = field_value; - /* Check if update rule needs to be applied (not if mask is all ones) */ - /* Decode the update rule */ @@ -401,13 +413,17 @@ acpi_aml_write_field_data_with_update_rule ( case UPDATE_PRESERVE: - /* - * Read the current contents of the byte/word/dword containing - * the field, and merge with the new field value. - */ - status = acpi_aml_read_field_data (obj_desc, this_field_byte_offset, - bit_granularity, ¤t_value); - merged_value |= (current_value & ~mask); + /* Check if update rule needs to be applied (not if mask is all ones) */ + + if (((1 << bit_granularity) -1) & ~mask) { + /* + * Read the current contents of the byte/word/dword containing + * the field, and merge with the new field value. + */ + status = acpi_aml_read_field_data (obj_desc, this_field_byte_offset, + bit_granularity, ¤t_value); + merged_value |= (current_value & ~mask); + } break; diff --git a/drivers/acpi/interpreter/ammisc.c b/drivers/acpi/interpreter/ammisc.c index 907169dfc..3c58daeab 100644 --- a/drivers/acpi/interpreter/ammisc.c +++ b/drivers/acpi/interpreter/ammisc.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes - * $Revision: 71 $ + * $Revision: 73 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -172,7 +172,7 @@ acpi_aml_exec_index ( if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { /* Object to be indexed is a Package */ - if (idx_desc->number.value >= obj_desc->package.count) { + if (idx_desc->integer.value >= obj_desc->package.count) { status = AE_AML_PACKAGE_LIMIT; goto cleanup; } @@ -195,7 +195,7 @@ acpi_aml_exec_index ( * we are after. */ - tmp_desc = obj_desc->package.elements[idx_desc->number.value]; + tmp_desc = obj_desc->package.elements[idx_desc->integer.value]; ret_desc->reference.op_code = AML_INDEX_OP; ret_desc->reference.target_type = tmp_desc->common.type; ret_desc->reference.object = tmp_desc; @@ -210,13 +210,13 @@ acpi_aml_exec_index ( */ ret_desc->reference.op_code = AML_INDEX_OP; ret_desc->reference.target_type = ACPI_TYPE_PACKAGE; - ret_desc->reference.where = &obj_desc->package.elements[idx_desc->number.value]; + ret_desc->reference.where = &obj_desc->package.elements[idx_desc->integer.value]; } else { /* Object to be indexed is a Buffer */ - if (idx_desc->number.value >= obj_desc->buffer.length) { + if (idx_desc->integer.value >= obj_desc->buffer.length) { status = AE_AML_BUFFER_LIMIT; goto cleanup; } @@ -224,7 +224,7 @@ acpi_aml_exec_index ( ret_desc->reference.op_code = AML_INDEX_OP; ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; ret_desc->reference.object = obj_desc; - ret_desc->reference.offset = (u32) idx_desc->number.value; + ret_desc->reference.offset = (u32) idx_desc->integer.value; status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); } @@ -314,20 +314,20 @@ acpi_aml_exec_match ( /* Validate match comparison sub-opcodes */ - if ((op1_desc->number.value > MAX_MATCH_OPERATOR) || - (op2_desc->number.value > MAX_MATCH_OPERATOR)) + if ((op1_desc->integer.value > MAX_MATCH_OPERATOR) || + (op2_desc->integer.value > MAX_MATCH_OPERATOR)) { status = AE_AML_OPERAND_VALUE; goto cleanup; } - index = (u32) start_desc->number.value; + index = (u32) start_desc->integer.value; if (index >= (u32) pkg_desc->package.count) { status = AE_AML_PACKAGE_LIMIT; goto cleanup; } - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -351,7 +351,7 @@ acpi_aml_exec_match ( * should we examine its value? */ if (!pkg_desc->package.elements[index] || - ACPI_TYPE_NUMBER != pkg_desc->package.elements[index]->common.type) + ACPI_TYPE_INTEGER != pkg_desc->package.elements[index]->common.type) { continue; } @@ -362,7 +362,7 @@ acpi_aml_exec_match ( * "continue" (proceed to next iteration of enclosing * "for" loop) signifies a non-match. */ - switch (op1_desc->number.value) + switch (op1_desc->integer.value) { case MATCH_MTR: /* always true */ @@ -372,8 +372,8 @@ acpi_aml_exec_match ( case MATCH_MEQ: /* true if equal */ - if (pkg_desc->package.elements[index]->number.value - != V1_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + != V1_desc->integer.value) { continue; } @@ -382,8 +382,8 @@ acpi_aml_exec_match ( case MATCH_MLE: /* true if less than or equal */ - if (pkg_desc->package.elements[index]->number.value - > V1_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + > V1_desc->integer.value) { continue; } @@ -392,8 +392,8 @@ acpi_aml_exec_match ( case MATCH_MLT: /* true if less than */ - if (pkg_desc->package.elements[index]->number.value - >= V1_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + >= V1_desc->integer.value) { continue; } @@ -402,8 +402,8 @@ acpi_aml_exec_match ( case MATCH_MGE: /* true if greater than or equal */ - if (pkg_desc->package.elements[index]->number.value - < V1_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + < V1_desc->integer.value) { continue; } @@ -412,8 +412,8 @@ acpi_aml_exec_match ( case MATCH_MGT: /* true if greater than */ - if (pkg_desc->package.elements[index]->number.value - <= V1_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + <= V1_desc->integer.value) { continue; } @@ -426,7 +426,7 @@ acpi_aml_exec_match ( } - switch(op2_desc->number.value) + switch(op2_desc->integer.value) { case MATCH_MTR: @@ -436,8 +436,8 @@ acpi_aml_exec_match ( case MATCH_MEQ: - if (pkg_desc->package.elements[index]->number.value - != V2_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + != V2_desc->integer.value) { continue; } @@ -446,8 +446,8 @@ acpi_aml_exec_match ( case MATCH_MLE: - if (pkg_desc->package.elements[index]->number.value - > V2_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + > V2_desc->integer.value) { continue; } @@ -456,8 +456,8 @@ acpi_aml_exec_match ( case MATCH_MLT: - if (pkg_desc->package.elements[index]->number.value - >= V2_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + >= V2_desc->integer.value) { continue; } @@ -466,8 +466,8 @@ acpi_aml_exec_match ( case MATCH_MGE: - if (pkg_desc->package.elements[index]->number.value - < V2_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + < V2_desc->integer.value) { continue; } @@ -476,8 +476,8 @@ acpi_aml_exec_match ( case MATCH_MGT: - if (pkg_desc->package.elements[index]->number.value - <= V2_desc->number.value) + if (pkg_desc->package.elements[index]->integer.value + <= V2_desc->integer.value) { continue; } @@ -497,7 +497,7 @@ acpi_aml_exec_match ( /* Match_value is the return value */ - ret_desc->number.value = match_value; + ret_desc->integer.value = match_value; cleanup: diff --git a/drivers/acpi/interpreter/ammonad.c b/drivers/acpi/interpreter/ammonad.c index df9671c06..ea8834a5c 100644 --- a/drivers/acpi/interpreter/ammonad.c +++ b/drivers/acpi/interpreter/ammonad.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: ammonad - ACPI AML (p-code) execution for monadic operators - * $Revision: 88 $ + * $Revision: 89 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -180,7 +180,7 @@ acpi_aml_exec_monadic1 ( case AML_SLEEP_OP: - acpi_aml_system_do_suspend ((u32) obj_desc->number.value); + acpi_aml_system_do_suspend ((u32) obj_desc->integer.value); break; @@ -188,7 +188,7 @@ acpi_aml_exec_monadic1 ( case AML_STALL_OP: - acpi_aml_system_do_stall ((u32) obj_desc->number.value); + acpi_aml_system_do_stall ((u32) obj_desc->integer.value); break; @@ -267,7 +267,7 @@ acpi_aml_exec_monadic2_r ( case AML_TO_BCD_OP: case AML_COND_REF_OF_OP: - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -283,7 +283,7 @@ acpi_aml_exec_monadic2_r ( case AML_BIT_NOT_OP: - ret_desc->number.value = ~obj_desc->number.value; + ret_desc->integer.value = ~obj_desc->integer.value; break; @@ -291,17 +291,17 @@ acpi_aml_exec_monadic2_r ( case AML_FIND_SET_LEFT_BIT_OP: - ret_desc->number.value = obj_desc->number.value; + ret_desc->integer.value = obj_desc->integer.value; /* * Acpi specification describes Integer type as a little * endian unsigned value, so this boundry condition is valid. */ - for (res_val = 0; ret_desc->number.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { - ret_desc->number.value >>= 1; + for (res_val = 0; ret_desc->integer.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { + ret_desc->integer.value >>= 1; } - ret_desc->number.value = res_val; + ret_desc->integer.value = res_val; break; @@ -309,19 +309,19 @@ acpi_aml_exec_monadic2_r ( case AML_FIND_SET_RIGHT_BIT_OP: - ret_desc->number.value = obj_desc->number.value; + ret_desc->integer.value = obj_desc->integer.value; /* * Acpi specification describes Integer type as a little * endian unsigned value, so this boundry condition is valid. */ - for (res_val = 0; ret_desc->number.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { - ret_desc->number.value <<= 1; + for (res_val = 0; ret_desc->integer.value && res_val < ACPI_INTEGER_BIT_SIZE; ++res_val) { + ret_desc->integer.value <<= 1; } /* Since returns must be 1-based, subtract from 33 (65) */ - ret_desc->number.value = res_val == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - res_val; + ret_desc->integer.value = res_val == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - res_val; break; @@ -332,11 +332,11 @@ acpi_aml_exec_monadic2_r ( /* * The 64-bit ACPI integer can hold 16 4-bit BCD integers */ - ret_desc->number.value = 0; + ret_desc->integer.value = 0; for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { /* Get one BCD digit */ - digit = (ACPI_INTEGER) ((obj_desc->number.value >> (i * 4)) & 0xF); + digit = (ACPI_INTEGER) ((obj_desc->integer.value >> (i * 4)) & 0xF); /* Check the range of the digit */ @@ -352,7 +352,7 @@ acpi_aml_exec_monadic2_r ( digit *= 10; } - ret_desc->number.value += digit; + ret_desc->integer.value += digit; } } break; @@ -363,16 +363,16 @@ acpi_aml_exec_monadic2_r ( case AML_TO_BCD_OP: - if (obj_desc->number.value > ACPI_MAX_BCD_VALUE) { + if (obj_desc->integer.value > ACPI_MAX_BCD_VALUE) { status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } - ret_desc->number.value = 0; + ret_desc->integer.value = 0; for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { /* Divide by nth factor of 10 */ - digit = obj_desc->number.value; + digit = obj_desc->integer.value; for (j = 0; j < i; j++) { digit /= 10; } @@ -380,7 +380,7 @@ acpi_aml_exec_monadic2_r ( /* Create the BCD digit */ if (digit > 0) { - ret_desc->number.value += (ACPI_MODULO (digit, 10) << (i * 4)); + ret_desc->integer.value += (ACPI_MODULO (digit, 10) << (i * 4)); } } break; @@ -402,7 +402,7 @@ acpi_aml_exec_monadic2_r ( * return FALSE */ - ret_desc->number.value = 0; + ret_desc->integer.value = 0; /* * Must delete the result descriptor since there is no reference @@ -424,7 +424,7 @@ acpi_aml_exec_monadic2_r ( /* The object exists in the namespace, return TRUE */ - ret_desc->number.value = ACPI_INTEGER_MAX; + ret_desc->integer.value = ACPI_INTEGER_MAX; goto cleanup; break; @@ -579,13 +579,13 @@ acpi_aml_exec_monadic2 ( case AML_LNOT_OP: - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; } - ret_desc->number.value = !obj_desc->number.value; + ret_desc->integer.value = !obj_desc->integer.value; break; @@ -638,10 +638,10 @@ acpi_aml_exec_monadic2 ( /* Do the actual increment or decrement */ if (AML_INCREMENT_OP == opcode) { - ret_desc->number.value++; + ret_desc->integer.value++; } else { - ret_desc->number.value--; + ret_desc->integer.value--; } /* Store the result back in the original descriptor */ @@ -672,7 +672,7 @@ acpi_aml_exec_monadic2 ( /* Constants are of type Number */ - type = ACPI_TYPE_NUMBER; + type = ACPI_TYPE_INTEGER; break; @@ -733,13 +733,13 @@ acpi_aml_exec_monadic2 ( /* Allocate a descriptor to hold the type. */ - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; } - ret_desc->number.value = type; + ret_desc->integer.value = type; break; @@ -793,13 +793,13 @@ acpi_aml_exec_monadic2 ( * object to hold the value */ - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; } - ret_desc->number.value = value; + ret_desc->integer.value = value; break; @@ -910,14 +910,14 @@ acpi_aml_exec_monadic2 ( * sub-buffer of the main buffer, it is only a pointer to a * single element (byte) of the buffer! */ - ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!ret_desc) { status = AE_NO_MEMORY; goto cleanup; } tmp_desc = obj_desc->reference.object; - ret_desc->number.value = + ret_desc->integer.value = tmp_desc->buffer.pointer[obj_desc->reference.offset]; /* TBD: [Investigate] (see below) Don't add an additional diff --git a/drivers/acpi/interpreter/amnames.c b/drivers/acpi/interpreter/amnames.c index ea4c26e08..07be1a37c 100644 --- a/drivers/acpi/interpreter/amnames.c +++ b/drivers/acpi/interpreter/amnames.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amnames - interpreter/scanner name load/execute - * $Revision: 71 $ + * $Revision: 73 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/interpreter/amprep.c b/drivers/acpi/interpreter/amprep.c index 266cb0105..2a56d4826 100644 --- a/drivers/acpi/interpreter/amprep.c +++ b/drivers/acpi/interpreter/amprep.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amprep - ACPI AML (p-code) execution - field prep utilities - * $Revision: 72 $ + * $Revision: 73 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/interpreter/amregion.c b/drivers/acpi/interpreter/amregion.c index dfe4fab85..1a2e7351d 100644 --- a/drivers/acpi/interpreter/amregion.c +++ b/drivers/acpi/interpreter/amregion.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amregion - ACPI default Op_region (address space) handlers - * $Revision: 41 $ + * $Revision: 44 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -99,8 +99,8 @@ acpi_aml_system_memory_space_handler ( */ if ((address < mem_info->mapped_physical_address) || - ((address + length) > - (mem_info->mapped_physical_address + mem_info->mapped_length))) + (((ACPI_INTEGER) address + length) > + ((ACPI_INTEGER) mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; @@ -139,7 +139,7 @@ acpi_aml_system_memory_space_handler ( /* TBD: should these pointers go to 64-bit in all cases ? */ logical_addr_ptr = mem_info->mapped_logical_address + - (address - mem_info->mapped_physical_address); + ((ACPI_INTEGER) address - (ACPI_INTEGER) mem_info->mapped_physical_address); /* Perform the memory read or write */ diff --git a/drivers/acpi/interpreter/amresnte.c b/drivers/acpi/interpreter/amresnte.c index 20c6a0b11..0dc67b613 100644 --- a/drivers/acpi/interpreter/amresnte.c +++ b/drivers/acpi/interpreter/amresnte.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amresnte - AML Interpreter object resolution - * $Revision: 25 $ + * $Revision: 27 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,7 +55,7 @@ * can be either a pointer to an actual internal object or a pointer into the * AML stream itself. These types are currently: * - * ACPI_TYPE_NUMBER + * ACPI_TYPE_INTEGER * ACPI_TYPE_STRING * ACPI_TYPE_BUFFER * ACPI_TYPE_MUTEX @@ -208,14 +208,14 @@ acpi_aml_resolve_node_to_value ( break; - case ACPI_TYPE_NUMBER: + case ACPI_TYPE_INTEGER: /* * The Node has an attached internal object, make sure that it's a * number */ - if (ACPI_TYPE_NUMBER != val_desc->common.type) { + if (ACPI_TYPE_INTEGER != val_desc->common.type) { return (AE_AML_OPERAND_TYPE); } @@ -244,7 +244,7 @@ acpi_aml_resolve_node_to_value ( object_type = ACPI_TYPE_BUFFER; } else { - object_type = ACPI_TYPE_NUMBER; + object_type = ACPI_TYPE_INTEGER; } /* @@ -282,7 +282,7 @@ acpi_aml_resolve_node_to_value ( return (status); } - obj_desc->number.value = temp_val; + obj_desc->integer.value = temp_val; } @@ -330,12 +330,12 @@ acpi_aml_resolve_node_to_value ( /* Create an object for the result */ - obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!obj_desc) { return (AE_NO_MEMORY); } - obj_desc->number.value = temp_val; + obj_desc->integer.value = temp_val; break; @@ -378,12 +378,12 @@ acpi_aml_resolve_node_to_value ( /* Create an object for the result */ - obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!obj_desc) { return (AE_NO_MEMORY); } - obj_desc->number.value = temp_val; + obj_desc->integer.value = temp_val; break; @@ -477,12 +477,12 @@ acpi_aml_resolve_node_to_value ( /* Create object for result */ - obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); + obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER); if (!obj_desc) { return (AE_NO_MEMORY); } - obj_desc->number.value = temp_val; + obj_desc->integer.value = temp_val; /* Truncate value if we are executing from a 32-bit ACPI table */ diff --git a/drivers/acpi/interpreter/amresolv.c b/drivers/acpi/interpreter/amresolv.c index 2fa59e9bb..c08a4731c 100644 --- a/drivers/acpi/interpreter/amresolv.c +++ b/drivers/acpi/interpreter/amresolv.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amresolv - AML Interpreter object resolution - * $Revision: 78 $ + * $Revision: 81 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -118,19 +118,19 @@ acpi_aml_get_field_unit_value ( mask = ACPI_UINT32_MAX; } - result_desc->number.type = (u8) ACPI_TYPE_NUMBER; + result_desc->integer.type = (u8) ACPI_TYPE_INTEGER; /* Get the 32 bit value at the location */ - MOVE_UNALIGNED32_TO_32 (&result_desc->number.value, location); + MOVE_UNALIGNED32_TO_32 (&result_desc->integer.value, location); /* * Shift the 32-bit word containing the field, and mask off the * resulting value */ - result_desc->number.value = - (result_desc->number.value >> field_desc->field_unit.bit_offset) & mask; + result_desc->integer.value = + (result_desc->integer.value >> field_desc->field_unit.bit_offset) & mask; /* Release global lock if we acquired it earlier */ @@ -150,7 +150,7 @@ acpi_aml_get_field_unit_value ( * * RETURN: Status * - * DESCRIPTION: Convert Reference entries on Obj_stack to Rvalues + * DESCRIPTION: Convert Reference objects to values * ******************************************************************************/ @@ -279,7 +279,7 @@ acpi_aml_resolve_object_to_value ( acpi_cm_remove_reference (stack_desc); *stack_ptr = obj_desc; - if (ACPI_TYPE_NUMBER == obj_desc->common.type) { + if (ACPI_TYPE_INTEGER == obj_desc->common.type) { /* Value is a Number */ } @@ -311,7 +311,7 @@ acpi_aml_resolve_object_to_value ( acpi_cm_remove_reference (stack_desc); *stack_ptr = obj_desc; - if (ACPI_TYPE_NUMBER == obj_desc->common.type) { + if (ACPI_TYPE_INTEGER == obj_desc->common.type) { /* Value is a Number */ } @@ -326,22 +326,22 @@ acpi_aml_resolve_object_to_value ( case AML_ZERO_OP: - stack_desc->common.type = (u8) ACPI_TYPE_NUMBER; - stack_desc->number.value = 0; + stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; + stack_desc->integer.value = 0; break; case AML_ONE_OP: - stack_desc->common.type = (u8) ACPI_TYPE_NUMBER; - stack_desc->number.value = 1; + stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; + stack_desc->integer.value = 1; break; case AML_ONES_OP: - stack_desc->common.type = (u8) ACPI_TYPE_NUMBER; - stack_desc->number.value = ACPI_INTEGER_MAX; + stack_desc->common.type = (u8) ACPI_TYPE_INTEGER; + stack_desc->integer.value = ACPI_INTEGER_MAX; /* Truncate value if we are executing from a 32-bit ACPI table */ diff --git a/drivers/acpi/interpreter/amresop.c b/drivers/acpi/interpreter/amresop.c index 83fda4455..a837fd66b 100644 --- a/drivers/acpi/interpreter/amresop.c +++ b/drivers/acpi/interpreter/amresop.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amresop - AML Interpreter operand/object resolution - * $Revision: 18 $ + * $Revision: 22 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -214,8 +214,13 @@ acpi_aml_resolve_operands ( switch (this_arg_type) { - case ARGI_REFERENCE: /* Reference */ - case ARGI_TARGETREF: + case ARGI_REFERENCE: /* References */ + case ARGI_INTEGER_REF: + case ARGI_OBJECT_REF: + case ARGI_DEVICE_REF: + case ARGI_TARGETREF: /* TBD: must implement implicit conversion rules before store */ + case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ + case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ /* Need an operand of type INTERNAL_TYPE_REFERENCE */ @@ -283,20 +288,6 @@ acpi_aml_resolve_operands ( * For the simple cases, only one type of resolved object * is allowed */ - case ARGI_NUMBER: /* Number */ - - /* Need an operand of type ACPI_TYPE_NUMBER */ - - type_needed = ACPI_TYPE_NUMBER; - break; - - case ARGI_BUFFER: - - /* Need an operand of type ACPI_TYPE_BUFFER */ - - type_needed = ACPI_TYPE_BUFFER; - break; - case ARGI_MUTEX: /* Need an operand of type ACPI_TYPE_MUTEX */ @@ -344,11 +335,69 @@ acpi_aml_resolve_operands ( * The more complex cases allow multiple resolved object types */ + case ARGI_INTEGER: /* Number */ + + /* + * Need an operand of type ACPI_TYPE_INTEGER, + * But we can implicitly convert from a STRING or BUFFER + */ + status = acpi_aml_convert_to_integer (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { + if (status == AE_TYPE) { + return (AE_AML_OPERAND_TYPE); + } + + return (status); + } + + goto next_operand; + break; + + + case ARGI_BUFFER: + + /* + * Need an operand of type ACPI_TYPE_BUFFER, + * But we can implicitly convert from a STRING or INTEGER + */ + status = acpi_aml_convert_to_buffer (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { + if (status == AE_TYPE) { + return (AE_AML_OPERAND_TYPE); + } + + return (status); + } + + goto next_operand; + break; + + case ARGI_STRING: - /* Need an operand of type ACPI_TYPE_STRING or ACPI_TYPE_BUFFER */ + /* + * Need an operand of type ACPI_TYPE_STRING, + * But we can implicitly convert from a BUFFER or INTEGER + */ + status = acpi_aml_convert_to_string (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { + if (status == AE_TYPE) { + return (AE_AML_OPERAND_TYPE); + } + + return (status); + } + + goto next_operand; + break; + + + case ARGI_COMPUTEDATA: + + /* Need an operand of type INTEGER, STRING or BUFFER */ - if ((ACPI_TYPE_STRING != (*stack_ptr)->common.type) && + if ((ACPI_TYPE_INTEGER != (*stack_ptr)->common.type) && + (ACPI_TYPE_STRING != (*stack_ptr)->common.type) && (ACPI_TYPE_BUFFER != (*stack_ptr)->common.type)) { return (AE_AML_OPERAND_TYPE); diff --git a/drivers/acpi/interpreter/amstore.c b/drivers/acpi/interpreter/amstore.c index 8887e0997..9f350bb29 100644 --- a/drivers/acpi/interpreter/amstore.c +++ b/drivers/acpi/interpreter/amstore.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amstore - AML Interpreter object store support - * $Revision: 117 $ + * $Revision: 121 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,12 +64,7 @@ acpi_aml_exec_store ( ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; - ACPI_OPERAND_OBJECT *delete_dest_desc = NULL; - ACPI_OPERAND_OBJECT *tmp_desc; - ACPI_NAMESPACE_NODE *node = NULL; - u8 value = 0; - u32 length; - u32 i; + ACPI_OPERAND_OBJECT *ref_desc = dest_desc; /* Validate parameters */ @@ -78,27 +73,23 @@ acpi_aml_exec_store ( return (AE_AML_NO_OPERAND); } - /* Examine the datatype of the Dest_desc */ + /* Dest_desc can be either a namespace node or an ACPI object */ if (VALID_DESCRIPTOR_TYPE (dest_desc, ACPI_DESC_TYPE_NAMED)) { - /* Dest is an ACPI_HANDLE, create a new object */ - - node = (ACPI_NAMESPACE_NODE *) dest_desc; - dest_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); - if (!dest_desc) { - /* Allocation failure */ - - return (AE_NO_MEMORY); - } + /* + * Dest is a namespace node, + * Storing an object into a Name "container" + */ + status = acpi_aml_store_object_to_node (val_desc, + (ACPI_NAMESPACE_NODE *) dest_desc, walk_state); - /* Build a new Reference wrapper around the handle */ + /* All done, that's it */ - dest_desc->reference.op_code = AML_NAME_OP; - dest_desc->reference.object = node; + return (status); } - /* Destination object must be of type Reference */ + /* Destination object must be an object of type Reference */ if (dest_desc->common.type != INTERNAL_TYPE_REFERENCE) { /* Destination is not an Reference */ @@ -106,36 +97,130 @@ acpi_aml_exec_store ( return (AE_AML_OPERAND_TYPE); } - /* Examine the Reference opcode */ - switch (dest_desc->reference.op_code) + /* + * Examine the Reference opcode. These cases are handled: + * + * 1) Store to Name (Change the object associated with a name) + * 2) Store to an indexed area of a Buffer or Package + * 3) Store to a Method Local or Arg + * 4) Store to the debug object + * 5) Store to a constant -- a noop + */ + + switch (ref_desc->reference.op_code) { case AML_NAME_OP: - /* - * Storing into a Name - */ - delete_dest_desc = dest_desc; - status = acpi_aml_store_object_to_node (val_desc, dest_desc->reference.object, - walk_state); + /* Storing an object into a Name "container" */ - break; /* Case Name_op */ + status = acpi_aml_store_object_to_node (val_desc, ref_desc->reference.object, + walk_state); + break; case AML_INDEX_OP: - delete_dest_desc = dest_desc; + /* Storing to an Index (pointer into a packager or buffer) */ + + status = acpi_aml_store_object_to_index (val_desc, ref_desc, walk_state); + break; + + + case AML_LOCAL_OP: + + status = acpi_ds_method_data_set_value (MTH_TYPE_LOCAL, + (ref_desc->reference.offset), val_desc, walk_state); + break; + + + case AML_ARG_OP: + + status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, + (ref_desc->reference.offset), val_desc, walk_state); + break; + + + case AML_DEBUG_OP: /* - * Valid source value and destination reference pointer. + * Storing to the Debug object causes the value stored to be + * displayed and otherwise has no effect -- see ACPI Specification * - * ACPI Specification 1.0B section 15.2.3.4.2.13: - * Destination should point to either a buffer or a package + * TBD: print known object types "prettier". */ + break; + + + case AML_ZERO_OP: + case AML_ONE_OP: + case AML_ONES_OP: + /* - * Actually, storing to a package is not so simple. The source must be + * Storing to a constant is a no-op -- see ACPI Specification + * Delete the reference descriptor, however + */ + break; + + + default: + + /* TBD: [Restructure] use object dump routine !! */ + + status = AE_AML_INTERNAL; + break; + + } /* switch (Ref_desc->Reference.Op_code) */ + + + /* Always delete the reference descriptor object */ + + if (ref_desc) { + acpi_cm_remove_reference (ref_desc); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_store_object_to_index + * + * PARAMETERS: *Val_desc - Value to be stored + * *Node - Named object to recieve the value + * + * RETURN: Status + * + * DESCRIPTION: Store the object to the named object. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_store_object_to_index ( + ACPI_OPERAND_OBJECT *val_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state) +{ + ACPI_STATUS status = AE_OK; + ACPI_OPERAND_OBJECT *obj_desc; + u32 length; + u32 i; + u8 value = 0; + + + /* + * Destination must be a reference pointer, and + * must point to either a buffer or a package + */ + + switch (dest_desc->reference.target_type) + { + case ACPI_TYPE_PACKAGE: + /* + * Storing to a package element is not simple. The source must be * evaluated and converted to the type of the destination and then the * source is copied into the destination - we can't just point to the * source object. @@ -145,8 +230,8 @@ acpi_aml_exec_store ( * The object at *(Dest_desc->Reference.Where) is the * element within the package that is to be modified. */ - tmp_desc = *(dest_desc->reference.where); - if (tmp_desc) { + obj_desc = *(dest_desc->reference.where); + if (obj_desc) { /* * If the Destination element is a package, we will delete * that object and construct a new one. @@ -155,41 +240,39 @@ acpi_aml_exec_store ( * to be packages? * && (Val_desc->Common.Type == ACPI_TYPE_PACKAGE) */ - if (tmp_desc->common.type == ACPI_TYPE_PACKAGE) { + if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { /* * Take away the reference for being part of a package and * delete */ - acpi_cm_remove_reference (tmp_desc); - acpi_cm_remove_reference (tmp_desc); + acpi_cm_remove_reference (obj_desc); + acpi_cm_remove_reference (obj_desc); - tmp_desc = NULL; + obj_desc = NULL; } } - if (!tmp_desc) { + if (!obj_desc) { /* - * If the Tmp_desc is NULL, that means an uninitialized package - * has been used as a destination, therefore, we must create - * the destination element to match the type of the source - * element NOTE: Val_desc can be of any type. + * If the Obj_desc is NULL, it means that an uninitialized package + * element has been used as a destination (this is OK), therefore, + * we must create the destination element to match the type of the + * source element NOTE: Val_desc can be of any type. */ - tmp_desc = acpi_cm_create_internal_object (val_desc->common.type); - if (!tmp_desc) { - status = AE_NO_MEMORY; - goto cleanup; + obj_desc = acpi_cm_create_internal_object (val_desc->common.type); + if (!obj_desc) { + return (AE_NO_MEMORY); } /* * If the source is a package, copy the source to the new dest */ - if (ACPI_TYPE_PACKAGE == tmp_desc->common.type) { + if (ACPI_TYPE_PACKAGE == obj_desc->common.type) { status = acpi_aml_build_copy_internal_package_object ( - val_desc, tmp_desc, walk_state); + val_desc, obj_desc, walk_state); if (ACPI_FAILURE (status)) { - acpi_cm_remove_reference (tmp_desc); - tmp_desc = NULL; - goto cleanup; + acpi_cm_remove_reference (obj_desc); + return (status); } } @@ -199,38 +282,31 @@ acpi_aml_exec_store ( * part of the parent package */ - *(dest_desc->reference.where) = tmp_desc; - acpi_cm_add_reference (tmp_desc); + *(dest_desc->reference.where) = obj_desc; + acpi_cm_add_reference (obj_desc); } - if (ACPI_TYPE_PACKAGE != tmp_desc->common.type) { + if (ACPI_TYPE_PACKAGE != obj_desc->common.type) { /* * The destination element is not a package, so we need to * convert the contents of the source (Val_desc) and copy into - * the destination (Tmp_desc) + * the destination (Obj_desc) */ - status = acpi_aml_store_object_to_object (val_desc, tmp_desc, + status = acpi_aml_store_object_to_object (val_desc, obj_desc, walk_state); if (ACPI_FAILURE (status)) { /* * An error occurrered when copying the internal object * so delete the reference. */ - status = AE_AML_OPERAND_TYPE; + return (AE_AML_OPERAND_TYPE); } } - - break; } + break; - /* - * Check that the destination is a Buffer Field type - */ - if (dest_desc->reference.target_type != ACPI_TYPE_BUFFER_FIELD) { - status = AE_AML_OPERAND_TYPE; - break; - } + case ACPI_TYPE_BUFFER_FIELD: /* * Storing into a buffer at a location defined by an Index. * @@ -239,13 +315,11 @@ acpi_aml_exec_store ( */ /* - * Set the Tmp_desc to the destination object and type check. + * Set the Obj_desc to the destination object and type check. */ - tmp_desc = dest_desc->reference.object; - - if (tmp_desc->common.type != ACPI_TYPE_BUFFER) { - status = AE_AML_OPERAND_TYPE; - break; + obj_desc = dest_desc->reference.object; + if (obj_desc->common.type != ACPI_TYPE_BUFFER) { + return (AE_AML_OPERAND_TYPE); } /* @@ -256,15 +330,15 @@ acpi_aml_exec_store ( switch (val_desc->common.type) { /* - * If the type is Integer, the Length is 4. + * If the type is Integer, assign bytewise * This loop to assign each of the elements is somewhat - * backward because of the Big Endian-ness of IA-64 + * backward because of the Big Endian-ness of IA-64 */ - case ACPI_TYPE_NUMBER: - length = 4; + case ACPI_TYPE_INTEGER: + length = sizeof (ACPI_INTEGER); for (i = length; i != 0; i--) { - value = (u8)(val_desc->number.value >> (MUL_8 (i - 1))); - tmp_desc->buffer.pointer[dest_desc->reference.offset] = value; + value = (u8)(val_desc->integer.value >> (MUL_8 (i - 1))); + obj_desc->buffer.pointer[dest_desc->reference.offset] = value; } break; @@ -276,7 +350,7 @@ acpi_aml_exec_store ( length = val_desc->buffer.length; for (i = 0; i < length; i++) { value = *(val_desc->buffer.pointer + i); - tmp_desc->buffer.pointer[dest_desc->reference.offset] = value; + obj_desc->buffer.pointer[dest_desc->reference.offset] = value; } break; @@ -288,7 +362,7 @@ acpi_aml_exec_store ( length = val_desc->string.length; for (i = 0; i < length; i++) { value = *(val_desc->string.pointer + i); - tmp_desc->buffer.pointer[dest_desc->reference.offset] = value; + obj_desc->buffer.pointer[dest_desc->reference.offset] = value; } break; @@ -299,80 +373,207 @@ acpi_aml_exec_store ( status = AE_AML_OPERAND_TYPE; break; } + break; - /* - * If we had an error, break out of this case statement. - */ - if (ACPI_FAILURE (status)) { - break; - } - - /* - * Set the return pointer - */ - dest_desc = tmp_desc; + default: + status = AE_AML_OPERAND_TYPE; break; + } - case AML_ZERO_OP: - case AML_ONE_OP: - case AML_ONES_OP: - /* - * Storing to a constant is a no-op -- see ACPI Specification - * Delete the result descriptor. - */ + return (status); +} - delete_dest_desc = dest_desc; - break; + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_store_object_to_node + * + * PARAMETERS: *Source_desc - Value to be stored + * *Node - Named object to recieve the value + * + * RETURN: Status + * + * DESCRIPTION: Store the object to the named object. + * + * The Assignment of an object to a named object is handled here + * The val passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. + * + * NOTE: the global lock is acquired early. This will result + * in the global lock being held a bit longer. Also, if the + * function fails during set up we may get the lock when we + * don't really need it. I don't think we care. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_store_object_to_node ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_NAMESPACE_NODE *node, + ACPI_WALK_STATE *walk_state) +{ + ACPI_STATUS status = AE_OK; + ACPI_OPERAND_OBJECT *target_desc; + OBJECT_TYPE_INTERNAL target_type = ACPI_TYPE_ANY; - case AML_LOCAL_OP: + /* + * Assuming the parameters were already validated + */ + ACPI_ASSERT((node) && (source_desc)); - status = acpi_ds_method_data_set_value (MTH_TYPE_LOCAL, - (dest_desc->reference.offset), val_desc, walk_state); - delete_dest_desc = dest_desc; - break; + /* + * Get current type of the node, and object attached to Node + */ + target_type = acpi_ns_get_type (node); + target_desc = acpi_ns_get_attached_object (node); - case AML_ARG_OP: - status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, - (dest_desc->reference.offset), val_desc, walk_state); - delete_dest_desc = dest_desc; + /* + * Resolve the source object to an actual value + * (If it is a reference object) + */ + status = acpi_aml_resolve_object (&source_desc, target_type, walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + + + /* + * Do the actual store operation + */ + switch (target_type) + { + case INTERNAL_TYPE_DEF_FIELD: + + /* Raw data copy for target types Integer/String/Buffer */ + + status = acpi_aml_copy_data_to_named_field (source_desc, node); break; - case AML_DEBUG_OP: + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case INTERNAL_TYPE_BANK_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: + case ACPI_TYPE_FIELD_UNIT: /* - * Storing to the Debug object causes the value stored to be - * displayed and otherwise has no effect -- see ACPI Specification + * These target types are all of type Integer/String/Buffer, and + * therefore support implicit conversion before the store. + * + * Copy and/or convert the source object to a new target object */ + status = acpi_aml_store_object (source_desc, target_type, &target_desc, walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } - delete_dest_desc = dest_desc; + /* + * Store the new Target_desc as the new value of the Name, and set + * the Name's type to that of the value being stored in it. + * Source_desc reference count is incremented by Attach_object. + */ + status = acpi_ns_attach_object (node, target_desc, target_type); break; default: - /* TBD: [Restructure] use object dump routine !! */ + /* No conversions for all other types. Just attach the source object */ - delete_dest_desc = dest_desc; - status = AE_AML_INTERNAL; + status = acpi_ns_attach_object (node, source_desc, source_desc->common.type); - } /* switch(Dest_desc->Reference.Op_code) */ + break; + } -cleanup: + return (status); +} - /* Cleanup and exit*/ - if (delete_dest_desc) { - acpi_cm_remove_reference (delete_dest_desc); +/******************************************************************************* + * + * FUNCTION: Acpi_aml_store_object_to_object + * + * PARAMETERS: *Source_desc - Value to be stored + * *Dest_desc - Object to receive the value + * + * RETURN: Status + * + * DESCRIPTION: Store an object to another object. + * + * The Assignment of an object to another (not named) object + * is handled here. + * The val passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. + * + * This module allows destination types of Number, String, + * and Buffer. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_store_object_to_object ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state) +{ + ACPI_STATUS status = AE_OK; + OBJECT_TYPE_INTERNAL destination_type = dest_desc->common.type; + + + /* + * Assuming the parameters are valid! + */ + ACPI_ASSERT((dest_desc) && (source_desc)); + + + /* + * From this interface, we only support Integers/Strings/Buffers + */ + switch (destination_type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + break; + + default: + return (AE_NOT_IMPLEMENTED); } + + /* + * Resolve the source object to an actual value + * (If it is a reference object) + */ + status = acpi_aml_resolve_object (&source_desc, destination_type, walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + + + /* + * Copy and/or convert the source object to the destination object + */ + status = acpi_aml_store_object (source_desc, destination_type, &dest_desc, walk_state); + + return (status); } - diff --git a/drivers/acpi/interpreter/amstoren.c b/drivers/acpi/interpreter/amstoren.c index 91b2095c5..eb62ed2f1 100644 --- a/drivers/acpi/interpreter/amstoren.c +++ b/drivers/acpi/interpreter/amstoren.c @@ -2,13 +2,13 @@ /****************************************************************************** * * Module Name: amstoren - AML Interpreter object store support, - * Store to Node (namespace object) - * $Revision: 24 $ + * Store to Node (namespace object) + * $Revision: 28 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,127 +41,72 @@ /******************************************************************************* * - * FUNCTION: Acpi_aml_store_object_to_node + * FUNCTION: Acpi_aml_resolve_object * - * PARAMETERS: *Val_desc - Value to be stored - * *Node - Named object to recieve the value + * PARAMETERS: Source_desc_ptr - Pointer to the source object + * Target_type - Current type of the target + * Walk_state - Current walk state * - * RETURN: Status - * - * DESCRIPTION: Store the object to the named object. - * - * The Assignment of an object to a named object is handled here - * The val passed in will replace the current value (if any) - * with the input value. + * RETURN: Status, resolved object in Source_desc_ptr. * - * When storing into an object the data is converted to the - * target object type then stored in the object. This means - * that the target object type (for an initialized target) will - * not be changed by a store operation. - * - * NOTE: the global lock is acquired early. This will result - * in the global lock being held a bit longer. Also, if the - * function fails during set up we may get the lock when we - * don't really need it. I don't think we care. + * DESCRIPTION: Resolve an object. If the object is a reference, dereference + * it and return the actual object in the Source_desc_ptr. * ******************************************************************************/ ACPI_STATUS -acpi_aml_store_object_to_node ( - ACPI_OPERAND_OBJECT *val_desc, - ACPI_NAMESPACE_NODE *node, +acpi_aml_resolve_object ( + ACPI_OPERAND_OBJECT **source_desc_ptr, + OBJECT_TYPE_INTERNAL target_type, ACPI_WALK_STATE *walk_state) { + ACPI_OPERAND_OBJECT *source_desc = *source_desc_ptr; ACPI_STATUS status = AE_OK; - u8 *buffer = NULL; - u32 length = 0; - u32 mask; - u32 new_value; - u8 locked = FALSE; - u8 *location=NULL; - ACPI_OPERAND_OBJECT *dest_desc; - OBJECT_TYPE_INTERNAL destination_type = ACPI_TYPE_ANY; /* - * Assuming the parameters are valid!!! + * Ensure we have a Source that can be stored in the target */ - ACPI_ASSERT((node) && (val_desc)); + switch (target_type) + { - destination_type = acpi_ns_get_type (node); + /* This case handles the "interchangeable" types Integer, String, and Buffer. */ /* - * First ensure we have a value that can be stored in the target + * These cases all require only Integers or values that + * can be converted to Integers (Strings or Buffers) */ - switch (destination_type) - { - /* Type of Name's existing value */ - - case INTERNAL_TYPE_ALIAS: - - /* - * Aliases are resolved by Acpi_aml_prep_operands - */ - - status = AE_AML_INTERNAL; - break; - - + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_FIELD_UNIT: case INTERNAL_TYPE_BANK_FIELD: case INTERNAL_TYPE_INDEX_FIELD: - case ACPI_TYPE_FIELD_UNIT: - case ACPI_TYPE_NUMBER: - - /* - * These cases all require only number values or values that - * can be converted to numbers. - * - * If value is not a Number, try to resolve it to one. - */ - - if (val_desc->common.type != ACPI_TYPE_NUMBER) { - /* - * Initially not a number, convert - */ - status = acpi_aml_resolve_to_value (&val_desc, walk_state); - if (ACPI_SUCCESS (status) && - (val_desc->common.type != ACPI_TYPE_NUMBER)) - { - /* - * Conversion successful but still not a number - */ - status = AE_AML_OPERAND_TYPE; - } - } - - break; + /* + * Stores into a Field/Region or into a Buffer/String + * are all essentially the same. + */ case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: case INTERNAL_TYPE_DEF_FIELD: /* - * Storing into a Field in a region or into a buffer or into - * a string all is essentially the same. - * - * If value is not a valid type, try to resolve it to one. + * If Source_desc is not a valid type, try to resolve it to one. */ - - if ((val_desc->common.type != ACPI_TYPE_NUMBER) && - (val_desc->common.type != ACPI_TYPE_BUFFER) && - (val_desc->common.type != ACPI_TYPE_STRING)) + if ((source_desc->common.type != ACPI_TYPE_INTEGER) && + (source_desc->common.type != ACPI_TYPE_BUFFER) && + (source_desc->common.type != ACPI_TYPE_STRING)) { /* - * Initially not a valid type, convert + * Initially not a valid type, convert */ - status = acpi_aml_resolve_to_value (&val_desc, walk_state); + status = acpi_aml_resolve_to_value (source_desc_ptr, walk_state); if (ACPI_SUCCESS (status) && - (val_desc->common.type != ACPI_TYPE_NUMBER) && - (val_desc->common.type != ACPI_TYPE_BUFFER) && - (val_desc->common.type != ACPI_TYPE_STRING)) + (source_desc->common.type != ACPI_TYPE_INTEGER) && + (source_desc->common.type != ACPI_TYPE_BUFFER) && + (source_desc->common.type != ACPI_TYPE_STRING)) { /* - * Conversion successful but still not a valid type + * Conversion successful but still not a valid type */ status = AE_AML_OPERAND_TYPE; } @@ -169,347 +114,133 @@ acpi_aml_store_object_to_node ( break; - case ACPI_TYPE_PACKAGE: + case INTERNAL_TYPE_ALIAS: /* - * TBD: [Unhandled] Not real sure what to do here + * Aliases are resolved by Acpi_aml_prep_operands */ - status = AE_NOT_IMPLEMENTED; + status = AE_AML_INTERNAL; break; + case ACPI_TYPE_PACKAGE: default: /* - * All other types than Alias and the various Fields come here. - * Store Val_desc as the new value of the Name, and set - * the Name's type to that of the value being stored in it. - * Val_desc reference count is incremented by Attach_object. + * All other types than Alias and the various Fields come here, + * including the untyped case - ACPI_TYPE_ANY. */ - - status = acpi_ns_attach_object (node, val_desc, val_desc->common.type); - - goto clean_up_and_bail_out; break; } - /* Exit now if failure above */ + return (status); +} + - if (ACPI_FAILURE (status)) { - goto clean_up_and_bail_out; - } +/******************************************************************************* + * + * FUNCTION: Acpi_aml_store_object + * + * PARAMETERS: Source_desc - Object to store + * Target_type - Current type of the target + * Target_desc_ptr - Pointer to the target + * Walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: "Store" an object to another object. This may include + * converting the source type to the target type (implicit + * conversion), and a copy of the value of the source to + * the target. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_store_object ( + ACPI_OPERAND_OBJECT *source_desc, + OBJECT_TYPE_INTERNAL target_type, + ACPI_OPERAND_OBJECT **target_desc_ptr, + ACPI_WALK_STATE *walk_state) +{ + ACPI_OPERAND_OBJECT *target_desc = *target_desc_ptr; + ACPI_STATUS status; - /* - * Get descriptor for object attached to Node - */ - dest_desc = acpi_ns_get_attached_object (node); - if (!dest_desc) { - /* - * There is no existing object attached to this Node - */ - status = AE_AML_INTERNAL; - goto clean_up_and_bail_out; - } /* - * Make sure the destination Object is the same as the Node + * Perform the "implicit conversion" of the source to the current type + * of the target - As per the ACPI specification. + * + * If no conversion performed, Source_desc is left alone, otherwise it + * is updated with a new object. */ - if (dest_desc->common.type != (u8) destination_type) { - status = AE_AML_INTERNAL; - goto clean_up_and_bail_out; + status = acpi_aml_convert_to_target_type (target_type, &source_desc, walk_state); + if (ACPI_FAILURE (status)) { + return (status); } + /* - * Acpi_everything is ready to execute now, We have - * a value we can handle, just perform the update + * We now have two objects of identical types, and we can perform a + * copy of the *value* of the source object. */ - - switch (destination_type) + switch (target_type) { - /* Type of Name's existing value */ - - case INTERNAL_TYPE_BANK_FIELD: + case ACPI_TYPE_ANY: + case INTERNAL_TYPE_DEF_ANY: /* - * Get the global lock if needed + * The target namespace node is uninitialized (has no target object), + * and will take on the type of the source object */ - locked = acpi_aml_acquire_global_lock (dest_desc->bank_field.lock_rule); - - /* - * Set Bank value to select proper Bank - * Perform the update (Set Bank Select) - */ - - status = acpi_aml_access_named_field (ACPI_WRITE, - dest_desc->bank_field.bank_select, - &dest_desc->bank_field.value, - sizeof (dest_desc->bank_field.value)); - if (ACPI_SUCCESS (status)) { - /* Set bank select successful, set data value */ - - status = acpi_aml_access_named_field (ACPI_WRITE, - dest_desc->bank_field.bank_select, - &val_desc->bank_field.value, - sizeof (val_desc->bank_field.value)); - } + *target_desc_ptr = source_desc; break; - case INTERNAL_TYPE_DEF_FIELD: - - /* - * Get the global lock if needed - */ - locked = acpi_aml_acquire_global_lock (val_desc->field.lock_rule); - - /* - * Perform the update - */ + case ACPI_TYPE_INTEGER: - switch (val_desc->common.type) - { - case ACPI_TYPE_NUMBER: - buffer = (u8 *) &val_desc->number.value; - length = sizeof (val_desc->number.value); - break; - - case ACPI_TYPE_BUFFER: - buffer = (u8 *) val_desc->buffer.pointer; - length = val_desc->buffer.length; - break; - - case ACPI_TYPE_STRING: - buffer = (u8 *) val_desc->string.pointer; - length = val_desc->string.length; - break; - } - - status = acpi_aml_access_named_field (ACPI_WRITE, - node, buffer, length); - - break; /* Global Lock released below */ + target_desc->integer.value = source_desc->integer.value; + /* Truncate value if we are executing from a 32-bit ACPI table */ - case ACPI_TYPE_STRING: - - /* - * Perform the update - */ - - switch (val_desc->common.type) - { - case ACPI_TYPE_NUMBER: - buffer = (u8 *) &val_desc->number.value; - length = sizeof (val_desc->number.value); - break; - - case ACPI_TYPE_BUFFER: - buffer = (u8 *) val_desc->buffer.pointer; - length = val_desc->buffer.length; - break; - - case ACPI_TYPE_STRING: - buffer = (u8 *) val_desc->string.pointer; - length = val_desc->string.length; - break; - } - - /* - * Setting a string value replaces the old string - */ - - if (length < dest_desc->string.length) { - /* - * Zero fill, not willing to do pointer arithmetic for - * archetecture independance. Just clear the whole thing - */ - MEMSET(dest_desc->string.pointer, 0, dest_desc->string.length); - MEMCPY(dest_desc->string.pointer, buffer, length); - } - else { - /* - * Free the current buffer, then allocate a buffer - * large enough to hold the value - */ - if ( dest_desc->string.pointer && - !acpi_tb_system_table_pointer (dest_desc->string.pointer)) - { - /* - * Only free if not a pointer into the DSDT - */ - - acpi_cm_free(dest_desc->string.pointer); - } + acpi_aml_truncate_for32bit_table (target_desc, walk_state); + break; - dest_desc->string.pointer = acpi_cm_allocate (length + 1); - dest_desc->string.length = length; - if (!dest_desc->string.pointer) { - status = AE_NO_MEMORY; - goto clean_up_and_bail_out; - } + case ACPI_TYPE_FIELD_UNIT: - MEMCPY(dest_desc->string.pointer, buffer, length); - } + status = acpi_aml_copy_integer_to_field_unit (source_desc, target_desc); break; - case ACPI_TYPE_BUFFER: - - /* - * Perform the update to the buffer - */ - - switch (val_desc->common.type) - { - case ACPI_TYPE_NUMBER: - buffer = (u8 *) &val_desc->number.value; - length = sizeof (val_desc->number.value); - break; - - case ACPI_TYPE_BUFFER: - buffer = (u8 *) val_desc->buffer.pointer; - length = val_desc->buffer.length; - break; - - case ACPI_TYPE_STRING: - buffer = (u8 *) val_desc->string.pointer; - length = val_desc->string.length; - break; - } + case INTERNAL_TYPE_BANK_FIELD: - /* - * Buffer is a static allocation, - * only place what will fit in the buffer. - */ - if (length <= dest_desc->buffer.length) { - /* - * Zero fill first, not willing to do pointer arithmetic for - * archetecture independence. Just clear the whole thing - */ - MEMSET(dest_desc->buffer.pointer, 0, dest_desc->buffer.length); - MEMCPY(dest_desc->buffer.pointer, buffer, length); - } - else { - /* - * truncate, copy only what will fit - */ - MEMCPY(dest_desc->buffer.pointer, buffer, dest_desc->buffer.length); - } + status = acpi_aml_copy_integer_to_bank_field (source_desc, target_desc); break; case INTERNAL_TYPE_INDEX_FIELD: - /* - * Get the global lock if needed - */ - locked = acpi_aml_acquire_global_lock (dest_desc->index_field.lock_rule); - - /* - * Set Index value to select proper Data register - * perform the update (Set index) - */ - - status = acpi_aml_access_named_field (ACPI_WRITE, - dest_desc->index_field.index, - &dest_desc->index_field.value, - sizeof (dest_desc->index_field.value)); - - if (ACPI_SUCCESS (status)) { - /* set index successful, next set Data value */ - - status = acpi_aml_access_named_field (ACPI_WRITE, - dest_desc->index_field.data, - &val_desc->number.value, - sizeof (val_desc->number.value)); - } + status = acpi_aml_copy_integer_to_index_field (source_desc, target_desc); break; - case ACPI_TYPE_FIELD_UNIT: - - - /* - * If the Field Buffer and Index have not been previously evaluated, - * evaluate them and save the results. - */ - if (!(dest_desc->common.flags & AOPOBJ_DATA_VALID)) { - status = acpi_ds_get_field_unit_arguments (dest_desc); - if (ACPI_FAILURE (status)) { - return (status); - } - } - - if ((!dest_desc->field_unit.container || - ACPI_TYPE_BUFFER != dest_desc->field_unit.container->common.type)) - { - status = AE_AML_INTERNAL; - goto clean_up_and_bail_out; - } - - /* - * Get the global lock if needed - */ - locked = acpi_aml_acquire_global_lock (dest_desc->field_unit.lock_rule); - - /* - * TBD: [Unhandled] REMOVE this limitation - * Make sure the operation is within the limits of our implementation - * this is not a Spec limitation!! - */ - if (dest_desc->field_unit.length + dest_desc->field_unit.bit_offset > 32) { - status = AE_NOT_IMPLEMENTED; - goto clean_up_and_bail_out; - } - - /* Field location is (base of buffer) + (byte offset) */ - - location = dest_desc->field_unit.container->buffer.pointer - + dest_desc->field_unit.offset; - - /* - * Construct Mask with 1 bits where the field is, - * 0 bits elsewhere - */ - mask = ((u32) 1 << dest_desc->field_unit.length) - ((u32)1 - << dest_desc->field_unit.bit_offset); - - /* Zero out the field in the buffer */ - - MOVE_UNALIGNED32_TO_32 (&new_value, location); - new_value &= ~mask; - - /* - * Shift and mask the new value into position, - * and or it into the buffer. - */ - new_value |= (val_desc->number.value << dest_desc->field_unit.bit_offset) & - mask; - - /* Store back the value */ - - MOVE_UNALIGNED32_TO_32 (location, &new_value); + case ACPI_TYPE_STRING: + status = acpi_aml_copy_string_to_string (source_desc, target_desc); break; - case ACPI_TYPE_NUMBER: - - - dest_desc->number.value = val_desc->number.value; - - /* Truncate value if we are executing from a 32-bit ACPI table */ + case ACPI_TYPE_BUFFER: - acpi_aml_truncate_for32bit_table (dest_desc, walk_state); + status = acpi_aml_copy_buffer_to_buffer (source_desc, target_desc); break; case ACPI_TYPE_PACKAGE: /* - * TBD: [Unhandled] Not real sure what to do here + * TBD: [Unhandled] Not real sure what to do here */ status = AE_NOT_IMPLEMENTED; break; @@ -518,24 +249,13 @@ acpi_aml_store_object_to_node ( default: /* - * All other types than Alias and the various Fields come here. - * Store Val_desc as the new value of the Name, and set - * the Name's type to that of the value being stored in it. - * Val_desc reference count is incremented by Attach_object. + * All other types come here. */ - status = AE_NOT_IMPLEMENTED; break; } -clean_up_and_bail_out: - - /* - * Release global lock if we acquired it earlier - */ - acpi_aml_release_global_lock (locked); - return (status); } diff --git a/drivers/acpi/interpreter/amstorob.c b/drivers/acpi/interpreter/amstorob.c index f3a098bd2..8118f08bd 100644 --- a/drivers/acpi/interpreter/amstorob.c +++ b/drivers/acpi/interpreter/amstorob.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amstorob - AML Interpreter object store support, store to object - * $Revision: 18 $ + * $Revision: 22 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,281 +40,383 @@ /******************************************************************************* * - * FUNCTION: Acpi_aml_store_object_to_object + * FUNCTION: Acpi_aml_copy_buffer_to_buffer * - * PARAMETERS: *Val_desc - Value to be stored - * *Dest_desc - Object to receive the value + * PARAMETERS: Source_desc - Source object to copy + * Target_desc - Destination object of the copy * * RETURN: Status * - * DESCRIPTION: Store an object to another object. + * DESCRIPTION: Copy a buffer object to another buffer object. * - * The Assignment of an object to another (not named) object - * is handled here. - * The val passed in will replace the current value (if any) - * with the input value. + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_copy_buffer_to_buffer ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc) +{ + u32 length; + u8 *buffer; + + /* + * We know that Source_desc is a buffer by now + */ + buffer = (u8 *) source_desc->buffer.pointer; + length = source_desc->buffer.length; + + /* + * Buffer is a static allocation, + * only place what will fit in the buffer. + */ + if (length <= target_desc->buffer.length) { + /* Clear existing buffer and copy in the new one */ + + MEMSET(target_desc->buffer.pointer, 0, target_desc->buffer.length); + MEMCPY(target_desc->buffer.pointer, buffer, length); + } + + else { + /* + * Truncate the source, copy only what will fit + */ + MEMCPY(target_desc->buffer.pointer, buffer, target_desc->buffer.length); + + } + + return (AE_OK); +} + + +/******************************************************************************* * - * When storing into an object the data is converted to the - * target object type then stored in the object. This means - * that the target object type (for an initialized target) will - * not be changed by a store operation. + * FUNCTION: Acpi_aml_copy_string_to_string + * + * PARAMETERS: Source_desc - Source object to copy + * Target_desc - Destination object of the copy + * + * RETURN: Status * - * This module allows destination types of Number, String, - * and Buffer. + * DESCRIPTION: Copy a String object to another String object * ******************************************************************************/ ACPI_STATUS -acpi_aml_store_object_to_object ( - ACPI_OPERAND_OBJECT *val_desc, - ACPI_OPERAND_OBJECT *dest_desc, - ACPI_WALK_STATE *walk_state) +acpi_aml_copy_string_to_string ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc) { - ACPI_STATUS status = AE_OK; - u8 *buffer = NULL; - u32 length = 0; - OBJECT_TYPE_INTERNAL destination_type = dest_desc->common.type; + u32 length; + u8 *buffer; /* - * Assuming the parameters are valid!!! + * We know that Source_desc is a string by now. */ - ACPI_ASSERT((dest_desc) && (val_desc)); + buffer = (u8 *) source_desc->string.pointer; + length = source_desc->string.length; /* - * First ensure we have a value that can be stored in the target + * Setting a string value replaces the old string */ - switch (destination_type) - { - /* Type of Name's existing value */ + if (length < target_desc->string.length) { + /* Clear old string and copy in the new one */ - case ACPI_TYPE_NUMBER: + MEMSET(target_desc->string.pointer, 0, target_desc->string.length); + MEMCPY(target_desc->string.pointer, buffer, length); + } + else { /* - * These cases all require only number values or values that - * can be converted to numbers. - * - * If value is not a Number, try to resolve it to one. + * Free the current buffer, then allocate a buffer + * large enough to hold the value */ - - if (val_desc->common.type != ACPI_TYPE_NUMBER) { + if (target_desc->string.pointer && + !acpi_tb_system_table_pointer (target_desc->string.pointer)) + { /* - * Initially not a number, convert + * Only free if not a pointer into the DSDT */ - status = acpi_aml_resolve_to_value (&val_desc, walk_state); - if (ACPI_SUCCESS (status) && - (val_desc->common.type != ACPI_TYPE_NUMBER)) - { - /* - * Conversion successful but still not a number - */ - status = AE_AML_OPERAND_TYPE; - } + acpi_cm_free(target_desc->string.pointer); } - break; + target_desc->string.pointer = acpi_cm_allocate (length + 1); + target_desc->string.length = length; - case ACPI_TYPE_STRING: - case ACPI_TYPE_BUFFER: + if (!target_desc->string.pointer) { + return (AE_NO_MEMORY); + } - /* - * Storing into a Field in a region or into a buffer or into - * a string all is essentially the same. - * - * If value is not a valid type, try to resolve it to one. - */ + MEMCPY(target_desc->string.pointer, buffer, length); + } - if ((val_desc->common.type != ACPI_TYPE_NUMBER) && - (val_desc->common.type != ACPI_TYPE_BUFFER) && - (val_desc->common.type != ACPI_TYPE_STRING)) - { - /* - * Initially not a valid type, convert - */ - status = acpi_aml_resolve_to_value (&val_desc, walk_state); - if (ACPI_SUCCESS (status) && - (val_desc->common.type != ACPI_TYPE_NUMBER) && - (val_desc->common.type != ACPI_TYPE_BUFFER) && - (val_desc->common.type != ACPI_TYPE_STRING)) - { - /* - * Conversion successful but still not a valid type - */ - status = AE_AML_OPERAND_TYPE; - } - } - break; + return (AE_OK); +} - default: +/******************************************************************************* + * + * FUNCTION: Acpi_aml_copy_integer_to_index_field + * + * PARAMETERS: Source_desc - Source object to copy + * Target_desc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Write an Integer to an Index Field + * + ******************************************************************************/ - /* - * TBD: [Unhandled] What other combinations must be implemented? - */ - status = AE_NOT_IMPLEMENTED; - break; - } +ACPI_STATUS +acpi_aml_copy_integer_to_index_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc) +{ + ACPI_STATUS status; + u8 locked; + + + /* + * Get the global lock if needed + */ + locked = acpi_aml_acquire_global_lock (target_desc->index_field.lock_rule); - /* Exit now if failure above */ + /* + * Set Index value to select proper Data register + * perform the update (Set index) + */ + status = acpi_aml_access_named_field (ACPI_WRITE, + target_desc->index_field.index, + &target_desc->index_field.value, + sizeof (target_desc->index_field.value)); + if (ACPI_SUCCESS (status)) { + /* Set_index was successful, next set Data value */ + + status = acpi_aml_access_named_field (ACPI_WRITE, + target_desc->index_field.data, + &source_desc->integer.value, + sizeof (source_desc->integer.value)); - if (ACPI_FAILURE (status)) { - goto clean_up_and_bail_out; } + + /* - * Acpi_everything is ready to execute now, We have - * a value we can handle, just perform the update + * Release global lock if we acquired it earlier */ + acpi_aml_release_global_lock (locked); - switch (destination_type) - { + return (status); +} - case ACPI_TYPE_STRING: - /* - * Perform the update - */ +/******************************************************************************* + * + * FUNCTION: Acpi_aml_copy_integer_to_bank_field + * + * PARAMETERS: Source_desc - Source object to copy + * Target_desc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Write an Integer to a Bank Field + * + ******************************************************************************/ - switch (val_desc->common.type) - { - case ACPI_TYPE_NUMBER: - buffer = (u8 *) &val_desc->number.value; - length = sizeof (val_desc->number.value); - break; - - case ACPI_TYPE_BUFFER: - buffer = (u8 *) val_desc->buffer.pointer; - length = val_desc->buffer.length; - break; - - case ACPI_TYPE_STRING: - buffer = (u8 *) val_desc->string.pointer; - length = val_desc->string.length; - break; - } +ACPI_STATUS +acpi_aml_copy_integer_to_bank_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc) +{ + ACPI_STATUS status; + u8 locked; - /* - * Setting a string value replaces the old string - */ - if (length < dest_desc->string.length) { - /* - * Zero fill, not willing to do pointer arithmetic for - * architecture independence. Just clear the whole thing - */ - MEMSET(dest_desc->string.pointer, 0, dest_desc->string.length); - MEMCPY(dest_desc->string.pointer, buffer, length); - } - else { - /* - * Free the current buffer, then allocate a buffer - * large enough to hold the value - */ - if ( dest_desc->string.pointer && - !acpi_tb_system_table_pointer (dest_desc->string.pointer)) - { - /* - * Only free if not a pointer into the DSDT - */ + /* + * Get the global lock if needed + */ + locked = acpi_aml_acquire_global_lock (target_desc->index_field.lock_rule); - acpi_cm_free(dest_desc->string.pointer); - } - dest_desc->string.pointer = acpi_cm_allocate (length + 1); - dest_desc->string.length = length; + /* + * Set Bank value to select proper Bank + * Perform the update (Set Bank Select) + */ - if (!dest_desc->string.pointer) { - status = AE_NO_MEMORY; - goto clean_up_and_bail_out; - } + status = acpi_aml_access_named_field (ACPI_WRITE, + target_desc->bank_field.bank_select, + &target_desc->bank_field.value, + sizeof (target_desc->bank_field.value)); + if (ACPI_SUCCESS (status)) { + /* Set bank select successful, set data value */ + + status = acpi_aml_access_named_field (ACPI_WRITE, + target_desc->bank_field.bank_select, + &source_desc->bank_field.value, + sizeof (source_desc->bank_field.value)); + } - MEMCPY(dest_desc->string.pointer, buffer, length); - } - break; - case ACPI_TYPE_BUFFER: + /* + * Release global lock if we acquired it earlier + */ + acpi_aml_release_global_lock (locked); - /* - * Perform the update to the buffer - */ + return (status); +} - switch (val_desc->common.type) - { - case ACPI_TYPE_NUMBER: - buffer = (u8 *) &val_desc->number.value; - length = sizeof (val_desc->number.value); - break; - - case ACPI_TYPE_BUFFER: - buffer = (u8 *) val_desc->buffer.pointer; - length = val_desc->buffer.length; - break; - - case ACPI_TYPE_STRING: - buffer = (u8 *) val_desc->string.pointer; - length = val_desc->string.length; - break; - } - /* - * If the buffer is uninitialized, - * memory needs to be allocated for the copy. - */ - if(0 == dest_desc->buffer.length) { - dest_desc->buffer.pointer = acpi_cm_callocate(length); - dest_desc->buffer.length = length; - - if (!dest_desc->buffer.pointer) { - status = AE_NO_MEMORY; - goto clean_up_and_bail_out; - } - } +/******************************************************************************* + * + * FUNCTION: Acpi_aml_copy_data_to_named_field + * + * PARAMETERS: Source_desc - Source object to copy + * Node - Destination Namespace node + * + * RETURN: Status + * + * DESCRIPTION: Copy raw data to a Named Field. No implicit conversion + * is performed on the source object + * + ******************************************************************************/ - /* - * Buffer is a static allocation, - * only place what will fit in the buffer. - */ - if (length <= dest_desc->buffer.length) { - /* - * Zero fill first, not willing to do pointer arithmetic for - * architecture independence. Just clear the whole thing - */ - MEMSET(dest_desc->buffer.pointer, 0, dest_desc->buffer.length); - MEMCPY(dest_desc->buffer.pointer, buffer, length); - } - else { - /* - * truncate, copy only what will fit - */ - MEMCPY(dest_desc->buffer.pointer, buffer, dest_desc->buffer.length); - } - break; +ACPI_STATUS +acpi_aml_copy_data_to_named_field ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_NAMESPACE_NODE *node) +{ + ACPI_STATUS status; + u8 locked; + u32 length; + u8 *buffer; - case ACPI_TYPE_NUMBER: - dest_desc->number.value = val_desc->number.value; + /* + * Named fields (Create_xxx_field) - We don't perform any conversions on the + * source operand, just use the raw data + */ + switch (source_desc->common.type) + { + case ACPI_TYPE_INTEGER: + buffer = (u8 *) &source_desc->integer.value; + length = sizeof (source_desc->integer.value); + break; - /* Truncate value if we are executing from a 32-bit ACPI table */ + case ACPI_TYPE_BUFFER: + buffer = (u8 *) source_desc->buffer.pointer; + length = source_desc->buffer.length; + break; - acpi_aml_truncate_for32bit_table (dest_desc, walk_state); + case ACPI_TYPE_STRING: + buffer = (u8 *) source_desc->string.pointer; + length = source_desc->string.length; break; default: + return (AE_TYPE); + } - /* - * All other types than Alias and the various Fields come here. - * Store Val_desc as the new value of the Name, and set - * the Name's type to that of the value being stored in it. - * Val_desc reference count is incremented by Attach_object. - */ + /* + * Get the global lock if needed before the update + * TBD: not needed! + */ + locked = acpi_aml_acquire_global_lock (source_desc->field.lock_rule); - status = AE_NOT_IMPLEMENTED; - break; - } + status = acpi_aml_access_named_field (ACPI_WRITE, + node, buffer, length); -clean_up_and_bail_out: + acpi_aml_release_global_lock (locked); return (status); } + +/******************************************************************************* + * + * FUNCTION: Acpi_aml_copy_integer_to_field_unit + * + * PARAMETERS: Source_desc - Source object to copy + * Target_desc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Write an Integer to a Field Unit. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_aml_copy_integer_to_field_unit ( + ACPI_OPERAND_OBJECT *source_desc, + ACPI_OPERAND_OBJECT *target_desc) +{ + ACPI_STATUS status = AE_OK; + u8 *location = NULL; + u32 mask; + u32 new_value; + u8 locked = FALSE; + + + /* + * If the Field Buffer and Index have not been previously evaluated, + * evaluate them and save the results. + */ + if (!(target_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_field_unit_arguments (target_desc); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + if ((!target_desc->field_unit.container || + ACPI_TYPE_BUFFER != target_desc->field_unit.container->common.type)) + { + return (AE_AML_INTERNAL); + } + + /* + * Get the global lock if needed + */ + locked = acpi_aml_acquire_global_lock (target_desc->field_unit.lock_rule); + + /* + * TBD: [Unhandled] REMOVE this limitation + * Make sure the operation is within the limits of our implementation + * this is not a Spec limitation!! + */ + if (target_desc->field_unit.length + target_desc->field_unit.bit_offset > 32) { + return (AE_NOT_IMPLEMENTED); + } + + /* Field location is (base of buffer) + (byte offset) */ + + location = target_desc->field_unit.container->buffer.pointer + + target_desc->field_unit.offset; + + /* + * Construct Mask with 1 bits where the field is, + * 0 bits elsewhere + */ + mask = ((u32) 1 << target_desc->field_unit.length) - ((u32)1 + << target_desc->field_unit.bit_offset); + + /* Zero out the field in the buffer */ + + MOVE_UNALIGNED32_TO_32 (&new_value, location); + new_value &= ~mask; + + /* + * Shift and mask the new value into position, + * and or it into the buffer. + */ + new_value |= (source_desc->integer.value << target_desc->field_unit.bit_offset) & + mask; + + /* Store back the value */ + + MOVE_UNALIGNED32_TO_32 (location, &new_value); + + return (AE_OK); +} + + diff --git a/drivers/acpi/interpreter/amsystem.c b/drivers/acpi/interpreter/amsystem.c index 9ad72c161..5e60538af 100644 --- a/drivers/acpi/interpreter/amsystem.c +++ b/drivers/acpi/interpreter/amsystem.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amsystem - Interface to OS services - * $Revision: 52 $ + * $Revision: 54 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -202,7 +202,7 @@ acpi_aml_system_acquire_mutex ( } status = acpi_aml_system_wait_semaphore (obj_desc->mutex.semaphore, - (u32) time_desc->number.value); + (u32) time_desc->integer.value); return (status); } @@ -299,7 +299,7 @@ acpi_aml_system_wait_event ( if (obj_desc) { status = acpi_aml_system_wait_semaphore (obj_desc->event.semaphore, - (u32) time_desc->number.value); + (u32) time_desc->integer.value); } diff --git a/drivers/acpi/interpreter/amutils.c b/drivers/acpi/interpreter/amutils.c index 4e1359888..e3456099c 100644 --- a/drivers/acpi/interpreter/amutils.c +++ b/drivers/acpi/interpreter/amutils.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amutils - interpreter/scanner utilities - * $Revision: 66 $ + * $Revision: 68 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,14 +46,11 @@ typedef struct internal_search_st /* Used to traverse nested packages when copying*/ +/* TBD: This must be removed! */ INTERNAL_PKG_SEARCH_INFO copy_level[MAX_PACKAGE_DEPTH]; -static NATIVE_CHAR hex[] = - {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; - - /******************************************************************************* * * FUNCTION: Acpi_aml_enter_interpreter @@ -156,7 +153,7 @@ acpi_aml_truncate_for32bit_table ( */ if ((!obj_desc) || - (obj_desc->common.type != ACPI_TYPE_NUMBER) || + (obj_desc->common.type != ACPI_TYPE_INTEGER) || (!walk_state->method_node)) { return; @@ -167,7 +164,7 @@ acpi_aml_truncate_for32bit_table ( * We are running a method that exists in a 32-bit ACPI table. * Truncate the value to 32 bits by zeroing out the upper 32-bit field */ - obj_desc->number.value &= (ACPI_INTEGER) ACPI_UINT32_MAX; + obj_desc->integer.value &= (ACPI_INTEGER) ACPI_UINT32_MAX; } } @@ -343,10 +340,10 @@ acpi_aml_eisa_id_to_string ( out_string[0] = (char) ('@' + ((id >> 26) & 0x1f)); out_string[1] = (char) ('@' + ((id >> 21) & 0x1f)); out_string[2] = (char) ('@' + ((id >> 16) & 0x1f)); - out_string[3] = hex[(id >> 12) & 0xf]; - out_string[4] = hex[(id >> 8) & 0xf]; - out_string[5] = hex[(id >> 4) & 0xf]; - out_string[6] = hex[id & 0xf]; + out_string[3] = acpi_gbl_hex_to_ascii[(id >> 12) & 0xf]; + out_string[4] = acpi_gbl_hex_to_ascii[(id >> 8) & 0xf]; + out_string[5] = acpi_gbl_hex_to_ascii[(id >> 4) & 0xf]; + out_string[6] = acpi_gbl_hex_to_ascii[id & 0xf]; out_string[7] = 0; return (AE_OK); diff --git a/drivers/acpi/interpreter/amxface.c b/drivers/acpi/interpreter/amxface.c index fd589d39b..20cf9820e 100644 --- a/drivers/acpi/interpreter/amxface.c +++ b/drivers/acpi/interpreter/amxface.c @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: amxface - External interpreter interfaces - * $Revision: 22 $ + * $Revision: 24 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 27c02e22a..c2e6a71e0 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nsaccess - Top-level functions for accessing ACPI namespace - * $Revision: 117 $ + * $Revision: 119 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -117,9 +117,9 @@ acpi_ns_root_initialize (void) switch (init_val->type) { - case ACPI_TYPE_NUMBER: + case ACPI_TYPE_INTEGER: - obj_desc->number.value = + obj_desc->integer.value = (ACPI_INTEGER) STRTOUL (init_val->val, NULL, 10); break; @@ -239,7 +239,7 @@ acpi_ns_lookup ( ACPI_NAMESPACE_NODE **return_node) { ACPI_STATUS status; - ACPI_NAMESPACE_NODE *prefix_node; + ACPI_NAMESPACE_NODE *prefix_node; ACPI_NAMESPACE_NODE *current_node = NULL; ACPI_NAMESPACE_NODE *scope_to_push = NULL; ACPI_NAMESPACE_NODE *this_node = NULL; @@ -248,8 +248,7 @@ acpi_ns_lookup ( u8 null_name_path = FALSE; OBJECT_TYPE_INTERNAL type_to_check_for; OBJECT_TYPE_INTERNAL this_search_type; - - DEBUG_ONLY_MEMBERS (u32 i) + u32 local_flags = flags & ~NS_ERROR_IF_FOUND; if (!return_node) { @@ -437,6 +436,7 @@ acpi_ns_lookup ( this_search_type = ACPI_TYPE_ANY; if (!num_segments) { this_search_type = type; + local_flags = flags; } /* Pluck one ACPI name from the front of the pathname */ @@ -447,7 +447,7 @@ acpi_ns_lookup ( status = acpi_ns_search_and_enter (simple_name, walk_state, current_node, interpreter_mode, - this_search_type, flags, + this_search_type, local_flags, &this_node); if (ACPI_FAILURE (status)) { diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index 9f1d5377e..5cac5d111 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nsalloc - Namespace allocation and deletion utilities - * $Revision: 43 $ + * $Revision: 45 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index fbba7840c..6c040d22e 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -2,12 +2,12 @@ * * Module Name: nseval - Object evaluation interfaces -- includes control * method lookup and execution. - * $Revision: 79 $ + * $Revision: 81 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index ddacd7b8c..76b535205 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nsinit - namespace initialization - * $Revision: 9 $ + * $Revision: 12 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -239,7 +239,9 @@ acpi_ns_init_one_device ( status = acpi_cm_execute_STA (node, &flags); if (ACPI_FAILURE (status)) { - return (status); + /* Ignore error and move on to next device */ + + return (AE_OK); } info->num_STA++; @@ -260,12 +262,15 @@ acpi_ns_init_one_device ( } else if (ACPI_FAILURE (status)) { - return (status); + /* Ignore error and move on to next device */ + } else { + /* Count of successfull INIs */ + info->num_INI++; } - return (status); + return (AE_OK); } diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index 28a26376d..f0eaf273b 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nsload - namespace loading/expanding/contracting procedures - * $Revision: 33 $ + * $Revision: 35 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index faf8fe56a..c2fb49163 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nsnames - Name manipulation and search - * $Revision: 51 $ + * $Revision: 53 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index 6d41b91ce..493cb1317 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -2,12 +2,12 @@ * * Module Name: nsobject - Utilities for objects attached to namespace * table entries - * $Revision: 47 $ + * $Revision: 49 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -205,7 +205,7 @@ acpi_ns_attach_object ( case AML_ZERO_OP: case AML_ONES_OP: case AML_ONE_OP: case AML_BYTE_OP: case AML_WORD_OP: case AML_DWORD_OP: - obj_type = ACPI_TYPE_NUMBER; + obj_type = ACPI_TYPE_INTEGER; break; diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 001f57d9d..7a29e7542 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nssearch - Namespace search - * $Revision: 62 $ + * $Revision: 64 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,8 +70,6 @@ acpi_ns_search_node ( ACPI_NAMESPACE_NODE *next_node; - - /* * Search for name in this table, which is to say that we must search * for the name among the children of this object diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 593064dbb..11457b33f 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -2,12 +2,12 @@ * * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing * parents and siblings and Scope manipulation - * $Revision: 74 $ + * $Revision: 77 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index 3682266b3..cf84be326 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nswalk - Functions for walking the APCI namespace - * $Revision: 17 $ + * $Revision: 19 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index 2947f7f06..957481a6d 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -2,12 +2,12 @@ * * Module Name: nsxfname - Public interfaces to the ACPI subsystem * ACPI Namespace oriented interfaces - * $Revision: 73 $ + * $Revision: 75 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index d4432ee8a..742c5da66 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -2,12 +2,12 @@ * * Module Name: nsxfobj - Public interfaces to the ACPI subsystem * ACPI Object oriented interfaces - * $Revision: 75 $ + * $Revision: 78 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -695,4 +695,3 @@ acpi_get_devices ( return (status); } - diff --git a/drivers/acpi/os.c b/drivers/acpi/os.c index 7bf86171b..172b6659b 100644 --- a/drivers/acpi/os.c +++ b/drivers/acpi/os.c @@ -24,8 +24,8 @@ #include <linux/mm.h> #include <linux/pci.h> #include <linux/acpi.h> +#include <linux/delay.h> #include <asm/io.h> -#include <asm/delay.h> #include "acpi.h" #include "driver.h" diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index 35d623668..da3ef9b30 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psargs - Parse AML opcode arguments - * $Revision: 42 $ + * $Revision: 43 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index a7f061363..90a73f45b 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psopcode - Parser opcode information table - * $Revision: 24 $ + * $Revision: 27 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ #define _PFX 0x6D #define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */ -#define MAX_EXTENDED_OPCODE 0x87 +#define MAX_EXTENDED_OPCODE 0x88 #define NUM_EXTENDED_OPCODE MAX_EXTENDED_OPCODE + 1 #define MAX_INTERNAL_OPCODE #define NUM_INTERNAL_OPCODE MAX_INTERNAL_OPCODE + 1 @@ -83,9 +83,11 @@ #define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) #define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) #define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) +#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) #define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) #define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) #define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) +#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) #define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) #define ARGP_LOCAL0 ARG_NONE #define ARGP_LOCAL1 ARG_NONE @@ -122,6 +124,8 @@ #define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) #define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) #define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) #define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) @@ -131,12 +135,21 @@ #define ARGP_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) #define ARGP_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) #define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) #define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) #define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME) +#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_CONTINUE_OP ARG_NONE #define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) #define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) #define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) @@ -149,6 +162,7 @@ #define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) #define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) #define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) #define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) #define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) @@ -171,6 +185,7 @@ #define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) #define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) #define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAMESTRING, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) #define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) @@ -187,7 +202,7 @@ * All AML opcodes and the runtime arguments for each. Used by the AML interpreter Each list is compressed * into a 32-bit number and stored in the master opcode table at the end of this file. * - * (Used by Acpi_aml_prep_operands procedure) + * (Used by Acpi_aml_prep_operands procedure and the ASL Compiler) */ #define ARGI_ZERO_OP ARG_NONE @@ -198,9 +213,11 @@ #define ARGI_WORD_OP ARGI_INVALID_OPCODE #define ARGI_DWORD_OP ARGI_INVALID_OPCODE #define ARGI_STRING_OP ARGI_INVALID_OPCODE +#define ARGI_QWORD_OP ARGI_INVALID_OPCODE #define ARGI_SCOPE_OP ARGI_INVALID_OPCODE #define ARGI_BUFFER_OP ARGI_INVALID_OPCODE #define ARGI_PACKAGE_OP ARGI_INVALID_OPCODE +#define ARGI_VAR_PACKAGE_OP ARGI_INVALID_OPCODE #define ARGI_METHOD_OP ARGI_INVALID_OPCODE #define ARGI_LOCAL0 ARG_NONE #define ARGI_LOCAL1 ARG_NONE @@ -218,40 +235,51 @@ #define ARGI_ARG5 ARG_NONE #define ARGI_ARG6 ARG_NONE #define ARGI_STORE_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_TARGETREF) -#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_REFERENCE) -#define ARGI_ADD_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_TARGETREF) -#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_REFERENCE) -#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_REFERENCE) -#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF, ARGI_TARGETREF) -#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) +#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) +#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) +#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) +#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) +#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) +#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REFERENCE) -#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_REFERENCE, ARGI_NUMBER) +#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) +#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) #define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) -#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER) -#define ARGI_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE) -#define ARGI_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE) -#define ARGI_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE) -#define ARGI_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE) +#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) -#define ARGI_LAND_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER) -#define ARGI_LOR_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER) -#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_NUMBER) -#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER) -#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER) -#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER) +#define ARGI_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) +#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFERSTRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE #define ARGI_IF_OP ARGI_INVALID_OPCODE #define ARGI_ELSE_OP ARGI_INVALID_OPCODE #define ARGI_WHILE_OP ARGI_INVALID_OPCODE @@ -262,23 +290,24 @@ #define ARGI_ONES_OP ARG_NONE #define ARGI_MUTEX_OP ARGI_INVALID_OPCODE #define ARGI_EVENT_OP ARGI_INVALID_OPCODE -#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_REFERENCE, ARGI_TARGETREF) -#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_NUMBER, ARGI_NUMBER, ARGI_REFERENCE) +#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) +#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_TARGETREF) #define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION, ARGI_TARGETREF) -#define ARGI_STALL_OP ARGI_LIST1 (ARGI_NUMBER) -#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_NUMBER) -#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_NUMBER) +#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) #define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) -#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_NUMBER) +#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) #define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) #define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) -#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) #define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) #define ARGI_REVISION_OP ARG_NONE #define ARGI_DEBUG_OP ARG_NONE -#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER) -#define ARGI_REGION_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER) +#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) #define ARGI_DEF_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_DEVICE_OP ARGI_INVALID_OPCODE #define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE @@ -286,6 +315,7 @@ #define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE #define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) #define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE @@ -307,8 +337,8 @@ static ACPI_OPCODE_INFO aml_op_info[] = { /* Index Opcode Type Class Has Arguments? Name Parser Args Interpreter Args */ -/* 00 */ /* AML_ZERO_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Zero_op", ARGP_ZERO_OP, ARGI_ZERO_OP), -/* 01 */ /* AML_ONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "One_op", ARGP_ONE_OP, ARGI_ONE_OP), +/* 00 */ /* AML_ZERO_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Zero", ARGP_ZERO_OP, ARGI_ZERO_OP), +/* 01 */ /* AML_ONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "One", ARGP_ONE_OP, ARGI_ONE_OP), /* 02 */ /* AML_ALIAS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP), /* 03 */ /* AML_NAME_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Name", ARGP_NAME_OP, ARGI_NAME_OP), /* 04 */ /* AML_BYTE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP), @@ -337,7 +367,7 @@ static ACPI_OPCODE_INFO aml_op_info[] = /* 1_b */ /* AML_STORE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Store", ARGP_STORE_OP, ARGI_STORE_OP), /* 1_c */ /* AML_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP), /* 1_d */ /* AML_ADD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Add", ARGP_ADD_OP, ARGI_ADD_OP), -/* 1_e */ /* AML_CONCAT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concat", ARGP_CONCAT_OP, ARGI_CONCAT_OP), +/* 1_e */ /* AML_CONCAT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP), /* 1_f */ /* AML_SUBTRACT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP), /* 20 */ /* AML_INCREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP), /* 21 */ /* AML_DECREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP), @@ -376,7 +406,7 @@ static ACPI_OPCODE_INFO aml_op_info[] = /* 42 */ /* AML_RETURN_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Return", ARGP_RETURN_OP, ARGI_RETURN_OP), /* 43 */ /* AML_BREAK_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break", ARGP_BREAK_OP, ARGI_BREAK_OP), /* 44 */ /* AML_BREAK_POINT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP), -/* 45 */ /* AML_ONES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Ones_op", ARGP_ONES_OP, ARGI_ONES_OP), +/* 45 */ /* AML_ONES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Ones", ARGP_ONES_OP, ARGI_ONES_OP), /* Prefixed opcodes (Two-byte opcodes with a prefix op) */ @@ -402,7 +432,7 @@ static ACPI_OPCODE_INFO aml_op_info[] = /* 59 */ /* AML_DEF_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Field", ARGP_DEF_FIELD_OP, ARGI_DEF_FIELD_OP), /* 5_a */ /* AML_DEVICE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP), /* 5_b */ /* AML_PROCESSOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP), -/* 5_c */ /* AML_POWER_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Power_res", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP), +/* 5_c */ /* AML_POWER_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Power_resource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP), /* 5_d */ /* AML_THERMAL_ZONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP), /* 5_e */ /* AML_INDEX_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP), /* 5_f */ /* AML_BANK_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP), @@ -423,6 +453,26 @@ static ACPI_OPCODE_INFO aml_op_info[] = /* 6_b */ /* UNKNOWN OPCODES */ OP_INFO_ENTRY (ACPI_OP_TYPE_UNKNOWN | OPTYPE_BOGUS| AML_HAS_ARGS, "UNKNOWN_OP!", ARG_NONE, ARG_NONE), /* 6_c */ /* ASCII CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_ASCII | OPTYPE_BOGUS| AML_HAS_ARGS, "ASCII_ONLY!", ARG_NONE, ARG_NONE), /* 6_d */ /* PREFIX CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_PREFIX | OPTYPE_BOGUS| AML_HAS_ARGS, "PREFIX_ONLY!", ARG_NONE, ARG_NONE), + + +/* ACPI 2.0 (new) opcodes */ + +/* 6_e */ /* AML_QWORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Qword_const", ARGP_QWORD_OP, ARGI_QWORD_OP), +/* 6_f */ /* AML_VAR_PACKAGE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Var_package", ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP), +/* 70 */ /* AML_CONCAT_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concat_res", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP), +/* 71 */ /* AML_MOD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Mod", ARGP_MOD_OP, ARGI_MOD_OP), +/* 72 */ /* AML_QWORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_qWord_field", ARGP_QWORD_FIELD_OP, ARGI_QWORD_FIELD_OP), +/* 73 */ /* AML_TO_BUFFER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_buffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP), +/* 74 */ /* AML_TO_DEC_STR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_dec_string", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP), +/* 75 */ /* AML_TO_HEX_STR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_hex_string", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP), +/* 76 */ /* AML_TO_INTEGER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_integer", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP), +/* 77 */ /* AML_TO_STRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_string", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP), +/* 78 */ /* AML_COPY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Copy", ARGP_COPY_OP, ARGI_COPY_OP), +/* 79 */ /* AML_MID_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Mid", ARGP_MID_OP, ARGI_MID_OP), +/* 7_a */ /* AML_CONTINUE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP), +/* 7_b */ /* AML_LOAD_TABLE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Load_table", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP), +/* 7_c */ /* AML_DATA_REGION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Data_op_region", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP), + }; /* @@ -433,9 +483,10 @@ static ACPI_OPCODE_INFO aml_op_info[] = static u8 aml_short_op_info_index[256] = { /* 0 1 2 3 4 5 6 7 */ +/* 8 9 A B C D E F */ /* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK, -/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, _UNK, _UNK, -/* 0x10 */ 0x08, 0x09, 0x0a, _UNK, 0x0b, _UNK, _UNK, _UNK, +/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK, +/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK, /* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, @@ -449,10 +500,10 @@ static u8 aml_short_op_info_index[256] = /* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK, /* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, /* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, -/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, _UNK, _UNK, 0x2f, 0x30, -/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, _UNK, -/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, _UNK, _UNK, -/* 0x98 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30, +/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72, +/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74, +/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A, /* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, /* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, @@ -471,10 +522,11 @@ static u8 aml_short_op_info_index[256] = static u8 aml_long_op_info_index[NUM_EXTENDED_OPCODE] = { /* 0 1 2 3 4 5 6 7 */ +/* 8 9 A B C D E F */ /* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK, -/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B, /* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, /* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x30 */ 0x55, 0x56, 0x57, _UNK, _UNK, _UNK, _UNK, _UNK, @@ -488,13 +540,10 @@ static u8 aml_long_op_info_index[NUM_EXTENDED_OPCODE] = /* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, +/* 0x88 */ 0x7C, }; -/* 0 1 2 3 4 5 6 7 */ -/* 0x00 */ - - /******************************************************************************* * * FUNCTION: Acpi_ps_get_opcode_info diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index 7471efdcb..7373013da 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines - * $Revision: 71 $ + * $Revision: 74 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -537,6 +537,12 @@ acpi_ps_parse_loop ( */ status = acpi_ds_get_predicate_value (walk_state, NULL, TRUE); + if (ACPI_FAILURE (status) && + ((status & AE_CODE_MASK) != AE_CODE_CONTROL)) + { + return (status); + } + status = acpi_ps_next_parse_state (walk_state, op, status); } diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index 2e8926ad1..37b5d2265 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psscope - Parser scope stack management routines - * $Revision: 22 $ + * $Revision: 24 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index a22bb646d..dc2e6d4d7 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: pstree - Parser op tree manipulation/traversal/search - * $Revision: 25 $ + * $Revision: 27 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index 3bac4a647..94518a920 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psutils - Parser miscellaneous utilities (Parser only) - * $Revision: 30 $ + * $Revision: 32 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index 04a75917d..48c11eff3 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: pswalk - Parser routines to walk parsed op tree(s) - * $Revision: 50 $ + * $Revision: 52 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index a33ace051..328c755d9 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psxface - Parser external interfaces - * $Revision: 37 $ + * $Revision: 40 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -121,6 +121,12 @@ acpi_psx_execute ( return (AE_NO_MEMORY); } + + /* Init new op with the method name and pointer back to the NS node */ + + acpi_ps_set_name (op, method_node->name); + op->node = method_node; + /* * The walk of the parse tree is where we actually execute the method */ diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0422bf94d..d24392895 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -81,12 +81,12 @@ proc_read_ac_adapter_status(char *page, char **start, off_t off, buf.length = sizeof(obj); buf.pointer = &obj; if (!ACPI_SUCCESS(acpi_evaluate_object(ac_handle, "_PSR", NULL, &buf)) - || obj.type != ACPI_TYPE_NUMBER) { + || obj.type != ACPI_TYPE_INTEGER) { p += sprintf(p, "Could not read AC status\n"); goto end; } - if (obj.number.value) + if (obj.integer.value) p += sprintf(p, "on-line\n"); else p += sprintf(p, "off-line\n"); diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c index e48666113..af91bc59f 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/resources/rsaddr.c @@ -4,12 +4,12 @@ * Acpi_rs_address16_stream * Acpi_rs_address32_resource * Acpi_rs_address32_stream - * $Revision: 12 $ + * $Revision: 14 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 2874aa3d0..86ff91be8 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -2,12 +2,12 @@ * * Module Name: rscalc - Acpi_rs_calculate_byte_stream_length * Acpi_rs_calculate_list_length - * $Revision: 16 $ + * $Revision: 18 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index bc95686a7..f221a41dc 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -3,12 +3,12 @@ * Module Name: rscreate - Acpi_rs_create_resource_list * Acpi_rs_create_pci_routing_table * Acpi_rs_create_byte_stream - * $Revision: 22 $ + * $Revision: 24 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -223,9 +223,9 @@ acpi_rs_create_pci_routing_table ( /* * Dereference the Address */ - if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) { + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { user_prt->data.address = - (*sub_object_list)->number.value; + (*sub_object_list)->integer.value; } else { @@ -237,9 +237,9 @@ acpi_rs_create_pci_routing_table ( */ sub_object_list++; - if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) { + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { user_prt->data.pin = - (u32) (*sub_object_list)->number.value; + (u32) (*sub_object_list)->integer.value; } else { @@ -267,7 +267,7 @@ acpi_rs_create_pci_routing_table ( * is NULL, since the entire buffer was zeroed * out, we can leave this alone. */ - if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) { + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { /* * Add to the Length field the length of * the u32 NULL @@ -289,9 +289,9 @@ acpi_rs_create_pci_routing_table ( */ sub_object_list++; - if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) { + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { user_prt->data.source_index = - (u32) (*sub_object_list)->number.value; + (u32) (*sub_object_list)->integer.value; } else { diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index 073f4ddd4..03d2da6f2 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsdump - Functions do dump out the resource structures. - * $Revision: 13 $ + * $Revision: 15 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c index 0d6c507c0..58fcf8cd8 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/resources/rsio.c @@ -6,12 +6,12 @@ * Acpi_rs_fixed_io_stream * Acpi_rs_dma_resource * Acpi_rs_dma_stream - * $Revision: 10 $ + * $Revision: 12 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c index 28a3a5045..eb47669ad 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/resources/rsirq.c @@ -4,12 +4,12 @@ * Acpi_rs_irq_stream * Acpi_rs_extended_irq_resource * Acpi_rs_extended_irq_stream - * $Revision: 11 $ + * $Revision: 13 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 8e39ddded..de47563d0 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -2,12 +2,12 @@ * * Module Name: rslist - Acpi_rs_byte_stream_to_list * Acpi_list_to_byte_stream - * $Revision: 8 $ + * $Revision: 10 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c index 8aa4914f4..f9437e60c 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/resources/rsmemory.c @@ -6,12 +6,12 @@ * Acpi_rs_fixed_memory32_resource * Acpi_rs_memory32_range_stream * Acpi_rs_fixed_memory32_stream - * $Revision: 10 $ + * $Revision: 12 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index 01bbb377e..be0a1a6a0 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -8,12 +8,12 @@ * Acpi_rs_end_dependent_functions_resource * Acpi_rs_start_dependent_functions_stream * Acpi_rs_end_dependent_functions_stream - * $Revision: 10 $ + * $Revision: 12 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index 0a3f76668..2994bf0d3 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsutils - Utilities for the resource manager - * $Revision: 12 $ + * $Revision: 14 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 8691f8200..5c126aaa5 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsxface - Public interfaces to the ACPI subsystem - * $Revision: 8 $ + * $Revision: 10 $ * ******************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/sys.c b/drivers/acpi/sys.c index 13648c255..2011174a1 100644 --- a/drivers/acpi/sys.c +++ b/drivers/acpi/sys.c @@ -27,18 +27,13 @@ #define _COMPONENT OS_DEPENDENT MODULE_NAME ("sys") -#define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb)) -#define ACPI_SLP_TYPA(value) ((value) >> 8) -#define ACPI_SLP_TYPB(value) ((value) & 0xff) - struct acpi_enter_sx_ctx { wait_queue_head_t wait; unsigned int state; }; -volatile acpi_sstate_t acpi_sleep_state = ACPI_S0; -static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,}; +volatile acpi_sstate_t acpi_sleep_state = ACPI_STATE_S0; /* * Enter system sleep state @@ -50,56 +45,32 @@ acpi_enter_sx_async(void *context) ACPI_OBJECT_LIST arg_list; ACPI_OBJECT arg; - /* - * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. - */ - - // run the _PTS method - memset(&arg_list, 0, sizeof(arg_list)); - arg_list.count = 1; - arg_list.pointer = &arg; - - memset(&arg, 0, sizeof(arg)); - arg.type = ACPI_TYPE_NUMBER; - arg.number.value = ctx->state; + acpi_enter_sleep_state(ctx->state); - acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL); - - // clear wake status by writing a 1 - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, WAK_STS, 1); - - acpi_sleep_state = ctx->state; - - // set ACPI_SLP_TYPA/b and ACPI_SLP_EN - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, SLP_TYPE_A, - ACPI_SLP_TYPA(acpi_slptyp[ctx->state])); - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, SLP_TYPE_B, - ACPI_SLP_TYPB(acpi_slptyp[ctx->state])); - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, SLP_EN, 1); - - if (ctx->state != ACPI_S1) { - /* we should have just shut off - what are we doing here? */ - printk(KERN_ERR "ACPI: S%d failed\n", ctx->state); + /* either we are in S1, or the transition failed, as the other states resume + from the waking vector */ + if (ctx->state != ACPI_STATE_S1) { + printk(KERN_ERR "Could not enter S%d\n", ctx->state); goto out; } - // wait until S1 is entered + /* wait until S1 is entered */ while (!(acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, WAK_STS))) safe_halt(); - // run the _WAK method + /* run the _WAK method */ memset(&arg_list, 0, sizeof(arg_list)); arg_list.count = 1; arg_list.pointer = &arg; memset(&arg, 0, sizeof(arg)); - arg.type = ACPI_TYPE_NUMBER; - arg.number.value = ctx->state; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = ctx->state; acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL); out: - acpi_sleep_state = ACPI_S0; + acpi_sleep_state = ACPI_STATE_S0; if (waitqueue_active(&ctx->wait)) wake_up_interruptible(&ctx->wait); @@ -112,13 +83,9 @@ static void acpi_power_off(void) { struct acpi_enter_sx_ctx ctx; - - if ((STRNCMP(acpi_fadt.header.signature, ACPI_FADT_SIGNATURE, ACPI_SIG_LEN) != 0) - || acpi_slptyp[ACPI_S5] == ACPI_INVALID) - return; init_waitqueue_head(&ctx.wait); - ctx.state = ACPI_S5; + ctx.state = ACPI_STATE_S5; acpi_enter_sx_async(&ctx); } @@ -132,10 +99,6 @@ acpi_enter_sx(acpi_sstate_t state) DECLARE_WAITQUEUE(wait, current); int ret = 0; - if ((STRNCMP(acpi_fadt.header.signature, ACPI_FADT_SIGNATURE, ACPI_SIG_LEN) != 0) - || acpi_slptyp[state] == ACPI_INVALID) - return -EINVAL; - init_waitqueue_head(&ctx.wait); ctx.state = state; @@ -166,19 +129,14 @@ acpi_sys_init(void) printk(KERN_INFO "ACPI: System firmware supports:"); - for (sx = ACPI_S0; sx <= ACPI_S5; sx++) { - int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1); + for (sx = ACPI_STATE_S0; sx <= ACPI_STATE_S5; sx++) { if (ACPI_SUCCESS( - acpi_hw_obtain_sleep_type_register_data(ca_sx, + acpi_hw_obtain_sleep_type_register_data(sx, &type_a, &type_b))) { - acpi_slptyp[sx] = ACPI_SLP_TYP(type_a, type_b); printk(" S%d", sx); } - else { - acpi_slptyp[sx] = ACPI_INVALID; - } } printk("\n"); diff --git a/drivers/acpi/table.c b/drivers/acpi/table.c index 8379b4204..de0f99a27 100644 --- a/drivers/acpi/table.c +++ b/drivers/acpi/table.c @@ -47,21 +47,6 @@ acpi_fetch_fadt(void) return -ENODEV; } - if (acpi_fadt.plvl2_lat - && acpi_fadt.plvl2_lat <= ACPI_MAX_P_LVL2_LAT) { - acpi_c2_exit_latency - = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl2_lat); - acpi_c2_enter_latency - = ACPI_MICROSEC_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); - } - if (acpi_fadt.plvl3_lat - && acpi_fadt.plvl3_lat <= ACPI_MAX_P_LVL3_LAT) { - acpi_c3_exit_latency - = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl3_lat); - acpi_c3_enter_latency - = ACPI_MICROSEC_TO_TMR_TICKS(acpi_fadt.plvl3_lat * 5); - } - return 0; } @@ -71,11 +56,7 @@ acpi_fetch_fadt(void) int acpi_find_and_load_tables(u64 rsdp) { - if (ACPI_SUCCESS(acpi_load_tables(rsdp))) - { - printk(KERN_INFO "ACPI: System description tables loaded\n"); - } - else { + if (!ACPI_SUCCESS(acpi_load_tables(rsdp))) { printk(KERN_INFO "ACPI: System description table load failed\n"); acpi_terminate(); return -1; diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 624926d27..76d7fff15 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbconvrt - ACPI Table conversion utilities - * $Revision: 15 $ + * $Revision: 18 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ a.register_bit_width = (u8) MUL_8 (b);\ a.register_bit_offset = 0;\ a.reserved = 0;\ - a.address = (UINT64) c;} + ACPI_STORE_ADDRESS (a.address,c);} /* ACPI V1.0 entries -- address space is always I/O */ @@ -126,8 +126,8 @@ acpi_tb_convert_to_xsdt ( new_table->table_offset_entry[i] = ((RSDT_DESCRIPTOR_REV071 *) table_info->pointer)->table_offset_entry[i]; #else - new_table->table_offset_entry[i] = - ((RSDT_DESCRIPTOR_REV1 *) table_info->pointer)->table_offset_entry[i]; + ACPI_STORE_ADDRESS (new_table->table_offset_entry[i], + ((RSDT_DESCRIPTOR_REV1 *) table_info->pointer)->table_offset_entry[i]); #endif } else { @@ -312,11 +312,11 @@ acpi_tb_convert_table_fadt (void) /* No 0.71 equivalence. Leave pre-zeroed. */ /* FADT2->Flush_stride = 0; */ - /* Processor’s duty cycle index in processor's P_CNT reg*/ + /* Processor's duty cycle index in processor's P_CNT reg*/ /* No 0.71 equivalence. Leave pre-zeroed. */ /* FADT2->Duty_offset = 0; */ - /* Processor’s duty cycle value bit width in P_CNT register.*/ + /* Processor's duty cycle value bit width in P_CNT register.*/ /* No 0.71 equivalence. Leave pre-zeroed. */ /* FADT2->Duty_width = 0; */ @@ -384,8 +384,8 @@ acpi_tb_convert_table_fadt (void) /* Convert table pointers to 64-bit fields */ - FADT2->Xfirmware_ctrl = (UINT64) FADT1->firmware_ctrl; - FADT2->Xdsdt = (UINT64) FADT1->dsdt; + ACPI_STORE_ADDRESS (FADT2->Xfirmware_ctrl, FADT1->firmware_ctrl); + ACPI_STORE_ADDRESS (FADT2->Xdsdt, FADT1->dsdt); /* System Interrupt Model isn't used in ACPI 2.0*/ /* FADT2->Reserved1 = 0; */ @@ -448,6 +448,7 @@ acpi_tb_convert_table_fadt (void) * Global FADT pointer will point to the common V2.0 FADT */ acpi_gbl_FADT = FADT2; + acpi_gbl_FADT->header.length = sizeof (FADT_DESCRIPTOR); /* Free the original table */ @@ -464,8 +465,6 @@ acpi_tb_convert_table_fadt (void) table_desc->length = sizeof (FADT_DESCRIPTOR_REV2); - /* Dump the FADT Header */ - /* Dump the entire FADT */ diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 2cf8eede7..8e05e2c7d 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbget - ACPI Table get* routines - * $Revision: 40 $ + * $Revision: 43 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -243,7 +243,7 @@ acpi_tb_get_all_tables ( /* Get the table via the XSDT */ status = acpi_tb_get_table ((ACPI_PHYSICAL_ADDRESS) - acpi_gbl_XSDT->table_offset_entry[index], + ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[index]), table_ptr, &table_info); /* Ignore a table that failed verification */ @@ -326,7 +326,8 @@ acpi_tb_get_all_tables ( * Get the DSDT (We know that the FADT is valid now) */ - status = acpi_tb_get_table (acpi_gbl_FADT->Xdsdt, table_ptr, &table_info); + status = acpi_tb_get_table ((ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt), + table_ptr, &table_info); if (ACPI_FAILURE (status)) { return (status); } @@ -472,13 +473,14 @@ acpi_tb_get_table_rsdt ( /* 0.71 RSDP has 64bit Rsdt address field */ physical_address = ((RSDP_DESCRIPTOR_REV071 *)acpi_gbl_RSDP)->rsdt_physical_address; #else - physical_address = acpi_gbl_RSDP->rsdt_physical_address; + physical_address = (ACPI_PHYSICAL_ADDRESS) acpi_gbl_RSDP->rsdt_physical_address; #endif table_signature = RSDT_SIG; signature_length = sizeof (RSDT_SIG) -1; } else { - physical_address = (ACPI_PHYSICAL_ADDRESS) acpi_gbl_RSDP->xsdt_physical_address; + physical_address = (ACPI_PHYSICAL_ADDRESS) + ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address); table_signature = XSDT_SIG; signature_length = sizeof (XSDT_SIG) -1; } @@ -586,7 +588,7 @@ acpi_tb_get_table_facs ( else { /* Just map the physical memory to our address space */ - status = acpi_tb_map_acpi_table (acpi_gbl_FADT->Xfirmware_ctrl, + status = acpi_tb_map_acpi_table ((ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl), &size, &table_ptr); if (ACPI_FAILURE(status)) { return (status); diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index b3926a0e3..e753917b7 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbinstal - ACPI table installation and removal - * $Revision: 34 $ + * $Revision: 36 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index baae6fb4c..d89b1508c 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbutils - Table manipulation utilities - * $Revision: 31 $ + * $Revision: 33 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index ee9eba62a..98c99873c 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -2,12 +2,12 @@ * * Module Name: tbxface - Public interfaces to the ACPI subsystem * ACPI table oriented interfaces - * $Revision: 32 $ + * $Revision: 34 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 4c31f1c37..606e8ad10 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbxfroot - Find the root ACPI table (RSDT) - * $Revision: 33 $ + * $Revision: 35 $ * *****************************************************************************/ /* - * Copyright (C) 2000 R. Byron Moore + * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 2157f1570..5b602f9ba 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -46,7 +46,7 @@ ifeq ($(CONFIG_ATM_FORE200E_SBA),y) endif endif -obj-$(CONFIG_ATM_FORE200E) += fore200e.o $(FORE200E_FW_OBJS) +obj-$(CONFIG_ATM_FORE200E) += fore_200e.o EXTRA_CFLAGS=-g diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 5e8dc19f9..d0aac4c7d 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -1820,7 +1820,6 @@ static int DAC960_BackMergeFunction(RequestQueue_T *RequestQueue, Request->nr_segments < Controller->DriverScatterGatherLimit) { Request->nr_segments++; - RequestQueue->elevator.nr_segments++; return true; } return false; @@ -1844,7 +1843,6 @@ static int DAC960_FrontMergeFunction(RequestQueue_T *RequestQueue, Request->nr_segments < Controller->DriverScatterGatherLimit) { Request->nr_segments++; - RequestQueue->elevator.nr_segments++; return true; } return false; @@ -1864,17 +1862,12 @@ static int DAC960_MergeRequestsFunction(RequestQueue_T *RequestQueue, DAC960_Controller_T *Controller = (DAC960_Controller_T *) RequestQueue->queuedata; int TotalSegments = Request->nr_segments + NextRequest->nr_segments; - int SameSegment = 0; if (Request->bhtail->b_data + Request->bhtail->b_size == NextRequest->bh->b_data) - { TotalSegments--; - SameSegment = 1; - } if (TotalSegments > MaxSegments || TotalSegments > Controller->DriverScatterGatherLimit) return false; - RequestQueue->elevator.nr_segments -= SameSegment; Request->nr_segments = TotalSegments; return true; } @@ -2834,6 +2827,7 @@ static void DAC960_RequestFunction(RequestQueue_T *RequestQueue) static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader, boolean SuccessfulIO) { + blk_finished_io(BufferHeader->b_size >> 9); BufferHeader->b_end_io(BufferHeader, SuccessfulIO); } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 35afe2a7f..47937edcc 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1086,6 +1086,7 @@ static inline void complete_buffers( struct buffer_head *bh, int status) { xbh = bh->b_reqnext; bh->b_reqnext = NULL; + blk_finished_io(bh->b_size >> 9); bh->b_end_io(bh, status); bh = xbh; } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index afbf60ddc..7016cfff4 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -140,23 +140,7 @@ static int ida_release(struct inode *inode, struct file *filep); static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io); -static void do_ida_request(int i); -/* - * This is a hack. This driver eats a major number for each controller, and - * sets blkdev[xxx].request_fn to each one of these so the real request - * function knows what controller its working with. - */ -#define DO_IDA_REQUEST(x) { do_ida_request(x); } - -static void do_ida_request0(request_queue_t * q) DO_IDA_REQUEST(0); -static void do_ida_request1(request_queue_t * q) DO_IDA_REQUEST(1); -static void do_ida_request2(request_queue_t * q) DO_IDA_REQUEST(2); -static void do_ida_request3(request_queue_t * q) DO_IDA_REQUEST(3); -static void do_ida_request4(request_queue_t * q) DO_IDA_REQUEST(4); -static void do_ida_request5(request_queue_t * q) DO_IDA_REQUEST(5); -static void do_ida_request6(request_queue_t * q) DO_IDA_REQUEST(6); -static void do_ida_request7(request_queue_t * q) DO_IDA_REQUEST(7); - +static void do_ida_request(request_queue_t *q); static void start_io(ctlr_info_t *h); static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c); @@ -362,6 +346,47 @@ void cleanup_module(void) } #endif /* MODULE */ +static inline int cpq_new_segment(request_queue_t *q, struct request *rq, + int max_segments) +{ + if (rq->nr_segments < SG_MAX) { + rq->nr_segments++; + return 1; + } + return 0; +} + +static int cpq_back_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segments) +{ + if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data) + return 1; + return cpq_new_segment(q, rq, max_segments); +} + +static int cpq_front_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segments) +{ + if (bh->b_data + bh->b_size == rq->bh->b_data) + return 1; + return cpq_new_segment(q, rq, max_segments); +} + +static int cpq_merge_requests_fn(request_queue_t *q, struct request *rq, + struct request *nxt, int max_segments) +{ + int total_segments = rq->nr_segments + nxt->nr_segments; + + if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data) + total_segments--; + + if (total_segments > SG_MAX) + return 0; + + rq->nr_segments = total_segments; + return 1; +} + /* * This is it. Find all the controllers and register them. I really hate * stealing all these major device numbers. @@ -369,12 +394,7 @@ void cleanup_module(void) */ int __init cpqarray_init(void) { - void (*request_fns[MAX_CTLR])(request_queue_t *) = { - do_ida_request0, do_ida_request1, - do_ida_request2, do_ida_request3, - do_ida_request4, do_ida_request5, - do_ida_request6, do_ida_request7, - }; + request_queue_t *q; int i,j; int num_cntlrs_reg = 0; @@ -495,16 +515,20 @@ int __init cpqarray_init(void) hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); - ida_procinit(i); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), - request_fns[i]); - blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0); + q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); + q->queuedata = hba[i]; + blk_init_queue(q, do_ida_request); + blk_queue_headactive(q, 0); blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); read_ahead[MAJOR_NR+i] = READ_AHEAD; + q->back_merge_fn = cpq_back_merge_fn; + q->front_merge_fn = cpq_front_merge_fn; + q->merge_requests_fn = cpq_merge_requests_fn; + ida_gendisk[i].major = MAJOR_NR + i; ida_gendisk[i].major_name = "ida"; ida_gendisk[i].minor_shift = NWD_SHIFT; @@ -872,37 +896,30 @@ static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c) * are in here (either via the dummy do_ida_request functions or by being * called from the interrupt handler */ -static void do_ida_request(int ctlr) +static void do_ida_request(request_queue_t *q) { - ctlr_info_t *h = hba[ctlr]; + ctlr_info_t *h = q->queuedata; cmdlist_t *c; int seg, sect; char *lastdataend; - struct list_head * queue_head; + struct list_head * queue_head = &q->queue_head; struct buffer_head *bh; struct request *creq; - queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head; - - if (list_empty(queue_head)) - { + if (q->plugged || list_empty(queue_head)) { start_io(h); return; } creq = blkdev_entry_next_request(queue_head); - if (creq->rq_status == RQ_INACTIVE) - { - start_io(h); - return; - } - + if (creq->nr_segments > SG_MAX) + BUG(); - if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || - ctlr > nr_ctlr || h == NULL) + if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr) { printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", - ctlr, creq->rq_dev, creq); + h->ctlr, creq->rq_dev, creq); + blkdev_dequeue_request(creq); complete_buffers(creq->bh, 0); start_io(h); return; @@ -916,12 +933,12 @@ static void do_ida_request(int ctlr) bh = creq->bh; - c->ctlr = ctlr; + c->ctlr = h->ctlr; c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT; c->hdr.size = sizeof(rblk_t) >> 2; c->size += sizeof(rblk_t); - c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector; + c->req.hdr.blk = ida[(h->ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector; c->bh = bh; DBGPX( if (bh == NULL) @@ -933,21 +950,16 @@ DBGPX( sect = 0; while(bh) { sect += bh->b_size/512; -DBGPX( - if (bh->b_size % 512) { - printk("Oh damn. %d+%d, size = %d\n", creq->sector, sect, bh->b_size); - panic("b_size %% 512 != 0"); - } -); if (bh->b_data == lastdataend) { c->req.sg[seg-1].size += bh->b_size; lastdataend += bh->b_size; } else { + if (seg == SG_MAX) + BUG(); c->req.sg[seg].size = bh->b_size; c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data); lastdataend = bh->b_data + bh->b_size; - if (++seg == SG_MAX) - break; + seg++; } bh = bh->b_reqnext; } @@ -955,30 +967,24 @@ DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); ); c->req.hdr.sg_cnt = seg; c->req.hdr.blk_cnt = sect; - creq->sector += sect; - creq->nr_sectors -= sect; - - /* Ready the next request: - * Fix up creq if we still have more buffers in the buffer chain, or - * mark this request as done and ready the next one. + /* + * Since we control our own merging, we know that this request + * is now fully setup and there's nothing left. */ - if (creq->nr_sectors) { -DBGPX( - if (bh==NULL) { - printk("sector=%d, nr_sectors=%d, sect=%d, seg=%d\n", - creq->sector, creq->nr_sectors, sect, seg); - panic("mother..."); - } -); - creq->bh = bh->b_reqnext; - bh->b_reqnext = NULL; -DBGPX( printk("More to do on same request %p\n", creq); ); - } else { -DBGPX( printk("Done with %p\n", creq); ); - blkdev_dequeue_request(creq); - end_that_request_last(creq); + if (creq->nr_sectors != sect) { + printk("ida: %ld != %d sectors\n", creq->nr_sectors, sect); + BUG(); } + blkdev_dequeue_request(creq); + + /* + * ehh, we can't really end the request here since it's not + * even started yet. for now it shouldn't hurt though + */ +DBGPX( printk("Done with %p\n", creq); ); + end_that_request_last(creq); + c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE; c->type = CMD_RWREQ; @@ -1025,6 +1031,7 @@ static inline void complete_buffers(struct buffer_head *bh, int ok) xbh = bh->b_reqnext; bh->b_reqnext = NULL; + blk_finished_io(bh->b_size >> 9); bh->b_end_io(bh, ok); bh = xbh; @@ -1072,7 +1079,6 @@ static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) unsigned long flags; __u32 a,a1; - istat = h->access.intr_pending(h); /* Is this interrupt for us? */ if (istat == 0) @@ -1116,7 +1122,7 @@ static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) /* * See if we can queue up some more IO */ - do_ida_request(h->ctlr); + do_ida_request(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr)); spin_unlock_irqrestore(&io_request_lock, flags); } diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 1200773c2..9917ad055 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -24,125 +24,115 @@ #include <linux/blkdev.h> #include <linux/elevator.h> #include <linux/blk.h> +#include <linux/module.h> #include <asm/uaccess.h> -/* - * Order ascending, but only allow a request to be skipped a certain - * number of times - */ -void elevator_linus(struct request *req, elevator_t *elevator, - struct list_head *real_head, - struct list_head *head, int orig_latency) -{ - struct list_head *entry = real_head; - struct request *tmp; - - req->elevator_sequence = orig_latency; - - while ((entry = entry->prev) != head) { - tmp = blkdev_entry_to_request(entry); - if (IN_ORDER(tmp, req)) - break; - if (!tmp->elevator_sequence) - break; - tmp->elevator_sequence--; - } - list_add(&req->queue, entry); -} - int elevator_linus_merge(request_queue_t *q, struct request **req, + struct list_head * head, struct buffer_head *bh, int rw, - int *max_sectors, int *max_segments) + int max_sectors, int max_segments) { - struct list_head *entry, *head = &q->queue_head; + struct list_head *entry = &q->queue_head; unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE; - entry = head; - if (q->head_active && !q->plugged) - head = head->next; - while ((entry = entry->prev) != head) { - struct request *__rq = *req = blkdev_entry_to_request(entry); + struct request *__rq = blkdev_entry_to_request(entry); + + /* + * simply "aging" of requests in queue + */ + if (__rq->elevator_sequence-- <= 0) { + *req = __rq; + break; + } + if (__rq->sem) continue; if (__rq->cmd != rw) continue; - if (__rq->nr_sectors + count > *max_sectors) - continue; if (__rq->rq_dev != bh->b_rdev) continue; + if (__rq->nr_sectors + count > max_sectors) + continue; + if (__rq->elevator_sequence < count) + break; if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { ret = ELEVATOR_BACK_MERGE; + *req = __rq; break; - } - if (!__rq->elevator_sequence) - break; - if (__rq->sector - count == bh->b_rsector) { - __rq->elevator_sequence--; + } else if (__rq->sector - count == bh->b_rsector) { ret = ELEVATOR_FRONT_MERGE; + __rq->elevator_sequence -= count; + *req = __rq; break; - } + } else if (!*req && BHRQ_IN_ORDER(bh, __rq)) + *req = __rq; } + return ret; +} + +void elevator_linus_merge_cleanup(request_queue_t *q, struct request *req, int count) +{ + struct list_head *entry = &req->queue, *head = &q->queue_head; + /* * second pass scan of requests that got passed over, if any */ - if (ret != ELEVATOR_NO_MERGE && *req) { - while ((entry = entry->next) != &q->queue_head) { - struct request *tmp = blkdev_entry_to_request(entry); - tmp->elevator_sequence--; - } + while ((entry = entry->next) != head) { + struct request *tmp = blkdev_entry_to_request(entry); + tmp->elevator_sequence -= count; } - - return ret; } -/* - * No request sorting, just add it to the back of the list - */ -void elevator_noop(struct request *req, elevator_t *elevator, - struct list_head *real_head, struct list_head *head, - int orig_latency) +void elevator_linus_merge_req(struct request *req, struct request *next) { - list_add_tail(&req->queue, real_head); + if (next->elevator_sequence < req->elevator_sequence) + req->elevator_sequence = next->elevator_sequence; } /* - * See if we can find a request that is buffer can be coalesced with. + * See if we can find a request that this buffer can be coalesced with. */ int elevator_noop_merge(request_queue_t *q, struct request **req, + struct list_head * head, struct buffer_head *bh, int rw, - int *max_sectors, int *max_segments) + int max_sectors, int max_segments) { - struct list_head *entry, *head = &q->queue_head; + struct list_head *entry; unsigned int count = bh->b_size >> 9; - if (q->head_active && !q->plugged) - head = head->next; + if (list_empty(&q->queue_head)) + return ELEVATOR_NO_MERGE; - entry = head; + entry = &q->queue_head; while ((entry = entry->prev) != head) { - struct request *__rq = *req = blkdev_entry_to_request(entry); - if (__rq->sem) - continue; + struct request *__rq = blkdev_entry_to_request(entry); + if (__rq->cmd != rw) continue; - if (__rq->nr_sectors + count > *max_sectors) - continue; if (__rq->rq_dev != bh->b_rdev) continue; - if (__rq->sector + __rq->nr_sectors == bh->b_rsector) + if (__rq->nr_sectors + count > max_sectors) + continue; + if (__rq->sem) + continue; + if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { + *req = __rq; return ELEVATOR_BACK_MERGE; - if (__rq->sector - count == bh->b_rsector) + } else if (__rq->sector - count == bh->b_rsector) { + *req = __rq; return ELEVATOR_FRONT_MERGE; + } } + + *req = blkdev_entry_to_request(q->queue_head.prev); return ELEVATOR_NO_MERGE; } -/* - * The noop "elevator" does not do any accounting - */ -void elevator_noop_dequeue(struct request *req) {} +void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {} + +void elevator_noop_merge_req(struct request *req, struct request *next) {} int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg) { diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index ef71dddc7..836a89f1e 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -19,6 +19,7 @@ #include <linux/config.h> #include <linux/locks.h> #include <linux/mm.h> +#include <linux/swap.h> #include <linux/init.h> #include <linux/smp_lock.h> @@ -38,8 +39,6 @@ extern int mac_floppy_init(void); #endif -extern int lvm_init(void); - /* * For the allocated request tables */ @@ -118,6 +117,19 @@ int * max_readahead[MAX_BLKDEV]; */ int * max_sectors[MAX_BLKDEV]; +/* + * queued sectors for all devices, used to make sure we don't fill all + * of memory with locked buffers + */ +atomic_t queued_sectors; + +/* + * high and low watermark for above + */ +static int high_queued_sectors, low_queued_sectors; +static int batch_requests, queue_nr_requests; +static DECLARE_WAIT_QUEUE_HEAD(blk_buffers_wait); + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -125,7 +137,7 @@ static inline int get_max_sectors(kdev_t dev) return max_sectors[MAJOR(dev)][MINOR(dev)]; } -static inline request_queue_t *__blk_get_queue(kdev_t dev) +inline request_queue_t *__blk_get_queue(kdev_t dev) { struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); @@ -153,17 +165,14 @@ request_queue_t *blk_get_queue(kdev_t dev) static int __blk_cleanup_queue(struct list_head *head) { - struct list_head *entry; struct request *rq; int i = 0; if (list_empty(head)) return 0; - entry = head->next; do { - rq = list_entry(entry, struct request, table); - entry = entry->next; + rq = list_entry(head->next, struct request, table); list_del(&rq->table); kmem_cache_free(request_cachep, rq); i++; @@ -188,10 +197,12 @@ static int __blk_cleanup_queue(struct list_head *head) **/ void blk_cleanup_queue(request_queue_t * q) { - int count = QUEUE_NR_REQUESTS; + int count = queue_nr_requests; count -= __blk_cleanup_queue(&q->request_freelist[READ]); count -= __blk_cleanup_queue(&q->request_freelist[WRITE]); + count -= __blk_cleanup_queue(&q->pending_freelist[READ]); + count -= __blk_cleanup_queue(&q->pending_freelist[WRITE]); if (count) printk("blk_cleanup_queue: leaked requests (%d)\n", count); @@ -290,7 +301,6 @@ static inline int ll_new_segment(request_queue_t *q, struct request *req, int ma { if (req->nr_segments < max_segments) { req->nr_segments++; - q->elevator.nr_segments++; return 1; } return 0; @@ -316,18 +326,13 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req, struct request *next, int max_segments) { int total_segments = req->nr_segments + next->nr_segments; - int same_segment; - same_segment = 0; - if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) { + if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) total_segments--; - same_segment = 1; - } if (total_segments > max_segments) return 0; - q->elevator.nr_segments -= same_segment; req->nr_segments = total_segments; return 1; } @@ -364,7 +369,7 @@ static inline void __generic_unplug_device(request_queue_t *q) } } -static void generic_unplug_device(void *data) +void generic_unplug_device(void *data) { request_queue_t *q = (request_queue_t *) data; unsigned long flags; @@ -379,19 +384,24 @@ static void blk_init_free_list(request_queue_t *q) struct request *rq; int i; + INIT_LIST_HEAD(&q->request_freelist[READ]); + INIT_LIST_HEAD(&q->request_freelist[WRITE]); + INIT_LIST_HEAD(&q->pending_freelist[READ]); + INIT_LIST_HEAD(&q->pending_freelist[WRITE]); + q->pending_free[READ] = q->pending_free[WRITE] = 0; + /* - * Divide requests in half between read and write. This used to - * be a 2/3 advantage for reads, but now reads can steal from - * the write free list. + * Divide requests in half between read and write */ - for (i = 0; i < QUEUE_NR_REQUESTS; i++) { + for (i = 0; i < queue_nr_requests; i++) { rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); + memset(rq, 0, sizeof(struct request)); rq->rq_status = RQ_INACTIVE; list_add(&rq->table, &q->request_freelist[i & 1]); } init_waitqueue_head(&q->wait_for_request); - spin_lock_init(&q->request_lock); + spin_lock_init(&q->queue_lock); } static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); @@ -426,14 +436,12 @@ static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); * blk_queue_headactive(). * * Note: - * blk_init_queue() must be paired with a blk_cleanup-queue() call + * blk_init_queue() must be paired with a blk_cleanup_queue() call * when the block device is deactivated (such as at module unload). **/ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) { INIT_LIST_HEAD(&q->queue_head); - INIT_LIST_HEAD(&q->request_freelist[READ]); - INIT_LIST_HEAD(&q->request_freelist[WRITE]); elevator_init(&q->elevator, ELEVATOR_LINUS); blk_init_free_list(q); q->request_fn = rfn; @@ -455,7 +463,6 @@ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) q->head_active = 1; } - #define blkdev_free_rq(list) list_entry((list)->next, struct request, table); /* * Get a free request. io_request_lock must be held and interrupts @@ -463,37 +470,16 @@ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) */ static inline struct request *get_request(request_queue_t *q, int rw) { - struct list_head *list = &q->request_freelist[rw]; - struct request *rq; - - /* - * Reads get preferential treatment and are allowed to steal - * from the write free list if necessary. - */ - if (!list_empty(list)) { - rq = blkdev_free_rq(list); - goto got_rq; - } + struct request *rq = NULL; - /* - * if the WRITE list is non-empty, we know that rw is READ - * and that the READ list is empty. allow reads to 'steal' - * from the WRITE list. - */ - if (!list_empty(&q->request_freelist[WRITE])) { - list = &q->request_freelist[WRITE]; - rq = blkdev_free_rq(list); - goto got_rq; + if (!list_empty(&q->request_freelist[rw])) { + rq = blkdev_free_rq(&q->request_freelist[rw]); + list_del(&rq->table); + rq->rq_status = RQ_ACTIVE; + rq->special = NULL; + rq->q = q; } - return NULL; - -got_rq: - list_del(&rq->table); - rq->free_list = list; - rq->rq_status = RQ_ACTIVE; - rq->special = NULL; - rq->q = q; return rq; } @@ -581,40 +567,42 @@ inline void drive_stat_acct (kdev_t dev, int rw, /* * add-request adds a request to the linked list. - * It disables interrupts (acquires the request spinlock) so that it can muck - * with the request-lists in peace. Thus it should be called with no spinlocks - * held. + * io_request_lock is held and interrupts disabled, as we muck with the + * request queue list. * * By this point, req->cmd is always either READ/WRITE, never READA, * which is important for drive_stat_acct() above. */ - static inline void add_request(request_queue_t * q, struct request * req, - struct list_head *head, int lat) + struct list_head *insert_here) { int major; drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1); + if (!q->plugged && q->head_active && insert_here == &q->queue_head) { + spin_unlock_irq(&io_request_lock); + BUG(); + } + /* - * let selected elevator insert the request + * elevator indicated where it wants this request to be + * inserted at elevator_merge time */ - q->elevator.elevator_fn(req, &q->elevator, &q->queue_head, head, lat); - - /* - * FIXME(eric) I don't understand why there is a need for this - * special case code. It clearly doesn't fit any more with - * the new queueing architecture, and it got added in 2.3.10. - * I am leaving this in here until I hear back from the COMPAQ - * people. - */ + list_add(&req->queue, insert_here); + major = MAJOR(req->rq_dev); - if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7) - (q->request_fn)(q); - if (major >= COMPAQ_CISS_MAJOR+0 && major <= COMPAQ_CISS_MAJOR+7) - (q->request_fn)(q); if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) - (q->request_fn)(q); + q->request_fn(q); +} + +void inline blk_refill_freelist(request_queue_t *q, int rw) +{ + if (q->pending_free[rw]) { + list_splice(&q->pending_freelist[rw], &q->request_freelist[rw]); + INIT_LIST_HEAD(&q->pending_freelist[rw]); + q->pending_free[rw] = 0; + } } /* @@ -622,15 +610,34 @@ static inline void add_request(request_queue_t * q, struct request * req, */ void inline blkdev_release_request(struct request *req) { + request_queue_t *q = req->q; + int rw = req->cmd; + req->rq_status = RQ_INACTIVE; + req->q = NULL; /* - * Request may not have originated from ll_rw_blk + * Request may not have originated from ll_rw_blk. if not, + * asumme it has free buffers and check waiters */ - if (req->free_list) { - list_add(&req->table, req->free_list); - req->free_list = NULL; - wake_up(&req->q->wait_for_request); + if (q) { + /* + * we've released enough buffers to start I/O again + */ + if (waitqueue_active(&blk_buffers_wait) + && atomic_read(&queued_sectors) < low_queued_sectors) + wake_up(&blk_buffers_wait); + + /* + * Add to pending free list and batch wakeups + */ + list_add(&req->table, &q->pending_freelist[rw]); + + if (++q->pending_free[rw] >= batch_requests) { + int wake_up = q->pending_free[rw]; + blk_refill_freelist(q, rw); + wake_up_nr(&q->wait_for_request, wake_up); + } } } @@ -658,9 +665,10 @@ static void attempt_merge(request_queue_t * q, * will have been updated to the appropriate number, * and we shouldn't do it here too. */ - if(!(q->merge_requests_fn)(q, req, next, max_segments)) + if (!q->merge_requests_fn(q, req, next, max_segments)) return; + q->elevator.elevator_merge_req_fn(req, next); req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; @@ -699,7 +707,7 @@ static int __make_request(request_queue_t * q, int rw, int max_segments = MAX_SEGMENTS; struct request * req = NULL, *freereq = NULL; int rw_ahead, max_sectors, el_ret; - struct list_head *head; + struct list_head *head, *insert_here; int latency; elevator_t *elevator = &q->elevator; @@ -713,6 +721,7 @@ static int __make_request(request_queue_t * q, int rw, rw = READ; /* drop into READ */ case READ: case WRITE: + latency = elevator_request_latency(elevator, rw); break; default: BUG(); @@ -741,38 +750,33 @@ static int __make_request(request_queue_t * q, int rw, */ max_sectors = get_max_sectors(bh->b_rdev); - latency = elevator_request_latency(elevator, rw); - +again: + head = &q->queue_head; /* * Now we acquire the request spinlock, we have to be mega careful * not to schedule or do something nonatomic */ -again: spin_lock_irq(&io_request_lock); - /* - * skip first entry, for devices with active queue head - */ - head = &q->queue_head; - if (q->head_active && !q->plugged) - head = head->next; - + insert_here = head->prev; if (list_empty(head)) { q->plug_device_fn(q, bh->b_rdev); /* is atomic */ goto get_rq; - } + } else if (q->head_active && !q->plugged) + head = head->next; - el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, - &max_sectors, &max_segments); + el_ret = elevator->elevator_merge_fn(q, &req, head, bh, rw, + max_sectors, max_segments); switch (el_ret) { case ELEVATOR_BACK_MERGE: if (!q->back_merge_fn(q, req, bh, max_segments)) break; + elevator->elevator_merge_cleanup_fn(q, req, count); req->bhtail->b_reqnext = bh; req->bhtail = bh; req->nr_sectors = req->hard_nr_sectors += count; - req->e = elevator; + blk_started_io(count); drive_stat_acct(req->rq_dev, req->cmd, count, 0); attempt_back_merge(q, req, max_sectors, max_segments); goto out; @@ -780,20 +784,29 @@ again: case ELEVATOR_FRONT_MERGE: if (!q->front_merge_fn(q, req, bh, max_segments)) break; + elevator->elevator_merge_cleanup_fn(q, req, count); bh->b_reqnext = req->bh; req->bh = bh; req->buffer = bh->b_data; req->current_nr_sectors = count; req->sector = req->hard_sector = sector; req->nr_sectors = req->hard_nr_sectors += count; - req->e = elevator; + blk_started_io(count); drive_stat_acct(req->rq_dev, req->cmd, count, 0); attempt_front_merge(q, head, req, max_sectors, max_segments); goto out; + /* * elevator says don't/can't merge. get new request */ case ELEVATOR_NO_MERGE: + /* + * use elevator hints as to where to insert the + * request. if no hints, just add it to the back + * of the queue + */ + if (req) + insert_here = &req->queue; break; default: @@ -802,10 +815,9 @@ again: } /* - * Grab a free request from the freelist. Read first try their - * own queue - if that is empty, we steal from the write list. - * Writes must block if the write list is empty, and read aheads - * are not crucial. + * Grab a free request from the freelist - if that is empty, check + * if we are doing read ahead and abort instead of blocking for + * a free slot. */ get_rq: if (freereq) { @@ -821,6 +833,7 @@ get_rq: } /* fill up the request-info, and add it to the queue */ + req->elevator_sequence = latency; req->cmd = rw; req->errors = 0; req->hard_sector = req->sector = sector; @@ -833,13 +846,13 @@ get_rq: req->bh = bh; req->bhtail = bh; req->rq_dev = bh->b_rdev; - req->e = elevator; - add_request(q, req, head, latency); + blk_started_io(count); + add_request(q, req, insert_here); out: - if (!q->plugged) - (q->request_fn)(q); if (freereq) blkdev_release_request(freereq); + if (!q->plugged) + q->request_fn(q); spin_unlock_irq(&io_request_lock); return 0; end_io: @@ -886,13 +899,13 @@ void generic_make_request (int rw, struct buffer_head * bh) int major = MAJOR(bh->b_rdev); request_queue_t *q; - if (!bh->b_end_io) BUG(); + if (!bh->b_end_io) + BUG(); + if (blk_size[major]) { unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; - unsigned int sector, count; - - count = bh->b_size >> 9; - sector = bh->b_rsector; + unsigned long sector = bh->b_rsector; + unsigned int count = bh->b_size >> 9; if (maxsector < count || maxsector - count < sector) { bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); @@ -903,7 +916,7 @@ void generic_make_request (int rw, struct buffer_head * bh) when mounting a device. */ printk(KERN_INFO "attempt to access beyond end of device\n"); - printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", + printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n", kdevname(bh->b_rdev), rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]); @@ -930,15 +943,13 @@ void generic_make_request (int rw, struct buffer_head * bh) buffer_IO_error(bh); break; } - - } - while (q->make_request_fn(q, rw, bh)); + } while (q->make_request_fn(q, rw, bh)); } /** * submit_bh: submit a buffer_head to the block device later for I/O - * @rw: whether to %READ or %WRITE, or mayve to %READA (read ahead) + * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) * @bh: The &struct buffer_head which describes the I/O * * submit_bh() is very similar in purpose to generic_make_request(), and @@ -961,7 +972,7 @@ void submit_bh(int rw, struct buffer_head * bh) * further remap this. */ bh->b_rdev = bh->b_dev; - bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); + bh->b_rsector = bh->b_blocknr * (bh->b_size >> 9); generic_make_request(rw, bh); @@ -1021,6 +1032,9 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) int correct_size; int i; + if (!nr) + return; + major = MAJOR(bhs[0]->b_dev); /* Determine correct block size for this device. */ @@ -1033,9 +1047,8 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { - struct buffer_head *bh; - bh = bhs[i]; - if (bh->b_size != correct_size) { + struct buffer_head *bh = bhs[i]; + if (bh->b_size % correct_size) { printk(KERN_NOTICE "ll_rw_block: device %s: " "only %d-char blocks implemented (%u)\n", kdevname(bhs[0]->b_dev), @@ -1051,8 +1064,17 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) } for (i = 0; i < nr; i++) { - struct buffer_head *bh; - bh = bhs[i]; + struct buffer_head *bh = bhs[i]; + + /* + * don't lock any more buffers if we are above the high + * water mark. instead start I/O on the queued stuff. + */ + if (atomic_read(&queued_sectors) >= high_queued_sectors) { + run_task_queue(&tq_disk); + wait_event(blk_buffers_wait, + atomic_read(&queued_sectors) < low_queued_sectors); + } /* Only one thread can actually submit the I/O. */ if (test_and_set_bit(BH_Lock, &bh->b_state)) @@ -1096,12 +1118,25 @@ sorry: extern int stram_device_init (void); #endif -/* - * First step of what used to be end_request + +/** + * end_that_request_first - end I/O on one buffer. + * @req: the request being processed + * @uptodate: 0 for I/O error + * @name: the name printed for an I/O error * - * 0 means continue with end_that_request_last, - * 1 means we are done - */ + * Description: + * Ends I/O on the first buffer attached to @req, and sets it up + * for the next buffer_head (if any) in the cluster. + * + * Return: + * 0 - we are done with this request, call end_that_request_last() + * 1 - still buffers pending for this request + * + * Caveat: + * Drivers implementing their own end_request handling must call + * blk_finished_io() appropriately. + **/ int end_that_request_first (struct request *req, int uptodate, char *name) { @@ -1115,6 +1150,7 @@ int end_that_request_first (struct request *req, int uptodate, char *name) if ((bh = req->bh) != NULL) { nsect = bh->b_size >> 9; + blk_finished_io(nsect); req->bh = bh->b_reqnext; bh->b_reqnext = NULL; bh->b_end_io(bh, uptodate); @@ -1138,19 +1174,18 @@ int end_that_request_first (struct request *req, int uptodate, char *name) void end_that_request_last(struct request *req) { - if (req->e) { - printk("end_that_request_last called with non-dequeued req\n"); - BUG(); - } if (req->sem != NULL) up(req->sem); blkdev_release_request(req); } +#define MB(kb) ((kb) << 10) + int __init blk_dev_init(void) { struct blk_dev_struct *dev; + int total_ram; request_cachep = kmem_cache_create("blkdev_requests", sizeof(struct request), @@ -1165,6 +1200,44 @@ int __init blk_dev_init(void) memset(ro_bits,0,sizeof(ro_bits)); memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); + + atomic_set(&queued_sectors, 0); + total_ram = nr_free_pages() << (PAGE_SHIFT - 10); + + /* + * Try to keep 128MB max hysteris. If not possible, + * use half of RAM + */ + high_queued_sectors = (total_ram * 2) / 3; + low_queued_sectors = high_queued_sectors / 3; + if (high_queued_sectors - low_queued_sectors > MB(128)) + low_queued_sectors = high_queued_sectors - MB(128); + + + /* + * make it sectors (512b) + */ + high_queued_sectors <<= 1; + low_queued_sectors <<= 1; + + /* + * Scale free request slots per queue too + */ + total_ram = (total_ram + MB(32) - 1) & ~(MB(32) - 1); + if ((queue_nr_requests = total_ram >> 9) > QUEUE_NR_REQUESTS) + queue_nr_requests = QUEUE_NR_REQUESTS; + + /* + * adjust batch frees according to queue length, with upper limit + */ + if ((batch_requests = queue_nr_requests >> 3) > 32) + batch_requests = 32; + + printk("block: queued sectors max/low %dkB/%dkB, %d slots per queue\n", + high_queued_sectors / 2, + low_queued_sectors / 2, + queue_nr_requests); + #ifdef CONFIG_AMIGA_Z2RAM z2_init(); #endif @@ -1268,9 +1341,6 @@ int __init blk_dev_init(void) #ifdef CONFIG_SUN_JSFLASH jsfd_init(); #endif -#ifdef CONFIG_BLK_DEV_LVM - lvm_init(); -#endif return 0; }; @@ -1279,9 +1349,12 @@ EXPORT_SYMBOL(end_that_request_first); EXPORT_SYMBOL(end_that_request_last); EXPORT_SYMBOL(blk_init_queue); EXPORT_SYMBOL(blk_get_queue); +EXPORT_SYMBOL(__blk_get_queue); EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_queue_headactive); EXPORT_SYMBOL(blk_queue_pluggable); EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(generic_make_request); EXPORT_SYMBOL(blkdev_release_request); +EXPORT_SYMBOL(generic_unplug_device); +EXPORT_SYMBOL(queued_sectors); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 9b1ff3a32..172acadbe 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -392,7 +392,6 @@ static inline int pd_new_segment(request_queue_t *q, struct request *req, int ma if (req->nr_segments < max_segments) { req->nr_segments++; - q->elevator.nr_segments++; return 1; } return 0; @@ -432,7 +431,6 @@ static int pd_merge_requests_fn(request_queue_t *q, struct request *req, if (total_segments > max_segments) return 0; - q->elevator.nr_segments -= same_segment; req->nr_segments = total_segments; return 1; } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 53f6ca3df..b71703f9b 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -346,7 +346,6 @@ static inline int pf_new_segment(request_queue_t *q, struct request *req, int ma if (req->nr_segments < max_segments) { req->nr_segments++; - q->elevator.nr_segments++; return 1; } return 0; @@ -386,7 +385,6 @@ static int pf_merge_requests_fn(request_queue_t *q, struct request *req, if (total_segments > max_segments) return 0; - q->elevator.nr_segments -= same_segment; req->nr_segments = total_segments; return 1; } diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 1e555da55..cafe72afd 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -295,11 +295,11 @@ MODULE_PARM(check_media_type, "i"); /* These are used to simplify getting data in from and back to user land */ #define IOCTL_IN(arg, type, in) \ - if (copy_from_user(&in, (type *) arg, sizeof in)) \ + if (copy_from_user(&(in), (type *) (arg), sizeof (in))) \ return -EFAULT; #define IOCTL_OUT(arg, type, out) \ - if (copy_to_user((type *) arg, &out, sizeof out)) \ + if (copy_to_user((type *) (arg), &(out), sizeof (out))) \ return -EFAULT; /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index 942142832..ccd53dacc 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -1384,9 +1384,11 @@ static void via_cleanup(void) aper_size_info_8 *previous_size; previous_size = A_SIZE_8(agp_bridge.previous_size); - pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, 0); pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, previous_size->size_value); + /* Do not disable by writing 0 to VIA_ATTBASE, it screws things up + * during reinitialization. + */ } static void via_tlbflush(agp_memory * mem) @@ -2373,9 +2375,10 @@ static int __init agp_find_supported_device(void) if (i810_dev == NULL) { printk(KERN_ERR PFX "agpgart: Detected an " "Intel i815, but could not find the" - " secondary device.\n"); - agp_bridge.type = NOT_SUPPORTED; - return -ENODEV; + " secondary device.\n" + "Assuming user has added an external AGP" + " card\n"); + break; } printk(KERN_INFO PFX "agpgart: Detected an Intel i815 " "Chipset.\n"); diff --git a/drivers/char/drm/Config.in b/drivers/char/drm/Config.in index c69d37db5..6d7649eb0 100644 --- a/drivers/char/drm/Config.in +++ b/drivers/char/drm/Config.in @@ -9,7 +9,8 @@ bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM if [ "$CONFIG_DRM" != "n" ]; then tristate ' 3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA - tristate ' ATI Rage 128' CONFIG_DRM_R128 + dep_tristate ' ATI Rage 128' CONFIG_DRM_R128 $CONFIG_AGP + dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP fi diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index d25e33d47..41017340b 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -42,16 +42,18 @@ else endif endif -gamma-objs := gamma_drv.o gamma_dma.o -tdfx-objs := tdfx_drv.o tdfx_context.o -r128-objs := r128_drv.o r128_cce.o r128_context.o r128_bufs.o r128_state.o -ffb-objs := ffb_drv.o ffb_context.o -mga-objs := mga_drv.o mga_dma.o mga_context.o mga_bufs.o mga_state.o -i810-objs := i810_drv.o i810_dma.o i810_context.o i810_bufs.o +gamma-objs := gamma_drv.o gamma_dma.o +tdfx-objs := tdfx_drv.o tdfx_context.o +r128-objs := r128_drv.o r128_cce.o r128_context.o r128_bufs.o r128_state.o +ffb-objs := ffb_drv.o ffb_context.o +mga-objs := mga_drv.o mga_dma.o mga_context.o mga_bufs.o mga_state.o +i810-objs := i810_drv.o i810_dma.o i810_context.o i810_bufs.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_context.o radeon_bufs.o radeon_state.o obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o obj-$(CONFIG_DRM_R128) += r128.o +obj-$(CONFIG_DRM_RADEON)+= radeon.o obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o @@ -96,5 +98,8 @@ i810.o: $(i810-objs) $(lib) r128.o: $(r128-objs) $(lib) $(LD) -r -o $@ $(r128-objs) $(lib) +radeon.o: $(radeon-objs) $(lib) + $(LD) -r -o $@ $(radeon-objs) $(lib) + ffb.o: $(ffb-objs) $(lib) $(LD) -r -o $@ $(ffb-objs) $(lib) diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index aeecca77b..101556540 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -83,6 +83,7 @@ typedef struct drm_clip_rect { #include "mga_drm.h" #include "i810_drm.h" #include "r128_drm.h" +#include "radeon_drm.h" #ifdef CONFIG_DRM_SIS #include "sis_drm.h" #endif @@ -298,100 +299,116 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; -#define DRM_IOCTL_BASE 'd' -#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) -#define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) -#define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size) -#define DRM_IOWR(nr,size) _IOWR(DRM_IOCTL_BASE,nr,size) - - -#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t) -#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t) -#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t) -#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t) - -#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) -#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) -#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t) -#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t) -#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t) -#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t) -#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t) -#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t) -#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t) -#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t) -#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t) - -#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t) -#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t) -#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t) -#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t) -#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t) -#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t) -#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) -#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t) -#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t) -#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t) -#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t) -#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) -#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) - -#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) -#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) -#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t) -#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t) -#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) -#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) -#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) -#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_BASE 'd' +#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) +#define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) +#define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size) +#define DRM_IOWR(nr,size) _IOWR(DRM_IOCTL_BASE,nr,size) + + +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t) +#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t) + +#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) +#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) +#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t) +#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t) +#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t) +#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t) +#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t) +#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t) +#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t) +#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t) +#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t) + +#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t) +#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t) +#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t) +#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t) +#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t) +#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t) +#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) +#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t) +#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t) +#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t) +#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t) +#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) +#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) + +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t) +#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) /* Mga specific ioctls */ -#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) -#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) -#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) -#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) -#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) -#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) -#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) -#define DRM_IOCTL_MGA_BLIT DRM_IOW( 0x47, drm_mga_blit_t) +#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) +#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) +#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) +#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) +#define DRM_IOCTL_MGA_BLIT DRM_IOW( 0x47, drm_mga_blit_t) /* I810 specific ioctls */ -#define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) -#define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) -#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) -#define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) -#define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) -#define DRM_IOCTL_I810_GETBUF DRM_IOWR(0x45, drm_i810_dma_t) -#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) -#define DRM_IOCTL_I810_COPY DRM_IOW( 0x47, drm_i810_copy_t) -#define DRM_IOCTL_I810_DOCOPY DRM_IO ( 0x48) +#define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) +#define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) +#define DRM_IOCTL_I810_FLUSH DRM_IO( 0x43) +#define DRM_IOCTL_I810_GETAGE DRM_IO( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOWR(0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO( 0x46) +#define DRM_IOCTL_I810_COPY DRM_IOW( 0x47, drm_i810_copy_t) +#define DRM_IOCTL_I810_DOCOPY DRM_IO( 0x48) /* Rage 128 specific ioctls */ -#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) -#define DRM_IOCTL_R128_CCE_START DRM_IO( 0x41) -#define DRM_IOCTL_R128_CCE_STOP DRM_IOW( 0x42, drm_r128_cce_stop_t) -#define DRM_IOCTL_R128_CCE_RESET DRM_IO( 0x43) -#define DRM_IOCTL_R128_CCE_IDLE DRM_IO( 0x44) -#define DRM_IOCTL_R128_RESET DRM_IO( 0x46) -#define DRM_IOCTL_R128_SWAP DRM_IO( 0x47) -#define DRM_IOCTL_R128_CLEAR DRM_IOW( 0x48, drm_r128_clear_t) -#define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x49, drm_r128_vertex_t) -#define DRM_IOCTL_R128_INDICES DRM_IOW( 0x4a, drm_r128_indices_t) -#define DRM_IOCTL_R128_BLIT DRM_IOW( 0x4b, drm_r128_blit_t) -#define DRM_IOCTL_R128_DEPTH DRM_IOW( 0x4c, drm_r128_depth_t) -#define DRM_IOCTL_R128_STIPPLE DRM_IOW( 0x4d, drm_r128_stipple_t) -#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x4e, drm_r128_packet_t) +#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) +#define DRM_IOCTL_R128_CCE_START DRM_IO( 0x41) +#define DRM_IOCTL_R128_CCE_STOP DRM_IOW( 0x42, drm_r128_cce_stop_t) +#define DRM_IOCTL_R128_CCE_RESET DRM_IO( 0x43) +#define DRM_IOCTL_R128_CCE_IDLE DRM_IO( 0x44) +#define DRM_IOCTL_R128_RESET DRM_IO( 0x46) +#define DRM_IOCTL_R128_SWAP DRM_IO( 0x47) +#define DRM_IOCTL_R128_CLEAR DRM_IOW( 0x48, drm_r128_clear_t) +#define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x49, drm_r128_vertex_t) +#define DRM_IOCTL_R128_INDICES DRM_IOW( 0x4a, drm_r128_indices_t) +#define DRM_IOCTL_R128_BLIT DRM_IOW( 0x4b, drm_r128_blit_t) +#define DRM_IOCTL_R128_DEPTH DRM_IOW( 0x4c, drm_r128_depth_t) +#define DRM_IOCTL_R128_STIPPLE DRM_IOW( 0x4d, drm_r128_stipple_t) +#define DRM_IOCTL_R128_PACKET DRM_IOWR(0x4e, drm_r128_packet_t) + +/* Radeon specific ioctls */ +#define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( 0x40, drm_radeon_init_t) +#define DRM_IOCTL_RADEON_CP_START DRM_IO( 0x41) +#define DRM_IOCTL_RADEON_CP_STOP DRM_IOW( 0x42, drm_radeon_cp_stop_t) +#define DRM_IOCTL_RADEON_CP_RESET DRM_IO( 0x43) +#define DRM_IOCTL_RADEON_CP_IDLE DRM_IO( 0x44) +#define DRM_IOCTL_RADEON_RESET DRM_IO( 0x45) +#define DRM_IOCTL_RADEON_FULLSCREEN DRM_IOW( 0x46, drm_radeon_fullscreen_t) +#define DRM_IOCTL_RADEON_SWAP DRM_IO( 0x47) +#define DRM_IOCTL_RADEON_CLEAR DRM_IOW( 0x48, drm_radeon_clear_t) +#define DRM_IOCTL_RADEON_VERTEX DRM_IOW( 0x49, drm_radeon_vertex_t) +#define DRM_IOCTL_RADEON_INDICES DRM_IOW( 0x4a, drm_radeon_indices_t) +#define DRM_IOCTL_RADEON_BLIT DRM_IOW( 0x4b, drm_radeon_blit_t) +#define DRM_IOCTL_RADEON_STIPPLE DRM_IOW( 0x4c, drm_radeon_stipple_t) +#define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #ifdef CONFIG_DRM_SIS /* SiS specific ioctls */ -#define SIS_IOCTL_FB_ALLOC DRM_IOWR( 0x44, drm_sis_mem_t) -#define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) -#define SIS_IOCTL_AGP_INIT DRM_IOWR( 0x53, drm_sis_agp_t) -#define SIS_IOCTL_AGP_ALLOC DRM_IOWR( 0x54, drm_sis_mem_t) -#define SIS_IOCTL_AGP_FREE DRM_IOW( 0x55, drm_sis_mem_t) -#define SIS_IOCTL_FLIP DRM_IOW( 0x48, drm_sis_flip_t) -#define SIS_IOCTL_FLIP_INIT DRM_IO( 0x49) -#define SIS_IOCTL_FLIP_FINAL DRM_IO( 0x50) +#define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) +#define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) +#define SIS_IOCTL_AGP_INIT DRM_IOWR(0x53, drm_sis_agp_t) +#define SIS_IOCTL_AGP_ALLOC DRM_IOWR(0x54, drm_sis_mem_t) +#define SIS_IOCTL_AGP_FREE DRM_IOW( 0x55, drm_sis_mem_t) +#define SIS_IOCTL_FLIP DRM_IOW( 0x48, drm_sis_flip_t) +#define SIS_IOCTL_FLIP_INIT DRM_IO( 0x49) +#define SIS_IOCTL_FLIP_FINAL DRM_IO( 0x50) #endif #endif diff --git a/drivers/char/drm/radeon_bufs.c b/drivers/char/drm/radeon_bufs.c new file mode 100644 index 000000000..9a3093eb1 --- /dev/null +++ b/drivers/char/drm/radeon_bufs.c @@ -0,0 +1,298 @@ +/* radeon_bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Kevin E. Martin <martin@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * Jeff Hartmann <jhartmann@valinux.com> + * + */ + +#define __NO_VERSION__ +#include <linux/config.h> +#include "drmP.h" +#include "radeon_drv.h" +#include "linux/un.h" + + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +int radeon_addbufs_agp(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if (!dma) return -EINVAL; + + if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) + return -EFAULT; + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = dev->agp->base + request.agp_start; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + for (offset = 0; + entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + offset); + buf->address = (void *)(agp_offset + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_priv_size = sizeof(drm_radeon_buf_priv_t); + buf->dev_private = drm_alloc(sizeof(drm_radeon_buf_priv_t), + DRM_MEM_BUFS); + memset(buf->dev_private, 0, buf->dev_priv_size); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + DRM_DEBUG("byte_count: %d\n", byte_count); + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + if (copy_to_user((drm_buf_desc_t *)arg, &request, sizeof(request))) + return -EFAULT; + + dma->flags = _DRM_DMA_USE_AGP; + + atomic_dec(&dev->buf_alloc); + return 0; +} +#endif + +int radeon_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_buf_desc_t request; + + if (!dev_priv || dev_priv->is_pci) return -EINVAL; + + if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) + return -EFAULT; + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + if (request.flags & _DRM_AGP_BUFFER) + return radeon_addbufs_agp(inode, filp, cmd, arg); + else +#endif + return -EINVAL; +} + +int radeon_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL; + + DRM_DEBUG("\n"); + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + if (copy_from_user(&request, (drm_buf_map_t *)arg, sizeof(request))) + return -EFAULT; + + if (request.count >= dma->buf_count) { + if (dma->flags & _DRM_DMA_USE_AGP) { + drm_map_t *map; + + map = dev_priv->buffers; + if (!map) { + retcode = -EINVAL; + goto done; + } + + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, map->size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset); + up(¤t->mm->mmap_sem); + } else { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + } + if (virtual > -1024UL) { + /* Real error */ + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } + done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + + if (copy_to_user((drm_buf_map_t *)arg, &request, sizeof(request))) + return -EFAULT; + + return retcode; +} diff --git a/drivers/char/drm/radeon_context.c b/drivers/char/drm/radeon_context.c new file mode 100644 index 000000000..e428dc22c --- /dev/null +++ b/drivers/char/drm/radeon_context.c @@ -0,0 +1,215 @@ +/* radeon_context.c -- IOCTLs for Radeon contexts -*- linux-c -*- + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Kevin E. Martin <martin@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "radeon_drv.h" + +extern drm_ctx_t radeon_res_ctx; + +static int radeon_alloc_queue(drm_device_t *dev) +{ + return drm_ctxbitmap_next(dev); +} + +int radeon_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + + atomic_inc(&dev->total_ctx); + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + if (drm_flags & DRM_FLAG_NOCTX) { + radeon_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int radeon_context_switch_complete(drm_device_t *dev, int new) +{ + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Lock isn't held after context switch\n"); + } + + /* If a context switch is ever initiated + when the kernel holds the lock, release + that lock here. */ +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() + - dev->ctx_start)]); + +#endif + clear_bit(0, &dev->context_flag); + wake_up(&dev->context_wait); + + return 0; +} + + +int radeon_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) + return -EFAULT; + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + if (copy_to_user(&res.contexts[i], &i, sizeof(i))) + return -EFAULT; + } + } + res.count = DRM_RESERVED_CONTEXTS; + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; + return 0; +} + + +int radeon_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + if ((ctx.handle = radeon_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = radeon_alloc_queue(dev); + } + DRM_DEBUG("%d\n", ctx.handle); + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; + return 0; +} + +int radeon_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; + if (ctx.flags==_DRM_CONTEXT_PRESERVED) + radeon_res_ctx.handle=ctx.handle; + return 0; +} + +int radeon_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) + return -EFAULT; + /* This is 0, because we don't hanlde any context flags */ + ctx.flags = 0; + if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) + return -EFAULT; + return 0; +} + +int radeon_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + DRM_DEBUG("%d\n", ctx.handle); + return radeon_context_switch(dev, dev->last_context, ctx.handle); +} + +int radeon_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + DRM_DEBUG("%d\n", ctx.handle); + radeon_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int radeon_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + DRM_DEBUG("%d\n", ctx.handle); + drm_ctxbitmap_free(dev, ctx.handle); + + return 0; +} diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c new file mode 100644 index 000000000..5d662bc08 --- /dev/null +++ b/drivers/char/drm/radeon_cp.c @@ -0,0 +1,1314 @@ +/* radeon_cp.c -- CP support for Radeon -*- linux-c -*- + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "radeon_drv.h" + +#include <linux/interrupt.h> /* For task queue support */ +#include <linux/delay.h> + +#define RADEON_FIFO_DEBUG 0 + + +/* CP microcode (from ATI) */ +static u32 radeon_cp_microcode[][2] = { + { 0x21007000, 0000000000 }, + { 0x20007000, 0000000000 }, + { 0x000000b4, 0x00000004 }, + { 0x000000b8, 0x00000004 }, + { 0x6f5b4d4c, 0000000000 }, + { 0x4c4c427f, 0000000000 }, + { 0x5b568a92, 0000000000 }, + { 0x4ca09c6d, 0000000000 }, + { 0xad4c4c4c, 0000000000 }, + { 0x4ce1af3d, 0000000000 }, + { 0xd8afafaf, 0000000000 }, + { 0xd64c4cdc, 0000000000 }, + { 0x4cd10d10, 0000000000 }, + { 0x000f0000, 0x00000016 }, + { 0x362f242d, 0000000000 }, + { 0x00000012, 0x00000004 }, + { 0x000f0000, 0x00000016 }, + { 0x362f282d, 0000000000 }, + { 0x000380e7, 0x00000002 }, + { 0x04002c97, 0x00000002 }, + { 0x000f0001, 0x00000016 }, + { 0x333a3730, 0000000000 }, + { 0x000077ef, 0x00000002 }, + { 0x00061000, 0x00000002 }, + { 0x00000021, 0x0000001a }, + { 0x00004000, 0x0000001e }, + { 0x00061000, 0x00000002 }, + { 0x00000021, 0x0000001a }, + { 0x00004000, 0x0000001e }, + { 0x00061000, 0x00000002 }, + { 0x00000021, 0x0000001a }, + { 0x00004000, 0x0000001e }, + { 0x00000017, 0x00000004 }, + { 0x0003802b, 0x00000002 }, + { 0x040067e0, 0x00000002 }, + { 0x00000017, 0x00000004 }, + { 0x000077e0, 0x00000002 }, + { 0x00065000, 0x00000002 }, + { 0x000037e1, 0x00000002 }, + { 0x040067e1, 0x00000006 }, + { 0x000077e0, 0x00000002 }, + { 0x000077e1, 0x00000002 }, + { 0x000077e1, 0x00000006 }, + { 0xffffffff, 0000000000 }, + { 0x10000000, 0000000000 }, + { 0x0003802b, 0x00000002 }, + { 0x040067e0, 0x00000006 }, + { 0x00007675, 0x00000002 }, + { 0x00007676, 0x00000002 }, + { 0x00007677, 0x00000002 }, + { 0x00007678, 0x00000006 }, + { 0x0003802c, 0x00000002 }, + { 0x04002676, 0x00000002 }, + { 0x00007677, 0x00000002 }, + { 0x00007678, 0x00000006 }, + { 0x0000002f, 0x00000018 }, + { 0x0000002f, 0x00000018 }, + { 0000000000, 0x00000006 }, + { 0x00000030, 0x00000018 }, + { 0x00000030, 0x00000018 }, + { 0000000000, 0x00000006 }, + { 0x01605000, 0x00000002 }, + { 0x00065000, 0x00000002 }, + { 0x00098000, 0x00000002 }, + { 0x00061000, 0x00000002 }, + { 0x64c0603e, 0x00000004 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00080000, 0x00000016 }, + { 0000000000, 0000000000 }, + { 0x0400251d, 0x00000002 }, + { 0x00007580, 0x00000002 }, + { 0x00067581, 0x00000002 }, + { 0x04002580, 0x00000002 }, + { 0x00067581, 0x00000002 }, + { 0x00000049, 0x00000004 }, + { 0x00005000, 0000000000 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00061000, 0x00000002 }, + { 0x0000750e, 0x00000002 }, + { 0x00019000, 0x00000002 }, + { 0x00011055, 0x00000014 }, + { 0x00000055, 0x00000012 }, + { 0x0400250f, 0x00000002 }, + { 0x0000504f, 0x00000004 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00007565, 0x00000002 }, + { 0x00007566, 0x00000002 }, + { 0x00000058, 0x00000004 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x01e655b4, 0x00000002 }, + { 0x4401b0e4, 0x00000002 }, + { 0x01c110e4, 0x00000002 }, + { 0x26667066, 0x00000018 }, + { 0x040c2565, 0x00000002 }, + { 0x00000066, 0x00000018 }, + { 0x04002564, 0x00000002 }, + { 0x00007566, 0x00000002 }, + { 0x0000005d, 0x00000004 }, + { 0x00401069, 0x00000008 }, + { 0x00101000, 0x00000002 }, + { 0x000d80ff, 0x00000002 }, + { 0x0080006c, 0x00000008 }, + { 0x000f9000, 0x00000002 }, + { 0x000e00ff, 0x00000002 }, + { 0000000000, 0x00000006 }, + { 0x0000008f, 0x00000018 }, + { 0x0000005b, 0x00000004 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00007576, 0x00000002 }, + { 0x00065000, 0x00000002 }, + { 0x00009000, 0x00000002 }, + { 0x00041000, 0x00000002 }, + { 0x0c00350e, 0x00000002 }, + { 0x00049000, 0x00000002 }, + { 0x00051000, 0x00000002 }, + { 0x01e785f8, 0x00000002 }, + { 0x00200000, 0x00000002 }, + { 0x0060007e, 0x0000000c }, + { 0x00007563, 0x00000002 }, + { 0x006075f0, 0x00000021 }, + { 0x20007073, 0x00000004 }, + { 0x00005073, 0x00000004 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00007576, 0x00000002 }, + { 0x00007577, 0x00000002 }, + { 0x0000750e, 0x00000002 }, + { 0x0000750f, 0x00000002 }, + { 0x00a05000, 0x00000002 }, + { 0x00600083, 0x0000000c }, + { 0x006075f0, 0x00000021 }, + { 0x000075f8, 0x00000002 }, + { 0x00000083, 0x00000004 }, + { 0x000a750e, 0x00000002 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x0020750f, 0x00000002 }, + { 0x00600086, 0x00000004 }, + { 0x00007570, 0x00000002 }, + { 0x00007571, 0x00000002 }, + { 0x00007572, 0x00000006 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00005000, 0x00000002 }, + { 0x00a05000, 0x00000002 }, + { 0x00007568, 0x00000002 }, + { 0x00061000, 0x00000002 }, + { 0x00000095, 0x0000000c }, + { 0x00058000, 0x00000002 }, + { 0x0c607562, 0x00000002 }, + { 0x00000097, 0x00000004 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x00600096, 0x00000004 }, + { 0x400070e5, 0000000000 }, + { 0x000380e6, 0x00000002 }, + { 0x040025c5, 0x00000002 }, + { 0x000380e5, 0x00000002 }, + { 0x000000a8, 0x0000001c }, + { 0x000650aa, 0x00000018 }, + { 0x040025bb, 0x00000002 }, + { 0x000610ab, 0x00000018 }, + { 0x040075bc, 0000000000 }, + { 0x000075bb, 0x00000002 }, + { 0x000075bc, 0000000000 }, + { 0x00090000, 0x00000006 }, + { 0x00090000, 0x00000002 }, + { 0x000d8002, 0x00000006 }, + { 0x00007832, 0x00000002 }, + { 0x00005000, 0x00000002 }, + { 0x000380e7, 0x00000002 }, + { 0x04002c97, 0x00000002 }, + { 0x00007820, 0x00000002 }, + { 0x00007821, 0x00000002 }, + { 0x00007800, 0000000000 }, + { 0x01200000, 0x00000002 }, + { 0x20077000, 0x00000002 }, + { 0x01200000, 0x00000002 }, + { 0x20007000, 0x00000002 }, + { 0x00061000, 0x00000002 }, + { 0x0120751b, 0x00000002 }, + { 0x8040750a, 0x00000002 }, + { 0x8040750b, 0x00000002 }, + { 0x00110000, 0x00000002 }, + { 0x000380e5, 0x00000002 }, + { 0x000000c6, 0x0000001c }, + { 0x000610ab, 0x00000018 }, + { 0x844075bd, 0x00000002 }, + { 0x000610aa, 0x00000018 }, + { 0x840075bb, 0x00000002 }, + { 0x000610ab, 0x00000018 }, + { 0x844075bc, 0x00000002 }, + { 0x000000c9, 0x00000004 }, + { 0x804075bd, 0x00000002 }, + { 0x800075bb, 0x00000002 }, + { 0x804075bc, 0x00000002 }, + { 0x00108000, 0x00000002 }, + { 0x01400000, 0x00000002 }, + { 0x006000cd, 0x0000000c }, + { 0x20c07000, 0x00000020 }, + { 0x000000cf, 0x00000012 }, + { 0x00800000, 0x00000006 }, + { 0x0080751d, 0x00000006 }, + { 0000000000, 0000000000 }, + { 0x0000775c, 0x00000002 }, + { 0x00a05000, 0x00000002 }, + { 0x00661000, 0x00000002 }, + { 0x0460275d, 0x00000020 }, + { 0x00004000, 0000000000 }, + { 0x01e00830, 0x00000002 }, + { 0x21007000, 0000000000 }, + { 0x6464614d, 0000000000 }, + { 0x69687420, 0000000000 }, + { 0x00000073, 0000000000 }, + { 0000000000, 0000000000 }, + { 0x00005000, 0x00000002 }, + { 0x000380d0, 0x00000002 }, + { 0x040025e0, 0x00000002 }, + { 0x000075e1, 0000000000 }, + { 0x00000001, 0000000000 }, + { 0x000380e0, 0x00000002 }, + { 0x04002394, 0x00000002 }, + { 0x00005000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0x00000008, 0000000000 }, + { 0x00000004, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, + { 0000000000, 0000000000 }, +}; + + +#define DO_IOREMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) + +#define DO_IOREMAPFREE(_m) \ + do { \ + if ((_m)->handle && (_m)->size) \ + drm_ioremapfree((_m)->handle, (_m)->size); \ + } while (0) + +#define DO_FIND_MAP(_m, _o) \ + do { \ + int _i; \ + for (_i = 0; _i < dev->map_count; _i++) { \ + if (dev->maplist[_i]->offset == _o) { \ + _m = dev->maplist[_i]; \ + break; \ + } \ + } \ + } while (0) + + +int RADEON_READ_PLL(drm_device_t *dev, int addr) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f); + return RADEON_READ(RADEON_CLOCK_CNTL_DATA); +} + +#if RADEON_FIFO_DEBUG +static void radeon_status( drm_radeon_private_t *dev_priv ) +{ + printk( "%s:\n", __FUNCTION__ ); + printk( "RBBM_STATUS = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_RBBM_STATUS ) ); + printk( "CP_RB_RTPR = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_CP_RB_RPTR ) ); + printk( "CP_RB_WTPR = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_CP_RB_WPTR ) ); +} +#endif + + +/* ================================================================ + * Engine, FIFO control + */ + +static int radeon_do_pixcache_flush( drm_radeon_private_t *dev_priv ) +{ + u32 tmp; + int i; + + tmp = RADEON_READ( RADEON_RB2D_DSTCACHE_CTLSTAT ); + tmp |= RADEON_RB2D_DC_FLUSH_ALL; + RADEON_WRITE( RADEON_RB2D_DSTCACHE_CTLSTAT, tmp ); + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + if ( !(RADEON_READ( RADEON_RB2D_DSTCACHE_CTLSTAT ) + & RADEON_RB2D_DC_BUSY) ) { + return 0; + } + udelay( 1 ); + } + +#if RADEON_FIFO_DEBUG + DRM_ERROR( "failed!\n" ); + radeon_status( dev_priv ); +#endif + return -EBUSY; +} + +static int radeon_do_wait_for_fifo( drm_radeon_private_t *dev_priv, + int entries ) +{ + int i; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + int slots = ( RADEON_READ( RADEON_RBBM_STATUS ) + & RADEON_RBBM_FIFOCNT_MASK ); + if ( slots >= entries ) return 0; + udelay( 1 ); + } + +#if RADEON_FIFO_DEBUG + DRM_ERROR( "failed!\n" ); + radeon_status( dev_priv ); +#endif + return -EBUSY; +} + +static int radeon_do_wait_for_idle( drm_radeon_private_t *dev_priv ) +{ + int i, ret; + + ret = radeon_do_wait_for_fifo( dev_priv, 64 ); + if ( ret < 0 ) return ret; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + if ( !(RADEON_READ( RADEON_RBBM_STATUS ) + & RADEON_RBBM_ACTIVE) ) { + radeon_do_pixcache_flush( dev_priv ); + return 0; + } + udelay( 1 ); + } + +#if RADEON_FIFO_DEBUG + DRM_ERROR( "failed!\n" ); + radeon_status( dev_priv ); +#endif + return -EBUSY; +} + + +/* ================================================================ + * CP control, initialization + */ + +/* Load the microcode for the CP */ +static void radeon_cp_load_microcode( drm_radeon_private_t *dev_priv ) +{ + int i; + + radeon_do_wait_for_idle( dev_priv ); + + RADEON_WRITE( RADEON_CP_ME_RAM_ADDR, 0 ); + for ( i = 0 ; i < 256 ; i++ ) { + RADEON_WRITE( RADEON_CP_ME_RAM_DATAH, + radeon_cp_microcode[i][1] ); + RADEON_WRITE( RADEON_CP_ME_RAM_DATAL, + radeon_cp_microcode[i][0] ); + } +} + +/* Flush any pending commands to the CP. This should only be used just + * prior to a wait for idle, as it informs the engine that the command + * stream is ending. + */ +static void radeon_do_cp_flush( drm_radeon_private_t *dev_priv ) +{ +#if 0 + u32 tmp; + + tmp = RADEON_READ( RADEON_CP_RB_WPTR ) | (1 << 31); + RADEON_WRITE( RADEON_CP_RB_WPTR, tmp ); +#endif +} + +/* Wait for the CP to go idle. + */ +int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ) +{ + RING_LOCALS; + + BEGIN_RING( 6 ); + + RADEON_PURGE_CACHE(); + RADEON_PURGE_ZCACHE(); + RADEON_WAIT_UNTIL_IDLE(); + + ADVANCE_RING(); + + return radeon_do_wait_for_idle( dev_priv ); +} + +/* Start the Command Processor. + */ +static void radeon_do_cp_start( drm_radeon_private_t *dev_priv ) +{ + RING_LOCALS; + + radeon_do_wait_for_idle( dev_priv ); + + RADEON_WRITE( RADEON_CP_CSQ_CNTL, dev_priv->cp_mode ); + + dev_priv->cp_running = 1; + + BEGIN_RING( 6 ); + + RADEON_PURGE_CACHE(); + RADEON_PURGE_ZCACHE(); + RADEON_WAIT_UNTIL_IDLE(); + + ADVANCE_RING(); +} + +/* Reset the Command Processor. This will not flush any pending + * commands, so you must wait for the CP command stream to complete + * before calling this routine. + */ +static void radeon_do_cp_reset( drm_radeon_private_t *dev_priv ) +{ + u32 cur_read_ptr; + + cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); + RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); + *dev_priv->ring.head = cur_read_ptr; + dev_priv->ring.tail = cur_read_ptr; +} + +/* Stop the Command Processor. This will not flush any pending + * commands, so you must flush the command stream and wait for the CP + * to go idle before calling this routine. + */ +static void radeon_do_cp_stop( drm_radeon_private_t *dev_priv ) +{ + RADEON_WRITE( RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS ); + + dev_priv->cp_running = 0; +} + +/* Reset the engine. This will stop the CP if it is running. + */ +static int radeon_do_engine_reset( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + radeon_do_pixcache_flush( dev_priv ); + + clock_cntl_index = RADEON_READ( RADEON_CLOCK_CNTL_INDEX ); + mclk_cntl = RADEON_READ_PLL( dev, RADEON_MCLK_CNTL ); + + /* FIXME: remove magic number here and in radeon ddx driver!!! */ + RADEON_WRITE_PLL( RADEON_MCLK_CNTL, mclk_cntl | 0x003f00000 ); + + rbbm_soft_reset = RADEON_READ( RADEON_RBBM_SOFT_RESET ); + + RADEON_WRITE( RADEON_RBBM_SOFT_RESET, ( rbbm_soft_reset | + RADEON_SOFT_RESET_CP | + RADEON_SOFT_RESET_HI | + RADEON_SOFT_RESET_SE | + RADEON_SOFT_RESET_RE | + RADEON_SOFT_RESET_PP | + RADEON_SOFT_RESET_E2 | + RADEON_SOFT_RESET_RB | + RADEON_SOFT_RESET_HDP ) ); + RADEON_READ( RADEON_RBBM_SOFT_RESET ); + RADEON_WRITE( RADEON_RBBM_SOFT_RESET, ( rbbm_soft_reset & + ~( RADEON_SOFT_RESET_CP | + RADEON_SOFT_RESET_HI | + RADEON_SOFT_RESET_SE | + RADEON_SOFT_RESET_RE | + RADEON_SOFT_RESET_PP | + RADEON_SOFT_RESET_E2 | + RADEON_SOFT_RESET_RB | + RADEON_SOFT_RESET_HDP ) ) ); + RADEON_READ( RADEON_RBBM_SOFT_RESET ); + + + RADEON_WRITE_PLL( RADEON_MCLK_CNTL, mclk_cntl ); + RADEON_WRITE( RADEON_CLOCK_CNTL_INDEX, clock_cntl_index ); + RADEON_WRITE( RADEON_RBBM_SOFT_RESET, rbbm_soft_reset ); + + /* Reset the CP ring */ + radeon_do_cp_reset( dev_priv ); + + /* The CP is no longer running after an engine reset */ + dev_priv->cp_running = 0; + + /* Reset any pending vertex, indirect buffers */ + radeon_freelist_reset( dev ); + + return 0; +} + +static void radeon_cp_init_ring_buffer( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u32 ring_start, cur_read_ptr; + u32 tmp; + + /* Initialize the memory controller */ + RADEON_WRITE( RADEON_MC_FB_LOCATION, + (dev_priv->agp_vm_start - 1) & 0xffff0000 ); + RADEON_WRITE( RADEON_MC_AGP_LOCATION, + (((dev_priv->agp_vm_start - 1 + + dev_priv->agp_size) & 0xffff0000) | + (dev_priv->agp_vm_start >> 16)) ); + + ring_start = (dev_priv->cp_ring->offset + - dev->agp->base + + dev_priv->agp_vm_start); + + RADEON_WRITE( RADEON_CP_RB_BASE, ring_start ); + + /* Set the write pointer delay */ + RADEON_WRITE( RADEON_CP_RB_WPTR_DELAY, 0 ); + + /* Initialize the ring buffer's read and write pointers */ + cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); + RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); + *dev_priv->ring.head = cur_read_ptr; + dev_priv->ring.tail = cur_read_ptr; + + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset ); + + /* Set ring buffer size */ + RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw ); + + radeon_do_wait_for_idle( dev_priv ); + + /* Turn off PCI GART */ + tmp = RADEON_READ( RADEON_AIC_CNTL ) & ~RADEON_PCIGART_TRANSLATE_EN; + RADEON_WRITE( RADEON_AIC_CNTL, tmp ); + + /* Turn on bus mastering */ + tmp = RADEON_READ( RADEON_BUS_CNTL ) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE( RADEON_BUS_CNTL, tmp ); + + /* Sync everything up */ + RADEON_WRITE( RADEON_ISYNC_CNTL, + (RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI) ); +} + +static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) +{ + drm_radeon_private_t *dev_priv; + int i; + + dev_priv = drm_alloc( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); + if ( dev_priv == NULL ) + return -ENOMEM; + dev->dev_private = (void *)dev_priv; + + memset( dev_priv, 0, sizeof(drm_radeon_private_t) ); + + dev_priv->is_pci = init->is_pci; + + /* We don't support PCI cards until PCI GART is implemented. + * Fail here so we can remove all checks for PCI cards around + * the CP ring code. + */ + if ( dev_priv->is_pci ) { + drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } + + dev_priv->usec_timeout = init->usec_timeout; + if ( dev_priv->usec_timeout < 1 || + dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT ) { + drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } + + dev_priv->cp_mode = init->cp_mode; + + /* Simple idle check. + */ + atomic_set( &dev_priv->idle_count, 0 ); + + /* We don't support anything other than bus-mastering ring mode, + * but the ring can be in either AGP or PCI space for the ring + * read pointer. + */ + if ( ( init->cp_mode != RADEON_CSQ_PRIBM_INDDIS ) && + ( init->cp_mode != RADEON_CSQ_PRIBM_INDBM ) ) { + drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } + + switch ( init->fb_bpp ) { + case 16: + dev_priv->color_fmt = RADEON_COLOR_FORMAT_RGB565; + break; + case 32: + default: + dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888; + break; + } + dev_priv->front_offset = init->front_offset; + dev_priv->front_pitch = init->front_pitch; + dev_priv->back_offset = init->back_offset; + dev_priv->back_pitch = init->back_pitch; + + switch ( init->depth_bpp ) { + case 16: + dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z; + break; + case 32: + default: + dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z; + break; + } + dev_priv->depth_offset = init->depth_offset; + dev_priv->depth_pitch = init->depth_pitch; + + dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | + (dev_priv->front_offset >> 10)); + dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | + (dev_priv->back_offset >> 10)); + dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | + (dev_priv->depth_offset >> 10)); + + /* Hardware state for depth clears. Remove this if/when we no + * longer clear the depth buffer with a 3D rectangle. Hard-code + * all values to prevent unwanted 3D state from slipping through + * and screwing with the clear operation. + */ + dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE | + RADEON_Z_ENABLE | + (dev_priv->color_fmt << 10) | + RADEON_ZBLOCK16); + + dev_priv->depth_clear.rb3d_zstencilcntl = (dev_priv->depth_fmt | + RADEON_Z_TEST_ALWAYS | + RADEON_STENCIL_TEST_ALWAYS | + RADEON_STENCIL_S_FAIL_KEEP | + RADEON_STENCIL_ZPASS_KEEP | + RADEON_STENCIL_ZFAIL_KEEP | + RADEON_Z_WRITE_ENABLE); + + dev_priv->depth_clear.se_cntl = (RADEON_FFACE_CULL_CW | + RADEON_BFACE_SOLID | + RADEON_FFACE_SOLID | + RADEON_FLAT_SHADE_VTX_LAST | + + RADEON_DIFFUSE_SHADE_FLAT | + RADEON_ALPHA_SHADE_FLAT | + RADEON_SPECULAR_SHADE_FLAT | + RADEON_FOG_SHADE_FLAT | + + RADEON_VTX_PIX_CENTER_OGL | + RADEON_ROUND_MODE_TRUNC | + RADEON_ROUND_PREC_8TH_PIX); + + /* FIXME: We want multiple shared areas, including one shared + * only by the X Server and kernel module. + */ + for ( i = 0 ; i < dev->map_count ; i++ ) { + if ( dev->maplist[i]->type == _DRM_SHM ) { + dev_priv->sarea = dev->maplist[i]; + break; + } + } + + DO_FIND_MAP( dev_priv->fb, init->fb_offset ); + DO_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + DO_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); + DO_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); + DO_FIND_MAP( dev_priv->buffers, init->buffers_offset ); + + if ( !dev_priv->is_pci ) { + DO_FIND_MAP( dev_priv->agp_textures, + init->agp_textures_offset ); + } + + dev_priv->sarea_priv = + (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + + init->sarea_priv_offset); + + DO_IOREMAP( dev_priv->cp_ring ); + DO_IOREMAP( dev_priv->ring_rptr ); + DO_IOREMAP( dev_priv->buffers ); +#if 0 + if ( !dev_priv->is_pci ) { + DO_IOREMAP( dev_priv->agp_textures ); + } +#endif + + dev_priv->agp_size = init->agp_size; + dev_priv->agp_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ); + dev_priv->agp_buffers_offset = (dev_priv->buffers->offset + - dev->agp->base + + dev_priv->agp_vm_start); + + dev_priv->ring.head = ((__volatile__ u32 *) + dev_priv->ring_rptr->handle); + + dev_priv->ring.start = (u32 *)dev_priv->cp_ring->handle; + dev_priv->ring.end = ((u32 *)dev_priv->cp_ring->handle + + init->ring_size / sizeof(u32)); + dev_priv->ring.size = init->ring_size; + dev_priv->ring.size_l2qw = drm_order( init->ring_size / 8 ); + + dev_priv->ring.tail_mask = + (dev_priv->ring.size / sizeof(u32)) - 1; + +#if 0 + /* Initialize the scratch register pointer. This will cause + * the scratch register values to be written out to memory + * whenever they are updated. + * FIXME: This doesn't quite work yet, so we're disabling it + * for the release. + */ + RADEON_WRITE( RADEON_SCRATCH_ADDR, (dev_priv->ring_rptr->offset + + RADEON_SCRATCH_REG_OFFSET) ); + RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 ); +#endif + + dev_priv->scratch = ((__volatile__ u32 *) + dev_priv->ring_rptr->handle + + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); + + dev_priv->sarea_priv->last_frame = 0; + RADEON_WRITE( RADEON_LAST_FRAME_REG, + dev_priv->sarea_priv->last_frame ); + + dev_priv->sarea_priv->last_dispatch = 0; + RADEON_WRITE( RADEON_LAST_DISPATCH_REG, + dev_priv->sarea_priv->last_dispatch ); + + dev_priv->sarea_priv->last_clear = 0; + RADEON_WRITE( RADEON_LAST_CLEAR_REG, + dev_priv->sarea_priv->last_clear ); + + radeon_cp_load_microcode( dev_priv ); + radeon_cp_init_ring_buffer( dev ); + radeon_do_engine_reset( dev ); + +#if ROTATE_BUFS + dev_priv->last_buf = 0; +#endif + + return 0; +} + +static int radeon_do_cleanup_cp( drm_device_t *dev ) +{ + if ( dev->dev_private ) { + drm_radeon_private_t *dev_priv = dev->dev_private; + + DO_IOREMAPFREE( dev_priv->cp_ring ); + DO_IOREMAPFREE( dev_priv->ring_rptr ); + DO_IOREMAPFREE( dev_priv->buffers ); +#if 0 + if ( !dev_priv->is_pci ) { + DO_IOREMAPFREE( dev_priv->agp_textures ); + } +#endif + + drm_free( dev->dev_private, sizeof(drm_radeon_private_t), + DRM_MEM_DRIVER ); + dev->dev_private = NULL; + } + + return 0; +} + +int radeon_cp_init( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_init_t init; + + if ( copy_from_user( &init, (drm_radeon_init_t *)arg, sizeof(init) ) ) + return -EFAULT; + + switch ( init.func ) { + case RADEON_INIT_CP: + return radeon_do_init_cp( dev, &init ); + case RADEON_CLEANUP_CP: + return radeon_do_cleanup_cp( dev ); + } + + return -EINVAL; +} + +int radeon_cp_start( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + if ( dev_priv->cp_running ) { + DRM_DEBUG( "%s while CP running\n", __FUNCTION__ ); + return 0; + } + if ( dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS ) { + DRM_DEBUG( "%s called with bogus CP mode (%d)\n", + __FUNCTION__, dev_priv->cp_mode ); + return 0; + } + + radeon_do_cp_start( dev_priv ); + + return 0; +} + +/* Stop the CP. The engine must have been idled before calling this + * routine. + */ +int radeon_cp_stop( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_cp_stop_t stop; + int ret; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &stop, (drm_radeon_init_t *)arg, sizeof(stop) ) ) + return -EFAULT; + + /* Flush any pending CP commands. This ensures any outstanding + * commands are exectuted by the engine before we turn it off. + */ + if ( stop.flush ) { + radeon_do_cp_flush( dev_priv ); + } + + /* If we fail to make the engine go idle, we return an error + * code so that the DRM ioctl wrapper can try again. + */ + if ( stop.idle ) { + ret = radeon_do_cp_idle( dev_priv ); + if ( ret < 0 ) return ret; + } + + /* Finally, we can turn off the CP. If the engine isn't idle, + * we will get some dropped triangles as they won't be fully + * rendered before the CP is shut down. + */ + radeon_do_cp_stop( dev_priv ); + + /* Reset the engine */ + radeon_do_engine_reset( dev ); + + return 0; +} + +/* Just reset the CP ring. Called as part of an X Server engine reset. + */ +int radeon_cp_reset( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + if ( !dev_priv ) { + DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); + return -EINVAL; + } + + radeon_do_cp_reset( dev_priv ); + + /* The CP is no longer running after an engine reset */ + dev_priv->cp_running = 0; + + return 0; +} + +int radeon_cp_idle( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + return radeon_do_cp_idle( dev_priv ); +} + +int radeon_engine_reset( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + return radeon_do_engine_reset( dev ); +} + + +/* ================================================================ + * Fullscreen mode + */ + +static int radeon_do_init_pageflip( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + dev_priv->crtc_offset = RADEON_READ( RADEON_CRTC_OFFSET ); + dev_priv->crtc_offset_cntl = RADEON_READ( RADEON_CRTC_OFFSET_CNTL ); + + RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->front_offset ); + RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL, + dev_priv->crtc_offset_cntl | + RADEON_CRTC_OFFSET_FLIP_CNTL ); + + dev_priv->page_flipping = 1; + dev_priv->current_page = 0; + + return 0; +} + +int radeon_do_cleanup_pageflip( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->crtc_offset ); + RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl ); + + dev_priv->page_flipping = 0; + dev_priv->current_page = 0; + + return 0; +} + +int radeon_fullscreen( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_fullscreen_t fs; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &fs, (drm_radeon_fullscreen_t *)arg, + sizeof(fs) ) ) + return -EFAULT; + + switch ( fs.func ) { + case RADEON_INIT_FULLSCREEN: + return radeon_do_init_pageflip( dev ); + case RADEON_CLEANUP_FULLSCREEN: + return radeon_do_cleanup_pageflip( dev ); + } + + return -EINVAL; +} + + +/* ================================================================ + * Freelist management + */ +#define RADEON_BUFFER_USED 0xffffffff +#define RADEON_BUFFER_FREE 0 + +#if 0 +static int radeon_freelist_init( drm_device_t *dev ) +{ + drm_device_dma_t *dma = dev->dma; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_buf_t *buf; + drm_radeon_buf_priv_t *buf_priv; + drm_radeon_freelist_t *entry; + int i; + + dev_priv->head = drm_alloc( sizeof(drm_radeon_freelist_t), + DRM_MEM_DRIVER ); + if ( dev_priv->head == NULL ) + return -ENOMEM; + + memset( dev_priv->head, 0, sizeof(drm_radeon_freelist_t) ); + dev_priv->head->age = RADEON_BUFFER_USED; + + for ( i = 0 ; i < dma->buf_count ; i++ ) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + + entry = drm_alloc( sizeof(drm_radeon_freelist_t), + DRM_MEM_DRIVER ); + if ( !entry ) return -ENOMEM; + + entry->age = RADEON_BUFFER_FREE; + entry->buf = buf; + entry->prev = dev_priv->head; + entry->next = dev_priv->head->next; + if ( !entry->next ) + dev_priv->tail = entry; + + buf_priv->discard = 0; + buf_priv->dispatched = 0; + buf_priv->list_entry = entry; + + dev_priv->head->next = entry; + + if ( dev_priv->head->next ) + dev_priv->head->next->prev = entry; + } + + return 0; + +} +#endif + +drm_buf_t *radeon_freelist_get( drm_device_t *dev ) +{ + drm_device_dma_t *dma = dev->dma; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, t; +#if ROTATE_BUFS + int start; +#endif + + /* FIXME: Optimize -- use freelist code */ + + for ( i = 0 ; i < dma->buf_count ; i++ ) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if ( buf->pid == 0 ) { + DRM_DEBUG( " ret buf=%d last=%d pid=0\n", + buf->idx, dev_priv->last_buf ); + return buf; + } + DRM_DEBUG( " skipping buf=%d pid=%d\n", + buf->idx, buf->pid ); + } + +#if ROTATE_BUFS + if ( ++dev_priv->last_buf >= dma->buf_count ) + dev_priv->last_buf = 0; + start = dev_priv->last_buf; +#endif + for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) { +#if 0 + /* FIXME: Disable this for now */ + u32 done_age = dev_priv->scratch[RADEON_LAST_DISPATCH]; +#else + u32 done_age = RADEON_READ( RADEON_LAST_DISPATCH_REG ); +#endif +#if ROTATE_BUFS + for ( i = start ; i < dma->buf_count ; i++ ) { +#else + for ( i = 0 ; i < dma->buf_count ; i++ ) { +#endif + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if ( buf->pending && buf_priv->age <= done_age ) { + /* The buffer has been processed, so it + * can now be used. + */ + buf->pending = 0; + DRM_DEBUG( " ret buf=%d last=%d age=%d done=%d\n", buf->idx, dev_priv->last_buf, buf_priv->age, done_age ); + return buf; + } + DRM_DEBUG( " skipping buf=%d age=%d done=%d\n", + buf->idx, buf_priv->age, + done_age ); +#if ROTATE_BUFS + start = 0; +#endif + } + udelay( 1 ); + } + + DRM_ERROR( "returning NULL!\n" ); + return NULL; +} + +void radeon_freelist_reset( drm_device_t *dev ) +{ + drm_device_dma_t *dma = dev->dma; +#if ROTATE_BUFS + drm_radeon_private_t *dev_priv = dev->dev_private; +#endif + int i; + +#if ROTATE_BUFS + dev_priv->last_buf = 0; +#endif + for ( i = 0 ; i < dma->buf_count ; i++ ) { + drm_buf_t *buf = dma->buflist[i]; + drm_radeon_buf_priv_t *buf_priv = buf->dev_private; + buf_priv->age = 0; + } +} + + +/* ================================================================ + * CP command submission + */ + +int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ) +{ + drm_radeon_ring_buffer_t *ring = &dev_priv->ring; + int i; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + ring->space = *ring->head - ring->tail; + if ( ring->space <= 0 ) + ring->space += ring->size; + + if ( ring->space >= n ) + return 0; + + udelay( 1 ); + } + + /* FIXME: This return value is ignored in the BEGIN_RING macro! */ + DRM_ERROR( "failed!\n" ); + return -EBUSY; +} + +void radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_ring_buffer_t *ring = &dev_priv->ring; + + ring->space = *ring->head - ring->tail; + if ( ring->space == 0 ) + atomic_inc( &dev_priv->idle_count ); + if ( ring->space <= 0 ) + ring->space += ring->size; +} + +static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d ) +{ + int i; + drm_buf_t *buf; + + for ( i = d->granted_count ; i < d->request_count ; i++ ) { + buf = radeon_freelist_get( dev ); + if ( !buf ) return -EAGAIN; + + buf->pid = current->pid; + + if ( copy_to_user( &d->request_indices[i], &buf->idx, + sizeof(buf->idx) ) ) + return -EFAULT; + if ( copy_to_user( &d->request_sizes[i], &buf->total, + sizeof(buf->total) ) ) + return -EFAULT; + + d->granted_count++; + } + return 0; +} + +int radeon_cp_buffers( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + int ret = 0; + drm_dma_t d; + + if ( copy_from_user( &d, (drm_dma_t *) arg, sizeof(d) ) ) + return -EFAULT; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + /* Please don't send us buffers. + */ + if ( d.send_count != 0 ) { + DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count ); + return -EINVAL; + } + + /* We'll send you buffers. + */ + if ( d.request_count < 0 || d.request_count > dma->buf_count ) { + DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count ); + return -EINVAL; + } + + d.granted_count = 0; + + if ( d.request_count ) { + ret = radeon_cp_get_buffers( dev, &d ); + } + + if ( copy_to_user( (drm_dma_t *) arg, &d, sizeof(d) ) ) + return -EFAULT; + + return ret; +} diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h new file mode 100644 index 000000000..c5f9f66d1 --- /dev/null +++ b/drivers/char/drm/radeon_drm.h @@ -0,0 +1,325 @@ +/* radeon_drm.h -- Public header for the radeon driver -*- linux-c -*- + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_DRM_H__ +#define __RADEON_DRM_H__ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the X server file (radeon_sarea.h) + */ +#ifndef __RADEON_SAREA_DEFINES__ +#define __RADEON_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? + */ +#define RADEON_UPLOAD_CONTEXT 0x00000001 +#define RADEON_UPLOAD_VERTFMT 0x00000002 +#define RADEON_UPLOAD_LINE 0x00000004 +#define RADEON_UPLOAD_BUMPMAP 0x00000008 +#define RADEON_UPLOAD_MASKS 0x00000010 +#define RADEON_UPLOAD_VIEWPORT 0x00000020 +#define RADEON_UPLOAD_SETUP 0x00000040 +#define RADEON_UPLOAD_TCL 0x00000080 +#define RADEON_UPLOAD_MISC 0x00000100 +#define RADEON_UPLOAD_TEX0 0x00000200 +#define RADEON_UPLOAD_TEX1 0x00000400 +#define RADEON_UPLOAD_TEX2 0x00000800 +#define RADEON_UPLOAD_TEX0IMAGES 0x00001000 +#define RADEON_UPLOAD_TEX1IMAGES 0x00002000 +#define RADEON_UPLOAD_TEX2IMAGES 0x00004000 +#define RADEON_UPLOAD_CLIPRECTS 0x00008000 /* handled client-side */ +#define RADEON_REQUIRE_QUIESCENCE 0x00010000 +#define RADEON_UPLOAD_ALL 0x0001ffff + +#define RADEON_FRONT 0x1 +#define RADEON_BACK 0x2 +#define RADEON_DEPTH 0x4 + +/* Primitive types + */ +#define RADEON_POINTS 0x1 +#define RADEON_LINES 0x2 +#define RADEON_LINE_STRIP 0x3 +#define RADEON_TRIANGLES 0x4 +#define RADEON_TRIANGLE_FAN 0x5 +#define RADEON_TRIANGLE_STRIP 0x6 + +/* Vertex/indirect buffer size + */ +#define RADEON_BUFFER_SIZE 16384 + +/* Byte offsets for indirect buffer data + */ +#define RADEON_INDEX_PRIM_OFFSET 20 +#define RADEON_HOSTDATA_BLIT_OFFSET 32 + +#define RADEON_SCRATCH_REG_OFFSET 32 + +/* Keep these small for testing + */ +#define RADEON_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/AGP). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define RADEON_LOCAL_TEX_HEAP 0 +#define RADEON_AGP_TEX_HEAP 1 +#define RADEON_NR_TEX_HEAPS 2 +#define RADEON_NR_TEX_REGIONS 64 +#define RADEON_LOG_TEX_GRANULARITY 16 + +#define RADEON_MAX_TEXTURE_LEVELS 11 +#define RADEON_MAX_TEXTURE_UNITS 3 + +#endif /* __RADEON_SAREA_DEFINES__ */ + +typedef struct { + unsigned int red; + unsigned int green; + unsigned int blue; + unsigned int alpha; +} radeon_color_regs_t; + +typedef struct { + /* Context state */ + unsigned int pp_misc; /* 0x1c14 */ + unsigned int pp_fog_color; + unsigned int re_solid_color; + unsigned int rb3d_blendcntl; + unsigned int rb3d_depthoffset; + unsigned int rb3d_depthpitch; + unsigned int rb3d_zstencilcntl; + + unsigned int pp_cntl; /* 0x1c38 */ + unsigned int rb3d_cntl; + unsigned int rb3d_coloroffset; + unsigned int re_width_height; + unsigned int rb3d_colorpitch; + unsigned int se_cntl; + + /* Vertex format state */ + unsigned int se_coord_fmt; /* 0x1c50 */ + + /* Line state */ + unsigned int re_line_pattern; /* 0x1cd0 */ + unsigned int re_line_state; + + unsigned int se_line_width; /* 0x1db8 */ + + /* Bumpmap state */ + unsigned int pp_lum_matrix; /* 0x1d00 */ + + unsigned int pp_rot_matrix_0; /* 0x1d58 */ + unsigned int pp_rot_matrix_1; + + /* Mask state */ + unsigned int rb3d_stencilrefmask; /* 0x1d7c */ + unsigned int rb3d_ropcntl; + unsigned int rb3d_planemask; + + /* Viewport state */ + unsigned int se_vport_xscale; /* 0x1d98 */ + unsigned int se_vport_xoffset; + unsigned int se_vport_yscale; + unsigned int se_vport_yoffset; + unsigned int se_vport_zscale; + unsigned int se_vport_zoffset; + + /* Setup state */ + unsigned int se_cntl_status; /* 0x2140 */ + +#ifdef TCL_ENABLE + /* TCL state */ + radeon_color_regs_t se_tcl_material_emmissive; /* 0x2210 */ + radeon_color_regs_t se_tcl_material_ambient; + radeon_color_regs_t se_tcl_material_diffuse; + radeon_color_regs_t se_tcl_material_specular; + unsigned int se_tcl_shininess; + unsigned int se_tcl_output_vtx_fmt; + unsigned int se_tcl_output_vtx_sel; + unsigned int se_tcl_matrix_select_0; + unsigned int se_tcl_matrix_select_1; + unsigned int se_tcl_ucp_vert_blend_ctl; + unsigned int se_tcl_texture_proc_ctl; + unsigned int se_tcl_light_model_ctl; + unsigned int se_tcl_per_light_ctl[4]; +#endif + + /* Misc state */ + unsigned int re_top_left; /* 0x26c0 */ + unsigned int re_misc; +} drm_radeon_context_regs_t; + +/* Setup registers for each texture unit + */ +typedef struct { + unsigned int pp_txfilter; + unsigned int pp_txformat; + unsigned int pp_txoffset; + unsigned int pp_txcblend; + unsigned int pp_txablend; + unsigned int pp_tfactor; + + unsigned int pp_border_color; + +#ifdef CUBIC_ENABLE + unsigned int pp_cubic_faces; + unsigned int pp_cubic_offset[5]; +#endif +} drm_radeon_texture_regs_t; + +typedef struct { + unsigned char next, prev; + unsigned char in_use; + int age; +} drm_radeon_tex_region_t; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + drm_radeon_context_regs_t context_state; + drm_radeon_texture_regs_t tex_state[RADEON_MAX_TEXTURE_UNITS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + + /* The current cliprects, or a subset thereof. + */ + drm_clip_rect_t boxes[RADEON_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Counters for client-side throttling of rendering clients. + */ + unsigned int last_frame; + unsigned int last_dispatch; + unsigned int last_clear; + + drm_radeon_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; + int tex_age[RADEON_NR_TEX_HEAPS]; + int ctx_owner; +} drm_radeon_sarea_t; + + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmRadeon.h) + */ +typedef struct drm_radeon_init { + enum { + RADEON_INIT_CP = 0x01, + RADEON_CLEANUP_CP = 0x02 + } func; + int sarea_priv_offset; + int is_pci; + int cp_mode; + int agp_size; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned int fb_offset; + unsigned int mmio_offset; + unsigned int ring_offset; + unsigned int ring_rptr_offset; + unsigned int buffers_offset; + unsigned int agp_textures_offset; +} drm_radeon_init_t; + +typedef struct drm_radeon_cp_stop { + int flush; + int idle; +} drm_radeon_cp_stop_t; + +typedef struct drm_radeon_fullscreen { + enum { + RADEON_INIT_FULLSCREEN = 0x01, + RADEON_CLEANUP_FULLSCREEN = 0x02 + } func; +} drm_radeon_fullscreen_t; + +#define CLEAR_X1 0 +#define CLEAR_Y1 1 +#define CLEAR_X2 2 +#define CLEAR_Y2 3 +#define CLEAR_DEPTH 4 + +typedef struct drm_radeon_clear { + unsigned int flags; + int x, y, w, h; + unsigned int clear_color; + unsigned int clear_depth; + union { + float f[5]; + unsigned int ui[5]; + } rect; +} drm_radeon_clear_t; + +typedef struct drm_radeon_vertex { + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ +} drm_radeon_vertex_t; + +typedef struct drm_radeon_indices { + int prim; + int idx; + int start; + int end; + int discard; /* Client finished with buffer? */ +} drm_radeon_indices_t; + +typedef struct drm_radeon_blit { + int idx; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drm_radeon_blit_t; + +typedef struct drm_radeon_stipple { + unsigned int *mask; +} drm_radeon_stipple_t; + +typedef struct drm_radeon_indirect { + int idx; + int start; + int end; + int discard; +} drm_radeon_indirect_t; + +#endif diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c new file mode 100644 index 000000000..0113ed97c --- /dev/null +++ b/drivers/char/drm/radeon_drv.c @@ -0,0 +1,702 @@ +/* radeon_drv.c -- ATI Radeon driver -*- linux-c -*- + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Kevin E. Martin <martin@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#include <linux/config.h> +#include "drmP.h" +#include "radeon_drv.h" + +#define RADEON_NAME "radeon" +#define RADEON_DESC "ATI Radeon" +#define RADEON_DATE "20010105" +#define RADEON_MAJOR 1 +#define RADEON_MINOR 0 +#define RADEON_PATCHLEVEL 0 + +static drm_device_t radeon_device; +drm_ctx_t radeon_res_ctx; + +static struct file_operations radeon_fops = { +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ + owner: THIS_MODULE, +#endif + open: radeon_open, + flush: drm_flush, + release: radeon_release, + ioctl: radeon_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +static struct miscdevice radeon_misc = { + minor: MISC_DYNAMIC_MINOR, + name: RADEON_NAME, + fops: &radeon_fops, +}; + +static drm_ioctl_desc_t radeon_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { radeon_version, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { radeon_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { radeon_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { radeon_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { radeon_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { radeon_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { radeon_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { radeon_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { radeon_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { radeon_resctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { radeon_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { radeon_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, +#endif + + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_INIT)] = { radeon_cp_init, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_START)] = { radeon_cp_start, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)] = { radeon_cp_stop, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)] = { radeon_cp_reset, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)] = { radeon_cp_idle, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)] = { radeon_engine_reset, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)] = { radeon_cp_swap, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CLEAR)] = { radeon_cp_clear, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX)] = { radeon_cp_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDICES)] = { radeon_cp_indices, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_BLIT)] = { radeon_cp_blit, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)]= { radeon_cp_indirect,1, 1 }, +}; +#define RADEON_IOCTL_COUNT DRM_ARRAY_SIZE(radeon_ioctls) + +#ifdef MODULE +static char *radeon = NULL; +#endif + +MODULE_AUTHOR("VA Linux Systems, Inc."); +MODULE_DESCRIPTION("radeon"); +MODULE_PARM(radeon, "s"); + +#ifndef MODULE +/* radeon_options is called by the kernel to parse command-line options + * passed via the boot-loader (e.g., LILO). It calls the insmod option + * routine, drm_parse_drm. + */ + +static int __init radeon_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("radeon=", radeon_options); +#endif + +static int radeon_setup(drm_device_t *dev) +{ + int i; + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + drm_dma_setup(dev); + + atomic_set(&dev->total_open, 0); + atomic_set(&dev->total_close, 0); + atomic_set(&dev->total_ioctl, 0); + atomic_set(&dev->total_irq, 0); + atomic_set(&dev->total_ctx, 0); + atomic_set(&dev->total_locks, 0); + atomic_set(&dev->total_unlocks, 0); + atomic_set(&dev->total_contends, 0); + atomic_set(&dev->total_sleeps, 0); + + for (i = 0; i < DRM_HASH_SIZE; i++) { + dev->magiclist[i].head = NULL; + dev->magiclist[i].tail = NULL; + } + dev->maplist = NULL; + dev->map_count = 0; + dev->vmalist = NULL; + dev->lock.hw_lock = NULL; + init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; + dev->queue_reserved = 0; + dev->queue_slots = 0; + dev->queuelist = NULL; + dev->irq = 0; + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); + + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_rp = dev->buf; + dev->buf_wp = dev->buf; + dev->buf_end = dev->buf + DRM_BSZ; + dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); + init_waitqueue_head(&dev->buf_writers); + + radeon_res_ctx.handle = -1; + + DRM_DEBUG("\n"); + + /* The kernel's context could be created here, but is now created + in drm_dma_enqueue. This is more resource-efficient for + hardware that does not do DMA, but may mean that + drm_select_queue fails between the time the interrupt is + initialized and the time the queues are initialized. */ + + return 0; +} + + +static int radeon_takedown(drm_device_t *dev) +{ + int i; + drm_magic_entry_t *pt, *next; + drm_map_t *map; + drm_vma_entry_t *vma, *vma_next; + + DRM_DEBUG("\n"); + + down(&dev->struct_sem); + del_timer(&dev->timer); + + if (dev->devname) { + drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); + dev->devname = NULL; + } + + if (dev->unique) { + drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); + dev->unique = NULL; + dev->unique_len = 0; + } + /* Clear pid list */ + for (i = 0; i < DRM_HASH_SIZE; i++) { + for (pt = dev->magiclist[i].head; pt; pt = next) { + next = pt->next; + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + dev->magiclist[i].head = dev->magiclist[i].tail = NULL; + } + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + /* Clear AGP information */ + if (dev->agp) { + drm_agp_mem_t *entry; + drm_agp_mem_t *nexte; + + /* Remove AGP resources, but leave dev->agp + intact until radeon_cleanup is called. */ + for (entry = dev->agp->memory; entry; entry = nexte) { + nexte = entry->next; + if (entry->bound) drm_unbind_agp(entry->memory); + drm_free_agp(entry->memory, entry->pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + } + dev->agp->memory = NULL; + + if (dev->agp->acquired) _drm_agp_release(); + + dev->agp->acquired = 0; + dev->agp->enabled = 0; + } +#endif + + /* Clear vma list (only built for debugging) */ + if (dev->vmalist) { + for (vma = dev->vmalist; vma; vma = vma_next) { + vma_next = vma->next; + drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + } + dev->vmalist = NULL; + } + + /* Clear map area and mtrr information */ + if (dev->maplist) { + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#ifdef CONFIG_MTRR + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } +#endif + drm_ioremapfree(map->handle, map->size); + break; + case _DRM_SHM: + drm_free_pages((unsigned long)map->handle, + drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + break; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + break; + } + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + drm_free(dev->maplist, + dev->map_count * sizeof(*dev->maplist), + DRM_MEM_MAPS); + dev->maplist = NULL; + dev->map_count = 0; + } + + drm_dma_takedown(dev); + + dev->queue_count = 0; + if (dev->lock.hw_lock) { + dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + } + up(&dev->struct_sem); + + return 0; +} + +/* radeon_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +static int __init radeon_init(void) +{ + int retcode; + drm_device_t *dev = &radeon_device; + + DRM_DEBUG("\n"); + + memset((void *)dev, 0, sizeof(*dev)); + dev->count_lock = SPIN_LOCK_UNLOCKED; + sema_init(&dev->struct_sem, 1); + +#ifdef MODULE + drm_parse_options(radeon); +#endif + + if ((retcode = misc_register(&radeon_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", RADEON_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, radeon_misc.minor); + dev->name = RADEON_NAME; + + drm_mem_init(); + drm_proc_init(dev); + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + dev->agp = drm_agp_init(); + if (dev->agp == NULL) { + DRM_ERROR("Cannot initialize agpgart module.\n"); + drm_proc_cleanup(); + misc_deregister(&radeon_misc); + radeon_takedown(dev); + return -ENOMEM; + } + +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size*1024*1024, + MTRR_TYPE_WRCOMB, + 1); +#endif +#endif + + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&radeon_misc); + radeon_takedown(dev); + return retcode; + } + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + RADEON_NAME, + RADEON_MAJOR, + RADEON_MINOR, + RADEON_PATCHLEVEL, + RADEON_DATE, + radeon_misc.minor); + + return 0; +} + +/* radeon_cleanup is called via cleanup_module at module unload time. */ + +static void __exit radeon_cleanup(void) +{ + drm_device_t *dev = &radeon_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&radeon_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + drm_ctxbitmap_cleanup(dev); + radeon_takedown(dev); +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + if (dev->agp) { + drm_agp_uninit(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +#endif +} + +module_init(radeon_init); +module_exit(radeon_cleanup); + + +int radeon_version(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_version_t version; + int len; + + if (copy_from_user(&version, + (drm_version_t *)arg, + sizeof(version))) + return -EFAULT; + +#define DRM_COPY(name,value) \ + len = strlen(value); \ + if (len > name##_len) len = name##_len; \ + name##_len = strlen(value); \ + if (len && name) { \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ + } + + version.version_major = RADEON_MAJOR; + version.version_minor = RADEON_MINOR; + version.version_patchlevel = RADEON_PATCHLEVEL; + + DRM_COPY(version.name, RADEON_NAME); + DRM_COPY(version.date, RADEON_DATE); + DRM_COPY(version.desc, RADEON_DESC); + + if (copy_to_user((drm_version_t *)arg, + &version, + sizeof(version))) + return -EFAULT; + return 0; +} + +int radeon_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &radeon_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return radeon_setup(dev); + } + spin_unlock(&dev->count_lock); + } + + return retcode; +} + +int radeon_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + int retcode = 0; + + lock_kernel(); + dev = priv->dev; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + + /* Force the cleanup of page flipping when required */ + if ( dev->dev_private ) { + drm_radeon_private_t *dev_priv = dev->dev_private; + if ( dev_priv->page_flipping ) { + radeon_do_cleanup_pageflip( dev ); + } + } + + if (!(retcode = drm_release(inode, filp))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return radeon_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + + unlock_kernel(); + return retcode; +} + +/* radeon_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int radeon_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int nr = DRM_IOCTL_NR(cmd); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + + atomic_inc(&dev->ioctl_count); + atomic_inc(&dev->total_ioctl); + ++priv->ioctl_count; + + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, priv->authenticated); + + if (nr >= RADEON_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &radeon_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + retcode = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + retcode = -EACCES; + } else { + retcode = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + return retcode; +} + +int radeon_lock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_lock_t lock; +#if DRM_DMA_HISTOGRAM + cycles_t start; + + dev->lck_start = start = get_cycles(); +#endif + + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); + + if (lock.context < 0 /* || lock.context >= dev->queue_count */) + return -EINVAL; + + if (!ret) { + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + + if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_READY) { + /* Wait for space in DMA/FIFO */ + } + if (lock.flags & _DRM_LOCK_QUIESCENT) { + /* Make hardware quiescent */ + DRM_DEBUG("not quiescent!\n"); +#if 0 + radeon_quiescent(dev); +#endif + } + } + +#if LINUX_VERSION_CODE < 0x020400 + if (lock.context != radeon_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY/4; + } +#endif + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); +#endif + + return ret; +} + + +int radeon_unlock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d frees lock (%d holds)\n", + lock.context, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + atomic_inc(&dev->total_unlocks); + if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) + atomic_inc(&dev->total_contends); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + /* FIXME: Try to send data to card here */ + if (!dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + +#if LINUX_VERSION_CODE < 0x020400 + if (lock.context != radeon_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY; + } +#endif + unblock_all_signals(); + return 0; +} diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h new file mode 100644 index 000000000..06b541991 --- /dev/null +++ b/drivers/char/drm/radeon_drv.h @@ -0,0 +1,709 @@ +/* radeon_drv.h -- Private header for radeon driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Rickard E. (Rik) Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_DRV_H__ +#define __RADEON_DRV_H__ + +typedef struct drm_radeon_freelist { + unsigned int age; + drm_buf_t *buf; + struct drm_radeon_freelist *next; + struct drm_radeon_freelist *prev; +} drm_radeon_freelist_t; + +typedef struct drm_radeon_ring_buffer { + u32 *start; + u32 *end; + int size; + int size_l2qw; + + volatile u32 *head; + u32 tail; + u32 tail_mask; + int space; +} drm_radeon_ring_buffer_t; + +typedef struct drm_radeon_depth_clear_t { + u32 rb3d_cntl; + u32 rb3d_zstencilcntl; + u32 se_cntl; +} drm_radeon_depth_clear_t; + +typedef struct drm_radeon_private { + drm_radeon_ring_buffer_t ring; + drm_radeon_sarea_t *sarea_priv; + + int agp_size; + u32 agp_vm_start; + u32 agp_buffers_offset; + + int cp_mode; + int cp_running; + + drm_radeon_freelist_t *head; + drm_radeon_freelist_t *tail; +/* FIXME: ROTATE_BUFS is a hask to cycle through bufs until freelist + code is used. Note this hides a problem with the scratch register + (used to keep track of last buffer completed) being written to before + the last buffer has actually completed rendering. */ +#define ROTATE_BUFS 1 +#if ROTATE_BUFS + int last_buf; +#endif + volatile u32 *scratch; + + int usec_timeout; + int is_pci; + + atomic_t idle_count; + + int page_flipping; + int current_page; + u32 crtc_offset; + u32 crtc_offset_cntl; + + unsigned int color_fmt; + unsigned int front_offset; + unsigned int front_pitch; + unsigned int back_offset; + unsigned int back_pitch; + + unsigned int depth_fmt; + unsigned int depth_offset; + unsigned int depth_pitch; + + u32 front_pitch_offset; + u32 back_pitch_offset; + u32 depth_pitch_offset; + + drm_radeon_depth_clear_t depth_clear; + + drm_map_t *sarea; + drm_map_t *fb; + drm_map_t *mmio; + drm_map_t *cp_ring; + drm_map_t *ring_rptr; + drm_map_t *buffers; + drm_map_t *agp_textures; +} drm_radeon_private_t; + +typedef struct drm_radeon_buf_priv { + u32 age; + int prim; + int discard; + int dispatched; + drm_radeon_freelist_t *list_entry; +} drm_radeon_buf_priv_t; + + /* radeon_drv.c */ +extern int radeon_version( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_open( struct inode *inode, struct file *filp ); +extern int radeon_release( struct inode *inode, struct file *filp ); +extern int radeon_ioctl( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_lock( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_unlock( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + + /* radeon_cp.c */ +extern int radeon_cp_init( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_start( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_stop( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_reset( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_idle( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_engine_reset( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_fullscreen( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_buffers( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + +extern void radeon_freelist_reset( drm_device_t *dev ); +extern drm_buf_t *radeon_freelist_get( drm_device_t *dev ); + +extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ); +extern void radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv ); + +extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ); +extern int radeon_do_cleanup_pageflip( drm_device_t *dev ); + + /* radeon_state.c */ +extern int radeon_cp_clear( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_swap( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_vertex( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_indices( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_blit( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_stipple( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int radeon_cp_indirect( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + + /* radeon_bufs.c */ +extern int radeon_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_mapbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* radeon_context.c */ +extern int radeon_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int radeon_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int radeon_context_switch(drm_device_t *dev, int old, int new); +extern int radeon_context_switch_complete(drm_device_t *dev, int new); + + +/* Register definitions, register access macros and drmAddMap constants + * for Radeon kernel driver. + */ + +#define RADEON_AUX_SCISSOR_CNTL 0x26f0 +# define RADEON_EXCLUSIVE_SCISSOR_0 (1 << 24) +# define RADEON_EXCLUSIVE_SCISSOR_1 (1 << 25) +# define RADEON_EXCLUSIVE_SCISSOR_2 (1 << 26) +# define RADEON_SCISSOR_0_ENABLE (1 << 28) +# define RADEON_SCISSOR_1_ENABLE (1 << 29) +# define RADEON_SCISSOR_2_ENABLE (1 << 30) + +#define RADEON_BUS_CNTL 0x0030 +# define RADEON_BUS_MASTER_DIS (1 << 6) + +#define RADEON_CLOCK_CNTL_DATA 0x000c +# define RADEON_PLL_WR_EN (1 << 7) +#define RADEON_CLOCK_CNTL_INDEX 0x0008 +#define RADEON_CONFIG_APER_SIZE 0x0108 +#define RADEON_CRTC_OFFSET 0x0224 +#define RADEON_CRTC_OFFSET_CNTL 0x0228 +# define RADEON_CRTC_TILE_EN (1 << 15) +# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16) + +#define RADEON_RB3D_COLORPITCH 0x1c48 +#define RADEON_RB3D_DEPTHCLEARVALUE 0x1c30 +#define RADEON_RB3D_DEPTHXY_OFFSET 0x1c60 + +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define RADEON_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define RADEON_GMC_BRUSH_NONE (15 << 4) +# define RADEON_GMC_DST_16BPP (4 << 8) +# define RADEON_GMC_DST_24BPP (5 << 8) +# define RADEON_GMC_DST_32BPP (6 << 8) +# define RADEON_GMC_DST_DATATYPE_SHIFT 8 +# define RADEON_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define RADEON_DP_SRC_SOURCE_MEMORY (2 << 24) +# define RADEON_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define RADEON_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define RADEON_GMC_WR_MSK_DIS (1 << 30) +# define RADEON_ROP3_S 0x00cc0000 +# define RADEON_ROP3_P 0x00f00000 +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_DST_PITCH_OFFSET_C 0x1c80 +# define RADEON_DST_TILE_LINEAR (0 << 30) +# define RADEON_DST_TILE_MACRO (1 << 30) +# define RADEON_DST_TILE_MICRO (2 << 30) +# define RADEON_DST_TILE_BOTH (3 << 30) + +#define RADEON_SCRATCH_REG0 0x15e0 +#define RADEON_SCRATCH_REG1 0x15e4 +#define RADEON_SCRATCH_REG2 0x15e8 +#define RADEON_SCRATCH_REG3 0x15ec +#define RADEON_SCRATCH_REG4 0x15f0 +#define RADEON_SCRATCH_REG5 0x15f4 +#define RADEON_SCRATCH_UMSK 0x0770 +#define RADEON_SCRATCH_ADDR 0x0774 + +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28) +# define RADEON_HDP_WC_TIMEOUT_28BCLK (7 << 28) + +#define RADEON_ISYNC_CNTL 0x1724 +# define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0) +# define RADEON_ISYNC_ANY3D_IDLE2D (1 << 1) +# define RADEON_ISYNC_TRIG2D_IDLE3D (1 << 2) +# define RADEON_ISYNC_TRIG3D_IDLE2D (1 << 3) +# define RADEON_ISYNC_WAIT_IDLEGUI (1 << 4) +# define RADEON_ISYNC_CPSCRATCH_IDLEGUI (1 << 5) + +#define RADEON_MC_AGP_LOCATION 0x014c +#define RADEON_MC_FB_LOCATION 0x0148 +#define RADEON_MCLK_CNTL 0x0012 + +#define RADEON_PP_BORDER_COLOR_0 0x1d40 +#define RADEON_PP_BORDER_COLOR_1 0x1d44 +#define RADEON_PP_BORDER_COLOR_2 0x1d48 +#define RADEON_PP_CNTL 0x1c38 +# define RADEON_SCISSOR_ENABLE (1 << 1) +#define RADEON_PP_LUM_MATRIX 0x1d00 +#define RADEON_PP_MISC 0x1c14 +#define RADEON_PP_ROT_MATRIX_0 0x1d58 +#define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXFILTER_1 0x1c6c +#define RADEON_PP_TXFILTER_2 0x1c84 + +#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c +# define RADEON_RB2D_DC_FLUSH (3 << 0) +# define RADEON_RB2D_DC_FREE (3 << 2) +# define RADEON_RB2D_DC_FLUSH_ALL 0xf +# define RADEON_RB2D_DC_BUSY (1 << 31) +#define RADEON_RB3D_CNTL 0x1c3c +# define RADEON_ALPHA_BLEND_ENABLE (1 << 0) +# define RADEON_PLANE_MASK_ENABLE (1 << 1) +# define RADEON_DITHER_ENABLE (1 << 2) +# define RADEON_ROUND_ENABLE (1 << 3) +# define RADEON_SCALE_DITHER_ENABLE (1 << 4) +# define RADEON_DITHER_INIT (1 << 5) +# define RADEON_ROP_ENABLE (1 << 6) +# define RADEON_STENCIL_ENABLE (1 << 7) +# define RADEON_Z_ENABLE (1 << 8) +# define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9) +# define RADEON_ZBLOCK8 (0 << 15) +# define RADEON_ZBLOCK16 (1 << 15) +#define RADEON_RB3D_DEPTHOFFSET 0x1c24 +#define RADEON_RB3D_PLANEMASK 0x1d84 +#define RADEON_RB3D_STENCILREFMASK 0x1d7c +#define RADEON_RB3D_ZCACHE_MODE 0x3250 +#define RADEON_RB3D_ZCACHE_CTLSTAT 0x3254 +# define RADEON_RB3D_ZC_FLUSH (1 << 0) +# define RADEON_RB3D_ZC_FREE (1 << 2) +# define RADEON_RB3D_ZC_FLUSH_ALL 0x5 +# define RADEON_RB3D_ZC_BUSY (1 << 31) +#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c +# define RADEON_Z_TEST_MASK (7 << 4) +# define RADEON_Z_TEST_ALWAYS (7 << 4) +# define RADEON_STENCIL_TEST_ALWAYS (7 << 12) +# define RADEON_STENCIL_S_FAIL_KEEP (0 << 16) +# define RADEON_STENCIL_ZPASS_KEEP (0 << 20) +# define RADEON_STENCIL_ZFAIL_KEEP (0 << 20) +# define RADEON_Z_WRITE_ENABLE (1 << 30) +#define RADEON_RBBM_SOFT_RESET 0x00f0 +# define RADEON_SOFT_RESET_CP (1 << 0) +# define RADEON_SOFT_RESET_HI (1 << 1) +# define RADEON_SOFT_RESET_SE (1 << 2) +# define RADEON_SOFT_RESET_RE (1 << 3) +# define RADEON_SOFT_RESET_PP (1 << 4) +# define RADEON_SOFT_RESET_E2 (1 << 5) +# define RADEON_SOFT_RESET_RB (1 << 6) +# define RADEON_SOFT_RESET_HDP (1 << 7) +#define RADEON_RBBM_STATUS 0x0e40 +# define RADEON_RBBM_FIFOCNT_MASK 0x007f +# define RADEON_RBBM_ACTIVE (1 << 31) +#define RADEON_RE_LINE_PATTERN 0x1cd0 +#define RADEON_RE_MISC 0x26c4 +#define RADEON_RE_TOP_LEFT 0x26c0 +#define RADEON_RE_WIDTH_HEIGHT 0x1c44 +#define RADEON_RE_STIPPLE_ADDR 0x1cc8 +#define RADEON_RE_STIPPLE_DATA 0x1ccc + +#define RADEON_SCISSOR_TL_0 0x1cd8 +#define RADEON_SCISSOR_BR_0 0x1cdc +#define RADEON_SCISSOR_TL_1 0x1ce0 +#define RADEON_SCISSOR_BR_1 0x1ce4 +#define RADEON_SCISSOR_TL_2 0x1ce8 +#define RADEON_SCISSOR_BR_2 0x1cec +#define RADEON_SE_COORD_FMT 0x1c50 +#define RADEON_SE_CNTL 0x1c4c +# define RADEON_FFACE_CULL_CW (0 << 0) +# define RADEON_BFACE_SOLID (3 << 1) +# define RADEON_FFACE_SOLID (3 << 3) +# define RADEON_FLAT_SHADE_VTX_LAST (3 << 6) +# define RADEON_DIFFUSE_SHADE_FLAT (1 << 8) +# define RADEON_DIFFUSE_SHADE_GOURAUD (2 << 8) +# define RADEON_ALPHA_SHADE_FLAT (1 << 10) +# define RADEON_ALPHA_SHADE_GOURAUD (2 << 10) +# define RADEON_SPECULAR_SHADE_FLAT (1 << 12) +# define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12) +# define RADEON_FOG_SHADE_FLAT (1 << 14) +# define RADEON_FOG_SHADE_GOURAUD (2 << 14) +# define RADEON_VPORT_XY_XFORM_ENABLE (1 << 24) +# define RADEON_VPORT_Z_XFORM_ENABLE (1 << 25) +# define RADEON_VTX_PIX_CENTER_OGL (1 << 27) +# define RADEON_ROUND_MODE_TRUNC (0 << 28) +# define RADEON_ROUND_PREC_8TH_PIX (1 << 30) +#define RADEON_SE_CNTL_STATUS 0x2140 +#define RADEON_SE_LINE_WIDTH 0x1db8 +#define RADEON_SE_VPORT_XSCALE 0x1d98 +#define RADEON_SURFACE_ACCESS_FLAGS 0x0bf8 +#define RADEON_SURFACE_ACCESS_CLR 0x0bfc +#define RADEON_SURFACE_CNTL 0x0b00 +# define RADEON_SURF_TRANSLATION_DIS (1 << 8) +# define RADEON_NONSURF_AP0_SWP_MASK (3 << 20) +# define RADEON_NONSURF_AP0_SWP_LITTLE (0 << 20) +# define RADEON_NONSURF_AP0_SWP_BIG16 (1 << 20) +# define RADEON_NONSURF_AP0_SWP_BIG32 (2 << 20) +# define RADEON_NONSURF_AP1_SWP_MASK (3 << 22) +# define RADEON_NONSURF_AP1_SWP_LITTLE (0 << 22) +# define RADEON_NONSURF_AP1_SWP_BIG16 (1 << 22) +# define RADEON_NONSURF_AP1_SWP_BIG32 (2 << 22) +#define RADEON_SURFACE0_INFO 0x0b0c +# define RADEON_SURF_PITCHSEL_MASK (0x1ff << 0) +# define RADEON_SURF_TILE_MODE_MASK (3 << 16) +# define RADEON_SURF_TILE_MODE_MACRO (0 << 16) +# define RADEON_SURF_TILE_MODE_MICRO (1 << 16) +# define RADEON_SURF_TILE_MODE_32BIT_Z (2 << 16) +# define RADEON_SURF_TILE_MODE_16BIT_Z (3 << 16) +#define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +#define RADEON_SURFACE0_UPPER_BOUND 0x0b08 +#define RADEON_SURFACE1_INFO 0x0b1c +#define RADEON_SURFACE1_LOWER_BOUND 0x0b14 +#define RADEON_SURFACE1_UPPER_BOUND 0x0b18 +#define RADEON_SURFACE2_INFO 0x0b2c +#define RADEON_SURFACE2_LOWER_BOUND 0x0b24 +#define RADEON_SURFACE2_UPPER_BOUND 0x0b28 +#define RADEON_SURFACE3_INFO 0x0b3c +#define RADEON_SURFACE3_LOWER_BOUND 0x0b34 +#define RADEON_SURFACE3_UPPER_BOUND 0x0b38 +#define RADEON_SURFACE4_INFO 0x0b4c +#define RADEON_SURFACE4_LOWER_BOUND 0x0b44 +#define RADEON_SURFACE4_UPPER_BOUND 0x0b48 +#define RADEON_SURFACE5_INFO 0x0b5c +#define RADEON_SURFACE5_LOWER_BOUND 0x0b54 +#define RADEON_SURFACE5_UPPER_BOUND 0x0b58 +#define RADEON_SURFACE6_INFO 0x0b6c +#define RADEON_SURFACE6_LOWER_BOUND 0x0b64 +#define RADEON_SURFACE6_UPPER_BOUND 0x0b68 +#define RADEON_SURFACE7_INFO 0x0b7c +#define RADEON_SURFACE7_LOWER_BOUND 0x0b74 +#define RADEON_SURFACE7_UPPER_BOUND 0x0b78 +#define RADEON_SW_SEMAPHORE 0x013c + +#define RADEON_WAIT_UNTIL 0x1720 +# define RADEON_WAIT_CRTC_PFLIP (1 << 0) +# define RADEON_WAIT_2D_IDLECLEAN (1 << 16) +# define RADEON_WAIT_3D_IDLECLEAN (1 << 17) +# define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) + +#define RADEON_RB3D_ZMASKOFFSET 0x1c34 +#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c +# define RADEON_DEPTH_FORMAT_16BIT_INT_Z (0 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_INT_Z (2 << 0) + + +/* CP registers */ +#define RADEON_CP_ME_RAM_ADDR 0x07d4 +#define RADEON_CP_ME_RAM_RADDR 0x07d8 +#define RADEON_CP_ME_RAM_DATAH 0x07dc +#define RADEON_CP_ME_RAM_DATAL 0x07e0 + +#define RADEON_CP_RB_BASE 0x0700 +#define RADEON_CP_RB_CNTL 0x0704 +#define RADEON_CP_RB_RPTR_ADDR 0x070c +#define RADEON_CP_RB_RPTR 0x0710 +#define RADEON_CP_RB_WPTR 0x0714 + +#define RADEON_CP_RB_WPTR_DELAY 0x0718 +# define RADEON_PRE_WRITE_TIMER_SHIFT 0 +# define RADEON_PRE_WRITE_LIMIT_SHIFT 23 + +#define RADEON_CP_IB_BASE 0x0738 + +#define RADEON_CP_CSQ_CNTL 0x0740 +# define RADEON_CSQ_CNT_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_PRIDIS_INDDIS (0 << 28) +# define RADEON_CSQ_PRIPIO_INDDIS (1 << 28) +# define RADEON_CSQ_PRIBM_INDDIS (2 << 28) +# define RADEON_CSQ_PRIPIO_INDBM (3 << 28) +# define RADEON_CSQ_PRIBM_INDBM (4 << 28) +# define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) + +#define RADEON_AIC_CNTL 0x01d0 +# define RADEON_PCIGART_TRANSLATE_EN (1 << 0) + +/* CP command packets */ +#define RADEON_CP_PACKET0 0x00000000 +# define RADEON_ONE_REG_WR (1 << 15) +#define RADEON_CP_PACKET1 0x40000000 +#define RADEON_CP_PACKET2 0x80000000 +#define RADEON_CP_PACKET3 0xC0000000 +# define RADEON_3D_RNDR_GEN_INDX_PRIM 0x00002300 +# define RADEON_WAIT_FOR_IDLE 0x00002600 +# define RADEON_3D_DRAW_IMMD 0x00002900 +# define RADEON_3D_CLEAR_ZMASK 0x00003200 +# define RADEON_CNTL_HOSTDATA_BLT 0x00009400 +# define RADEON_CNTL_PAINT_MULTI 0x00009A00 +# define RADEON_CNTL_BITBLT_MULTI 0x00009B00 + +#define RADEON_CP_PACKET_MASK 0xC0000000 +#define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 +#define RADEON_CP_PACKET0_REG_MASK 0x000007ff +#define RADEON_CP_PACKET1_REG0_MASK 0x000007ff +#define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 + +#define RADEON_VTX_Z_PRESENT (1 << 31) + +#define RADEON_PRIM_TYPE_NONE (0 << 0) +#define RADEON_PRIM_TYPE_POINT (1 << 0) +#define RADEON_PRIM_TYPE_LINE (2 << 0) +#define RADEON_PRIM_TYPE_LINE_STRIP (3 << 0) +#define RADEON_PRIM_TYPE_TRI_LIST (4 << 0) +#define RADEON_PRIM_TYPE_TRI_FAN (5 << 0) +#define RADEON_PRIM_TYPE_TRI_STRIP (6 << 0) +#define RADEON_PRIM_TYPE_TRI_TYPE2 (7 << 0) +#define RADEON_PRIM_TYPE_RECT_LIST (8 << 0) +#define RADEON_PRIM_TYPE_3VRT_POINT_LIST (9 << 0) +#define RADEON_PRIM_TYPE_3VRT_LINE_LIST (10 << 0) +#define RADEON_PRIM_WALK_IND (1 << 4) +#define RADEON_PRIM_WALK_LIST (2 << 4) +#define RADEON_PRIM_WALK_RING (3 << 4) +#define RADEON_COLOR_ORDER_BGRA (0 << 6) +#define RADEON_COLOR_ORDER_RGBA (1 << 6) +#define RADEON_MAOS_ENABLE (1 << 7) +#define RADEON_VTX_FMT_R128_MODE (0 << 8) +#define RADEON_VTX_FMT_RADEON_MODE (1 << 8) +#define RADEON_NUM_VERTICES_SHIFT 16 + +#define RADEON_COLOR_FORMAT_CI8 2 +#define RADEON_COLOR_FORMAT_ARGB1555 3 +#define RADEON_COLOR_FORMAT_RGB565 4 +#define RADEON_COLOR_FORMAT_ARGB8888 6 +#define RADEON_COLOR_FORMAT_RGB332 7 +#define RADEON_COLOR_FORMAT_RGB8 9 +#define RADEON_COLOR_FORMAT_ARGB4444 15 + +#define RADEON_TXF_8BPP_I 0 +#define RADEON_TXF_16BPP_AI88 1 +#define RADEON_TXF_8BPP_RGB332 2 +#define RADEON_TXF_16BPP_ARGB1555 3 +#define RADEON_TXF_16BPP_RGB565 4 +#define RADEON_TXF_16BPP_ARGB4444 5 +#define RADEON_TXF_32BPP_ARGB8888 6 +#define RADEON_TXF_32BPP_RGBA8888 7 + +/* Constants */ +#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ + +#define RADEON_LAST_FRAME_REG RADEON_SCRATCH_REG0 +#define RADEON_LAST_DISPATCH_REG RADEON_SCRATCH_REG1 +#define RADEON_LAST_CLEAR_REG RADEON_SCRATCH_REG2 +#define RADEON_LAST_DISPATCH 1 + +#define RADEON_MAX_VB_AGE 0x7fffffff +#define RADEON_MAX_VB_VERTS (0xffff) + + +#define RADEON_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define RADEON_ADDR(reg) (RADEON_BASE(reg) + reg) + +#define RADEON_DEREF(reg) *(__volatile__ u32 *)RADEON_ADDR(reg) +#define RADEON_READ(reg) RADEON_DEREF(reg) +#define RADEON_WRITE(reg,val) do { RADEON_DEREF(reg) = val; } while (0) + +#define RADEON_DEREF8(reg) *(__volatile__ u8 *)RADEON_ADDR(reg) +#define RADEON_READ8(reg) RADEON_DEREF8(reg) +#define RADEON_WRITE8(reg,val) do { RADEON_DEREF8(reg) = val; } while (0) + +#define RADEON_WRITE_PLL(addr,val) \ +do { \ + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, \ + ((addr) & 0x1f) | RADEON_PLL_WR_EN); \ + RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, (val)); \ +} while (0) + +extern int RADEON_READ_PLL(drm_device_t *dev, int addr); + + + +#define CP_PACKET0( reg, n ) \ + (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) +#define CP_PACKET0_TABLE( reg, n ) \ + (RADEON_CP_PACKET0 | RADEON_ONE_REG_WR | ((n) << 16) | ((reg) >> 2)) +#define CP_PACKET1( reg0, reg1 ) \ + (RADEON_CP_PACKET1 | (((reg1) >> 2) << 15) | ((reg0) >> 2)) +#define CP_PACKET2() \ + (RADEON_CP_PACKET2) +#define CP_PACKET3( pkt, n ) \ + (RADEON_CP_PACKET3 | (pkt) | ((n) << 16)) + + +/* ================================================================ + * Engine control helper macros + */ + +#define RADEON_WAIT_UNTIL_2D_IDLE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ + OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \ + RADEON_WAIT_HOST_IDLECLEAN) ); \ +} while (0) + +#define RADEON_WAIT_UNTIL_3D_IDLE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ + OUT_RING( (RADEON_WAIT_3D_IDLECLEAN | \ + RADEON_WAIT_HOST_IDLECLEAN) ); \ +} while (0) + +#define RADEON_WAIT_UNTIL_IDLE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ + OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \ + RADEON_WAIT_3D_IDLECLEAN | \ + RADEON_WAIT_HOST_IDLECLEAN) ); \ +} while (0) + +#define RADEON_WAIT_UNTIL_PAGE_FLIPPED() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ + OUT_RING( RADEON_WAIT_CRTC_PFLIP ); \ +} while (0) + +#define RADEON_FLUSH_CACHE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \ + OUT_RING( RADEON_RB2D_DC_FLUSH ); \ +} while (0) + +#define RADEON_PURGE_CACHE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \ + OUT_RING( RADEON_RB2D_DC_FLUSH_ALL ); \ +} while (0) + +#define RADEON_FLUSH_ZCACHE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ + OUT_RING( RADEON_RB3D_ZC_FLUSH ); \ +} while (0) + +#define RADEON_PURGE_ZCACHE() \ +do { \ + OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ + OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL ); \ +} while (0) + + +/* ================================================================ + * Misc helper macros + */ + +#define VB_AGE_CHECK_WITH_RET( dev_priv ) \ +do { \ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ + if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ + int __ret = radeon_do_cp_idle( dev_priv ); \ + if ( __ret < 0 ) return __ret; \ + sarea_priv->last_dispatch = 0; \ + radeon_freelist_reset( dev ); \ + } \ +} while (0) + +#define RADEON_DISPATCH_AGE( age ) \ +do { \ + OUT_RING( CP_PACKET0( RADEON_LAST_DISPATCH_REG, 0 ) ); \ + OUT_RING( age ); \ +} while (0) + +#define RADEON_FRAME_AGE( age ) \ +do { \ + OUT_RING( CP_PACKET0( RADEON_LAST_FRAME_REG, 0 ) ); \ + OUT_RING( age ); \ +} while (0) + +#define RADEON_CLEAR_AGE( age ) \ +do { \ + OUT_RING( CP_PACKET0( RADEON_LAST_CLEAR_REG, 0 ) ); \ + OUT_RING( age ); \ +} while (0) + + +/* ================================================================ + * Ring control + */ + +#define radeon_flush_write_combine() mb() + + +#define RADEON_VERBOSE 0 + +#define RING_LOCALS int write; unsigned int mask; volatile u32 *ring; + +#define BEGIN_RING( n ) do { \ + if ( RADEON_VERBOSE ) { \ + DRM_INFO( "BEGIN_RING( %d ) in %s\n", \ + n, __FUNCTION__ ); \ + } \ + if ( dev_priv->ring.space < (n) * sizeof(u32) ) { \ + radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \ + } \ + dev_priv->ring.space -= (n) * sizeof(u32); \ + ring = dev_priv->ring.start; \ + write = dev_priv->ring.tail; \ + mask = dev_priv->ring.tail_mask; \ +} while (0) + +#define ADVANCE_RING() do { \ + if ( RADEON_VERBOSE ) { \ + DRM_INFO( "ADVANCE_RING() tail=0x%06x wr=0x%06x\n", \ + write, dev_priv->ring.tail ); \ + } \ + radeon_flush_write_combine(); \ + dev_priv->ring.tail = write; \ + RADEON_WRITE( RADEON_CP_RB_WPTR, write ); \ +} while (0) + +#define OUT_RING( x ) do { \ + if ( RADEON_VERBOSE ) { \ + DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ + (unsigned int)(x), write ); \ + } \ + ring[write++] = (x); \ + write &= mask; \ +} while (0) + +#define RADEON_PERFORMANCE_BOXES 0 + +#endif /* __RADEON_DRV_H__ */ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c new file mode 100644 index 000000000..1a4da8005 --- /dev/null +++ b/drivers/char/drm/radeon_state.c @@ -0,0 +1,1447 @@ +/* radeon_state.c -- State support for Radeon -*- linux-c -*- + * + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "radeon_drv.h" +#include "drm.h" +#include <linux/delay.h> + + +/* ================================================================ + * CP hardware state programming functions + */ + +static inline void radeon_emit_clip_rect( drm_radeon_private_t *dev_priv, + drm_clip_rect_t *box ) +{ + RING_LOCALS; + + DRM_DEBUG( " box: x1=%d y1=%d x2=%d y2=%d\n", + box->x1, box->y1, box->x2, box->y2 ); + + BEGIN_RING( 4 ); + + OUT_RING( CP_PACKET0( RADEON_RE_TOP_LEFT, 0 ) ); + OUT_RING( (box->y1 << 16) | box->x1 ); + + OUT_RING( CP_PACKET0( RADEON_RE_WIDTH_HEIGHT, 0 ) ); + OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_context( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 14 ); + + OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) ); + OUT_RING( ctx->pp_misc ); + OUT_RING( ctx->pp_fog_color ); + OUT_RING( ctx->re_solid_color ); + OUT_RING( ctx->rb3d_blendcntl ); + OUT_RING( ctx->rb3d_depthoffset ); + OUT_RING( ctx->rb3d_depthpitch ); + OUT_RING( ctx->rb3d_zstencilcntl ); + + OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 2 ) ); + OUT_RING( ctx->pp_cntl ); + OUT_RING( ctx->rb3d_cntl ); + OUT_RING( ctx->rb3d_coloroffset ); + + OUT_RING( CP_PACKET0( RADEON_RB3D_COLORPITCH, 0 ) ); + OUT_RING( ctx->rb3d_colorpitch ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_vertfmt( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 2 ); + + OUT_RING( CP_PACKET0( RADEON_SE_COORD_FMT, 0 ) ); + OUT_RING( ctx->se_coord_fmt ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_line( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 5 ); + + OUT_RING( CP_PACKET0( RADEON_RE_LINE_PATTERN, 1 ) ); + OUT_RING( ctx->re_line_pattern ); + OUT_RING( ctx->re_line_state ); + + OUT_RING( CP_PACKET0( RADEON_SE_LINE_WIDTH, 0 ) ); + OUT_RING( ctx->se_line_width ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_bumpmap( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 5 ); + + OUT_RING( CP_PACKET0( RADEON_PP_LUM_MATRIX, 0 ) ); + OUT_RING( ctx->pp_lum_matrix ); + + OUT_RING( CP_PACKET0( RADEON_PP_ROT_MATRIX_0, 1 ) ); + OUT_RING( ctx->pp_rot_matrix_0 ); + OUT_RING( ctx->pp_rot_matrix_1 ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_masks( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 4 ); + + OUT_RING( CP_PACKET0( RADEON_RB3D_STENCILREFMASK, 2 ) ); + OUT_RING( ctx->rb3d_stencilrefmask ); + OUT_RING( ctx->rb3d_ropcntl ); + OUT_RING( ctx->rb3d_planemask ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_viewport( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 7 ); + + OUT_RING( CP_PACKET0( RADEON_SE_VPORT_XSCALE, 5 ) ); + OUT_RING( ctx->se_vport_xscale ); + OUT_RING( ctx->se_vport_xoffset ); + OUT_RING( ctx->se_vport_yscale ); + OUT_RING( ctx->se_vport_yoffset ); + OUT_RING( ctx->se_vport_zscale ); + OUT_RING( ctx->se_vport_zoffset ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_setup( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 4 ); + + OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) ); + OUT_RING( ctx->se_cntl ); + OUT_RING( CP_PACKET0( RADEON_SE_CNTL_STATUS, 0 ) ); + OUT_RING( ctx->se_cntl_status ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_tcl( drm_radeon_private_t *dev_priv ) +{ +#ifdef TCL_ENABLE + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 29 ); + + OUT_RING( CP_PACKET0( RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 27 ) ); + OUT_RING( ctx->se_tcl_material_emmissive.red ); + OUT_RING( ctx->se_tcl_material_emmissive.green ); + OUT_RING( ctx->se_tcl_material_emmissive.blue ); + OUT_RING( ctx->se_tcl_material_emmissive.alpha ); + OUT_RING( ctx->se_tcl_material_ambient.red ); + OUT_RING( ctx->se_tcl_material_ambient.green ); + OUT_RING( ctx->se_tcl_material_ambient.blue ); + OUT_RING( ctx->se_tcl_material_ambient.alpha ); + OUT_RING( ctx->se_tcl_material_diffuse.red ); + OUT_RING( ctx->se_tcl_material_diffuse.green ); + OUT_RING( ctx->se_tcl_material_diffuse.blue ); + OUT_RING( ctx->se_tcl_material_diffuse.alpha ); + OUT_RING( ctx->se_tcl_material_specular.red ); + OUT_RING( ctx->se_tcl_material_specular.green ); + OUT_RING( ctx->se_tcl_material_specular.blue ); + OUT_RING( ctx->se_tcl_material_specular.alpha ); + OUT_RING( ctx->se_tcl_shininess ); + OUT_RING( ctx->se_tcl_output_vtx_fmt ); + OUT_RING( ctx->se_tcl_output_vtx_sel ); + OUT_RING( ctx->se_tcl_matrix_select_0 ); + OUT_RING( ctx->se_tcl_matrix_select_1 ); + OUT_RING( ctx->se_tcl_ucp_vert_blend_ctl ); + OUT_RING( ctx->se_tcl_texture_proc_ctl ); + OUT_RING( ctx->se_tcl_light_model_ctl ); + for ( i = 0 ; i < 4 ; i++ ) { + OUT_RING( ctx->se_tcl_per_light_ctl[i] ); + } + + ADVANCE_RING(); +#else + DRM_ERROR( "TCL not enabled!\n" ); +#endif +} + +static inline void radeon_emit_misc( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 2 ); + + OUT_RING( CP_PACKET0( RADEON_RE_MISC, 0 ) ); + OUT_RING( ctx->re_misc ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_tex0( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[0]; + RING_LOCALS; + DRM_DEBUG( " %s: offset=0x%x\n", __FUNCTION__, tex->pp_txoffset ); + + BEGIN_RING( 9 ); + + OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) ); + OUT_RING( tex->pp_txfilter ); + OUT_RING( tex->pp_txformat ); + OUT_RING( tex->pp_txoffset ); + OUT_RING( tex->pp_txcblend ); + OUT_RING( tex->pp_txablend ); + OUT_RING( tex->pp_tfactor ); + + OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_0, 0 ) ); + OUT_RING( tex->pp_border_color ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_tex1( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[1]; + RING_LOCALS; + DRM_DEBUG( " %s: offset=0x%x\n", __FUNCTION__, tex->pp_txoffset ); + + BEGIN_RING( 9 ); + + OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) ); + OUT_RING( tex->pp_txfilter ); + OUT_RING( tex->pp_txformat ); + OUT_RING( tex->pp_txoffset ); + OUT_RING( tex->pp_txcblend ); + OUT_RING( tex->pp_txablend ); + OUT_RING( tex->pp_tfactor ); + + OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_1, 0 ) ); + OUT_RING( tex->pp_border_color ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_tex2( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[2]; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 9 ); + + OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) ); + OUT_RING( tex->pp_txfilter ); + OUT_RING( tex->pp_txformat ); + OUT_RING( tex->pp_txoffset ); + OUT_RING( tex->pp_txcblend ); + OUT_RING( tex->pp_txablend ); + OUT_RING( tex->pp_tfactor ); + + OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_2, 0 ) ); + OUT_RING( tex->pp_border_color ); + + ADVANCE_RING(); +} + +static inline void radeon_emit_state( drm_radeon_private_t *dev_priv ) +{ + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + DRM_DEBUG( "%s: dirty=0x%08x\n", __FUNCTION__, dirty ); + + if ( dirty & RADEON_UPLOAD_CONTEXT ) { + radeon_emit_context( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_CONTEXT; + } + + if ( dirty & RADEON_UPLOAD_VERTFMT ) { + radeon_emit_vertfmt( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_VERTFMT; + } + + if ( dirty & RADEON_UPLOAD_LINE ) { + radeon_emit_line( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_LINE; + } + + if ( dirty & RADEON_UPLOAD_BUMPMAP ) { + radeon_emit_bumpmap( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_BUMPMAP; + } + + if ( dirty & RADEON_UPLOAD_MASKS ) { + radeon_emit_masks( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_MASKS; + } + + if ( dirty & RADEON_UPLOAD_VIEWPORT ) { + radeon_emit_viewport( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_VIEWPORT; + } + + if ( dirty & RADEON_UPLOAD_SETUP ) { + radeon_emit_setup( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_SETUP; + } + + if ( dirty & RADEON_UPLOAD_TCL ) { +#ifdef TCL_ENABLE + radeon_emit_tcl( dev_priv ); +#endif + sarea_priv->dirty &= ~RADEON_UPLOAD_TCL; + } + + if ( dirty & RADEON_UPLOAD_MISC ) { + radeon_emit_misc( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_MISC; + } + + if ( dirty & RADEON_UPLOAD_TEX0 ) { + radeon_emit_tex0( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_TEX0; + } + + if ( dirty & RADEON_UPLOAD_TEX1 ) { + radeon_emit_tex1( dev_priv ); + sarea_priv->dirty &= ~RADEON_UPLOAD_TEX1; + } + + if ( dirty & RADEON_UPLOAD_TEX2 ) { +#if 0 + radeon_emit_tex2( dev_priv ); +#endif + sarea_priv->dirty &= ~RADEON_UPLOAD_TEX2; + } + + sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | + RADEON_UPLOAD_TEX1IMAGES | + RADEON_UPLOAD_TEX2IMAGES | + RADEON_REQUIRE_QUIESCENCE); +} + + +#if RADEON_PERFORMANCE_BOXES +/* ================================================================ + * Performance monitoring functions + */ + +static void radeon_clear_box( drm_radeon_private_t *dev_priv, + int x, int y, int w, int h, + int r, int g, int b ) +{ + u32 pitch, offset; + u32 color; + RING_LOCALS; + + switch ( dev_priv->color_fmt ) { + case RADEON_COLOR_FORMAT_RGB565: + color = (((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + ((b & 0xf8) >> 3)); + break; + case RADEON_COLOR_FORMAT_ARGB8888: + default: + color = (((0xff) << 24) | (r << 16) | (g << 8) | b); + break; + } + + offset = dev_priv->back_offset; + pitch = dev_priv->back_pitch >> 3; + + BEGIN_RING( 6 ); + + OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) ); + OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_SOLID_COLOR | + (dev_priv->color_fmt << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_P | + RADEON_GMC_CLR_CMP_CNTL_DIS ); + + OUT_RING( (pitch << 22) | (offset >> 5) ); + OUT_RING( color ); + + OUT_RING( (x << 16) | y ); + OUT_RING( (w << 16) | h ); + + ADVANCE_RING(); +} + +static void radeon_cp_performance_boxes( drm_radeon_private_t *dev_priv ) +{ + if ( atomic_read( &dev_priv->idle_count ) == 0 ) { + radeon_clear_box( dev_priv, 64, 4, 8, 8, 0, 255, 0 ); + } else { + atomic_set( &dev_priv->idle_count, 0 ); + } +} + +#endif + + +/* ================================================================ + * CP command dispatch functions + */ + +static void radeon_print_dirty( const char *msg, unsigned int flags ) +{ + DRM_DEBUG( "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + msg, + flags, + (flags & RADEON_UPLOAD_CONTEXT) ? "context, " : "", + (flags & RADEON_UPLOAD_VERTFMT) ? "vertfmt, " : "", + (flags & RADEON_UPLOAD_LINE) ? "line, " : "", + (flags & RADEON_UPLOAD_BUMPMAP) ? "bumpmap, " : "", + (flags & RADEON_UPLOAD_MASKS) ? "masks, " : "", + (flags & RADEON_UPLOAD_VIEWPORT) ? "viewport, " : "", + (flags & RADEON_UPLOAD_SETUP) ? "setup, " : "", + (flags & RADEON_UPLOAD_TCL) ? "tcl, " : "", + (flags & RADEON_UPLOAD_MISC) ? "misc, " : "", + (flags & RADEON_UPLOAD_TEX0) ? "tex0, " : "", + (flags & RADEON_UPLOAD_TEX1) ? "tex1, " : "", + (flags & RADEON_UPLOAD_TEX2) ? "tex2, " : "", + (flags & RADEON_UPLOAD_CLIPRECTS) ? "cliprects, " : "", + (flags & RADEON_REQUIRE_QUIESCENCE) ? "quiescence, " : "" ); +} + +static void radeon_cp_dispatch_clear( drm_device_t *dev, + drm_radeon_clear_t *clear ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + unsigned int flags = clear->flags; + int i; + RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + radeon_update_ring_snapshot( dev_priv ); + + if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) { + unsigned int tmp = flags; + + flags &= ~(RADEON_FRONT | RADEON_BACK); + if ( tmp & RADEON_FRONT ) flags |= RADEON_BACK; + if ( tmp & RADEON_BACK ) flags |= RADEON_FRONT; + } + + for ( i = 0 ; i < nbox ; i++ ) { + int x = pbox[i].x1; + int y = pbox[i].y1; + int w = pbox[i].x2 - x; + int h = pbox[i].y2 - y; + + DRM_DEBUG( "dispatch clear %d,%d-%d,%d flags 0x%x\n", + x, y, w, h, flags ); + + if ( flags & (RADEON_FRONT | RADEON_BACK) ) { + BEGIN_RING( 4 ); + + /* Ensure the 3D stream is idle before doing a + * 2D fill to clear the front or back buffer. + */ + RADEON_WAIT_UNTIL_3D_IDLE(); + + OUT_RING( CP_PACKET0( RADEON_DP_WRITE_MASK, 0 ) ); + OUT_RING( sarea_priv->context_state.rb3d_planemask ); + + ADVANCE_RING(); + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_MASKS); + } + + if ( flags & RADEON_FRONT ) { + BEGIN_RING( 6 ); + + OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) ); + OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_SOLID_COLOR | + (dev_priv->color_fmt << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_P | + RADEON_GMC_CLR_CMP_CNTL_DIS ); + + OUT_RING( dev_priv->front_pitch_offset ); + OUT_RING( clear->clear_color ); + + OUT_RING( (x << 16) | y ); + OUT_RING( (w << 16) | h ); + + ADVANCE_RING(); + } + + if ( flags & RADEON_BACK ) { + BEGIN_RING( 6 ); + + OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) ); + OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_SOLID_COLOR | + (dev_priv->color_fmt << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_P | + RADEON_GMC_CLR_CMP_CNTL_DIS ); + + OUT_RING( dev_priv->back_pitch_offset ); + OUT_RING( clear->clear_color ); + + OUT_RING( (x << 16) | y ); + OUT_RING( (w << 16) | h ); + + ADVANCE_RING(); + + } + + if ( flags & RADEON_DEPTH ) { + drm_radeon_depth_clear_t *depth_clear = + &dev_priv->depth_clear; + + if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { + radeon_emit_state( dev_priv ); + } + + /* FIXME: Render a rectangle to clear the depth + * buffer. So much for those "fast Z clears"... + */ + BEGIN_RING( 23 ); + + RADEON_WAIT_UNTIL_2D_IDLE(); + + OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 1 ) ); + OUT_RING( 0x00000000 ); + OUT_RING( depth_clear->rb3d_cntl ); + OUT_RING( CP_PACKET0( RADEON_RB3D_ZSTENCILCNTL, 0 ) ); + OUT_RING( depth_clear->rb3d_zstencilcntl ); + OUT_RING( CP_PACKET0( RADEON_RB3D_PLANEMASK, 0 ) ); + OUT_RING( 0x00000000 ); + OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) ); + OUT_RING( depth_clear->se_cntl ); + + OUT_RING( CP_PACKET3( RADEON_3D_DRAW_IMMD, 10 ) ); + OUT_RING( RADEON_VTX_Z_PRESENT ); + OUT_RING( (RADEON_PRIM_TYPE_RECT_LIST | + RADEON_PRIM_WALK_RING | + RADEON_MAOS_ENABLE | + RADEON_VTX_FMT_RADEON_MODE | + (3 << RADEON_NUM_VERTICES_SHIFT)) ); + + OUT_RING( clear->rect.ui[CLEAR_X1] ); + OUT_RING( clear->rect.ui[CLEAR_Y1] ); + OUT_RING( clear->rect.ui[CLEAR_DEPTH] ); + + OUT_RING( clear->rect.ui[CLEAR_X1] ); + OUT_RING( clear->rect.ui[CLEAR_Y2] ); + OUT_RING( clear->rect.ui[CLEAR_DEPTH] ); + + OUT_RING( clear->rect.ui[CLEAR_X2] ); + OUT_RING( clear->rect.ui[CLEAR_Y2] ); + OUT_RING( clear->rect.ui[CLEAR_DEPTH] ); + + ADVANCE_RING(); + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_SETUP | + RADEON_UPLOAD_MASKS); + } + } + + /* Increment the clear counter. The client-side 3D driver must + * wait on this value before performing the clear ioctl. We + * need this because the card's so damned fast... + */ + dev_priv->sarea_priv->last_clear++; + + BEGIN_RING( 4 ); + + RADEON_CLEAR_AGE( dev_priv->sarea_priv->last_clear ); + RADEON_WAIT_UNTIL_IDLE(); + + ADVANCE_RING(); +} + +static void radeon_cp_dispatch_swap( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int i; + RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + radeon_update_ring_snapshot( dev_priv ); + +#if RADEON_PERFORMANCE_BOXES + /* Do some trivial performance monitoring... + */ + radeon_cp_performance_boxes( dev_priv ); +#endif + + /* Wait for the 3D stream to idle before dispatching the bitblt. + * This will prevent data corruption between the two streams. + */ + BEGIN_RING( 2 ); + + RADEON_WAIT_UNTIL_3D_IDLE(); + + ADVANCE_RING(); + + for ( i = 0 ; i < nbox ; i++ ) { + int x = pbox[i].x1; + int y = pbox[i].y1; + int w = pbox[i].x2 - x; + int h = pbox[i].y2 - y; + + DRM_DEBUG( "dispatch swap %d,%d-%d,%d\n", + x, y, w, h ); + + BEGIN_RING( 7 ); + + OUT_RING( CP_PACKET3( RADEON_CNTL_BITBLT_MULTI, 5 ) ); + OUT_RING( RADEON_GMC_SRC_PITCH_OFFSET_CNTL | + RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + (dev_priv->color_fmt << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_MEMORY | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS ); + + OUT_RING( dev_priv->back_pitch_offset ); + OUT_RING( dev_priv->front_pitch_offset ); + + OUT_RING( (x << 16) | y ); + OUT_RING( (x << 16) | y ); + OUT_RING( (w << 16) | h ); + + ADVANCE_RING(); + } + + /* Increment the frame counter. The client-side 3D driver must + * throttle the framerate by waiting for this value before + * performing the swapbuffer ioctl. + */ + dev_priv->sarea_priv->last_frame++; + + BEGIN_RING( 4 ); + + RADEON_FRAME_AGE( dev_priv->sarea_priv->last_frame ); + RADEON_WAIT_UNTIL_2D_IDLE(); + + ADVANCE_RING(); +} + +static void radeon_cp_dispatch_flip( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + DRM_DEBUG( "%s: page=%d\n", __FUNCTION__, dev_priv->current_page ); + + radeon_update_ring_snapshot( dev_priv ); + +#if RADEON_PERFORMANCE_BOXES + /* Do some trivial performance monitoring... + */ + radeon_cp_performance_boxes( dev_priv ); +#endif + + BEGIN_RING( 6 ); + + RADEON_WAIT_UNTIL_3D_IDLE(); + RADEON_WAIT_UNTIL_PAGE_FLIPPED(); + + OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET, 0 ) ); + + if ( dev_priv->current_page == 0 ) { + OUT_RING( dev_priv->back_offset ); + dev_priv->current_page = 1; + } else { + OUT_RING( dev_priv->front_offset ); + dev_priv->current_page = 0; + } + + ADVANCE_RING(); + + /* Increment the frame counter. The client-side 3D driver must + * throttle the framerate by waiting for this value before + * performing the swapbuffer ioctl. + */ + dev_priv->sarea_priv->last_frame++; + + BEGIN_RING( 2 ); + + RADEON_FRAME_AGE( dev_priv->sarea_priv->last_frame ); + + ADVANCE_RING(); +} + +static void radeon_cp_dispatch_vertex( drm_device_t *dev, + drm_buf_t *buf ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_buf_priv_t *buf_priv = buf->dev_private; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + int format = sarea_priv->vc_format; + int offset = dev_priv->agp_buffers_offset + buf->offset; + int size = buf->used; + int prim = buf_priv->prim; + int i = 0; + RING_LOCALS; + DRM_DEBUG( "%s: nbox=%d\n", __FUNCTION__, sarea_priv->nbox ); + + radeon_update_ring_snapshot( dev_priv ); + + if ( 0 ) + radeon_print_dirty( "dispatch_vertex", sarea_priv->dirty ); + + if ( buf->used ) { + buf_priv->dispatched = 1; + + if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { + radeon_emit_state( dev_priv ); + } + + do { + /* Emit the next set of up to three cliprects */ + if ( i < sarea_priv->nbox ) { + radeon_emit_clip_rect( dev_priv, + &sarea_priv->boxes[i] ); + } + + /* Emit the vertex buffer rendering commands */ + BEGIN_RING( 5 ); + + OUT_RING( CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, 3 ) ); + OUT_RING( offset ); + OUT_RING( size ); + OUT_RING( format ); + OUT_RING( prim | RADEON_PRIM_WALK_LIST | + RADEON_COLOR_ORDER_RGBA | + RADEON_VTX_FMT_RADEON_MODE | + (size << RADEON_NUM_VERTICES_SHIFT) ); + + ADVANCE_RING(); + + i++; + } while ( i < sarea_priv->nbox ); + } + + if ( buf_priv->discard ) { + buf_priv->age = dev_priv->sarea_priv->last_dispatch; + + /* Emit the vertex buffer age */ + BEGIN_RING( 2 ); + RADEON_DISPATCH_AGE( buf_priv->age ); + ADVANCE_RING(); + + buf->pending = 1; + buf->used = 0; + /* FIXME: Check dispatched field */ + buf_priv->dispatched = 0; + } + + dev_priv->sarea_priv->last_dispatch++; + + sarea_priv->dirty &= ~RADEON_UPLOAD_CLIPRECTS; + sarea_priv->nbox = 0; +} + + +static void radeon_cp_dispatch_indirect( drm_device_t *dev, + drm_buf_t *buf, + int start, int end ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_buf_priv_t *buf_priv = buf->dev_private; + RING_LOCALS; + DRM_DEBUG( "indirect: buf=%d s=0x%x e=0x%x\n", + buf->idx, start, end ); + + radeon_update_ring_snapshot( dev_priv ); + + if ( start != end ) { + int offset = (dev_priv->agp_buffers_offset + + buf->offset + start); + int dwords = (end - start + 3) / sizeof(u32); + + /* Indirect buffer data must be an even number of + * dwords, so if we've been given an odd number we must + * pad the data with a Type-2 CP packet. + */ + if ( dwords & 1 ) { + u32 *data = (u32 *) + ((char *)dev_priv->buffers->handle + + buf->offset + start); + data[dwords++] = RADEON_CP_PACKET2; + } + + buf_priv->dispatched = 1; + + /* Fire off the indirect buffer */ + BEGIN_RING( 3 ); + + OUT_RING( CP_PACKET0( RADEON_CP_IB_BASE, 1 ) ); + OUT_RING( offset ); + OUT_RING( dwords ); + + ADVANCE_RING(); + } + + if ( buf_priv->discard ) { + buf_priv->age = dev_priv->sarea_priv->last_dispatch; + + /* Emit the indirect buffer age */ + BEGIN_RING( 2 ); + RADEON_DISPATCH_AGE( buf_priv->age ); + ADVANCE_RING(); + + buf->pending = 1; + buf->used = 0; + /* FIXME: Check dispatched field */ + buf_priv->dispatched = 0; + } + + dev_priv->sarea_priv->last_dispatch++; +} + +static void radeon_cp_dispatch_indices( drm_device_t *dev, + drm_buf_t *buf, + int start, int end, + int count ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_buf_priv_t *buf_priv = buf->dev_private; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + int format = sarea_priv->vc_format; + int offset = dev_priv->agp_buffers_offset; + int prim = buf_priv->prim; + u32 *data; + int dwords; + int i = 0; + RING_LOCALS; + DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count ); + + radeon_update_ring_snapshot( dev_priv ); + + if ( 0 ) + radeon_print_dirty( "dispatch_indices", sarea_priv->dirty ); + + if ( start != end ) { + buf_priv->dispatched = 1; + + if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { + radeon_emit_state( dev_priv ); + } + + dwords = (end - start + 3) / sizeof(u32); + + data = (u32 *)((char *)dev_priv->buffers->handle + + buf->offset + start); + + data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 ); + + data[1] = offset; + data[2] = RADEON_MAX_VB_VERTS; + data[3] = format; + data[4] = (prim | RADEON_PRIM_WALK_IND | + RADEON_COLOR_ORDER_RGBA | + RADEON_VTX_FMT_RADEON_MODE | + (count << RADEON_NUM_VERTICES_SHIFT) ); + + if ( count & 0x1 ) { + data[dwords-1] &= 0x0000ffff; + } + + do { + /* Emit the next set of up to three cliprects */ + if ( i < sarea_priv->nbox ) { + radeon_emit_clip_rect( dev_priv, + &sarea_priv->boxes[i] ); + } + + radeon_cp_dispatch_indirect( dev, buf, start, end ); + + i++; + } while ( i < sarea_priv->nbox ); + } + + if ( buf_priv->discard ) { + buf_priv->age = dev_priv->sarea_priv->last_dispatch; + + /* Emit the vertex buffer age */ + BEGIN_RING( 2 ); + RADEON_DISPATCH_AGE( buf_priv->age ); + ADVANCE_RING(); + + buf->pending = 1; + /* FIXME: Check dispatched field */ + buf_priv->dispatched = 0; + } + + dev_priv->sarea_priv->last_dispatch++; + + sarea_priv->dirty &= ~RADEON_UPLOAD_CLIPRECTS; + sarea_priv->nbox = 0; +} + +static int radeon_cp_dispatch_blit( drm_device_t *dev, + drm_radeon_blit_t *blit ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_radeon_buf_priv_t *buf_priv; + u32 format; + u32 *data; + int dword_shift, dwords; + RING_LOCALS; + DRM_DEBUG( "blit: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n", + blit->offset >> 10, blit->pitch, blit->format, + blit->x, blit->y, blit->width, blit->height ); + + radeon_update_ring_snapshot( dev_priv ); + + /* The compiler won't optimize away a division by a variable, + * even if the only legal values are powers of two. Thus, we'll + * use a shift instead. + */ + switch ( blit->format ) { + case RADEON_TXF_32BPP_ARGB8888: + case RADEON_TXF_32BPP_RGBA8888: + format = RADEON_COLOR_FORMAT_ARGB8888; + dword_shift = 0; + break; + case RADEON_TXF_16BPP_AI88: + case RADEON_TXF_16BPP_ARGB1555: + case RADEON_TXF_16BPP_RGB565: + case RADEON_TXF_16BPP_ARGB4444: + format = RADEON_COLOR_FORMAT_RGB565; + dword_shift = 1; + break; + case RADEON_TXF_8BPP_I: + case RADEON_TXF_8BPP_RGB332: + format = RADEON_COLOR_FORMAT_CI8; + dword_shift = 2; + break; + default: + DRM_ERROR( "invalid blit format %d\n", blit->format ); + return -EINVAL; + } + + /* Flush the pixel cache. This ensures no pixel data gets mixed + * up with the texture data from the host data blit, otherwise + * part of the texture image may be corrupted. + */ + BEGIN_RING( 4 ); + + RADEON_FLUSH_CACHE(); + RADEON_WAIT_UNTIL_IDLE(); + + ADVANCE_RING(); + + /* Dispatch the indirect buffer. + */ + buf = dma->buflist[blit->idx]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", blit->idx ); + return -EINVAL; + } + + buf_priv->discard = 1; + + dwords = (blit->width * blit->height) >> dword_shift; + if ( !dwords ) dwords = 1; + + data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); + + data[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); + data[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + (format << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_HOST_DATA | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS); + + data[2] = (blit->pitch << 22) | (blit->offset >> 10); + data[3] = 0xffffffff; + data[4] = 0xffffffff; + data[5] = (blit->y << 16) | blit->x; + data[6] = (blit->height << 16) | blit->width; + data[7] = dwords; + + buf->used = (dwords + 8) * sizeof(u32); + + radeon_cp_dispatch_indirect( dev, buf, 0, buf->used ); + + /* Flush the pixel cache after the blit completes. This ensures + * the texture data is written out to memory before rendering + * continues. + */ + BEGIN_RING( 4 ); + + RADEON_FLUSH_CACHE(); + RADEON_WAIT_UNTIL_2D_IDLE(); + + ADVANCE_RING(); + + return 0; +} + +static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int i; + RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + radeon_update_ring_snapshot( dev_priv ); + + BEGIN_RING( 35 ); + + OUT_RING( CP_PACKET0( RADEON_RE_STIPPLE_ADDR, 0 ) ); + OUT_RING( 0x00000000 ); + + OUT_RING( CP_PACKET0_TABLE( RADEON_RE_STIPPLE_DATA, 31 ) ); + for ( i = 0 ; i < 32 ; i++ ) { + OUT_RING( stipple[i] ); + } + + ADVANCE_RING(); +} + + +/* ================================================================ + * IOCTL functions + */ + +int radeon_cp_clear( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_radeon_clear_t clear; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &clear, (drm_radeon_clear_t *) arg, + sizeof(clear) ) ) + return -EFAULT; + + if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS ) + sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; + + radeon_cp_dispatch_clear( dev, &clear ); + + return 0; +} + +int radeon_cp_swap( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS ) + sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; + + if ( !dev_priv->page_flipping ) { + radeon_cp_dispatch_swap( dev ); + dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_MASKS); + } else { + radeon_cp_dispatch_flip( dev ); + } + + return 0; +} + +int radeon_cp_vertex( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_radeon_buf_priv_t *buf_priv; + drm_radeon_vertex_t vertex; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + if ( !dev_priv || dev_priv->is_pci ) { + DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &vertex, (drm_radeon_vertex_t *)arg, + sizeof(vertex) ) ) + return -EFAULT; + + DRM_DEBUG( "%s: pid=%d index=%d count=%d discard=%d\n", + __FUNCTION__, current->pid, + vertex.idx, vertex.count, vertex.discard ); + + if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) { + DRM_ERROR( "buffer index %d (of %d max)\n", + vertex.idx, dma->buf_count - 1 ); + return -EINVAL; + } + if ( vertex.prim < 0 || + vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST ) { + DRM_ERROR( "buffer prim %d\n", vertex.prim ); + return -EINVAL; + } + + VB_AGE_CHECK_WITH_RET( dev_priv ); + + buf = dma->buflist[vertex.idx]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", vertex.idx ); + return -EINVAL; + } + + buf->used = vertex.count; + buf_priv->prim = vertex.prim; + buf_priv->discard = vertex.discard; + + radeon_cp_dispatch_vertex( dev, buf ); + + return 0; +} + +int radeon_cp_indices( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_radeon_buf_priv_t *buf_priv; + drm_radeon_indices_t elts; + int count; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + if ( !dev_priv || dev_priv->is_pci ) { + DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &elts, (drm_radeon_indices_t *)arg, + sizeof(elts) ) ) + return -EFAULT; + + DRM_DEBUG( "%s: pid=%d index=%d start=%d end=%d discard=%d\n", + __FUNCTION__, current->pid, + elts.idx, elts.start, elts.end, elts.discard ); + + if ( elts.idx < 0 || elts.idx >= dma->buf_count ) { + DRM_ERROR( "buffer index %d (of %d max)\n", + elts.idx, dma->buf_count - 1 ); + return -EINVAL; + } + if ( elts.prim < 0 || + elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST ) { + DRM_ERROR( "buffer prim %d\n", elts.prim ); + return -EINVAL; + } + + VB_AGE_CHECK_WITH_RET( dev_priv ); + + buf = dma->buflist[elts.idx]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", elts.idx ); + return -EINVAL; + } + + count = (elts.end - elts.start) / sizeof(u16); + elts.start -= RADEON_INDEX_PRIM_OFFSET; + + if ( elts.start & 0x7 ) { + DRM_ERROR( "misaligned buffer 0x%x\n", elts.start ); + return -EINVAL; + } + if ( elts.start < buf->used ) { + DRM_ERROR( "no header 0x%x - 0x%x\n", elts.start, buf->used ); + return -EINVAL; + } + + buf->used = elts.end; + buf_priv->prim = elts.prim; + buf_priv->discard = elts.discard; + + radeon_cp_dispatch_indices( dev, buf, elts.start, elts.end, count ); + + return 0; +} + +int radeon_cp_blit( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_radeon_blit_t blit; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &blit, (drm_radeon_blit_t *)arg, + sizeof(blit) ) ) + return -EFAULT; + + DRM_DEBUG( "%s: pid=%d index=%d\n", + __FUNCTION__, current->pid, blit.idx ); + + if ( blit.idx < 0 || blit.idx > dma->buf_count ) { + DRM_ERROR( "sending %d buffers (of %d max)\n", + blit.idx, dma->buf_count ); + return -EINVAL; + } + + VB_AGE_CHECK_WITH_RET( dev_priv ); + + return radeon_cp_dispatch_blit( dev, &blit ); +} + +int radeon_cp_stipple( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_stipple_t stipple; + u32 mask[32]; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &stipple, (drm_radeon_stipple_t *)arg, + sizeof(stipple) ) ) + return -EFAULT; + + if ( copy_from_user( &mask, stipple.mask, + 32 * sizeof(u32) ) ) + return -EFAULT; + + radeon_cp_dispatch_stipple( dev, mask ); + + return 0; +} + +int radeon_cp_indirect( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_radeon_buf_priv_t *buf_priv; + drm_radeon_indirect_t indirect; + RING_LOCALS; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + if ( !dev_priv || dev_priv->is_pci ) { + DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &indirect, (drm_radeon_indirect_t *)arg, + sizeof(indirect) ) ) + return -EFAULT; + + DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n", + indirect.idx, indirect.start, + indirect.end, indirect.discard ); + + if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) { + DRM_ERROR( "buffer index %d (of %d max)\n", + indirect.idx, dma->buf_count - 1 ); + return -EINVAL; + } + + buf = dma->buflist[indirect.idx]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", indirect.idx ); + return -EINVAL; + } + + if ( indirect.start < buf->used ) { + DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n", + indirect.start, buf->used ); + return -EINVAL; + } + + VB_AGE_CHECK_WITH_RET( dev_priv ); + + buf->used = indirect.end; + buf_priv->discard = indirect.discard; + + /* Wait for the 3D stream to idle before the indirect buffer + * containing 2D acceleration commands is processed. + */ + BEGIN_RING( 2 ); + + RADEON_WAIT_UNTIL_3D_IDLE(); + + ADVANCE_RING(); + + /* Dispatch the indirect buffer full of commands from the + * X server. This is insecure and is thus only available to + * privileged clients. + */ + radeon_cp_dispatch_indirect( dev, buf, indirect.start, indirect.end ); + + return 0; +} diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 4c141d668..e4edb9f07 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -70,7 +70,6 @@ extern int psaux_init(void); extern void gfx_register(void); #endif extern void streamable_init(void); -extern int rtc_sun_init(void); /* Combines MK48T02 and MK48T08 */ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int ds1286_init(void); @@ -259,9 +258,6 @@ int __init misc_init(void) #ifdef CONFIG_BVME6000 rtc_DP8570A_init(); #endif -#if defined(CONFIG_SUN_MOSTEK_RTC) - rtc_sun_init(); -#endif #ifdef CONFIG_SGI_DS1286 ds1286_init(); #endif diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 6f4ebe44c..c2ae319af 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -86,6 +86,15 @@ static inline void free_buf(unsigned char *buf) free_page((unsigned long) buf); } +static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) +{ + if (tty->read_cnt < N_TTY_BUF_SIZE) { + tty->read_buf[tty->read_head] = c; + tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1); + tty->read_cnt++; + } +} + static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) { unsigned long flags; @@ -94,11 +103,7 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) * Why didn't anyone see this one comming? --AJK */ spin_lock_irqsave(&tty->read_lock, flags); - if (tty->read_cnt < N_TTY_BUF_SIZE) { - tty->read_buf[tty->read_head] = c; - tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1); - tty->read_cnt++; - } + put_tty_queue_nolock(c, tty); spin_unlock_irqrestore(&tty->read_lock, flags); } @@ -499,6 +504,8 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { + unsigned long flags; + if (tty->raw) { put_tty_queue(c, tty); return; @@ -651,10 +658,12 @@ send_signal: put_tty_queue(c, tty); handle_newline: + spin_lock_irqsave(&tty->read_lock, flags); set_bit(tty->read_head, &tty->read_flags); - put_tty_queue(c, tty); + put_tty_queue_nolock(c, tty); tty->canon_head = tty->read_head; tty->canon_data++; + spin_unlock_irqrestore(&tty->read_lock, flags); kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); @@ -1055,12 +1064,6 @@ do_it_again: tty->read_tail = ((tty->read_tail+1) & (N_TTY_BUF_SIZE-1)); tty->read_cnt--; - spin_unlock_irqrestore(&tty->read_lock, flags); - - if (!eol || (c != __DISABLED_CHAR)) { - put_user(c, b++); - nr--; - } if (eol) { /* this test should be redundant: * we shouldn't be reading data if @@ -1068,8 +1071,15 @@ do_it_again: */ if (--tty->canon_data < 0) tty->canon_data = 0; - break; } + spin_unlock_irqrestore(&tty->read_lock, flags); + + if (!eol || (c != __DISABLED_CHAR)) { + put_user(c, b++); + nr--; + } + if (eol) + break; } } else { int uncopied; diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c index 8389039d6..857b32a7e 100644 --- a/drivers/i2o/i2o_block.c +++ b/drivers/i2o/i2o_block.c @@ -392,7 +392,6 @@ static inline int i2ob_new_segment(request_queue_t *q, struct request *req, if (req->nr_segments < max_segments) { req->nr_segments++; - q->elevator.nr_segments++; return 1; } return 0; @@ -421,22 +420,16 @@ static int i2ob_merge_requests(request_queue_t *q, { int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; int total_segments = req->nr_segments + next->nr_segments; - int same_segment; if (__max_segments < max_segments) max_segments = __max_segments; - same_segment = 0; if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) - { total_segments--; - same_segment = 1; - } if (total_segments > max_segments) return 0; - q->elevator.nr_segments -= same_segment; req->nr_segments = total_segments; return 1; } diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 62e2437e5..38cde0b40 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -55,6 +55,15 @@ const char *bad_ata100_5[] = { }; const char *bad_ata66_4[] = { + "IBM-DTLA-307075", + "IBM-DTLA-307060", + "IBM-DTLA-307045", + "IBM-DTLA-307030", + "IBM-DTLA-307020", + "IBM-DTLA-307015", + "IBM-DTLA-305040", + "IBM-DTLA-305030", + "IBM-DTLA-305020", "WDC AC310200R", NULL }; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 3a6a9e8d9..433951e95 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -288,6 +288,9 @@ * 4.59 Aug 11, 2000 - Fix changer problem in cdrom_read_toc, we weren't * correctly sensing a disc change. * - Rearranged some code + * - Use extended sense on drives that support it for + * correctly reporting tray status -- from + * Michael D Johnson <johnsom@orst.edu> * *************************************************************************/ @@ -759,16 +762,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, * changed 5 parameters to 3 for dvd-ram * struct packet_command *pc; now packet_command_t *pc; */ -#undef CLASSIC_PACKET_STRUCT static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, struct packet_command *pc, ide_handler_t *handler) { -#ifdef CLASSIC_PACKET_STRUCT unsigned char *cmd_buf = pc->c; int cmd_len = sizeof(pc->c); unsigned int timeout = pc->timeout; -#endif ide_startstop_t startstop; if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { @@ -786,22 +786,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, } /* Arm the interrupt handler. */ -#ifdef CLASSIC_PACKET_STRUCT - /* Arm the interrupt handler. */ ide_set_handler (drive, handler, timeout, cdrom_timer_expiry); /* Send the command to the device. */ atapi_output_bytes (drive, cmd_buf, cmd_len); -#else /* !CLASSIC_PACKET_STRUCT */ - /* Arm the interrupt handler. */ -// ide_set_handler (drive, handler, (unsigned int) pc->timeout, cdrom_timer_expiry); - ide_set_handler (drive, handler, pc->timeout, cdrom_timer_expiry); - - /* Send the command to the device. */ -// atapi_output_bytes (drive, (void *)pc->c, (unsigned int) sizeof(pc->c)); - atapi_output_bytes (drive, pc->c, sizeof(pc->c)); -#endif /* CLASSIC_PACKET_STRUCT */ - return ide_started; } @@ -1884,9 +1872,6 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) If it is, just return. */ (void) cdrom_check_status(drive, sense); - if (CDROM_STATE_FLAGS(drive)->toc_valid) - return 0; - /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, sizeof(struct atapi_toc_header), sense); @@ -2324,11 +2309,17 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) sense.ascq == 0x04) return CDS_DISC_OK; + + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ if (sense.sense_key == NOT_READY) { - /* ATAPI doesn't have anything that can help - us decide whether the drive is really - emtpy or the tray is just open. irk. */ - return CDS_TRAY_OPEN; + if (sense.asc == 0x3a && (!sense.ascq||sense.ascq == 1)) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; } return CDS_DRIVE_NOT_READY; @@ -2597,7 +2588,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram) printk (" DVD%s%s", (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); + (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : ""); if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) printk (" CD%s%s", diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 7caafab9b..7158d3461 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -226,6 +226,9 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq) unsigned char *virt_addr = bh->b_data; unsigned int size = bh->b_size; + if (nents >= PRD_ENTRIES) + return 0; + while ((bh = bh->b_reqnext) != NULL) { if ((virt_addr + size) != (unsigned char *) bh->b_data) break; @@ -259,6 +262,9 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func) HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq); + if (!i) + return 0; + sg = HWIF(drive)->sg_table; while (i && sg_dma_len(sg)) { u32 cur_addr; @@ -274,7 +280,7 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func) */ while (cur_len) { - if (++count >= PRD_ENTRIES) { + if (count++ >= PRD_ENTRIES) { printk("%s: DMA table too small\n", drive->name); pci_unmap_sg(HWIF(drive)->pci_dev, HWIF(drive)->sg_table, diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index decbc9f8d..64d9121c8 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -134,7 +134,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) break; } #endif - printk ("CDROM"); + printk ("CD/DVD-ROM"); break; case ide_tape: printk ("TAPE"); @@ -761,9 +761,10 @@ static void init_gendisk (ide_hwif_t *hwif) for (unit = 0; unit < minors; ++unit) { *bs++ = BLOCK_SIZE; #ifdef CONFIG_BLK_DEV_PDC4030 - *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : MAX_SECTORS); + *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 256); #else - *max_sect++ = MAX_SECTORS; + /* IDE can do up to 128K per request. */ + *max_sect++ = 256; #endif *max_ra++ = MAX_READAHEAD; } diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index 3ea1e261e..356e7a4cc 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -602,7 +602,9 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif) #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &via82cxxx_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO hwif->autodma = 1; +#endif } #endif /* CONFIG_BLK_DEV_IDEDMA */ } diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index 66f6b5d4a..72d990134 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -34,8 +34,8 @@ hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o -hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hfc_2bs0.o -hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hfc_2bs0.o +hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o hisax-objs-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 0b60e89b3..6d0366cf2 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1708,8 +1708,8 @@ int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard * } static struct pci_device_id hisax_pci_tbl[] __initdata = { -#ifdef CONFIG_HISAX_FRTIZPCI - {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_FRITZ, PCI_ANY_ID, PCI_ANY_ID}, +#ifdef CONFIG_HISAX_FRITZPCI + {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID}, #endif #ifdef CONFIG_HISAX_DIEHLDIVA {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, PCI_ANY_ID, PCI_ANY_ID}, diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index b484635f1..1c2ab1042 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -566,7 +566,7 @@ l3_msg(struct PStack *st, int pr, void *arg) } else { struct sk_buff *skb = arg; - skb_queue_head(&st->l3.squeue, skb); + skb_queue_tail(&st->l3.squeue, skb); FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); } break; diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 4cc1f8b83..5ffd61db0 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -10,7 +10,7 @@ ca7bd9bac39203f3074f3f093948cc3c isac.c a2ad619fd404b3149099a2984de9d23c isdnl1.c d2a78e407f3d94876deac160c6f9aae6 isdnl2.c -a109841c2e75b11fc8ef2c8718e24c3e isdnl3.c +e7932ca7ae39c497c17f13a2e1434fcd isdnl3.c afb5f2f4ac296d6de45c856993b161e1 tei.c 00023e2a482cb86a26ea870577ade5d6 callc.c a1834e9b2ec068440cff2e899eff4710 cert.c @@ -25,9 +25,9 @@ a1834e9b2ec068440cff2e899eff4710 cert.c Version: 2.6.3i Charset: noconv -iQCVAwUBOlMTgDpxHvX/mS9tAQFSbgP/W9y6tnnWHTRLGqyr3EY1OHZiQXERkAAu -hp+Y8PIoX1GgAh4yZ7xhYwUsk6y0z5USdGuhC9ZHh+oZd57lPsJMnhkEZR5BVsYT -r7jHwelP527+QCLkVUCHIVIWUW0ANzeZBhDV2vefkFb+gWLiZsBhaHssbcKGsMNG -Ak4xS1ByqsM= -=lsIJ +iQCVAwUBOlxeLTpxHvX/mS9tAQH6RwP8DhyvqAnXFV6WIGi16iQ3vKikkPoqnDQs +GEn5uCW0dPYKlwthD2Grj/JbMYZhOmCFuDxF7ufJnjTSDe/D8XNe2wngxzAiwcIe +WjCrT8X95cuP3HZHscbFTEinVV0GAnoI0ZEgs5eBDhVHDqILLYMaTFBQaRH3jgXc +i5VH88jPfUM= +=qc+J -----END PGP SIGNATURE----- diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 7a5074c79..f4c1d429d 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1512,7 +1512,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) int i; if ((ret = verify_area(VERIFY_READ, (void *) arg, - (ISDN_MODEM_NUMREG + ISDN_MSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; @@ -1521,6 +1521,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) ISDN_MODEM_NUMREG)) return -EFAULT; p += ISDN_MODEM_NUMREG; + if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 757c59ca9..672dd8c5c 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -2325,6 +2325,7 @@ isdn_net_new(char *name, struct net_device *master) memset(netdev, 0, sizeof(isdn_net_dev)); if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate device locals\n"); + kfree(netdev); return NULL; } memset(netdev->local, 0, sizeof(isdn_net_local)); diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 3bebcdfcf..f1cbb8ab7 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1131,9 +1131,9 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) proto = PPP_IPX; /* untested */ break; default: - dev_kfree_skb(skb); printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", skb->protocol); + dev_kfree_skb(skb); return 0; } @@ -2310,8 +2310,7 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc rsparm.data = rsdata; rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - /* !!!HACK,HACK,HACK!!! 2048 is only assumed */ - skb_out = dev_alloc_skb(2048); + skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN); len = ipc->decompress(stat, skb, skb_out, &rsparm); kfree_skb(skb); if (len <= 0) { @@ -2332,14 +2331,9 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc kfree_skb(skb_out); return NULL; } - - if (isdn_ppp_skip_ac(ri, skb) < 0) { - kfree_skb(skb); - return NULL; - } - *proto = isdn_ppp_strip_proto(skb); + *proto = isdn_ppp_strip_proto(skb_out); if (*proto < 0) { - kfree_skb(skb); + kfree_skb(skb_out); return NULL; } return skb_out; diff --git a/drivers/isdn/isdn_v110.c b/drivers/isdn/isdn_v110.c index 08c54a866..5dd9f2c58 100644 --- a/drivers/isdn/isdn_v110.c +++ b/drivers/isdn/isdn_v110.c @@ -102,7 +102,7 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize) int i; isdn_v110_stream *v; - if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_KERNEL)) == NULL) + if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL) return NULL; memset(v, 0, sizeof(isdn_v110_stream)); v->key = key; @@ -134,7 +134,7 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize) v->b = 0; v->skbres = hdrlen; v->maxsize = maxsize - hdrlen; - if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) { + if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) { kfree(v); return NULL; } diff --git a/drivers/md/Config.in b/drivers/md/Config.in index 565055a68..30438c77f 100644 --- a/drivers/md/Config.in +++ b/drivers/md/Config.in @@ -11,12 +11,7 @@ dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then - bool ' Boot support' CONFIG_MD_BOOT - bool ' Auto Detect support' CONFIG_AUTODETECT_RAID -fi dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD -dep_mbool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS $CONFIG_BLK_DEV_LVM endmenu diff --git a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c index 980694ee3..e28ffdbe9 100644 --- a/drivers/md/lvm-snap.c +++ b/drivers/md/lvm-snap.c @@ -21,6 +21,14 @@ * */ +/* + * Changelog + * + * 05/07/2000 - implemented persistent snapshot support + * 23/11/2000 - used cpu_to_le64 rather than my own macro + * + */ + #include <linux/kernel.h> #include <linux/vmalloc.h> #include <linux/blkdev.h> @@ -30,7 +38,9 @@ #include <linux/lvm.h> -static char *lvm_snap_version __attribute__ ((unused)) = "LVM 0.9 snapshot code (13/11/2000)\n"; +#include "lvm-snap.h" + +static char *lvm_snap_version __attribute__ ((unused)) = "LVM 0.9.1_beta2 snapshot code (18/01/2001)\n"; extern const char *const lvm_name; extern int lvm_blocksizes[]; @@ -214,10 +224,10 @@ void lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) memset(lv_COW_table, 0, blksize_snap); for ( ; is < lv_snap->lv_remap_ptr; is++, id++) { /* store new COW_table entry */ - lv_COW_table[id].pv_org_number = LVM_TO_DISK64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_org)); - lv_COW_table[id].pv_org_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[is].rsector_org); - lv_COW_table[id].pv_snap_number = LVM_TO_DISK64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_new)); - lv_COW_table[id].pv_snap_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[is].rsector_new); + lv_COW_table[id].pv_org_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_org)); + lv_COW_table[id].pv_org_rsector = cpu_to_le64(lv_snap->lv_block_exception[is].rsector_org); + lv_COW_table[id].pv_snap_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_new)); + lv_COW_table[id].pv_snap_rsector = cpu_to_le64(lv_snap->lv_block_exception[is].rsector_new); } } @@ -227,8 +237,7 @@ void lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) * */ -int lvm_write_COW_table_block(vg_t * vg, - lv_t * lv_snap) +int lvm_write_COW_table_block(vg_t * vg, lv_t * lv_snap) { int blksize_snap; int end_of_table; @@ -268,10 +277,10 @@ int lvm_write_COW_table_block(vg_t * vg, blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); /* store new COW_table entry */ - lv_COW_table[idx_COW_table].pv_org_number = LVM_TO_DISK64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[idx].rdev_org)); - lv_COW_table[idx_COW_table].pv_org_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[idx].rsector_org); - lv_COW_table[idx_COW_table].pv_snap_number = LVM_TO_DISK64(lvm_pv_get_number(vg, snap_phys_dev)); - lv_COW_table[idx_COW_table].pv_snap_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[idx].rsector_new); + lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[idx].rdev_org)); + lv_COW_table[idx_COW_table].pv_org_rsector = cpu_to_le64(lv_snap->lv_block_exception[idx].rsector_org); + lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(lvm_pv_get_number(vg, snap_phys_dev)); + lv_COW_table[idx_COW_table].pv_snap_rsector = cpu_to_le64(lv_snap->lv_block_exception[idx].rsector_new); length_tmp = iobuf->length; iobuf->length = blksize_snap; @@ -568,6 +577,7 @@ void lvm_snapshot_release(lv_t * lv) } if (lv->lv_iobuf) { + kiobuf_wait_for_io(lv->lv_iobuf); unmap_kiobuf(lv->lv_iobuf); free_kiovec(1, &lv->lv_iobuf); lv->lv_iobuf = NULL; diff --git a/drivers/md/lvm-snap.h b/drivers/md/lvm-snap.h new file mode 100644 index 000000000..23538a1b7 --- /dev/null +++ b/drivers/md/lvm-snap.h @@ -0,0 +1,47 @@ +/* + * kernel/lvm-snap.h + * + * Copyright (C) 2001 Sistina Software + * + * + * LVM driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 05/01/2001:Joe Thornber - Factored this file out of lvm.c + * + */ + +#ifndef LVM_SNAP_H +#define LVM_SNAP_H + +/* external snapshot calls */ +extern inline int lvm_get_blksize(kdev_t); +extern int lvm_snapshot_alloc(lv_t *); +extern void lvm_snapshot_fill_COW_page(vg_t *, lv_t *); +extern int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *); +extern int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); +extern void lvm_snapshot_release(lv_t *); +extern int lvm_write_COW_table_block(vg_t *, lv_t *); +extern inline void lvm_hash_link(lv_block_exception_t *, + kdev_t, ulong, lv_t *); +extern int lvm_snapshot_alloc_hash_table(lv_t *); +extern void lvm_drop_snapshot(lv_t *, const char *); + +#endif diff --git a/drivers/md/lvm.c b/drivers/md/lvm.c index ea276c57c..a4ca05e90 100644 --- a/drivers/md/lvm.c +++ b/drivers/md/lvm.c @@ -7,22 +7,23 @@ * April-May,July-August,November 1998 * January-March,May,July,September,October 1999 * January,February,July,September-November 2000 + * January 2001 * * * LVM driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * LVM driver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Boston, MA 02111-1307, USA. * */ @@ -138,13 +139,21 @@ * 01/11/2000 - added memory information on hash tables to * lvm_proc_get_global_info() * 02/11/2000 - implemented /proc/lvm/ hierarchy - * 07/12/2000 - make sure lvm_make_request_fn returns correct value - 0 or 1 - NeilBrown + * 22/11/2000 - changed lvm_do_create_proc_entry_of_pv () to work + * with devfs + * 26/11/2000 - corrected #ifdef locations for PROC_FS + * 28/11/2000 - fixed lvm_do_vg_extend() NULL pointer BUG + * - fixed lvm_do_create_proc_entry_of_pv() buffer tampering BUG + * 08/01/2001 - Removed conditional compiles related to PROC_FS, + * procfs is always supported now. (JT) + * 12/01/2001 - avoided flushing logical volume in case of shrinking + * because of unecessary overhead in case of heavy updates * */ -static char *lvm_version = "LVM version 0.9 by Heinz Mauelshagen (13/11/2000)\n"; -static char *lvm_short_version = "version 0.9 (13/11/2000)"; +static char *lvm_version = "LVM version 0.9.1_beta2 by Heinz Mauelshagen (18/01/2001)\n"; +static char *lvm_short_version = "version 0.9.1_beta2 (18/01/2001)"; #define MAJOR_NR LVM_BLK_MAJOR #define DEVICE_OFF(device) @@ -190,6 +199,8 @@ static char *lvm_short_version = "version 0.9 (13/11/2000)"; #include <linux/errno.h> #include <linux/lvm.h> +#include "lvm-snap.h" + #define LVM_CORRECT_READ_AHEAD( a) \ if ( a < LVM_MIN_READ_AHEAD || \ a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; @@ -198,19 +209,28 @@ static char *lvm_short_version = "version 0.9 (13/11/2000)"; # define WRITEA WRITE #endif -/* - * External function prototypes - */ -#ifdef MODULE -int init_module(void); -void cleanup_module(void); +/* debug macros */ +#ifdef DEBUG_IOCTL +#define P_IOCTL(fmt, args...) printk(KERN_DEBUG "lvm ioctl: " fmt, ## args) #else -extern int lvm_init(void); +#define P_IOCTL(fmt, args...) #endif -static void lvm_dummy_device_request(request_queue_t *); -#define DEVICE_REQUEST lvm_dummy_device_request +#ifdef DEBUG_MAP +#define P_MAP(fmt, args...) printk(KERN_DEBUG "lvm map: " fmt, ## args) +#else +#define P_MAP(fmt, args...) +#endif + +#ifdef DEBUG_KFREE +#define P_KFREE(fmt, args...) printk(KERN_DEBUG "lvm kfree: " fmt, ## args) +#else +#define P_KFREE(fmt, args...) +#endif +/* + * External function prototypes + */ static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); @@ -224,42 +244,29 @@ static int lvm_user_bmap(struct inode *, struct lv_bmap *); static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong); -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS int lvm_proc_read_vg_info(char *, char **, off_t, int, int *, void *); int lvm_proc_read_lv_info(char *, char **, off_t, int, int *, void *); int lvm_proc_read_pv_info(char *, char **, off_t, int, int *, void *); static int lvm_proc_get_global_info(char *, char **, off_t, int, int *, void *); + +void lvm_do_create_devfs_entry_of_vg ( vg_t *); + void lvm_do_create_proc_entry_of_vg ( vg_t *); -inline void lvm_do_remove_proc_entry_of_vg ( vg_t *); -inline void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *); -inline void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *); -inline void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *); -inline void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *); -#endif +void lvm_do_remove_proc_entry_of_vg ( vg_t *); +void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *); +void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *); +void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *); +void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *); -#ifdef LVM_HD_NAME -void lvm_hd_name(char *, int); -#endif /* End external function prototypes */ /* * Internal function prototypes */ +static void lvm_cleanup(void); static void lvm_init_vars(void); -/* external snapshot calls */ -extern inline int lvm_get_blksize(kdev_t); -extern int lvm_snapshot_alloc(lv_t *); -extern void lvm_snapshot_fill_COW_page(vg_t *, lv_t *); -extern int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *); -extern int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); -extern void lvm_snapshot_release(lv_t *); -extern int lvm_write_COW_table_block(vg_t *, lv_t *); -extern inline void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *); -extern int lvm_snapshot_alloc_hash_table(lv_t *); -extern void lvm_drop_snapshot(lv_t *, char *); - #ifdef LVM_HD_NAME extern void (*lvm_hd_name_ptr) (char *, int); #endif @@ -288,9 +295,9 @@ static int lvm_do_vg_reduce(vg_t *, void *); static int lvm_do_vg_rename(vg_t *, void *); static int lvm_do_vg_remove(int); static void lvm_geninit(struct gendisk *); -#ifdef LVM_GET_INODE -static struct inode *lvm_get_inode(int); -void lvm_clear_inode(struct inode *); +static char *lvm_show_uuid ( char *); +#ifdef LVM_HD_NAME +void lvm_hd_name(char *, int); #endif /* END Internal function prototypes */ @@ -298,12 +305,10 @@ void lvm_clear_inode(struct inode *); /* volume group descriptor area pointers */ static vg_t *vg[ABS_MAX_VG]; -#ifdef CONFIG_DEVFS_FS static devfs_handle_t lvm_devfs_handle; static devfs_handle_t vg_devfs_handle[MAX_VG]; static devfs_handle_t ch_devfs_handle[MAX_VG]; static devfs_handle_t lv_devfs_handle[MAX_LV]; -#endif static pv_t *pvp = NULL; static lv_t *lvp = NULL; @@ -340,18 +345,15 @@ static int loadtime = 0; static uint vg_count = 0; static long lvm_chr_open_count = 0; static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; -static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait); static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS static struct proc_dir_entry *lvm_proc_dir = NULL; static struct proc_dir_entry *lvm_proc_vg_subdir = NULL; struct proc_dir_entry *pde = NULL; -#endif static struct file_operations lvm_chr_fops = { @@ -360,7 +362,7 @@ static struct file_operations lvm_chr_fops = ioctl: lvm_chr_ioctl, }; -#define BLOCK_DEVICE_OPERATIONS + /* block device operations structure needed for 2.3.38? and above */ static struct block_device_operations lvm_blk_dops = { @@ -391,22 +393,10 @@ static struct gendisk lvm_gendisk = NULL, /* pointer to next gendisk struct (internal) */ }; - -#ifdef MODULE -/* - * Module initialization... - */ -int init_module(void) -#else /* * Driver initialization... */ -#ifdef __initfunc -__initfunc(int lvm_init(void)) -#else -int __init lvm_init(void) -#endif -#endif /* #ifdef MODULE */ +int lvm_init(void) { struct gendisk *gendisk_ptr = NULL; @@ -414,11 +404,7 @@ int __init lvm_init(void) printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); return -EIO; } -#ifdef BLOCK_DEVICE_OPERATIONS if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) -#else - if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0) -#endif { printk("%s -- register_blkdev failed\n", lvm_name); if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) @@ -426,21 +412,17 @@ int __init lvm_init(void) return -EIO; } -#ifdef CONFIG_DEVFS_FS lvm_devfs_handle = devfs_register( 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_chr_fops, NULL); -#endif -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_proc_dir = create_proc_entry (LVM_DIR, S_IFDIR, &proc_root); if (lvm_proc_dir != NULL) { lvm_proc_vg_subdir = create_proc_entry (LVM_VG_SUBDIR, S_IFDIR, lvm_proc_dir); pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir); if ( pde != NULL) pde->read_proc = &lvm_proc_get_global_info; } -#endif lvm_init_vars(); lvm_geninit(&lvm_gendisk); @@ -464,9 +446,9 @@ int __init lvm_init(void) lvm_hd_name_ptr = lvm_hd_name; #endif - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); + /* optional read root VGDA */ /* if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg); @@ -483,20 +465,17 @@ int __init lvm_init(void) lvm_version, lvm_name); return 0; -} /* init_module() / lvm_init() */ +} /* lvm_init() */ -#ifdef MODULE /* - * Module cleanup... + * cleanup... */ -void cleanup_module(void) +static void lvm_cleanup(void) { struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; -#ifdef CONFIG_DEVFS_FS devfs_unregister (lvm_devfs_handle); -#endif if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); @@ -504,7 +483,7 @@ void cleanup_module(void) if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) { printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name); } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + gendisk_ptr = gendisk_ptr_prev = gendisk_head; while (gendisk_ptr != NULL) { @@ -521,11 +500,9 @@ void cleanup_module(void) blksize_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS remove_proc_entry(LVM_GLOBAL, lvm_proc_dir); remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir); remove_proc_entry(LVM_DIR, &proc_root); -#endif #ifdef LVM_HD_NAME /* reference from linux/drivers/block/genhd.c */ @@ -535,18 +512,13 @@ void cleanup_module(void) printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); return; -} /* void cleanup_module() */ -#endif /* #ifdef MODULE */ +} /* lvm_cleanup() */ /* * support function to initialize lvm variables */ -#ifdef __initfunc -__initfunc(void lvm_init_vars(void)) -#else void __init lvm_init_vars(void) -#endif { int v; @@ -626,13 +598,9 @@ static int lvm_chr_ioctl(struct inode *inode, struct file *file, /* otherwise cc will complain about unused variables */ (void) lvm_lock; - -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " - "VG#: %d mode: 0x%X\n", - lvm_name, command, minor, VG_CHR(minor), file->f_mode); -#endif + P_IOCTL("%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " + "VG#: %d mode: 0x%X\n", + lvm_name, command, minor, VG_CHR(minor), file->f_mode); #ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) return -EACCES; @@ -890,14 +858,12 @@ static int lvm_blk_open(struct inode *inode, struct file *file) if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ - if (file->f_mode & O_RDWR) { - if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM; - if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; - } + if (!(lv_ptr->lv_status & LV_ACTIVE)) + return -EPERM; + if (!(lv_ptr->lv_access & LV_WRITE) && + (file->f_mode & FMODE_WRITE)) + return -EACCES; -#ifndef BLOCK_DEVICE_OPERATIONS - file->f_op = &lvm_blk_fops; -#endif /* be sure to increment VG counter */ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; @@ -930,24 +896,18 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, void *arg = (void *) a; struct hd_geometry *hd = (struct hd_geometry *) a; -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " - "VG#: %dl LV#: %d\n", - lvm_name, minor, command, (ulong) arg, - VG_BLK(minor), LV_BLK(minor)); -#endif + P_IOCTL("%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " + "VG#: %dl LV#: %d\n", + lvm_name, minor, command, (ulong) arg, + VG_BLK(minor), LV_BLK(minor)); switch (command) { case BLKGETSIZE: /* return device size */ -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n", - lvm_name, lv_ptr->lv_size); -#endif + P_IOCTL("%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n", + lvm_name, lv_ptr->lv_size); if (put_user(lv_ptr->lv_size, (long *)arg)) - return -EFAULT; + return -EFAULT; break; @@ -955,10 +915,8 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, /* flush buffer cache */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); -#endif + P_IOCTL("%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); + fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); break; @@ -968,11 +926,9 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, /* set read ahead for block device */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", - lvm_name, (long) arg, MAJOR(inode->i_rdev), minor); -#endif + P_IOCTL("%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", + lvm_name, (long) arg, MAJOR(inode->i_rdev), minor); + if ((long) arg < LVM_MIN_READ_AHEAD || (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL; @@ -982,10 +938,7 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, case BLKRAGET: /* get current read ahead setting */ -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name); -#endif + P_IOCTL("%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name); if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) return -EFAULT; break; @@ -993,10 +946,7 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, case HDIO_GETGEO: /* get disk geometry */ -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); -#endif + P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); if (hd == NULL) return -EINVAL; { @@ -1016,11 +966,8 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, return -EFAULT; } -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- cylinders: %d\n", - lvm_name, lv_ptr->lv_size / heads / sectors); -#endif + P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n", + lvm_name, lv_ptr->lv_size / heads / sectors); break; @@ -1127,22 +1074,22 @@ static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result) struct buffer_head bh; unsigned long block; int err; - + if (get_user(block, &user_result->lv_block)) - return -EFAULT; - + return -EFAULT; + memset(&bh,0,sizeof bh); bh.b_rsector = block; bh.b_dev = bh.b_rdev = inode->i_dev; bh.b_size = lvm_get_blksize(bh.b_dev); if ((err=lvm_map(&bh, READ)) < 0) { - printk("lvm map failed: %d\n", err); - return -EINVAL; + printk("lvm map failed: %d\n", err); + return -EINVAL; } - - return put_user( kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || + + return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || put_user(bh.b_rsector, &user_result->lv_block) ? -EFAULT : 0; -} +} /* @@ -1168,7 +1115,7 @@ int lvm_vg_info(vg_t *vg_ptr, char *buf) { vg_ptr->pe_total, vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, vg_ptr->pe_allocated, - (vg_ptr->pe_total - vg_ptr->pe_allocated) * + (vg_ptr->pe_total - vg_ptr->pe_allocated) * vg_ptr->pe_size >> 1, vg_ptr->pe_total - vg_ptr->pe_allocated); return sz; @@ -1263,7 +1210,6 @@ int lvm_pv_info(pv_t *pv_ptr, char *buf) { } -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS /* * Support functions /proc-Filesystem */ @@ -1325,10 +1271,7 @@ static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int cou lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); if (buf != NULL) { -#ifdef DEBUG_KFREE - printk(KERN_DEBUG - "%s -- vfree %d\n", lvm_name, __LINE__); -#endif + P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__); lock_kernel(); vfree(buf); unlock_kernel(); @@ -1452,7 +1395,6 @@ static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int cou else return count; } /* lvm_proc_get_global_info() */ -#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */ /* @@ -1478,7 +1420,7 @@ int lvm_proc_read_vg_info(char *page, char **start, off_t off, sz += sprintf ( page+sz, "PE size: %u\n", vg->pe_size / 2); sz += sprintf ( page+sz, "PE total: %u\n", vg->pe_total); sz += sprintf ( page+sz, "PE allocated: %u\n", vg->pe_allocated); - sz += sprintf ( page+sz, "uuid: %s\n", vg->vg_uuid); + sz += sprintf ( page+sz, "uuid: %s\n", lvm_show_uuid(vg->vg_uuid)); return sz; } @@ -1525,7 +1467,7 @@ int lvm_proc_read_pv_info(char *page, char **start, off_t off, sz += sprintf ( page+sz, "PE allocated: %u\n", pv->pe_allocated); sz += sprintf ( page+sz, "device: %02u:%02u\n", MAJOR(pv->pv_dev), MINOR(pv->pv_dev)); - sz += sprintf ( page+sz, "uuid: %s\n", pv->pv_uuid); + sz += sprintf ( page+sz, "uuid: %s\n", lvm_show_uuid(pv->pv_uuid)); return sz; @@ -1565,15 +1507,13 @@ static int lvm_map(struct buffer_head *bh, int rw) lvm_name, lv->lv_name); return -1; } -#ifdef DEBUG_MAP - printk(KERN_DEBUG - "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " - "size:%lu\n", - lvm_name, minor, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp, size); -#endif + + P_MAP("%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " + "size:%lu\n", + lvm_name, minor, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp, size); if (rsector_tmp + size > lv->lv_size) { printk(KERN_ALERT @@ -1595,15 +1535,13 @@ lvm_second_remap: (rsector_tmp % vg_this->pe_size); rdev_tmp = lv->lv_current_pe[index].dev; -#ifdef DEBUG_MAP - printk(KERN_DEBUG - "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n", + P_MAP("lv_current_pe[%ld].pe: %ld rdev: %02d:%02d " + "rsector:%ld\n", index, lv->lv_current_pe[index].pe, MAJOR(rdev_tmp), MINOR(rdev_tmp), rsector_tmp); -#endif /* striped mapping */ } else { @@ -1624,9 +1562,7 @@ lvm_second_remap: rdev_tmp = lv->lv_current_pe[index].dev; } -#ifdef DEBUG_MAP - printk(KERN_DEBUG - "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" + P_MAP("lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" "stripe_length: %ld stripe_index: %ld\n", index, lv->lv_current_pe[index].pe, @@ -1635,7 +1571,6 @@ lvm_second_remap: rsector_tmp, stripe_length, stripe_index); -#endif /* handle physical extents on the move */ if (pe_lock_req.lock == LOCK_PE) { @@ -1659,6 +1594,8 @@ lvm_second_remap: if (lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)) { /* original logical volume */ if (lv->lv_access & LV_SNAPSHOT_ORG) { + /* Serializes the access to the lv_snapshot_next list */ + down(&lv->lv_snapshot_sem); if (rw == WRITE || rw == WRITEA) { lv_t *lv_ptr; @@ -1669,7 +1606,8 @@ lvm_second_remap: lv_ptr = lv_ptr->lv_snapshot_next) { /* Check for inactive snapshot */ if (!(lv_ptr->lv_status & LV_ACTIVE)) continue; - down(&lv->lv_snapshot_org->lv_snapshot_sem); + /* Serializes the COW with the accesses to the snapshot device */ + down(&lv_ptr->lv_snapshot_sem); /* do we still have exception storage for this snapshot free? */ if (lv_ptr->lv_block_exception != NULL) { rdev_sav = rdev_tmp; @@ -1690,9 +1628,10 @@ lvm_second_remap: rdev_tmp = rdev_sav; rsector_tmp = rsector_sav; } - up(&lv->lv_snapshot_org->lv_snapshot_sem); + up(&lv_ptr->lv_snapshot_sem); } } + up(&lv->lv_snapshot_sem); } else { /* remap snapshot logical volume */ down(&lv->lv_snapshot_sem); @@ -1733,31 +1672,12 @@ void lvm_hd_name(char *buf, int minor) /* - * this one never should be called... - */ -static void lvm_dummy_device_request(request_queue_t * t) -{ - printk(KERN_EMERG - "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n", - lvm_name, - MAJOR(CURRENT->rq_dev), - MINOR(CURRENT->rq_dev), - CURRENT->sector); - return; -} - - -/* * make request function */ static int lvm_make_request_fn(request_queue_t *q, int rw, - struct buffer_head *bh) -{ - if (lvm_map(bh, rw)<0) - return 0; /* failure, buffer_IO_error has been called, don't recurse */ - else - return 1; /* all ok, mapping done, call lower level driver */ + struct buffer_head *bh) { + return (lvm_map(bh, rw) < 0) ? 0 : 1; } @@ -1774,10 +1694,8 @@ static int lvm_do_lock_lvm(void) lock_try_again: spin_lock(&lvm_lock); if (lock != 0 && lock != current->pid) { -#ifdef DEBUG_IOCTL - printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n", - lvm_name, lock); -#endif + P_IOCTL("lvm_do_lock_lvm: %s is locked by pid %d ...\n", + lvm_name, lock); spin_unlock(&lvm_lock); interruptible_sleep_on(&lvm_wait); if (current->sigpending != 0) @@ -1966,6 +1884,8 @@ int lvm_do_vg_create(int minor, void *arg) } } + lvm_do_create_devfs_entry_of_vg ( vg_ptr); + /* Second path to correct snapshot logical volumes which are not in place during first path above */ for (l = 0; l < ls; l++) { @@ -1980,18 +1900,7 @@ int lvm_do_vg_create(int minor, void *arg) } } -#ifdef CONFIG_DEVFS_FS - vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); - ch_devfs_handle[vg_ptr->vg_number] = devfs_register( - vg_devfs_handle[vg_ptr->vg_number] , "group", - DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_chr_fops, NULL); -#endif - -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_create_proc_entry_of_vg ( vg_ptr); -#endif vfree(snap_lv_ptr); @@ -2021,25 +1930,15 @@ static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) for (p = 0; p < vg_ptr->pv_max; p++) { if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) { ret = lvm_do_pv_create(arg, vg_ptr, p); - lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr); if ( ret != 0) return ret; - - /* We don't need the PE list - in kernel space like LVs pe_t list */ - pv_ptr->pe = NULL; - vg_ptr->pv_cur++; - vg_ptr->pv_act++; - vg_ptr->pe_total += - pv_ptr->pe_total; -#ifdef LVM_GET_INODE - /* insert a dummy inode for fs_may_mount */ - pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); -#endif + pv_ptr = vg_ptr->pv[p]; + vg_ptr->pe_total += pv_ptr->pe_total; + lvm_do_create_proc_entry_of_pv(vg_ptr, pv_ptr); return 0; } } } -return -EPERM; + return -EPERM; } /* lvm_do_vg_extend() */ @@ -2060,10 +1959,6 @@ static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) { strcmp(pv_ptr->pv_name, pv_name) == 0) { if (pv_ptr->lv_cur > 0) return -EPERM; - vg_ptr->pe_total -= - pv_ptr->pe_total; - vg_ptr->pv_cur--; - vg_ptr->pv_act--; lvm_do_pv_remove(vg_ptr, p); /* Make PV pointer array contiguous */ for (; p < vg_ptr->pv_max - 1; p++) @@ -2091,9 +1986,7 @@ static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg) if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0) return -EFAULT; -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_remove_proc_entry_of_vg ( vg_ptr); -#endif strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1); for ( l = 0; l < vg_ptr->lv_max; l++) @@ -2115,9 +2008,7 @@ static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg) strncpy(pv_ptr->vg_name, vg_name, NAME_LEN); } -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_create_proc_entry_of_vg ( vg_ptr); -#endif return 0; } /* lvm_do_vg_rename */ @@ -2166,27 +2057,17 @@ static int lvm_do_vg_remove(int minor) /* free PVs */ for (i = 0; i < vg_ptr->pv_max; i++) { if ((pv_ptr = vg_ptr->pv[i]) != NULL) { -#ifdef DEBUG_KFREE - printk(KERN_DEBUG - "%s -- kfree %d\n", lvm_name, __LINE__); -#endif + P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); lvm_do_pv_remove(vg_ptr, i); } } -#ifdef CONFIG_DEVFS_FS devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]); devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]); -#endif -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_remove_proc_entry_of_vg ( vg_ptr); -#endif - -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif + P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); kfree(vg_ptr); vg[VG_CHR(minor)] = NULL; @@ -2222,11 +2103,6 @@ static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) { vg_ptr->pv_act++; vg_ptr->pv_cur++; -#ifdef LVM_GET_INODE - /* insert a dummy inode for fs_may_mount */ - pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); -#endif - return 0; } /* lvm_do_pv_create() */ @@ -2237,11 +2113,8 @@ static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) { static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) { pv_t *pv_ptr = vg_ptr->pv[p]; -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv_ptr); -#endif - vg_ptr->pe_total -= - pv_ptr->pe_total; + vg_ptr->pe_total -= pv_ptr->pe_total; vg_ptr->pv_cur--; vg_ptr->pv_act--; #ifdef LVM_GET_INODE @@ -2320,11 +2193,9 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " "at line %d\n", lvm_name, size, __LINE__); -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif + P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); kfree(lv_ptr); - vg[VG_CHR(minor)]->lv[l] = NULL; + vg_ptr->lv[l] = NULL; return -ENOMEM; } if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) { @@ -2354,9 +2225,8 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION " "of %d byte at line %d\n", lvm_name, size, __LINE__); -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif + P_KFREE("%s -- kfree %d\n", lvm_name, + __LINE__); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return -ENOMEM; @@ -2364,7 +2234,7 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) { vfree(lv_ptr->lv_block_exception); kfree(lv_ptr); - vg[VG_CHR(minor)]->lv[l] = NULL; + vg_ptr->lv[l] = NULL; return -EFAULT; } /* point to the original logical volume */ @@ -2372,33 +2242,32 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) lv_ptr->lv_snapshot_minor = 0; lv_ptr->lv_snapshot_org = lv_ptr; - lv_ptr->lv_snapshot_prev = NULL; - /* walk thrugh the snapshot list */ - while (lv_ptr->lv_snapshot_next != NULL) - lv_ptr = lv_ptr->lv_snapshot_next; - /* now lv_ptr points to the last existing snapshot in the chain */ - vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; /* our new one now back points to the previous last in the chain which can be the original logical volume */ lv_ptr = vg_ptr->lv[l]; /* now lv_ptr points to our new last snapshot logical volume */ - lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org; - lv_ptr->lv_snapshot_next = NULL; lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; + lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le; lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes; lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize; + + /* Update the VG PE(s) used by snapshot reserve space. */ + vg_ptr->pe_allocated += lv_ptr->lv_allocated_snapshot_le; + if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0) { vfree(lv_ptr->lv_block_exception); kfree(lv_ptr); - vg[VG_CHR(minor)]->lv[l] = NULL; + vg_ptr->lv[l] = NULL; return ret; } for ( e = 0; e < lv_ptr->lv_remap_ptr; e++) - lvm_hash_link (lv_ptr->lv_block_exception + e, lv_ptr->lv_block_exception[e].rdev_org, lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); + lvm_hash_link (lv_ptr->lv_block_exception + e, + lv_ptr->lv_block_exception[e].rdev_org, + lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); /* need to fill the COW exception table data into the page for disk i/o */ lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr); @@ -2426,9 +2295,8 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; -#ifdef CONFIG_DEVFS_FS { - char *lv_tmp, *lv_buf = NULL; + char *lv_tmp, *lv_buf = lv->lv_name; strtok(lv->lv_name, "/"); /* /dev */ while((lv_tmp = strtok(NULL, "/")) != NULL) @@ -2440,24 +2308,29 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_blk_dops, NULL); } -#endif -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); -#endif /* optionally add our new snapshot LV */ if (lv_ptr->lv_access & LV_SNAPSHOT) { + lv_t *org = lv_ptr->lv_snapshot_org, *last; + /* sync the original logical volume */ - fsync_dev(lv_ptr->lv_snapshot_org->lv_dev); + fsync_dev(org->lv_dev); #ifdef LVM_VFS_ENHANCEMENT /* VFS function call to sync and lock the filesystem */ - fsync_dev_lockfs(lv_ptr->lv_snapshot_org->lv_dev); + fsync_dev_lockfs(org->lv_dev); #endif - lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG; - lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; - /* put ourselve into the chain */ - lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr; + + down(&org->lv_snapshot_sem); + org->lv_access |= LV_SNAPSHOT_ORG; + lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ + + /* Link in the list of snapshot volumes */ + for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next); + lv_ptr->lv_snapshot_prev = last; + last->lv_snapshot_next = lv_ptr; + up(&org->lv_snapshot_sem); } /* activate the logical volume */ @@ -2513,6 +2386,31 @@ static int lvm_do_lv_remove(int minor, char *lv_name, int l) lv_ptr->lv_snapshot_next != NULL) return -EPERM; + if (lv_ptr->lv_access & LV_SNAPSHOT) { + /* + * Atomically make the the snapshot invisible + * to the original lv before playing with it. + */ + lv_t * org = lv_ptr->lv_snapshot_org; + down(&org->lv_snapshot_sem); + + /* remove this snapshot logical volume from the chain */ + lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; + if (lv_ptr->lv_snapshot_next != NULL) { + lv_ptr->lv_snapshot_next->lv_snapshot_prev = + lv_ptr->lv_snapshot_prev; + } + up(&org->lv_snapshot_sem); + + /* no more snapshots? */ + if (!org->lv_snapshot_next) + org->lv_access &= ~LV_SNAPSHOT_ORG; + lvm_snapshot_release(lv_ptr); + + /* Update the VG PE(s) used by snapshot reserve space. */ + vg_ptr->pe_allocated -= lv_ptr->lv_allocated_snapshot_le; + } + lv_ptr->lv_status |= LV_SPINDOWN; /* sync the buffers */ @@ -2532,7 +2430,8 @@ static int lvm_do_lv_remove(int minor, char *lv_name, int l) vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG; vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1; - /* correct the PE count in PVs if this is no snapshot logical volume */ + /* correct the PE count in PVs if this is not a snapshot + logical volume */ if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { /* only if this is no snapshot logical volume because we share the lv_current_pe[] structs with the @@ -2546,31 +2445,13 @@ static int lvm_do_lv_remove(int minor, char *lv_name, int l) } } vfree(lv_ptr->lv_current_pe); - /* LV_SNAPSHOT */ - } else { - /* remove this snapshot logical volume from the chain */ - lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; - if (lv_ptr->lv_snapshot_next != NULL) { - lv_ptr->lv_snapshot_next->lv_snapshot_prev = - lv_ptr->lv_snapshot_prev; - } - /* no more snapshots? */ - if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL) - lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG; - lvm_snapshot_release(lv_ptr); } -#ifdef CONFIG_DEVFS_FS devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]); -#endif -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr); -#endif -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif + P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); kfree(lv_ptr); vg_ptr->lv[l] = NULL; vg_ptr->lv_cur--; @@ -2638,21 +2519,24 @@ static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) } memcpy(lvbe, lv_ptr->lv_block_exception, - (lv->lv_remap_end > lv_ptr->lv_remap_end ? lv_ptr->lv_remap_ptr : lv->lv_remap_end) * sizeof(lv_block_exception_t)); + (lv->lv_remap_end > lv_ptr->lv_remap_end ? + lv_ptr->lv_remap_ptr : lv->lv_remap_end) * sizeof(lv_block_exception_t)); lv_ptr->lv_block_exception = lvbe; lv_ptr->lv_remap_end = lv->lv_remap_end; if (lvm_snapshot_alloc_hash_table(lv_ptr) != 0) { - lvm_drop_snapshot(lv_ptr, "hash_alloc"); + lvm_drop_snapshot(lv_ptr, "no memory for hash table"); up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem); vfree(lvbe_old); vfree(lvs_hash_table_old); - return 1; + return -ENOMEM; } for (e = 0; e < lv_ptr->lv_remap_ptr; e++) - lvm_hash_link (lv_ptr->lv_block_exception + e, lv_ptr->lv_block_exception[e].rdev_org, lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); + lvm_hash_link (lv_ptr->lv_block_exception + e, + lv_ptr->lv_block_exception[e].rdev_org, + lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem); @@ -2677,15 +2561,6 @@ static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) return -EFAULT; } -#ifdef DEBUG - printk(KERN_DEBUG - "%s -- fsync_dev and " - "invalidate_buffers for %s [%s] in %s\n", - lvm_name, lv_ptr->lv_name, - kdevname(lv_ptr->lv_dev), - vg_ptr->vg_name); -#endif - /* reduce allocation counters on PV(s) */ for (le = 0; le < lv_ptr->lv_allocated_le; le++) { vg_ptr->pe_allocated--; @@ -2714,9 +2589,6 @@ static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) /* save # of old allocated logical extents */ old_allocated_le = lv_ptr->lv_allocated_le; - /* in case of shrinking -> let's flush */ - if ( end > lv->lv_current_le) fsync_dev(lv_ptr->lv_dev); - /* copy preloaded LV */ memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); @@ -2914,15 +2786,11 @@ static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv) if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue; if (lv_ptr->lv_dev == lv->lv_dev) { -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr); -#endif strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN); -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); -#endif break; } } @@ -3004,9 +2872,22 @@ static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) /* + * create a devfs entry for a volume group + */ +void lvm_do_create_devfs_entry_of_vg ( vg_t *vg_ptr) { + vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); + ch_devfs_handle[vg_ptr->vg_number] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number] , "group", + DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); +} + + +/* * create a /proc entry for a logical volume */ -inline void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { +void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { char *basename; if ( vg_ptr->lv_subdir_pde != NULL) { @@ -3026,7 +2907,7 @@ inline void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { /* * remove a /proc entry for a logical volume */ -inline void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { +void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { char *basename; if ( vg_ptr->lv_subdir_pde != NULL) { @@ -3041,13 +2922,17 @@ inline void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { /* * create a /proc entry for a physical volume */ -inline void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { +void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { + int offset = 0; char *basename; - - basename = strrchr(pv_ptr->pv_name, '/'); - if (basename == NULL) basename = pv_ptr->pv_name; - else basename++; - pde = create_proc_entry(basename, S_IFREG, vg_ptr->pv_subdir_pde); + char buffer[NAME_LEN]; + + basename = pv_ptr->pv_name; + if (strncmp(basename, "/dev/", 5) == 0) offset = 5; + strncpy(buffer, basename + offset, sizeof(buffer)); + basename = buffer; + while ( ( basename = strchr ( basename, '/')) != NULL) *basename = '_'; + pde = create_proc_entry(buffer, S_IFREG, vg_ptr->pv_subdir_pde); if ( pde != NULL) { pde->read_proc = lvm_proc_read_pv_info; pde->data = pv_ptr; @@ -3058,7 +2943,7 @@ inline void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { /* * remove a /proc entry for a physical volume */ -inline void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { +void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { char *basename; basename = strrchr(pv_ptr->pv_name, '/'); @@ -3074,7 +2959,6 @@ inline void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { /* * create a /proc entry for a volume group */ -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS void lvm_do_create_proc_entry_of_vg ( vg_t *vg_ptr) { int l, p; pv_t *pv_ptr; @@ -3090,24 +2974,25 @@ void lvm_do_create_proc_entry_of_vg ( vg_t *vg_ptr) { pde->read_proc = lvm_proc_read_vg_info; pde->data = vg_ptr; } - vg_ptr->lv_subdir_pde = - create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, - vg_ptr->vg_dir_pde); - vg_ptr->pv_subdir_pde = - create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, - vg_ptr->vg_dir_pde); - } - - if ( vg_ptr->pv_subdir_pde != NULL) { - for ( l = 0; l < vg_ptr->lv_max; l++) { - if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue; - lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); - } - for ( p = 0; p < vg_ptr->pv_max; p++) { - if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue; - lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr); - } - } + pde = create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, + vg_ptr->vg_dir_pde); + if ( pde != NULL) { + vg_ptr->lv_subdir_pde = pde; + for ( l = 0; l < vg_ptr->lv_max; l++) { + if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue; + lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); + } + } + pde = create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, + vg_ptr->vg_dir_pde); + if ( pde != NULL) { + vg_ptr->pv_subdir_pde = pde; + for ( p = 0; p < vg_ptr->pv_max; p++) { + if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue; + lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr); + } + } + } } /* @@ -3133,18 +3018,12 @@ void lvm_do_remove_proc_entry_of_vg ( vg_t *vg_ptr) { remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir); } } -#endif /* * support function initialize gendisk variables */ -#ifdef __initfunc -__initfunc(void lvm_geninit(struct gendisk *lvm_gdisk)) -#else -void __init - lvm_geninit(struct gendisk *lvm_gdisk) -#endif +void __init lvm_geninit(struct gendisk *lvm_gdisk) { int i = 0; @@ -3166,39 +3045,30 @@ void __init } /* lvm_gen_init() */ -#ifdef LVM_GET_INODE /* - * support function to get an empty inode - * - * Gets an empty inode to be inserted into the inode hash, - * so that a physical volume can't be mounted. - * This is analog to drivers/block/md.c - * - * Is this the real thing? - * + * return a pointer to a '-' padded uuid */ -struct inode *lvm_get_inode(int dev) -{ - struct inode *inode_this = NULL; +static char *lvm_show_uuid ( char *uuidstr) { + int i, j; + static char uuid[NAME_LEN] = { 0, }; - /* Lock the device by inserting a dummy inode. */ - inode_this = get_empty_inode(); - inode_this->i_dev = dev; - insert_inode_hash(inode_this); - return inode_this; -} + memset ( uuid, 0, NAME_LEN); + i = 6; + memcpy ( uuid, uuidstr, i); + uuidstr += i; -/* - * support function to clear an inode - * - */ -void lvm_clear_inode(struct inode *inode) -{ -#ifdef I_FREEING - inode->i_state |= I_FREEING; -#endif - clear_inode(inode); - return; + for ( j = 0; j < 6; j++) { + uuid[i++] = '-'; + memcpy ( &uuid[i], uuidstr, 4); + uuidstr += 4; + i += 4; + } + + memcpy ( &uuid[i], uuidstr, 2 ); + + return uuid; } -#endif /* #ifdef LVM_GET_INODE */ + +module_init(lvm_init); +module_exit(lvm_cleanup); diff --git a/drivers/md/md.c b/drivers/md/md.c index 8542bc2b0..5d4bab6c9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2033,68 +2033,65 @@ abort: struct { int set; int noautodetect; +} raid_setup_args md__initdata; -} raid_setup_args md__initdata = { 0, 0 }; - -void md_setup_drive(void) md__init; +void md_setup_drive (void) md__init; /* * Searches all registered partitions for autorun RAID arrays * at boot time. */ -#ifdef CONFIG_AUTODETECT_RAID -static int detected_devices[128] md__initdata = { 0, }; -static int dev_cnt=0; +static int detected_devices[128] md__initdata; +static int dev_cnt; + void md_autodetect_dev(kdev_t dev) { if (dev_cnt >= 0 && dev_cnt < 127) detected_devices[dev_cnt++] = dev; } -#endif -int md__init md_run_setup(void) + +static void autostart_arrays (void) { -#ifdef CONFIG_AUTODETECT_RAID mdk_rdev_t *rdev; int i; - if (raid_setup_args.noautodetect) - printk(KERN_INFO "skipping autodetection of RAID arrays\n"); - else { - - printk(KERN_INFO "autodetecting RAID arrays\n"); + printk(KERN_INFO "autodetecting RAID arrays\n"); - for (i=0; i<dev_cnt; i++) { - kdev_t dev = detected_devices[i]; + for (i=0; i<dev_cnt; i++) { + kdev_t dev = detected_devices[i]; - if (md_import_device(dev,1)) { - printk(KERN_ALERT "could not import %s!\n", - partition_name(dev)); - continue; - } - /* - * Sanity checks: - */ - rdev = find_rdev_all(dev); - if (!rdev) { - MD_BUG(); - continue; - } - if (rdev->faulty) { - MD_BUG(); - continue; - } - md_list_add(&rdev->pending, &pending_raid_disks); + if (md_import_device(dev,1)) { + printk(KERN_ALERT "could not import %s!\n", + partition_name(dev)); + continue; } - - autorun_devices(-1); + /* + * Sanity checks: + */ + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + continue; + } + if (rdev->faulty) { + MD_BUG(); + continue; + } + md_list_add(&rdev->pending, &pending_raid_disks); } + autorun_devices(-1); +} + +int md__init md_run_setup(void) +{ + if (raid_setup_args.noautodetect) + printk(KERN_INFO "skipping autodetection of RAID arrays\n"); + else + autostart_arrays(); dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */ -#endif -#ifdef CONFIG_MD_BOOT md_setup_drive(); -#endif return 0; } @@ -2558,6 +2555,11 @@ static int md_ioctl (struct inode *inode, struct file *file, md_print_devices(); goto done_unlock; + case RAID_AUTORUN: + err = 0; + autostart_arrays(); + goto done; + case BLKGETSIZE: /* Return device size */ if (!arg) { err = -EINVAL; @@ -3639,14 +3641,12 @@ int md__init md_init (void) return (0); } -#ifdef CONFIG_MD_BOOT -#define MAX_MD_BOOT_DEVS 8 -struct { - unsigned long set; - int pers[MAX_MD_BOOT_DEVS]; - int chunk[MAX_MD_BOOT_DEVS]; - kdev_t devices[MAX_MD_BOOT_DEVS][MD_SB_DISKS]; -} md_setup_args md__initdata = { 0, }; +static struct { + char device_set [MAX_MD_DEVS]; + int pers[MAX_MD_DEVS]; + int chunk[MAX_MD_DEVS]; + kdev_t devices[MAX_MD_DEVS][MD_SB_DISKS]; +} md_setup_args md__initdata; /* * Parse the command-line parameters given our kernel, but do not @@ -3676,10 +3676,10 @@ static int md__init md_setup(char *str) printk("md: Too few arguments supplied to md=.\n"); return 0; } - if (minor >= MAX_MD_BOOT_DEVS) { + if (minor >= MAX_MD_DEVS) { printk ("md: Minor device number too high.\n"); return 0; - } else if (md_setup_args.set & (1 << minor)) { + } else if (md_setup_args.device_set[minor]) { printk ("md: Warning - md=%d,... has been specified twice;\n" " will discard the first definition.\n", minor); } @@ -3737,7 +3737,7 @@ static int md__init md_setup(char *str) printk ("md: Will configure md%d (%s) from %s, below.\n", minor, pername, devnames); md_setup_args.devices[minor][i] = (kdev_t) 0; - md_setup_args.set |= (1 << minor); + md_setup_args.device_set[minor] = 1; return 1; } @@ -3747,10 +3747,11 @@ void md__init md_setup_drive(void) kdev_t dev; mddev_t*mddev; - for (minor = 0; minor < MAX_MD_BOOT_DEVS; minor++) { + for (minor = 0; minor < MAX_MD_DEVS; minor++) { mdu_disk_info_t dinfo; - int err=0; - if (!(md_setup_args.set & (1 << minor))) + + int err = 0; + if (!md_setup_args.device_set[minor]) continue; printk("md: Loading md%d.\n", minor); if (mddev_map[minor].mddev) { @@ -3776,7 +3777,7 @@ void md__init md_setup_drive(void) ainfo.layout = 0; ainfo.chunk_size = md_setup_args.chunk[minor]; err = set_array_info(mddev, &ainfo); - for (i=0; !err && (dev = md_setup_args.devices[minor][i]); i++) { + for (i = 0; !err && (dev = md_setup_args.devices[minor][i]); i++) { dinfo.number = i; dinfo.raid_disk = i; dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC); @@ -3807,7 +3808,6 @@ void md__init md_setup_drive(void) } __setup("md=", md_setup); -#endif #ifdef MODULE int init_module (void) @@ -3859,9 +3859,7 @@ void cleanup_module (void) #endif __initcall(md_init); -#if defined(CONFIG_AUTODETECT_RAID) || defined(CONFIG_MD_BOOT) __initcall(md_run_setup); -#endif MD_EXPORT_SYMBOL(md_size); MD_EXPORT_SYMBOL(register_md_personality); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 7981fe764..3ad3940a9 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -714,6 +714,11 @@ static void compute_parity(struct stripe_head *sh, int method) break; } spin_unlock_irq(&conf->device_lock); + if (count>1) { + xor_block(count, bh_ptr); + count = 1; + } + for (i = disks; i--;) if (chosen[i]) { struct buffer_head *bh = sh->bh_cache[i]; diff --git a/drivers/md/xor.c b/drivers/md/xor.c index b9b1cefe9..f0b76d466 100644 --- a/drivers/md/xor.c +++ b/drivers/md/xor.c @@ -57,8 +57,7 @@ xor_block(unsigned int count, struct buffer_head **bh_ptr) /* Set of all registered templates. */ static struct xor_block_template *template_list; -/* The -6*32 shift factor colors the cache. */ -#define BENCH_SIZE (PAGE_SIZE-6*32) +#define BENCH_SIZE (PAGE_SIZE) static void do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index ae4054d35..02c9204e9 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -118,6 +118,14 @@ LK1.1.11 13 Nov 2000 andrewm - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER + LK1.1.12 1 Jan 2001 andrewm + - Call pci_enable_device before we request our IRQ (Tobias Ringstrom) + - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra) + - Added extended wait_for_completion for the 3c905CX. + - Look for an MII on PHY index 24 first (3c905CX oddity). + - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) + - Don't free skbs we don't own on oom path in vortex_open(). + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - Also see Documentation/networking/vortex.txt */ @@ -203,7 +211,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include <linux/delay.h> static char version[] __devinitdata = -"3c59x.c:LK1.1.11 13 Nov 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n"; +"3c59x.c:LK1.1.12 06 Jan 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n"; MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); @@ -424,7 +432,7 @@ static struct vortex_chip_info { PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3cSOHO100-TX Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, {"3c555 Laptop Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, }, {"3c556 Laptop Tornado", @@ -843,10 +851,15 @@ static int __devinit vortex_init_one (struct pci_dev *pdev, { int rc; - rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, - ent->driver_data, vortex_cards_found); - if (rc == 0) - vortex_cards_found++; + /* wake up and enable device */ + if (pci_enable_device (pdev)) { + rc = -EIO; + } else { + rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, + ent->driver_data, vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + } return rc; } @@ -863,7 +876,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, struct vortex_private *vp; int option; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i; + int i, step; struct net_device *dev; static int printed_version; int retval; @@ -889,7 +902,6 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vci->name, ioaddr); - /* private struct aligned and zeroed by init_etherdev */ vp = dev->priv; dev->base_addr = ioaddr; dev->irq = irq; @@ -908,19 +920,29 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, if (pdev) { /* EISA resources already marked, so only PCI needs to do this here */ /* Ignore return value, because Cardbus drivers already allocate for us */ - if (request_region(ioaddr, vci->io_size, dev->name) != NULL) { + if (request_region(ioaddr, vci->io_size, dev->name) != NULL) vp->must_free_region = 1; - } - - /* wake up and enable device */ - if (pci_enable_device (pdev)) { - retval = -EIO; - goto free_region; - } /* enable bus-mastering if necessary */ if (vci->flags & PCI_USES_MASTER) pci_set_master (pdev); + + if (vci->drv_flags & IS_VORTEX) { + u8 pci_latency; + u8 new_latency = 248; + + /* Check the PCI latency value. On the 3c590 series the latency timer + must be set to the maximum value to avoid data corruption that occurs + when the timer expires during a transfer. This bug exists the Vortex + chip only. */ + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < new_latency) { + printk(KERN_INFO "%s: Overriding PCI latency" + " timer (CFLT) setting of %d, new value is %d.\n", + dev->name, pci_latency, new_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); + } + } } spin_lock_init(&vp->lock); @@ -1025,6 +1047,13 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, dev->irq); #endif + EL3WINDOW(4); + step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; + printk(KERN_INFO " product code '%c%c' rev %02x.%d date %02d-" + "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], + step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); + + if (pdev && vci->drv_flags & HAS_CB_FNS) { unsigned long fn_st_addr; /* Cardbus function status space */ unsigned short n; @@ -1089,8 +1118,19 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, mii_preamble_required++; mii_preamble_required++; mdio_read(dev, 24, 1); - for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { - int mii_status, phyx = phy & 0x1f; + for (phy = 0; phy < 32 && phy_idx < 1; phy++) { + int mii_status, phyx; + + /* + * For the 3c905CX we look at index 24 first, because it bogusly + * reports an external PHY at all indices + */ + if (phy == 0) + phyx = 24; + else if (phy <= 24) + phyx = phy - 1; + else + phyx = phy; mii_status = mdio_read(dev, phyx, 1); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; @@ -1135,12 +1175,13 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; - +// publish_netdev(dev); return 0; free_region: if (vp->must_free_region) release_region(ioaddr, vci->io_size); +// withdraw_netdev(dev); unregister_netdev(dev); kfree (dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1150,13 +1191,23 @@ out: static void wait_for_completion(struct net_device *dev, int cmd) { - int i = 4000; + int i; outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) { + for (i = 0; i < 2000; i++) { if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) return; } + + /* OK, that didn't work. Do it the slow way. One second */ + for (i = 0; i < 100000; i++) { + if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { + printk(KERN_INFO "%s: command 0x%04x took %d usecs! Please tell andrewm@uow.edu.au\n", + dev->name, cmd, i * 10); + return; + } + udelay(10); + } printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", dev->name, cmd, inw(dev->base_addr + EL3_STATUS)); } @@ -1331,6 +1382,7 @@ vortex_up(struct net_device *dev) set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ +// wait_for_completion(dev, SetTxStart|0x07ff); outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ @@ -1384,7 +1436,8 @@ vortex_open(struct net_device *dev) } if (i != RX_RING_SIZE) { int j; - for (j = 0; j < RX_RING_SIZE; j++) { + printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); + for (j = 0; j < i; j++) { if (vp->rx_skbuff[j]) { dev_kfree_skb(vp->rx_skbuff[j]); vp->rx_skbuff[j] = 0; @@ -1532,7 +1585,10 @@ static void vortex_tx_timeout(struct net_device *dev) printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); - + EL3WINDOW(4); + printk(KERN_ERR " diagnostics: net %04x media %04x dma %8.8x.\n", + inw(ioaddr + Wn4_NetDiag), inw(ioaddr + Wn4_Media), + inl(ioaddr + PktStatus)); /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" @@ -1663,6 +1719,12 @@ vortex_error(struct net_device *dev, int status) dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { + int bus_status = inl(ioaddr + PktStatus); + /* 0x80000000 PCI master abort. */ + /* 0x40000000 PCI target abort. */ + if (vortex_debug) + printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); + /* In this case, blow the card away */ vortex_down(dev); wait_for_completion(dev, TotalReset | 0xff); diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 290efb51c..5f9658fa5 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,7 +26,7 @@ ifeq ($(CONFIG_ISDN_PPP),y) obj-$(CONFIG_ISDN) += slhc.o endif -subdir-$(CONFIG_PCMCIA) += pcmcia +subdir-$(CONFIG_NET_PCMCIA) += pcmcia subdir-$(CONFIG_TULIP) += tulip subdir-$(CONFIG_IRDA) += irda subdir-$(CONFIG_TR) += tokenring diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 448baa800..d5d3fa19f 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1817,7 +1817,9 @@ EISA_signature(char *name, s32 eisa_id) ManCode[5]='\0'; for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) { - if (strstr(ManCode, signatures[i]) != NULL) { + const char * volatile lhs = ManCode; + const char * volatile rhs = signatures[i]; /* egcs-1.1.2 bug */ + if (strstr(lhs, rhs) != NULL) { strcpy(name,ManCode); status = 1; } diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index 481b28700..b160afd78 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -1596,10 +1596,10 @@ static int __init dmfe_init_module(void) break; } - rc = pci_register_driver(&dmfe_driver); + rc = pci_module_init(&dmfe_driver); if (rc < 0) return rc; - if (rc > 0) { + if (rc >= 0) { printk (KERN_INFO "Davicom DM91xx net driver loaded, version " DMFE_VERSION "\n"); return 0; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 298a317e2..2970fac9f 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -29,7 +29,7 @@ static const char *version = "eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n" -"eepro100.c: $Revision: 1.35 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n"; +"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n"; /* A few user-configurable values that apply to all boards. First set is undocumented and spelled per Intel recommendations. */ @@ -698,6 +698,7 @@ static int speedo_found1(struct pci_dev *pdev, This takes less than 10usec and will easily finish before the next action. */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); udelay(10); if (eeprom[3] & 0x0100) @@ -785,6 +786,7 @@ static int speedo_found1(struct pci_dev *pdev, #endif /* kernel_bloat */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); udelay(10); /* Return the chip to its original power state. */ @@ -801,7 +803,7 @@ static int speedo_found1(struct pci_dev *pdev, sp->tx_ring = tx_ring_space; sp->tx_ring_dma = tx_ring_dma; sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE); - sp->lstats_dma = cpu_to_le32(TX_RING_ELEM_DMA(sp, TX_RING_SIZE)); + sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE); init_timer(&sp->timer); /* used in ioctl() */ sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; @@ -1002,7 +1004,9 @@ static void speedo_resume(struct net_device *dev) /* Set the segment registers to '0'. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(0, ioaddr + SCBPointer); - inl(ioaddr + SCBPointer); /* XXX */ + /* impose a delay to avoid a bug */ + inl(ioaddr + SCBPointer); + udelay(10); outb(RxAddrLoad, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); outb(CUCmdBase, ioaddr + SCBCmd); @@ -1010,7 +1014,6 @@ static void speedo_resume(struct net_device *dev) /* Load the statistics block and rx ring addresses. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(sp->lstats_dma, ioaddr + SCBPointer); - inl(ioaddr + SCBPointer); /* XXX */ outb(CUStatsAddr, ioaddr + SCBCmd); sp->lstats->done_marker = 0; @@ -1045,7 +1048,7 @@ static void speedo_resume(struct net_device *dev) /* Start the chip's Tx process and unmask interrupts. */ wait_for_cmd_done(ioaddr + SCBCmd); - outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE)), + outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE), ioaddr + SCBPointer); /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should remain masked --Dragan */ @@ -1274,7 +1277,7 @@ static void speedo_tx_timeout(struct net_device *dev) /* Only the command unit has stopped. */ printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", dev->name); - outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE])), + outl(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE]), ioaddr + SCBPointer); outw(CUStart, ioaddr + SCBCmd); reset_mii(dev); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 7dab437e6..3ec09be5a 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -153,7 +153,7 @@ static int check_crc_flex(unsigned char *cp, int size) /* Find a free channel, and link in this `tty' line. */ static inline struct ax_disp *ax_alloc(void) { - ax25_ctrl_t *axp; + ax25_ctrl_t *axp=NULL; int i; for (i = 0; i < ax25_maxdev; i++) { diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index d65fddc41..cc31e9e30 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -136,7 +136,7 @@ /* ----------------------------------------------------------------------- */ -#undef SCC_LDELAY 1 /* slow it even a bit more down */ +#undef SCC_LDELAY /* slow it even a bit more down */ #undef SCC_DONT_CHECK /* don't look if the SCCs you specified are available */ #define SCC_MAXCHIPS 4 /* number of max. supported chips */ @@ -1776,7 +1776,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (hwcfg.vector_latch) { if (!request_region(Vector_Latch, 1, "scc vector latch")) - printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%x\n, disabled.", hwcfg.vector_latch); + printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%x\n, disabled.", (unsigned int)hwcfg.vector_latch); else Vector_Latch = hwcfg.vector_latch; } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index ba9c60250..56ca24689 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -892,6 +892,9 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, DET(("myri_ether_init(%p,%p,%d):\n", dev, sdev, num)); dev = init_etherdev(0, sizeof(struct myri_eth)); + if (!dev) + return -ENOMEM; + if (version_printed++ == 0) printk(version); @@ -982,7 +985,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, mp->reg_size, "MyriCOM Regs"); if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); - return -ENODEV; + goto err; } mp->lanai = (unsigned short *) (mp->regs + (256 * 1024)); mp->lanai3 = (unsigned int *) mp->lanai; @@ -1059,7 +1062,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, if (request_irq(dev->irq, &myri_interrupt, SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) { printk("MyriCOM: Cannot register interrupt handler.\n"); - return -ENODEV; + goto err; } DET(("ether_setup()\n")); @@ -1083,6 +1086,9 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, root_myri_dev = mp; #endif return 0; +err: unregister_netdev(dev); + kfree(dev); + return -ENODEV; } static int __init myri_sbus_match(struct sbus_dev *sdev) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index ccb92e8a5..fa8b951a7 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -695,6 +695,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car if (a == NULL) { printk(KERN_ERR "pcnet32: No access methods\n"); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); return -ENODEV; } lp->a = *a; @@ -741,6 +742,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car printk(", probed IRQ %d.\n", dev->irq); else { printk(", failed to detect IRQ line.\n"); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); return -ENODEV; } } diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index d6b2c47f3..c1234c5c8 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -33,13 +33,6 @@ #include <linux/init.h> #include <asm/uaccess.h> -#ifndef spin_trylock_bh -#define spin_trylock_bh(lock) ({ int __r; local_bh_disable(); \ - __r = spin_trylock(lock); \ - if (!__r) local_bh_enable(); \ - __r; }) -#endif - #define PPP_VERSION "2.4.1" #define OBUFSIZE 256 @@ -76,6 +69,7 @@ struct asyncppp { /* Bit numbers in xmit_flags */ #define XMIT_WAKEUP 0 #define XMIT_FULL 1 +#define XMIT_BUSY 2 /* State bits */ #define SC_TOSS 0x20000000 @@ -181,18 +175,14 @@ ppp_asynctty_close(struct tty_struct *tty) } /* - * Read does nothing. + * Read does nothing - no data is ever available this way. + * Pppd reads and writes packets via /dev/ppp instead. */ static ssize_t ppp_asynctty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t count) { - /* For now, do the same as the old 2.3.x code useta */ - struct asyncppp *ap = tty->disc_data; - - if (ap == 0) - return -ENXIO; - return ppp_channel_read(&ap->chan, file, buf, count); + return -EAGAIN; } /* @@ -203,12 +193,7 @@ static ssize_t ppp_asynctty_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t count) { - /* For now, do the same as the old 2.3.x code useta */ - struct asyncppp *ap = tty->disc_data; - - if (ap == 0) - return -ENXIO; - return ppp_channel_write(&ap->chan, buf, count); + return -EAGAIN; } static int @@ -259,25 +244,6 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, err = 0; break; -/* - * For now, do the same as the old 2.3 driver useta - */ - case PPPIOCGFLAGS: - case PPPIOCSFLAGS: - case PPPIOCGASYNCMAP: - case PPPIOCSASYNCMAP: - case PPPIOCGRASYNCMAP: - case PPPIOCSRASYNCMAP: - case PPPIOCGXASYNCMAP: - case PPPIOCSXASYNCMAP: - case PPPIOCGMRU: - case PPPIOCSMRU: - err = -EPERM; - if (!capable(CAP_NET_ADMIN)) - break; - err = ppp_async_ioctl(&ap->chan, cmd, arg); - break; - case PPPIOCATTACH: case PPPIOCDETACH: err = ppp_channel_ioctl(&ap->chan, cmd, arg); @@ -294,18 +260,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, static unsigned int ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { - unsigned int mask; - struct asyncppp *ap = tty->disc_data; - - mask = POLLOUT | POLLWRNORM; -/* - * For now, do the same as the old 2.3 driver useta - */ - if (ap != 0) - mask |= ppp_channel_poll(&ap->chan, file, wait); - if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file)) - mask |= POLLHUP; - return mask; + return 0; } static int @@ -637,8 +592,18 @@ ppp_async_push(struct asyncppp *ap) int tty_stuffed = 0; set_bit(XMIT_WAKEUP, &ap->xmit_flags); - if (!spin_trylock_bh(&ap->xmit_lock)) + /* + * We can get called recursively here if the tty write + * function calls our wakeup function. This can happen + * for example on a pty with both the master and slave + * set to PPP line discipline. + * We use the XMIT_BUSY bit to detect this and get out, + * leaving the XMIT_WAKEUP bit set to tell the other + * instance that it may now be able to write more now. + */ + if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) return 0; + spin_lock_bh(&ap->xmit_lock); for (;;) { if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags)) tty_stuffed = 0; @@ -653,7 +618,7 @@ ppp_async_push(struct asyncppp *ap) tty_stuffed = 1; continue; } - if (ap->optr == ap->olim && ap->tpkt != 0) { + if (ap->optr >= ap->olim && ap->tpkt != 0) { if (ppp_async_encode(ap)) { /* finished processing ap->tpkt */ clear_bit(XMIT_FULL, &ap->xmit_flags); @@ -661,17 +626,29 @@ ppp_async_push(struct asyncppp *ap) } continue; } - /* haven't made any progress */ - spin_unlock_bh(&ap->xmit_lock); + /* + * We haven't made any progress this time around. + * Clear XMIT_BUSY to let other callers in, but + * after doing so we have to check if anyone set + * XMIT_WAKEUP since we last checked it. If they + * did, we should try again to set XMIT_BUSY and go + * around again in case XMIT_BUSY was still set when + * the other caller tried. + */ + clear_bit(XMIT_BUSY, &ap->xmit_flags); + /* any more work to do? if not, exit the loop */ if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || (!tty_stuffed && ap->tpkt != 0))) break; - if (!spin_trylock_bh(&ap->xmit_lock)) + /* more work to do, see if we can do it now */ + if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) break; } + spin_unlock_bh(&ap->xmit_lock); return done; flush: + clear_bit(XMIT_BUSY, &ap->xmit_flags); if (ap->tpkt != 0) { kfree_skb(ap->tpkt); ap->tpkt = 0; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 8744f6186..7fffdf4f7 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -5,23 +5,24 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.4 + * Version: 0.6.5 * * 030700 : Fixed connect logic to allow for disconnect. - * 270700 : Fixed potential SMP problems; we must protect against - * simultaneous invocation of ppp_input + * 270700 : Fixed potential SMP problems; we must protect against + * simultaneous invocation of ppp_input * and ppp_unregister_channel. * 040800 : Respect reference count mechanisms on net-devices. * 200800 : fix kfree(skb) in pppoe_rcv (acme) * Module reference count is decremented in the right spot now, - * guards against sock_put not actually freeing the sk + * guards against sock_put not actually freeing the sk * in pppoe_release. * 051000 : Initialization cleanup. * 111100 : Fix recvmsg. + * 050101 : Fix PADT procesing. * * Author: Michal Ostrowski <mostrows@styx.uwaterloo.ca> * Contributors: - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * Arnaldo Carvalho de Melo <acme@xconectiva.com.br> * * License: * This program is free software; you can redistribute it and/or @@ -110,7 +111,7 @@ static int hash_item(unsigned long sid, unsigned char *addr) hash ^= sid >> (i*PPPOE_HASH_BITS); return hash & ( PPPOE_HASH_SIZE - 1 ); -} +} static struct pppox_opt *item_hash_table[PPPOE_HASH_SIZE] = { 0, }; @@ -238,7 +239,7 @@ static int pppoe_device_event(struct notifier_block *this, struct net_device *dev = (struct net_device *) ptr; struct pppox_opt *po = NULL; int hash = 0; - + /* Only look at sockets that are using this specific device. */ switch (event) { case NETDEV_CHANGEMTU: @@ -255,13 +256,13 @@ static int pppoe_device_event(struct notifier_block *this, po = item_hash_table[hash]; ++hash; } - + while (po && hash < PPPOE_HASH_SIZE){ if(po->pppoe_dev == dev){ lock_sock(po->sk); if (po->sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){ pppox_unbind_sock(po->sk); - + dev_put(po->pppoe_dev); po->pppoe_dev = NULL; @@ -308,7 +309,7 @@ int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb){ if (sk->state & PPPOX_BOUND) { skb_pull(skb, sizeof(struct pppoe_hdr)); - + ppp_input(&po->chan, skb); } else if( sk->state & PPPOX_RELAY ){ @@ -318,7 +319,7 @@ int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb){ !( relay_po->sk->state & PPPOX_CONNECTED ) ){ goto abort; } - + skb_pull(skb, sizeof(struct pppoe_hdr)); if( !__pppoe_xmit( relay_po->sk , skb) ){ goto abort; @@ -369,7 +370,7 @@ static int pppoe_rcv(struct sk_buff *skb, }else{ ret = pppoe_rcv_core(sk, skb); } - + bh_unlock_sock(sk); sock_put(sk); return ret; @@ -412,13 +413,12 @@ static int pppoe_disc_rcv(struct sk_buff *skb, po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); if (!po) - goto abort_put; + goto abort; sk = po->sk; pppox_unbind_sock(sk); - abort_put: sock_put(sk); abort: kfree_skb(skb); @@ -466,9 +466,9 @@ static int pppoe_create(struct socket *sock) { int error = 0; struct sock *sk; - + MOD_INC_USE_COUNT; - + sk = sk_alloc(PF_PPPOX, GFP_KERNEL, 1); if (!sk) return -ENOMEM; @@ -528,7 +528,7 @@ int pppoe_release(struct socket *sock) po = sk->protinfo.pppox; if (po->pppoe_pa.sid) delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote); - + if (po->pppoe_dev) dev_put(po->pppoe_dev); @@ -945,7 +945,7 @@ int pppoe_proc_info(char *buffer, char **start, off_t offset, int length) off_t begin = 0; int size; int i; - + len += sprintf(buffer, "Id Address Device\n"); pos = len; @@ -1025,9 +1025,10 @@ int __init pppoe_init(void) int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); if (err == 0) { - printk(KERN_INFO "Registered PPPoE v0.6.4\n"); + printk(KERN_INFO "Registered PPPoE v0.6.5\n"); dev_add_pack(&pppoes_ptype); + dev_add_pack(&pppoed_ptype); register_netdevice_notifier(&pppoe_notifier); proc_net_create("pppoe", 0, pppoe_proc_info); } @@ -1038,6 +1039,7 @@ void __exit pppoe_exit(void) { unregister_pppox_proto(PX_PROTO_OE); dev_remove_pack(&pppoes_ptype); + dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); proc_net_remove("pppoe"); } diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 3036684f9..253548599 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1,12 +1,9 @@ -/* $Id: sunbmac.c,v 1.21 2000/10/22 16:08:38 davem Exp $ +/* $Id: sunbmac.c,v 1.23 2001/01/20 03:36:40 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) */ -static char *version = - "sunbmac.c:v1.9 11/Sep/99 David S. Miller (davem@redhat.com)\n"; - #include <linux/module.h> #include <linux/kernel.h> @@ -41,6 +38,9 @@ static char *version = #include "sunbmac.h" +static char version[] __initdata = + "sunbmac.c:v1.9 11/Sep/99 David S. Miller (davem@redhat.com)\n"; + #undef DEBUG_PROBE #undef DEBUG_TX #undef DEBUG_IRQ @@ -1051,10 +1051,10 @@ static void bigmac_set_multicast(struct net_device *dev) static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec_sdev) { - static int version_printed = 0; - struct bigmac *bp = 0; + static int version_printed; + struct bigmac *bp; u8 bsizes, bsizes_more; - int i, res = ENOMEM; + int i; /* Get a new device struct for this interface. */ dev = init_etherdev(0, sizeof(struct bigmac)); @@ -1062,6 +1062,9 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec if (version_printed++ == 0) printk(KERN_INFO "%s", version); + if (!dev) + return -ENOMEM; + /* Report what we have found to the user. */ printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name); dev->base_addr = (long) qec_sdev; @@ -1077,9 +1080,6 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec spin_lock_init(&bp->lock); - /* All further failures we find return this. */ - res = ENODEV; - /* Verify the registers we expect, are actually there. */ if ((bp->bigmac_sdev->num_registers != 3) || (bp->qec_sdev->num_registers != 2)) { @@ -1205,28 +1205,25 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec fail_and_cleanup: /* Something went wrong, undo whatever we did so far. */ - if (bp) { - /* Free register mappings if any. */ - if (bp->gregs) - sbus_iounmap(bp->gregs, GLOB_REG_SIZE); - if (bp->creg) - sbus_iounmap(bp->creg, CREG_REG_SIZE); - if (bp->bregs) - sbus_iounmap(bp->bregs, BMAC_REG_SIZE); - if (bp->tregs) - sbus_iounmap(bp->tregs, TCVR_REG_SIZE); - - if (bp->bmac_block) - sbus_free_consistent(bp->bigmac_sdev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); - - /* Free the BigMAC softc. */ - kfree(bp); - dev->priv = 0; - } - return res; /* Return error code. */ + /* Free register mappings if any. */ + if (bp->gregs) + sbus_iounmap(bp->gregs, GLOB_REG_SIZE); + if (bp->creg) + sbus_iounmap(bp->creg, CREG_REG_SIZE); + if (bp->bregs) + sbus_iounmap(bp->bregs, BMAC_REG_SIZE); + if (bp->tregs) + sbus_iounmap(bp->tregs, TCVR_REG_SIZE); + + if (bp->bmac_block) + sbus_free_consistent(bp->bigmac_sdev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); + + unregister_netdev(dev); + kfree(dev); + return -ENODEV; } /* QEC can be the parent of either QuadEthernet or diff --git a/drivers/net/tulip/ChangeLog b/drivers/net/tulip/ChangeLog index dfac94349..bb5b70f01 100644 --- a/drivers/net/tulip/ChangeLog +++ b/drivers/net/tulip/ChangeLog @@ -1,7 +1,37 @@ -2000-12-17 Alan Cox <alan@redhat.com> +2001-01-16 Jeff Garzik <jgarzik@mandrakesoft.com> - * merge support for the Davicom's quirks into the main tulip. Patch - by Tobias Ringstrom + * tulip_core.c: static vars no longer explicitly + initialized to zero. + * eeprom.c (tulip_read_eeprom): Make sure to delay between + EE_ENB and EE_ENB|EE_SHIFT_CLK. Merged from becker tulip.c. + +2001-01-05 Peter De Schrijver <p2@mind.be> + + * eeprom.c (tulip_parse_eeprom): Interpret a bit more of 21142 + extended format type 3 info blocks in a tulip SROM. + +2001-01-03 Matti Aarnio <matti.aarnio@zmailer.org> + + * media.c (tulip_select_media): Support media types 5 and 6 + +2001-??-?? ?? + + * tulip_core.c: Add comment about LanMedia needing + a different driver. + Enable workarounds for early PCI chipsets. + Add IA64 csr0 support, update HPPA csr0 support. + +2000-12-17 Alan Cox <alan@redhat.com> + + * eeprom.c, timer.c, tulip.h, tulip_core.c: Merge support + for the Davicom's quirks into the main tulip. + Patch by Tobias Ringstrom + +2000-11-08 Jim Studt <jim@federated.com> + + * eeprom.c (tulip_parse_eeprom): Check array bounds for + medianame[] and block_name[] arrays to avoid oops due + to bad values returned from hardware. 2000-11-02 Jeff Garzik <jgarzik@mandrakesoft.com> diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 49e8bf42e..f42baefc2 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -207,8 +207,13 @@ subsequent_board: p += (p[0] & 0x3f) + 1; continue; } else if (p[1] & 1) { + int gpr_len, reset_len; + mtable->has_mii = 1; leaf->media = 11; + gpr_len=p[3]*2; + reset_len=p[4+gpr_len]*2; + new_advertise |= get_u16(&p[7+gpr_len+reset_len]); } else { mtable->has_nonmii = 1; leaf->media = p[2] & 0x0f; @@ -247,9 +252,9 @@ subsequent_board: } printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " "by a %s (%d) block.\n", - dev->name, i, medianame[leaf->media], leaf->media, - leaf->type >= ARRAY_SIZE(block_name) ? "UNKNOWN" : - block_name[leaf->type], leaf->type); + dev->name, i, medianame[leaf->media & 15], leaf->media, + leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>", + leaf->type); } if (new_advertise) tp->to_advertise = new_advertise; @@ -278,6 +283,7 @@ int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); } outl(EE_ENB, ee_addr); + eeprom_delay(); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index b8203f33a..bc8e7bbbc 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -148,7 +148,7 @@ void tulip_select_media(struct net_device *dev, int startup) long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; struct mediatable *mtable = tp->mtable; - u32 new_csr6; + u32 new_csr6=0; int i; if (mtable) { @@ -265,7 +265,9 @@ void tulip_select_media(struct net_device *dev, int startup) } case 5: case 6: { u16 setup[5]; - u32 csr13val, csr14val, csr15dir, csr15val; + + new_csr6 = 0; /* FIXME */ + for (i = 0; i < 5; i++) setup[i] = get_u16(&p[i*2 + 1]); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 765cd6c7c..0517b90af 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -28,7 +28,7 @@ #include <asm/unaligned.h> static char version[] __devinitdata = - "Linux Tulip driver version 0.9.13 (January 2, 2001)\n"; + "Linux Tulip driver version 0.9.13a (January 20, 2001)\n"; /* A few user-configurable values. */ diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index eaba0cd34..3f23aec1c 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -45,25 +45,10 @@ #include <linux/lapb.h> #include <linux/init.h> -static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - -static int lapbeth_rcv(struct sk_buff *, struct net_device *, struct packet_type *); -static int lapbeth_device_event(struct notifier_block *, unsigned long, void *); - -static struct packet_type lapbeth_packet_type = { - 0, /* ntohs(ETH_P_DEC),*/ - 0, /* copy */ - lapbeth_rcv, - NULL, - NULL, -}; - -static struct notifier_block lapbeth_dev_notifier = { - lapbeth_device_event, - 0 -}; - +static char bcast_addr[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; +/* If this number is made larger, check that the temporary string buffer + * in lapbeth_new_device is large enough to store the probe device name.*/ #define MAXLAPBDEV 100 static struct lapbethdev { @@ -72,29 +57,14 @@ static struct lapbethdev { struct net_device *ethdev; /* link to ethernet device */ struct net_device axdev; /* lapbeth device (lapb#) */ struct net_device_stats stats; /* some statistics */ -} *lapbeth_devices = NULL; - +} *lapbeth_devices /* = NULL initially */; /* ------------------------------------------------------------------------ */ - -/* - * Get the ethernet device for a LAPB device - */ -#if 0 -static __inline__ struct net_device *lapbeth_get_ether_dev(struct net_device *dev) -{ - struct lapbethdev *lapbeth; - - lapbeth = (struct lapbethdev *)dev->priv; - - return (lapbeth != NULL) ? lapbeth->ethdev : NULL; -} -#endif /* * Get the LAPB device for the ethernet device */ -static __inline__ struct net_device *lapbeth_get_x25_dev(struct net_device *dev) +static inline struct net_device *lapbeth_get_x25_dev(struct net_device *dev) { struct lapbethdev *lapbeth; @@ -105,7 +75,7 @@ static __inline__ struct net_device *lapbeth_get_x25_dev(struct net_device *dev) return NULL; } -static __inline__ int dev_is_ethdev(struct net_device *dev) +static inline int dev_is_ethdev(struct net_device *dev) { return ( dev->type == ARPHRD_ETHER @@ -122,7 +92,7 @@ static int lapbeth_check_devices(struct net_device *dev) struct lapbethdev *lapbeth, *lapbeth_prev; int result = 0; unsigned long flags; - + save_flags(flags); cli(); @@ -134,7 +104,7 @@ static int lapbeth_check_devices(struct net_device *dev) lapbeth_prev->next = lapbeth->next; else lapbeth_devices = lapbeth->next; - + if (&lapbeth->axdev == dev) result = 1; @@ -145,16 +115,14 @@ static int lapbeth_check_devices(struct net_device *dev) lapbeth_prev = lapbeth; } - + restore_flags(flags); - + return result; } - /* ------------------------------------------------------------------------ */ - /* * Receive a LAPB frame via an ethernet interface. */ @@ -164,7 +132,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe struct lapbethdev *lapbeth; skb->sk = NULL; /* Initially we don't know who it's for */ - + dev = lapbeth_get_x25_dev(dev); if (dev == NULL || !netif_running(dev)) { @@ -172,7 +140,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe return 0; } - lapbeth = (struct lapbethdev *)dev->priv; + lapbeth = (struct lapbethdev *) dev->priv; lapbeth->stats.rx_packets++; @@ -191,7 +159,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe static int lapbeth_data_indication(void *token, struct sk_buff *skb) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; + struct lapbethdev *lapbeth = (struct lapbethdev *) token; unsigned char *ptr; ptr = skb_push(skb, 1); @@ -206,14 +174,12 @@ static int lapbeth_data_indication(void *token, struct sk_buff *skb) } /* - * Send a LAPB frame via an ethernet interface + * Send a LAPB frame via an ethernet interface */ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lapbethdev *lapbeth; + struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv; int err; - - lapbeth = (struct lapbethdev *)dev->priv; /* * Just to be *really* sure not to send anything if the interface @@ -253,10 +219,10 @@ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } - + static void lapbeth_data_transmit(void *token, struct sk_buff *skb) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; + struct lapbethdev *lapbeth = (struct lapbethdev *) token; unsigned char *ptr; struct net_device *dev; int size; @@ -281,7 +247,7 @@ static void lapbeth_data_transmit(void *token, struct sk_buff *skb) static void lapbeth_connected(void *token, int reason) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; + struct lapbethdev *lapbeth = (struct lapbethdev *) token; struct sk_buff *skb; unsigned char *ptr; @@ -303,7 +269,7 @@ static void lapbeth_connected(void *token, int reason) static void lapbeth_disconnected(void *token, int reason) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; + struct lapbethdev *lapbeth = (struct lapbethdev *) token; struct sk_buff *skb; unsigned char *ptr; @@ -328,10 +294,7 @@ static void lapbeth_disconnected(void *token, int reason) */ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev) { - struct lapbethdev *lapbeth; - - lapbeth = (struct lapbethdev *)dev->priv; - + struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv; return &lapbeth->stats; } @@ -340,18 +303,11 @@ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev) */ static int lapbeth_set_mac_address(struct net_device *dev, void *addr) { - struct sockaddr *sa = (struct sockaddr *)addr; - + struct sockaddr *sa = (struct sockaddr *) addr; memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - return 0; } -static int lapbeth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - return -EINVAL; -} - /* * open/close a device */ @@ -363,8 +319,8 @@ static int lapbeth_open(struct net_device *dev) if (lapbeth_check_devices(dev)) return -ENODEV; /* oops, it's gone */ - - lapbeth = (struct lapbethdev *)dev->priv; + + lapbeth = (struct lapbethdev *) dev->priv; lapbeth_callbacks.connect_confirmation = lapbeth_connected; lapbeth_callbacks.connect_indication = lapbeth_connected; @@ -378,31 +334,20 @@ static int lapbeth_open(struct net_device *dev) return -ENODEV; } - MOD_INC_USE_COUNT; netif_start_queue(dev); - return 0; } static int lapbeth_close(struct net_device *dev) { - struct lapbethdev *lapbeth; + struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv; int err; netif_stop_queue(dev); - - lapbeth = (struct lapbethdev *)dev->priv; if ((err = lapb_unregister(lapbeth)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_unregister error - %d\n", err); - MOD_DEC_USE_COUNT; - - return 0; -} - -static int lapbeth_dev_init(struct net_device *dev) -{ return 0; } @@ -414,14 +359,14 @@ static int lapbeth_dev_init(struct net_device *dev) static int lapbeth_new_device(struct net_device *dev) { int k; - unsigned char *buf; + unsigned char buf[14]; struct lapbethdev *lapbeth, *lapbeth2; - + if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL) return -ENOMEM; - + memset(lapbeth, 0, sizeof(struct lapbethdev)); - + dev_hold(dev); lapbeth->ethdev = dev; @@ -429,7 +374,7 @@ static int lapbeth_new_device(struct net_device *dev) strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1); dev = &lapbeth->axdev; - buf = kmalloc(14, GFP_KERNEL); + SET_MODULE_OWNER(dev); for (k = 0; k < MAXLAPBDEV; k++) { struct net_device *odev; @@ -445,10 +390,9 @@ static int lapbeth_new_device(struct net_device *dev) kfree(lapbeth); return -ENODEV; } - + dev->priv = (void *)lapbeth; /* pointer back */ strcpy(dev->name, buf); - dev->init = lapbeth_dev_init; if (register_netdev(dev) != 0) { dev_put(dev); @@ -463,10 +407,6 @@ static int lapbeth_new_device(struct net_device *dev) dev->stop = lapbeth_close; dev->set_mac_address = lapbeth_set_mac_address; dev->get_stats = lapbeth_get_stats; - dev->do_ioctl = lapbeth_ioctl; - - dev->flags = 0; - dev->type = ARPHRD_X25; dev->hard_header_len = 3; dev->mtu = 1000; @@ -480,20 +420,19 @@ static int lapbeth_new_device(struct net_device *dev) for (lapbeth2 = lapbeth_devices; lapbeth2->next != NULL; lapbeth2 = lapbeth2->next); lapbeth2->next = lapbeth; } - + sti(); return 0; } - /* * Handle device status changes. */ -static int lapbeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) +static int lapbeth_device_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct net_device *dev = (struct net_device *)ptr; - + struct net_device *dev = (struct net_device *) ptr; + if (!dev_is_ethdev(dev)) return NOTIFY_DONE; @@ -518,23 +457,28 @@ static int lapbeth_device_event(struct notifier_block *this,unsigned long event, return NOTIFY_DONE; } - /* ------------------------------------------------------------------------ */ -/* - * Initialize driver. To be called from af_ax25 if not compiled as a - * module - */ -int lapbeth_init(void) +static struct packet_type lapbeth_packet_type = { + type: __constant_htons(ETH_P_DEC), + func: lapbeth_rcv, +}; + +static struct notifier_block lapbeth_dev_notifier = { + notifier_call: lapbeth_device_event, +}; + +static const char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.01\n"; + +static int __init lapbeth_init_driver(void) { struct net_device *dev; - lapbeth_packet_type.type = htons(ETH_P_DEC); dev_add_pack(&lapbeth_packet_type); register_netdevice_notifier(&lapbeth_dev_notifier); - printk(KERN_INFO "LAPB Ethernet driver version 0.01\n"); + printk(banner); read_lock_bh(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { @@ -548,19 +492,9 @@ int lapbeth_init(void) return 0; } +module_init(lapbeth_init_driver); -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); -MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver"); - -int init_module(void) -{ - return lapbeth_init(); -} - -void cleanup_module(void) +static void __exit lapbeth_cleanup_driver(void) { struct lapbethdev *lapbeth; @@ -571,4 +505,10 @@ void cleanup_module(void) for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) unregister_netdev(&lapbeth->axdev); } -#endif +module_exit(lapbeth_cleanup_driver); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); +MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver"); + diff --git a/drivers/net/wan/lmc/lmc.h b/drivers/net/wan/lmc/lmc.h index 91b9e8f00..882e58c1b 100644 --- a/drivers/net/wan/lmc/lmc.h +++ b/drivers/net/wan/lmc/lmc.h @@ -29,4 +29,5 @@ extern lmc_media_t lmc_hssi_media; static void lmcEventLog( u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3 ); #endif -#endif
\ No newline at end of file +#endif + diff --git a/drivers/net/wan/lmc/lmc_media.h b/drivers/net/wan/lmc/lmc_media.h index 7cc6c1650..ddcc00403 100644 --- a/drivers/net/wan/lmc/lmc_media.h +++ b/drivers/net/wan/lmc/lmc_media.h @@ -61,4 +61,5 @@ lmc_media_t lmc_t1_media = { }; -#endif
\ No newline at end of file +#endif + diff --git a/drivers/net/wan/lmc/lmc_prot.h b/drivers/net/wan/lmc/lmc_prot.h index 859ef0f00..f3b1df9e2 100644 --- a/drivers/net/wan/lmc/lmc_prot.h +++ b/drivers/net/wan/lmc/lmc_prot.h @@ -11,4 +11,5 @@ void lmc_proto_close(lmc_softc_t *sc const) unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb) -#endif
\ No newline at end of file +#endif + diff --git a/drivers/net/wan/lmc/lmc_proto.h b/drivers/net/wan/lmc/lmc_proto.h index 6136dfad7..080a55773 100644 --- a/drivers/net/wan/lmc/lmc_proto.h +++ b/drivers/net/wan/lmc/lmc_proto.h @@ -12,4 +12,5 @@ unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb); void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb); int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused); -#endif
\ No newline at end of file +#endif + diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index ef489b1a6..1eb66b44e 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -744,7 +744,7 @@ static void sdla_receive(struct net_device *dev) struct buf_entry *pbuf; unsigned long flags; - int i, received, success, addr, buf_base, buf_top; + int i=0, received, success, addr, buf_base, buf_top; short dlci, len, len2, split; flp = dev->priv; diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c index ee4c2aee3..9f3cc0fc3 100644 --- a/drivers/pnp/isapnp_proc.c +++ b/drivers/pnp/isapnp_proc.c @@ -783,7 +783,10 @@ static int isapnp_set_card(char *line) unsigned int id; char index[16], value[32]; - isapnp_info_card = NULL; + if (isapnp_info_card) { + isapnp_cfg_end(); + isapnp_info_card = NULL; + } line = isapnp_get_str(index, line, sizeof(index)); isapnp_get_str(value, line, sizeof(value)); idx = idx1 = simple_strtoul(index, NULL, 0); @@ -853,10 +856,7 @@ static int isapnp_set_device(char *line) static int isapnp_autoconfigure(void) { - if (isapnp_info_device == NULL) { - printk("isapnp: device is not set\n"); - return 0; - } + isapnp_cfg_end(); if (isapnp_info_device->active) isapnp_info_device->deactivate(isapnp_info_device); if (isapnp_info_device->prepare(isapnp_info_device) < 0) { @@ -867,6 +867,13 @@ static int isapnp_autoconfigure(void) printk("isapnp: cannot activate device"); return 0; } + if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) { + printk("isapnp: configuration start sequence for card %d failed\n", isapnp_info_card->number); + isapnp_info_card = NULL; + isapnp_info_device = NULL; + return 1; + } + isapnp_device(isapnp_info_device->devfn); return 0; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 55e27c7d8..a48213aea 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -952,7 +952,6 @@ do_dasd_request (request_queue_t *queue) go = 1; while (go && !list_empty(&queue->queue_head)) { req = blkdev_entry_next_request(&queue->queue_head); - req = blkdev_entry_next_request(&queue->queue_head); di = DEVICE_NR (req->rq_dev); dasd_debug ((unsigned long) req); /* req */ dasd_debug (0xc4d90000 + /* DR## */ diff --git a/drivers/sbus/audio/Config.in b/drivers/sbus/audio/Config.in index a9419f78c..40a431f81 100644 --- a/drivers/sbus/audio/Config.in +++ b/drivers/sbus/audio/Config.in @@ -8,9 +8,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then comment 'Linux/SPARC audio subsystem (EXPERIMENTAL)' tristate 'Audio support (EXPERIMENTAL)' CONFIG_SPARCAUDIO - dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO + if [ "$CONFIG_SPARC64" != "y" ]; then + dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO + dep_tristate ' DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO + fi dep_tristate ' CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO - dep_tristate ' DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO dep_tristate ' Dummy Lowlevel Driver' CONFIG_SPARCAUDIO_DUMMY $CONFIG_SPARCAUDIO endmenu fi diff --git a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c index f3f593bce..1ddfb5017 100644 --- a/drivers/sbus/audio/amd7930.c +++ b/drivers/sbus/audio/amd7930.c @@ -1,4 +1,4 @@ -/* $Id: amd7930.c,v 1.24 2000/01/22 05:10:27 anton Exp $ +/* $Id: amd7930.c,v 1.25 2001/01/08 04:19:16 davem Exp $ * drivers/sbus/audio/amd7930.c * * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -107,7 +107,7 @@ static __u8 mulaw2bilinear(__u8 data); static __u8 linear2mulaw(__u16 data); static __u16 mulaw2linear(__u8 data); -#if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +#if defined (AMD79C30_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff #include "../../isdn/hisax/hisax.h" #include "../../isdn/hisax/isdnl1.h" #include "../../isdn/hisax/foreign.h" @@ -1131,7 +1131,7 @@ static int amd7930_ioctl(struct inode * inode, struct file * file, * */ -#if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +#if defined (AMD79C30_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff static int amd7930_get_irqnum(int dev) { struct amd7930_info *info; diff --git a/drivers/sbus/audio/dbri.c b/drivers/sbus/audio/dbri.c index ad0d879b1..665bb4b31 100644 --- a/drivers/sbus/audio/dbri.c +++ b/drivers/sbus/audio/dbri.c @@ -1,4 +1,4 @@ -/* $Id: dbri.c,v 1.22 2000/10/27 07:01:38 uzi Exp $ +/* $Id: dbri.c,v 1.23 2001/01/08 04:19:16 davem Exp $ * drivers/sbus/audio/dbri.c * * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) @@ -61,7 +61,7 @@ #include <asm/audioio.h> #include "dbri.h" -#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +#if defined(DBRI_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff #include "../../isdn/hisax/hisax.h" #include "../../isdn/hisax/isdnl1.h" #include "../../isdn/hisax/foreign.h" @@ -2227,7 +2227,7 @@ void dbri_brecv(int dev, unsigned int chan, recv_on_pipe(dbri, 8+chan, buffer, size, callback, callback_arg); } -#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff +#if defined(DBRI_ISDN) && defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff struct foreign_interface dbri_foreign_interface = { dbri_get_irqnum, dbri_get_liu_state, diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index b3a736db5..437f2d28c 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PCI) += su.o pcikbd.o obj-$(CONFIG_SAB82532) += sab82532.o obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o +obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index c96a141a5..2be051503 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/smp_lock.h> +#include <linux/spinlock.h> #include <linux/timer.h> #include <linux/ioport.h> #include <linux/major.h> @@ -432,6 +433,7 @@ static int terminate(unsigned minor) return 0; } +static spinlock_t bpp_open_lock = SPIN_LOCK_UNLOCKED; /* * Allow only one process to open the device at a time. @@ -439,13 +441,25 @@ static int terminate(unsigned minor) static int bpp_open(struct inode *inode, struct file *f) { unsigned minor = MINOR(inode->i_rdev); - if (minor >= BPP_NO) return -ENODEV; - if (! instances[minor].present) return -ENODEV; - if (instances[minor].opened) return -EBUSY; - - instances[minor].opened = 1; + int ret; + + spin_lock(&bpp_open_lock); + ret = 0; + if (minor >= BPP_NO) { + ret = -ENODEV; + } else { + if (! instances[minor].present) { + ret = -ENODEV; + } else { + if (instances[minor].opened) + ret = -EBUSY; + else + instances[minor].opened = 1; + } + } + spin_unlock(&bpp_open_lock); - return 0; + return ret; } /* @@ -458,12 +472,14 @@ static int bpp_release(struct inode *inode, struct file *f) { unsigned minor = MINOR(inode->i_rdev); - lock_kernel(); + spin_lock(&bpp_open_lock); instances[minor].opened = 0; if (instances[minor].mode != COMPATIBILITY) - terminate(minor); - unlock_kernel(); + terminate(minor); + + spin_unlock(&bpp_open_lock); + return 0; } diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c new file mode 100644 index 000000000..c319b4d33 --- /dev/null +++ b/drivers/sbus/char/cpwatchdog.c @@ -0,0 +1,838 @@ +/* cpwatchdog.c - driver implementation for hardware watchdog + * timers found on Sun Microsystems CP1400 and CP1500 boards. + * + * This device supports both the generic Linux watchdog + * interface and Solaris-compatible ioctls as best it is + * able. + * + * NOTE: CP1400 systems appear to have a defective intr_mask + * register on the PLD, preventing the disabling of + * timer interrupts. We use a timer to periodically + * reset 'stopped' watchdogs on affected platforms. + * + * TODO: DevFS support (/dev/watchdogs/0 ... /dev/watchdogs/2) + * + * Copyright (c) 2000 Eric Brower (ebrower@usa.net) + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/major.h> +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timer.h> +#include <asm/irq.h> +#include <asm/ebus.h> +#include <asm/oplib.h> +#include <asm/uaccess.h> + +#include <asm/watchdog.h> + +#define WD_OBPNAME "watchdog" +#define WD_BADMODEL "SUNW,501-5336" +#define WD_BTIMEOUT (jiffies + (HZ * 1000)) +#define WD_BLIMIT 0xFFFF + +#define WD0_DEVNAME "watchdog0" +#define WD1_DEVNAME "watchdog1" +#define WD2_DEVNAME "watchdog2" + +#define WD0_MINOR 212 +#define WD1_MINOR 213 +#define WD2_MINOR 214 + + +/* Internal driver definitions + */ +#define WD0_ID 0 /* Watchdog0 */ +#define WD1_ID 1 /* Watchdog1 */ +#define WD2_ID 2 /* Watchdog2 */ +#define WD_NUMDEVS 3 /* Device contains 3 timers */ + +#define WD_INTR_OFF 0 /* Interrupt disable value */ +#define WD_INTR_ON 1 /* Interrupt enable value */ + +#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ +#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ +#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ + +/* Register value definitions + */ +#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ +#define WD1_INTR_MASK 0x02 +#define WD2_INTR_MASK 0x04 + +#define WD_S_RUNNING 0x01 /* Watchdog device status running */ +#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ + +/* Sun uses Altera PLD EPF8820ATC144-4 + * providing three hardware watchdogs: + * + * 1) RIC - sends an interrupt when triggered + * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU + * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board + * + *** Timer register block definition (struct wd_timer_regblk) + * + * dcntr and limit registers (halfword access): + * ------------------- + * | 15 | ...| 1 | 0 | + * ------------------- + * |- counter val -| + * ------------------- + * dcntr - Current 16-bit downcounter value. + * When downcounter reaches '0' watchdog expires. + * Reading this register resets downcounter with 'limit' value. + * limit - 16-bit countdown value in 1/10th second increments. + * Writing this register begins countdown with input value. + * Reading from this register does not affect counter. + * NOTES: After watchdog reset, dcntr and limit contain '1' + * + * status register (byte access): + * --------------------------- + * | 7 | ... | 2 | 1 | 0 | + * --------------+------------ + * |- UNUSED -| EXP | RUN | + * --------------------------- + * status- Bit 0 - Watchdog is running + * Bit 1 - Watchdog has expired + * + *** PLD register block definition (struct wd_pld_regblk) + * + * intr_mask register (byte access): + * --------------------------------- + * | 7 | ... | 3 | 2 | 1 | 0 | + * +-------------+------------------ + * |- UNUSED -| WD3 | WD2 | WD1 | + * --------------------------------- + * WD3 - 1 == Interrupt disabled for watchdog 3 + * WD2 - 1 == Interrupt disabled for watchdog 2 + * WD1 - 1 == Interrupt disabled for watchdog 1 + * + * pld_status register (byte access): + * UNKNOWN, MAGICAL MYSTERY REGISTER + * + */ +struct wd_timer_regblk { + volatile __u16 dcntr; /* down counter - hw */ + volatile __u16 dcntr_pad; + volatile __u16 limit; /* limit register - hw */ + volatile __u16 limit_pad; + volatile __u8 status; /* status register - b */ + volatile __u8 status_pad; + volatile __u16 status_pad2; + volatile __u32 pad32; /* yet more padding */ +}; + +struct wd_pld_regblk { + volatile __u8 intr_mask; /* interrupt mask - b */ + volatile __u8 intr_mask_pad; + volatile __u16 intr_mask_pad2; + volatile __u8 status; /* device status - b */ + volatile __u8 status_pad; + volatile __u16 status_pad2; +}; + +struct wd_regblk { + volatile struct wd_timer_regblk wd0_regs; + volatile struct wd_timer_regblk wd1_regs; + volatile struct wd_timer_regblk wd2_regs; + volatile struct wd_pld_regblk pld_regs; +}; + +/* Individual timer structure + */ +struct wd_timer { + __u16 timeout; + __u8 intr_mask; + unsigned char runstatus; + volatile struct wd_timer_regblk* regs; +}; + +/* Device structure + */ +struct wd_device { + int irq; + spinlock_t lock; + unsigned char isbaddoggie; /* defective PLD */ + unsigned char opt_enable; + unsigned char opt_reboot; + unsigned short opt_timeout; + unsigned char initialized; + struct wd_timer watchdog[WD_NUMDEVS]; + volatile struct wd_regblk* regs; +}; + +static struct wd_device wd_dev = { + 0, SPIN_LOCK_UNLOCKED, 0, 0, 0, 0, +}; + +struct timer_list wd_timer; + +static int wd0_timeout = 0; +static int wd1_timeout = 0; +static int wd2_timeout = 0; + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_PARM (wd0_timeout, "i"); +MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); +MODULE_PARM (wd1_timeout, "i"); +MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); +MODULE_PARM (wd2_timeout, "i"); +MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); + +MODULE_AUTHOR + ("Eric Brower <ebrower@usa.net>"); +MODULE_DESCRIPTION + ("Hardware watchdog driver for Sun Microsystems CP1400/1500"); +MODULE_SUPPORTED_DEVICE + ("watchdog"); +#endif /* ifdef MODULE */ + +/* Forward declarations of internal methods + */ +void wd_dumpregs(void); +void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); +void wd_toggleintr(struct wd_timer* pTimer, int enable); +void wd_pingtimer(struct wd_timer* pTimer); +void wd_starttimer(struct wd_timer* pTimer); +void wd_resetbrokentimer(struct wd_timer* pTimer); +void wd_stoptimer(struct wd_timer* pTimer); +void wd_brokentimer(unsigned long data); +int wd_getstatus(struct wd_timer* pTimer); + +/* PLD expects words to be written in LSB format, + * so we must flip all words prior to writing them to regs + */ +inline unsigned short flip_word(unsigned short word) +{ + return ((word & 0xff) << 8) | ((word >> 8) & 0xff); +} + +#define wd_writew(val, addr) (writew(flip_word(val), addr)) +#define wd_readw(addr) (flip_word(readw(addr))) +#define wd_writeb(val, addr) (writeb(val, addr)) +#define wd_readb(addr) (readb(addr)) + + +/* CP1400s seem to have broken PLD implementations-- + * the interrupt_mask register cannot be written, so + * no timer interrupts can be masked within the PLD. + */ +static inline int wd_isbroken(void) +{ + /* we could test this by read/write/read/restore + * on the interrupt mask register only if OBP + * 'watchdog-enable?' == FALSE, but it seems + * ubiquitous on CP1400s + */ + char val[32]; + prom_getproperty(prom_root_node, "model", val, sizeof(val)); + return((!strcmp(val, WD_BADMODEL)) ? 1 : 0); +} + +/* Retrieve watchdog-enable? option from OBP + * Returns 0 if false, 1 if true + */ +static inline int wd_opt_enable(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1); +} + +/* Retrieve watchdog-reboot? option from OBP + * Returns 0 if false, 1 if true + */ +static inline int wd_opt_reboot(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1); +} + +/* Retrieve watchdog-timeout option from OBP + * Returns OBP value, or 0 if not located + */ +static inline int wd_opt_timeout(void) +{ + int opt_node; + char value[32]; + char *p = value; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + opt_node = prom_getproperty(opt_node, + "watchdog-timeout", + value, + sizeof(value)); + if(-1 != opt_node) { + /* atoi implementation */ + for(opt_node = 0; /* nop */; p++) { + if(*p >= '0' && *p <= '9') { + opt_node = (10*opt_node)+(*p-'0'); + } + else { + break; + } + } + } + return((-1 == opt_node) ? (0) : (opt_node)); +} + +static int wd_open(struct inode *inode, struct file *f) +{ + switch(MINOR(inode->i_rdev)) + { + case WD0_MINOR: + f->private_data = &wd_dev.watchdog[WD0_ID]; + break; + case WD1_MINOR: + f->private_data = &wd_dev.watchdog[WD1_ID]; + break; + case WD2_MINOR: + f->private_data = &wd_dev.watchdog[WD2_ID]; + break; + default: + return(-ENODEV); + } + + /* Register IRQ on first open of device */ + if(0 == wd_dev.initialized) + { + if (request_irq(wd_dev.irq, + &wd_interrupt, + SA_SHIRQ, + WD_OBPNAME, + (void *)wd_dev.regs)) { + printk("%s: Cannot register IRQ %s\n", + WD_OBPNAME, __irq_itoa(wd_dev.irq)); + return(-EBUSY); + } + wd_dev.initialized = 1; + } + + MOD_INC_USE_COUNT; + return(0); +} + +static int wd_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int wd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int setopt = 0; + struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + struct watchdog_info info = { + 0, + 0, + "Altera EPF8820ATC144-4" + }; + + if(NULL == pTimer) { + return(-EINVAL); + } + + switch(cmd) + { + /* Generic Linux IOCTLs */ + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, + (struct watchdog_info *)&info, + sizeof(struct watchdog_info *))) { + return(-EFAULT); + } + break; + case WDIOC_KEEPALIVE: + wd_pingtimer(pTimer); + break; + case WDIOC_SETOPTIONS: + if(copy_from_user(&setopt, (void*) arg, sizeof(unsigned int))) { + return -EFAULT; + } + if(setopt & WDIOS_DISABLECARD) { + if(wd_dev.opt_enable) { + printk( + "%s: cannot disable watchdog in ENABLED mode\n", + WD_OBPNAME); + return(-EINVAL); + } + wd_stoptimer(pTimer); + } + else if(setopt & WDIOS_ENABLECARD) { + wd_starttimer(pTimer); + } + else { + return(-EINVAL); + } + break; + /* Solaris-compatible IOCTLs */ + case WIOCGSTAT: + setopt = wd_getstatus(pTimer); + if(copy_to_user((void*)arg, &setopt, sizeof(unsigned int))) { + return(-EFAULT); + } + break; + case WIOCSTART: + wd_starttimer(pTimer); + break; + case WIOCSTOP: + if(wd_dev.opt_enable) { + printk("%s: cannot disable watchdog in ENABLED mode\n", + WD_OBPNAME); + return(-EINVAL); + } + wd_stoptimer(pTimer); + break; + default: + return(-EINVAL); + } + return(0); +} + +static ssize_t wd_write( struct file *file, + const char *buf, + size_t count, + loff_t *ppos) +{ + struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + + if(NULL == pTimer) { + return(-EINVAL); + } + + wd_pingtimer(pTimer); + return(count); +} + +static ssize_t wd_read(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ +#ifdef WD_DEBUG + wd_dumpregs(); + return(0); +#else + return(-EINVAL); +#endif /* ifdef WD_DEBUG */ +} + +void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* Only WD0 will interrupt-- others are NMI and we won't + * see them here.... + */ + spin_lock_irq(&wd_dev.lock); + if((unsigned long)wd_dev.regs == (unsigned long)dev_id) + { + wd_stoptimer(&wd_dev.watchdog[WD0_ID]); + wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD; + } + spin_unlock_irq(&wd_dev.lock); + return; +} + +static struct file_operations wd_fops = { + owner: THIS_MODULE, + ioctl: wd_ioctl, + open: wd_open, + write: wd_write, + read: wd_read, + release: wd_release, +}; + +static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops }; +static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; +static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; + +void wd_dumpregs(void) +{ + /* Reading from downcounters initiates watchdog countdown-- + * Example is included below for illustration purposes. + */ + int i; + printk("%s: dumping register values\n", WD_OBPNAME); + for(i = WD0_ID; i < WD_NUMDEVS; ++i) { + /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n", + * WD_OBPNAME, + * i, + * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), + * readw(&wd_dev.watchdog[i].regs->dcntr)); + */ + printk("\t%s%i: limit at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->limit), + readw(&wd_dev.watchdog[i].regs->limit)); + printk("\t%s%i: status at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->status), + readb(&wd_dev.watchdog[i].regs->status)); + printk("\t%s%i: driver status: 0x%x\n", + WD_OBPNAME, + i, + wd_getstatus(&wd_dev.watchdog[i])); + } + printk("\tintr_mask at 0x%lx: 0x%x\n", + (unsigned long)(&wd_dev.regs->pld_regs.intr_mask), + readb(&wd_dev.regs->pld_regs.intr_mask)); + printk("\tpld_status at 0x%lx: 0x%x\n", + (unsigned long)(&wd_dev.regs->pld_regs.status), + readb(&wd_dev.regs->pld_regs.status)); +} + +/* Enable or disable watchdog interrupts + * Because of the CP1400 defect this should only be + * called during initialzation or by wd_[start|stop]timer() + * + * pTimer - pointer to timer device, or NULL to indicate all timers + * enable - non-zero to enable interrupts, zero to disable + */ +void wd_toggleintr(struct wd_timer* pTimer, int enable) +{ + unsigned char curregs = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char setregs = + (NULL == pTimer) ? + (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : + (pTimer->intr_mask); + + (WD_INTR_ON == enable) ? + (curregs &= ~setregs): + (curregs |= setregs); + + wd_writeb(curregs, &wd_dev.regs->pld_regs.intr_mask); + return; +} + +/* Reset countdown timer with 'limit' value and continue countdown. + * This will not start a stopped timer. + * + * pTimer - pointer to timer device + */ +void wd_pingtimer(struct wd_timer* pTimer) +{ + if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { + wd_readb(&pTimer->regs->dcntr); + } +} + +/* Stop a running watchdog timer-- the timer actually keeps + * running, but the interrupt is masked so that no action is + * taken upon expiration. + * + * pTimer - pointer to timer device + */ +void wd_stoptimer(struct wd_timer* pTimer) +{ + if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { + wd_toggleintr(pTimer, WD_INTR_OFF); + + if(wd_dev.isbaddoggie) { + pTimer->runstatus |= WD_STAT_BSTOP; + wd_brokentimer((unsigned long)&wd_dev); + } + } +} + +/* Start a watchdog timer with the specified limit value + * If the watchdog is running, it will be restarted with + * the provided limit value. + * + * This function will enable interrupts on the specified + * watchdog. + * + * pTimer - pointer to timer device + * limit - limit (countdown) value in 1/10th seconds + */ +void wd_starttimer(struct wd_timer* pTimer) +{ + if(wd_dev.isbaddoggie) { + pTimer->runstatus &= ~WD_STAT_BSTOP; + } + pTimer->runstatus &= ~WD_STAT_SVCD; + + wd_writew(pTimer->timeout, &pTimer->regs->limit); + wd_toggleintr(pTimer, WD_INTR_ON); +} + +/* Restarts timer with maximum limit value and + * does not unset 'brokenstop' value. + */ +void wd_resetbrokentimer(struct wd_timer* pTimer) +{ + wd_toggleintr(pTimer, WD_INTR_ON); + wd_writew(WD_BLIMIT, &pTimer->regs->limit); +} + +/* Timer device initialization helper. + * Returns 0 on success, other on failure + */ +int wd_inittimer(int whichdog) +{ + struct miscdevice *whichmisc; + volatile struct wd_timer_regblk *whichregs; + char whichident[8]; + int whichmask; + __u16 whichlimit; + + switch(whichdog) + { + case WD0_ID: + whichmisc = &wd0_miscdev; + strcpy(whichident, "RIC"); + whichregs = &wd_dev.regs->wd0_regs; + whichmask = WD0_INTR_MASK; + whichlimit= (0 == wd0_timeout) ? + (wd_dev.opt_timeout): + (wd0_timeout); + break; + case WD1_ID: + whichmisc = &wd1_miscdev; + strcpy(whichident, "XIR"); + whichregs = &wd_dev.regs->wd1_regs; + whichmask = WD1_INTR_MASK; + whichlimit= (0 == wd1_timeout) ? + (wd_dev.opt_timeout): + (wd1_timeout); + break; + case WD2_ID: + whichmisc = &wd2_miscdev; + strcpy(whichident, "POR"); + whichregs = &wd_dev.regs->wd2_regs; + whichmask = WD2_INTR_MASK; + whichlimit= (0 == wd2_timeout) ? + (wd_dev.opt_timeout): + (wd2_timeout); + break; + default: + printk("%s: %s: invalid watchdog id: %i\n", + WD_OBPNAME, __FUNCTION__, whichdog); + return(1); + } + if(0 != misc_register(whichmisc)) + { + return(1); + } + wd_dev.watchdog[whichdog].regs = whichregs; + wd_dev.watchdog[whichdog].timeout = whichlimit; + wd_dev.watchdog[whichdog].intr_mask = whichmask; + wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP; + wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT; + + printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", + WD_OBPNAME, + whichdog, + whichident, + wd_dev.watchdog[whichdog].timeout / 10, + wd_dev.watchdog[whichdog].timeout % 10, + (0 != wd_dev.opt_enable) ? "in ENABLED mode" : ""); + return(0); +} + +/* Timer method called to reset stopped watchdogs-- + * because of the PLD bug on CP1400, we cannot mask + * interrupts within the PLD so me must continually + * reset the timers ad infinitum. + */ +void wd_brokentimer(unsigned long data) +{ + struct wd_device* pDev = (struct wd_device*)data; + int id, tripped = 0; + + /* kill a running timer instance, in case we + * were called directly instead of by kernel timer + */ + if(timer_pending(&wd_timer)) { + del_timer(&wd_timer); + } + + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) { + ++tripped; + wd_resetbrokentimer(&pDev->watchdog[id]); + } + } + + if(tripped) { + /* there is at least one timer brokenstopped-- reschedule */ + wd_timer.expires = WD_BTIMEOUT; + add_timer(&wd_timer); + } +} + +int wd_getstatus(struct wd_timer* pTimer) +{ + unsigned char stat = wd_readb(&pTimer->regs->status); + unsigned char intr = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char ret = WD_STOPPED; + + /* determine STOPPED */ + if(0 == stat ) { + return(ret); + } + /* determine EXPIRED vs FREERUN vs RUNNING */ + else if(WD_S_EXPIRED & stat) { + ret = WD_EXPIRED; + } + else if(WD_S_RUNNING & stat) { + if(intr & pTimer->intr_mask) { + ret = WD_FREERUN; + } + else { + /* Fudge WD_EXPIRED status for defective CP1400-- + * IF timer is running + * AND brokenstop is set + * AND an interrupt has been serviced + * we are WD_EXPIRED. + * + * IF timer is running + * AND brokenstop is set + * AND no interrupt has been serviced + * we are WD_FREERUN. + */ + if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) { + if(pTimer->runstatus & WD_STAT_SVCD) { + ret = WD_EXPIRED; + } + else { + /* we could as well pretend we are expired */ + ret = WD_FREERUN; + } + } + else { + ret = WD_RUNNING; + } + } + } + + /* determine SERVICED */ + if(pTimer->runstatus & WD_STAT_SVCD) { + ret |= WD_SERVICED; + } + + return(ret); +} + +static int __init wd_init(void) +{ + int id; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, WD_OBPNAME)) + goto ebus_done; + } + } + +ebus_done: + if(!edev) { + printk("%s: unable to locate device\n", WD_OBPNAME); + return -ENODEV; + } + + wd_dev.regs = + ioremap(edev->resource[0].start, sizeof(struct wd_regblk)); + + if(NULL == wd_dev.regs) { + printk("%s: unable to map registers\n", WD_OBPNAME); + return(-ENODEV); + } + + /* initialize device structure from OBP parameters */ + wd_dev.irq = edev->irqs[0]; + wd_dev.opt_enable = wd_opt_enable(); + wd_dev.opt_reboot = wd_opt_reboot(); + wd_dev.opt_timeout = wd_opt_timeout(); + wd_dev.isbaddoggie = wd_isbroken(); + + /* disable all interrupts unless watchdog-enabled? == true */ + if(! wd_dev.opt_enable) { + wd_toggleintr(NULL, WD_INTR_OFF); + } + + /* register miscellaneous devices */ + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(0 != wd_inittimer(id)) { + printk("%s%i: unable to initialize\n", WD_OBPNAME, id); + } + } + + /* warn about possible defective PLD */ + if(wd_dev.isbaddoggie) { + init_timer(&wd_timer); + wd_timer.function = wd_brokentimer; + wd_timer.data = (unsigned long)&wd_dev; + wd_timer.expires = WD_BTIMEOUT; + + printk("%s: PLD defect workaround enabled for model %s\n", + WD_OBPNAME, WD_BADMODEL); + } + return(0); +} + +static void __exit wd_cleanup(void) +{ + int id; + + /* if 'watchdog-enable?' == TRUE, timers are not stopped + * when module is unloaded. All brokenstopped timers will + * also now eventually trip. + */ + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(WD_S_RUNNING == wd_readb(&wd_dev.watchdog[id].regs->status)) { + if(wd_dev.opt_enable) { + printk(KERN_WARNING "%s%i: timer not stopped at release\n", + WD_OBPNAME, id); + } + else { + wd_stoptimer(&wd_dev.watchdog[id]); + if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) { + wd_resetbrokentimer(&wd_dev.watchdog[id]); + printk(KERN_WARNING + "%s%i: defect workaround disabled at release, "\ + "timer expires in ~%01i sec\n", + WD_OBPNAME, id, + wd_readw(&wd_dev.watchdog[id].regs->limit) / 10); + } + } + } + } + + if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) { + del_timer(&wd_timer); + } + if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd0_miscdev); + } + if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd1_miscdev); + } + if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd2_miscdev); + } + if(0 != wd_dev.initialized) { + free_irq(wd_dev.irq, (void *)wd_dev.regs); + } + iounmap(wd_dev.regs); +} + +module_init(wd_init); +module_exit(wd_cleanup); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 71809b59d..c6c927712 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -1,4 +1,4 @@ -/* $Id: flash.c,v 1.20 2000/11/08 04:57:49 davem Exp $ +/* $Id: flash.c,v 1.21 2001/01/11 15:29:36 davem Exp $ * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -14,6 +14,7 @@ #include <linux/poll.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/spinlock.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -22,6 +23,7 @@ #include <asm/sbus.h> #include <asm/ebus.h> +static spinlock_t flash_lock = SPIN_LOCK_UNLOCKED; static struct { unsigned long read_base; /* Physical read address */ unsigned long write_base; /* Physical write address */ @@ -38,14 +40,14 @@ flash_mmap(struct file *file, struct vm_area_struct *vma) unsigned long addr; unsigned long size; - lock_kernel(); + spin_lock(&flash_lock); if (flash.read_base == flash.write_base) { addr = flash.read_base; size = flash.read_size; } else { if ((vma->vm_flags & VM_READ) && (vma->vm_flags & VM_WRITE)) { - unlock_kernel(); + spin_unlock(&flash_lock); return -EINVAL; } if (vma->vm_flags & VM_READ) { @@ -55,11 +57,11 @@ flash_mmap(struct file *file, struct vm_area_struct *vma) addr = flash.write_base; size = flash.write_size; } else { - unlock_kernel(); + spin_unlock(&flash_lock); return -ENXIO; } } - unlock_kernel(); + spin_unlock(&flash_lock); if ((vma->vm_pgoff << PAGE_SHIFT) > size) return -ENXIO; @@ -127,9 +129,10 @@ flash_open(struct inode *inode, struct file *file) static int flash_release(struct inode *inode, struct file *file) { - lock_kernel(); + spin_lock(&flash_lock); flash.busy = 0; - unlock_kernel(); + spin_unlock(&flash_lock); + return 0; } diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index f87850b2c..8faec19dd 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -505,9 +505,7 @@ static int jsfd_open(struct inode *inode, struct file *file) static int jsf_release(struct inode *inode, struct file *file) { - lock_kernel(); jsf0.busy = 0; - unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 6ddccf114..ea37949fa 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.49 2000/07/13 08:06:40 davem Exp $ +/* $Id: pcikbd.c,v 1.50 2001/01/11 15:29:36 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -746,13 +746,13 @@ static int aux_release(struct inode * inode, struct file * file) { unsigned long flags; - lock_kernel(); aux_fasync(-1, file, 0); - if (--aux_count) - goto out; spin_lock_irqsave(&pcikbd_lock, flags); + if (--aux_count) + goto out; + /* Disable controller ints */ aux_write_cmd(AUX_INTS_OFF); poll_aux_status(); @@ -761,9 +761,8 @@ static int aux_release(struct inode * inode, struct file * file) pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - spin_unlock_irqrestore(&pcikbd_lock, flags); out: - unlock_kernel(); + spin_unlock_irqrestore(&pcikbd_lock, flags); return 0; } @@ -780,11 +779,13 @@ static int aux_open(struct inode * inode, struct file * file) if (!aux_present) return -ENODEV; - if (aux_count++) - return 0; - spin_lock_irqsave(&pcikbd_lock, flags); + if (aux_count++) { + spin_unlock_irqrestore(&pcikbd_lock, flags); + return 0; + } + if (!poll_aux_status()) { aux_count--; spin_unlock_irqrestore(&pcikbd_lock, flags); diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index d8454cf25..6105e4229 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.23 2000/08/29 07:01:55 davem Exp $ +/* $Id: rtc.c,v 1.24 2001/01/11 15:07:09 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -31,11 +31,9 @@ static int rtc_busy = 0; void get_rtc_time(struct rtc_time *t) { unsigned long regs = mstk48t02_regs; - unsigned long flags; u8 tmp; - save_flags(flags); - cli(); + spin_lock_irq(&mostek_lock); tmp = mostek_read(regs + MOSTEK_CREG); tmp |= MSTK_CREG_READ; @@ -52,18 +50,18 @@ void get_rtc_time(struct rtc_time *t) tmp = mostek_read(regs + MOSTEK_CREG); tmp &= ~MSTK_CREG_READ; mostek_write(regs + MOSTEK_CREG, tmp); - restore_flags(flags); + + spin_unlock_irq(&mostek_lock); } /* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { unsigned long regs = mstk48t02_regs; - unsigned long flags; u8 tmp; - save_flags(flags); - cli(); + spin_lock_irq(&mostek_lock); + tmp = mostek_read(regs + MOSTEK_CREG); tmp |= MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); @@ -79,7 +77,8 @@ void set_rtc_time(struct rtc_time *t) tmp = mostek_read(regs + MOSTEK_CREG); tmp &= ~MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); - restore_flags(flags); + + spin_unlock_irq(&mostek_lock); } static long long rtc_lseek(struct file *file, long long offset, int origin) @@ -121,20 +120,24 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int rtc_open(struct inode *inode, struct file *file) { + int ret; + + spin_lock_irq(&mostek_lock); + if (rtc_busy) { + ret = -EBUSY; + } else { + rtc_busy = 1; + ret = 0; + } + spin_unlock_irq(&mostek_lock); - if (rtc_busy) - return -EBUSY; - - rtc_busy = 1; - - return 0; + return ret; } static int rtc_release(struct inode *inode, struct file *file) { - lock_kernel(); rtc_busy = 0; - unlock_kernel(); + return 0; } @@ -150,11 +153,7 @@ static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int __init rtc_sun_init(void) -#endif +static int __init rtc_sun_init(void) { int error; @@ -173,9 +172,10 @@ int __init rtc_sun_init(void) return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit rtc_sun_cleanup(void) { misc_deregister(&rtc_dev); } -#endif + +module_init(rtc_sun_init); +module_exit(rtc_sun_cleanup); diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index f34c12250..467200699 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -1521,15 +1521,17 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) static int kbd_open (struct inode *i, struct file *f) { + spin_lock_irq(&kbd_queue_lock); kbd_active++; if (kbd_opened) - return 0; + goto out; kbd_opened = fg_console + 1; - spin_lock_irq(&kbd_queue_lock); kbd_head = kbd_tail = 0; + + out: spin_unlock_irq(&kbd_queue_lock); return 0; @@ -1538,7 +1540,7 @@ kbd_open (struct inode *i, struct file *f) static int kbd_close (struct inode *i, struct file *f) { - lock_kernel(); + spin_lock_irq(&kbd_queue_lock); if (!--kbd_active) { if (kbd_redirected) kbd_table [kbd_redirected-1].kbdmode = VC_XLATE; @@ -1546,7 +1548,8 @@ kbd_close (struct inode *i, struct file *f) kbd_opened = 0; kbd_fasync (-1, f, 0); } - unlock_kernel(); + spin_unlock_irq(&kbd_queue_lock); + return 0; } diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c index fd92bc434..8bb45cbde 100644 --- a/drivers/sbus/char/sunmouse.c +++ b/drivers/sbus/char/sunmouse.c @@ -391,11 +391,14 @@ sun_mouse_inbyte(unsigned char byte, int is_break) static int sun_mouse_open(struct inode * inode, struct file * file) { + spin_lock_irq(&sunmouse.lock); if (sunmouse.active++) - return 0; + goto out; sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; sunmouse.vuid_mode = VUID_NATIVE; +out: + spin_unlock_irq(&sunmouse.lock); return 0; } @@ -412,10 +415,12 @@ static int sun_mouse_fasync (int fd, struct file *filp, int on) static int sun_mouse_close(struct inode *inode, struct file *file) { - lock_kernel(); sun_mouse_fasync (-1, file, 0); + + spin_lock_irq(&sunmouse.lock); sunmouse.active--; - unlock_kernel(); + spin_unlock_irq(&sunmouse.lock); + return 0; } diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 73158f351..a4c0f347e 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -22,6 +22,7 @@ #include <linux/sched.h> #include <linux/fs.h> #include <linux/smp_lock.h> +#include <linux/spinlock.h> #include <asm/openprom.h> #include <asm/oplib.h> @@ -181,17 +182,26 @@ struct vfc_dev *vfc_get_dev_ptr(int instance) return vfc_dev_lst[instance]; } +static spinlock_t vfc_dev_lock = SPIN_LOCK_UNLOCKED; + static int vfc_open(struct inode *inode, struct file *file) { struct vfc_dev *dev; + spin_lock(&vfc_dev_lock); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); - if (dev == NULL) + if (dev == NULL) { + spin_unlock(&vfc_dev_lock); return -ENODEV; - if (dev->busy) + } + if (dev->busy) { + spin_unlock(&vfc_dev_lock); return -EBUSY; + } dev->busy = 1; + spin_unlock(&vfc_dev_lock); + vfc_lock_device(dev); vfc_csr_init(dev); @@ -209,14 +219,14 @@ static int vfc_release(struct inode *inode,struct file *file) { struct vfc_dev *dev; - lock_kernel(); + spin_lock(&vfc_dev_lock); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); if (!dev || !dev->busy) { - unlock_kernel(); + spin_unlock(&vfc_dev_lock); return -EINVAL; } dev->busy = 0; - unlock_kernel(); + spin_unlock(&vfc_dev_lock); return 0; } @@ -611,12 +621,10 @@ static int vfc_mmap(struct inode *inode, struct file *file, unsigned int map_size, ret, map_offset; struct vfc_dev *dev; - lock_kernel(); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); - if(dev == NULL) { - unlock_kernel(); + if(dev == NULL) return -ENODEV; - } + map_size = vma->vm_end - vma->vm_start; if(map_size > sizeof(struct vfc_regs)) map_size = sizeof(struct vfc_regs); @@ -626,7 +634,7 @@ static int vfc_mmap(struct inode *inode, struct file *file, map_offset = (unsigned int) (long)dev->phys_regs; ret = io_remap_page_range(vma->vm_start, map_offset, map_size, vma->vm_page_prot, dev->which_io); - unlock_kernel(); + if(ret) return -EAGAIN; diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 942a6c59b..032776c70 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.91 2000/11/08 05:04:06 davem Exp $ +/* $Id: sbus.c,v 1.92 2001/01/25 17:15:59 davem Exp $ * sbus.c: SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -238,10 +238,14 @@ static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, break; } if (rngnum == num_ranges) { - prom_printf("sbus_apply_ranges: Cannot find matching " - "range nregs[%d] nranges[%d].\n", - num_regs, num_ranges); - prom_halt(); + /* We used to flag this as an error. Actually + * some devices do not report the regs as we expect. + * For example, see SUNW,pln device. In that case + * the reg property is in a format internal to that + * node, ie. it is not in the SBUS register space + * per se. -DaveM + */ + return; } regs[regnum].which_io = ranges[rngnum].ot_parent_space; regs[regnum].phys_addr += ranges[rngnum].ot_parent_base; diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 5a74bc2df..73bd8029e 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -776,7 +776,7 @@ void print_sense_internal(const char * devclass, printk("%s%s: sns = %2x %2x\n", devclass, kdevname(dev), sense_buffer[0], sense_buffer[2]); - printk("Non-extended sense class %d code 0x%0x ", sense_class, code); + printk("Non-extended sense class %d code 0x%0x\n", sense_class, code); s = 4; } diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index f966bf5a7..0e5ee6935 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -16,6 +16,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) #error "This driver works only with kernel 2.4.0 or higher!" #endif +#include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/ctype.h> @@ -38,7 +39,7 @@ #include <linux/config.h> /* current version of this driver-source: */ -#define IBMMCA_SCSI_DRIVER_VERSION "4.0a" +#define IBMMCA_SCSI_DRIVER_VERSION "4.0b" #define IBMLOCK spin_lock_irqsave(&io_request_lock, flags); #define IBMUNLOCK spin_unlock_irqrestore(&io_request_lock, flags); @@ -443,7 +444,6 @@ static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 }; (that is kernel version 2.1.x) */ #if defined(MODULE) static char *boot_options = NULL; -#include <linux/module.h> MODULE_PARM(boot_options, "s"); MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); @@ -2563,9 +2563,6 @@ static int option_setup(char *str) __setup("ibmmcascsi=", option_setup); -#ifdef MODULE -/* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = IBMMCA; +static Scsi_Host_Template driver_template = IBMMCA; #include "scsi_module.c" -#endif diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 264ae2fe0..106e39b8a 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -149,7 +149,6 @@ #include <linux/version.h> #ifdef MODULE -#include <linux/modversions.h> #include <linux/module.h> char kernel_version[] = UTS_RELEASE; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index d82eed0b7..fc0af0cbf 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -222,8 +222,8 @@ int ppa_detect(Scsi_Host_Template * host) printk(" supported by the imm (ZIP Plus) driver. If the\n"); printk(" cable is marked with \"AutoDetect\", this is what has\n"); printk(" happened.\n"); - return 0; spin_lock_irq(&io_request_lock); + return 0; } try_again = 1; goto retry_entry; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ace7c7e2c..dcde48437 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -50,6 +50,50 @@ * This entire source file deals with the new queueing code. */ +/* + * Function: __scsi_insert_special() + * + * Purpose: worker for scsi_insert_special_*() + * + * Arguments: q - request queue where request should be inserted + * rq - request to be inserted + * data - private data + * at_head - insert request at head or tail of queue + * + * Lock status: Assumed that io_request_lock is not held upon entry. + * + * Returns: Nothing + */ +static void __scsi_insert_special(request_queue_t *q, struct request *rq, + void *data, int at_head) +{ + unsigned long flags; + + ASSERT_LOCK(&io_request_lock, 0); + + rq->cmd = SPECIAL; + rq->special = data; + rq->q = NULL; + rq->nr_segments = 0; + rq->elevator_sequence = 0; + + /* + * We have the option of inserting the head or the tail of the queue. + * Typically we use the tail for new ioctls and so forth. We use the + * head of the queue for things like a QUEUE_FULL message from a + * device, or a host that is unable to accept a particular command. + */ + spin_lock_irqsave(&io_request_lock, flags); + + if (at_head) + list_add(&rq->queue, &q->queue_head); + else + list_add_tail(&rq->queue, &q->queue_head); + + q->request_fn(q); + spin_unlock_irqrestore(&io_request_lock, flags); +} + /* * Function: scsi_insert_special_cmd() @@ -73,52 +117,9 @@ */ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head) { - unsigned long flags; - request_queue_t *q; - - ASSERT_LOCK(&io_request_lock, 0); - - /* - * The SCpnt already contains a request structure - we will doctor the - * thing up with the appropriate values and use that in the actual - * request queue. - */ - q = &SCpnt->device->request_queue; - SCpnt->request.cmd = SPECIAL; - SCpnt->request.special = (void *) SCpnt; - SCpnt->request.q = NULL; - SCpnt->request.free_list = NULL; - SCpnt->request.nr_segments = 0; - - /* - * We have the option of inserting the head or the tail of the queue. - * Typically we use the tail for new ioctls and so forth. We use the - * head of the queue for things like a QUEUE_FULL message from a - * device, or a host that is unable to accept a particular command. - */ - spin_lock_irqsave(&io_request_lock, flags); - - if (at_head) { - list_add(&SCpnt->request.queue, &q->queue_head); - } else { - /* - * FIXME(eric) - we always insert at the tail of the - * list. Otherwise ioctl commands would always take - * precedence over normal I/O. An ioctl on a busy - * disk might be delayed indefinitely because the - * request might not float high enough in the queue - * to be scheduled. - */ - list_add_tail(&SCpnt->request.queue, &q->queue_head); - } + request_queue_t *q = &SCpnt->device->request_queue; - /* - * Now hit the requeue function for the queue. If the host is - * already busy, so be it - we have nothing special to do. If - * the host can queue it, then send it off. - */ - q->request_fn(q); - spin_unlock_irqrestore(&io_request_lock, flags); + __scsi_insert_special(q, &SCpnt->request, SCpnt, at_head); return 0; } @@ -144,51 +145,9 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head) */ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head) { - unsigned long flags; - request_queue_t *q; - - ASSERT_LOCK(&io_request_lock, 0); - - /* - * The SCpnt already contains a request structure - we will doctor the - * thing up with the appropriate values and use that in the actual - * request queue. - */ - q = &SRpnt->sr_device->request_queue; - SRpnt->sr_request.cmd = SPECIAL; - SRpnt->sr_request.special = (void *) SRpnt; - SRpnt->sr_request.q = NULL; - SRpnt->sr_request.nr_segments = 0; - - /* - * We have the option of inserting the head or the tail of the queue. - * Typically we use the tail for new ioctls and so forth. We use the - * head of the queue for things like a QUEUE_FULL message from a - * device, or a host that is unable to accept a particular command. - */ - spin_lock_irqsave(&io_request_lock, flags); + request_queue_t *q = &SRpnt->sr_device->request_queue; - if (at_head) { - list_add(&SRpnt->sr_request.queue, &q->queue_head); - } else { - /* - * FIXME(eric) - we always insert at the tail of the - * list. Otherwise ioctl commands would always take - * precedence over normal I/O. An ioctl on a busy - * disk might be delayed indefinitely because the - * request might not float high enough in the queue - * to be scheduled. - */ - list_add_tail(&SRpnt->sr_request.queue, &q->queue_head); - } - - /* - * Now hit the requeue function for the queue. If the host is - * already busy, so be it - we have nothing special to do. If - * the host can queue it, then send it off. - */ - q->request_fn(q); - spin_unlock_irqrestore(&io_request_lock, flags); + __scsi_insert_special(q, &SRpnt->sr_request, SRpnt, at_head); return 0; } @@ -403,6 +362,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, struct request *req; struct buffer_head *bh; Scsi_Device * SDpnt; + int nsect; ASSERT_LOCK(&io_request_lock, 0); @@ -414,11 +374,13 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, } do { if ((bh = req->bh) != NULL) { + nsect = bh->b_size >> 9; + blk_finished_io(nsect); req->bh = bh->b_reqnext; - req->nr_sectors -= bh->b_size >> 9; - req->sector += bh->b_size >> 9; + req->nr_sectors -= nsect; + req->sector += nsect; bh->b_reqnext = NULL; - sectors -= bh->b_size >> 9; + sectors -= nsect; bh->b_end_io(bh, uptodate); if ((bh = req->bh) != NULL) { req->current_nr_sectors = bh->b_size >> 9; @@ -863,17 +825,6 @@ void scsi_request_fn(request_queue_t * q) SHpnt = SDpnt->host; /* - * If the host for this device is in error recovery mode, don't - * do anything at all here. When the host leaves error recovery - * mode, it will automatically restart things and start queueing - * commands again. Same goes if the queue is actually plugged, - * if the device itself is blocked, or if the host is fully - * occupied. - */ - if (SHpnt->in_recovery || q->plugged) - return; - - /* * To start with, we keep looping until the queue is empty, or until * the host is no longer able to accept any more requests. */ @@ -896,10 +847,11 @@ void scsi_request_fn(request_queue_t * q) || (SHpnt->host_blocked) || (SHpnt->host_self_blocked)) { /* - * If we are unable to process any commands at all for this - * device, then we consider it to be starved. What this means - * is that there are no outstanding commands for this device - * and hence we need a little help getting it started again + * If we are unable to process any commands at all for + * this device, then we consider it to be starved. + * What this means is that there are no outstanding + * commands for this device and hence we need a + * little help getting it started again * once the host isn't quite so busy. */ if (SDpnt->device_busy == 0) { @@ -1000,8 +952,8 @@ void scsi_request_fn(request_queue_t * q) } /* * If so, we are ready to do something. Bump the count - * while the queue is locked and then break out of the loop. - * Otherwise loop around and try another request. + * while the queue is locked and then break out of the + * loop. Otherwise loop around and try another request. */ if (!SCpnt) { break; @@ -1029,8 +981,9 @@ void scsi_request_fn(request_queue_t * q) memcpy(&SCpnt->request, req, sizeof(struct request)); /* - * We have copied the data out of the request block - it is now in - * a field in SCpnt. Release the request block. + * We have copied the data out of the request block - + * it is now in a field in SCpnt. Release the request + * block. */ blkdev_release_request(req); } @@ -1047,12 +1000,14 @@ void scsi_request_fn(request_queue_t * q) /* * This will do a couple of things: * 1) Fill in the actual SCSI command. - * 2) Fill in any other upper-level specific fields (timeout). + * 2) Fill in any other upper-level specific fields + * (timeout). * - * If this returns 0, it means that the request failed (reading - * past end of disk, reading offline device, etc). This won't - * actually talk to the device, but some kinds of consistency - * checking may cause the request to be rejected immediately. + * If this returns 0, it means that the request failed + * (reading past end of disk, reading offline device, + * etc). This won't actually talk to the device, but + * some kinds of consistency checking may cause the + * request to be rejected immediately. */ if (STpnt == NULL) { STpnt = scsi_get_request_dev(req); @@ -1103,8 +1058,8 @@ void scsi_request_fn(request_queue_t * q) scsi_dispatch_cmd(SCpnt); /* - * Now we need to grab the lock again. We are about to mess with - * the request queue and try to find another command. + * Now we need to grab the lock again. We are about to mess + * with the request queue and try to find another command. */ spin_lock_irq(&io_request_lock); } diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c index 7483eb970..4ebadd868 100644 --- a/drivers/scsi/scsi_merge.c +++ b/drivers/scsi/scsi_merge.c @@ -324,7 +324,6 @@ static inline int scsi_new_mergeable(request_queue_t * q, req->nr_segments >= SHpnt->sg_tablesize) return 0; req->nr_segments++; - q->elevator.nr_segments++; return 1; } @@ -341,11 +340,8 @@ static inline int scsi_new_segment(request_queue_t * q, if (req->nr_hw_segments >= SHpnt->sg_tablesize || req->nr_segments >= SHpnt->sg_tablesize) return 0; - if (req->nr_segments >= max_segments) - return 0; req->nr_hw_segments++; req->nr_segments++; - q->elevator.nr_segments++; return 1; } #else @@ -361,7 +357,6 @@ static inline int scsi_new_segment(request_queue_t * q, * counter. */ req->nr_segments++; - q->elevator.nr_segments++; return 1; } else { return 0; @@ -417,8 +412,10 @@ __inline static int __scsi_back_merge_fn(request_queue_t * q, SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; +#ifdef DMA_CHUNK_SIZE if (max_segments > 64) max_segments = 64; +#endif if (use_clustering) { /* @@ -471,8 +468,10 @@ __inline static int __scsi_front_merge_fn(request_queue_t * q, SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; +#ifdef DMA_CHUNK_SIZE if (max_segments > 64) max_segments = 64; +#endif if (use_clustering) { /* @@ -601,10 +600,10 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q, SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; +#ifdef DMA_CHUNK_SIZE if (max_segments > 64) max_segments = 64; -#ifdef DMA_CHUNK_SIZE /* If it would not fit into prepared memory space for sg chain, * then don't allow the merge. */ @@ -664,7 +663,6 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q, * This one is OK. Let it go. */ req->nr_segments += next->nr_segments - 1; - q->elevator.nr_segments--; #ifdef DMA_CHUNK_SIZE req->nr_hw_segments += next->nr_hw_segments - 1; #endif diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 04e4a6a28..c064dfde4 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -694,6 +694,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, (void *)SRpnt->sr_buffer, hp->dxfer_len, sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES); /* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */ + generic_unplug_device(&SRpnt->sr_device->request_queue); return 0; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 71ec104f4..7a2cde23b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -671,12 +671,14 @@ void get_capabilities(int i) cmd[3] = cmd[5] = 0; rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL); - if (-EINVAL == rc) { - /* failed, drive has'nt this mode page */ + if (rc) { + /* failed, drive doesn't have capabilities mode page */ scsi_CDs[i].cdi.speed = 1; - /* disable speed select, drive probably can't do this either */ - scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; + scsi_CDs[i].cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R | + CDC_DVD | CDC_DVD_RAM | + CDC_SELECT_DISC | CDC_SELECT_SPEED); scsi_free(buffer, 512); + printk("sr%i: scsi-1 drive\n", i); return; } n = buffer[3] + 4; diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 9fd35efcb..10235dd2e 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -142,9 +142,9 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then dep_tristate ' Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS dep_tristate ' Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS - dep_tristate ' Yamaha YMF7xx PCI audio (legacy mode)' CONFIG_SOUND_YMPCI $CONFIG_SOUND_OSS $CONFIG_PCI - if [ "$CONFIG_SOUND_YMPCI" = "n" ]; then - dep_tristate ' Yamaha YMF7xx PCI audio (native mode) (EXPERIMENTAL)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS $CONFIG_PCI $CONFIG_EXPERIMENTAL + dep_tristate ' Yamaha YMF7xx PCI audio (native mode)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS $CONFIG_PCI + if [ "$CONFIG_SOUND_YMFPCI" != "n" ]; then + bool ' Yamaha PCI legacy ports support' CONFIG_SOUND_YMFPCI_LEGACY fi dep_tristate ' 6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index e7ee317e6..824f08ec8 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -47,8 +47,10 @@ obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o -obj-$(CONFIG_SOUND_YMPCI) += ymf_sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o +ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y) + obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o +endif obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o diff --git a/drivers/sound/emu10k1/audio.c b/drivers/sound/emu10k1/audio.c index 9623dcb2e..2280ca236 100644 --- a/drivers/sound/emu10k1/audio.c +++ b/drivers/sound/emu10k1/audio.c @@ -375,8 +375,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = wiinst->format; format.samplingrate = val; - if (emu10k1_wavein_setformat(wave_dev, &format) < 0) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&wiinst->lock, flags); return -EINVAL; + } val = wiinst->format.samplingrate; @@ -393,8 +395,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = woinst->format; format.samplingrate = val; - if (emu10k1_waveout_setformat(wave_dev, &format) < 0) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&woinst->lock, flags); return -EINVAL; + } val = woinst->format.samplingrate; @@ -430,8 +434,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = wiinst->format; format.channels = val ? 2 : 1; - if (emu10k1_wavein_setformat(wave_dev, &format) < 0) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&wiinst->lock, flags); return -EINVAL; + } val = wiinst->format.channels - 1; @@ -447,8 +453,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = woinst->format; format.channels = val ? 2 : 1; - if (emu10k1_waveout_setformat(wave_dev, &format) < 0) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&woinst->lock, flags); return -EINVAL; + } val = woinst->format.channels - 1; @@ -478,8 +486,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = wiinst->format; format.channels = val; - if (emu10k1_wavein_setformat(wave_dev, &format) < 0) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&wiinst->lock, flags); return -EINVAL; + } val = wiinst->format.channels; @@ -495,8 +505,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = woinst->format; format.channels = val; - if (emu10k1_waveout_setformat(wave_dev, &format) < 0) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&woinst->lock, flags); return -EINVAL; + } val = woinst->format.channels; @@ -542,8 +554,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = wiinst->format; format.bitsperchannel = val; - if (emu10k1_wavein_setformat(wave_dev, &format) < 0) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&wiinst->lock, flags); return -EINVAL; + } val = wiinst->format.bitsperchannel; @@ -559,8 +573,10 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned format = woinst->format; format.bitsperchannel = val; - if (emu10k1_waveout_setformat(wave_dev, &format) < 0) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { + spin_unlock_irqrestore(&woinst->lock, flags); return -EINVAL; + } val = woinst->format.bitsperchannel; @@ -968,6 +984,7 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) for (i = 0; i < woinst->buffer.pages; i++) { if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(woinst->buffer.addr[i]), PAGE_SIZE, vma->vm_page_prot)) { spin_unlock_irqrestore(&woinst->lock, flags); + unlock_kernel(); return -EAGAIN; } } diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 73c9dcf54..03b4b1999 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -17,7 +17,6 @@ * Arnaldo C. de Melo Got rid of attach_uart401 */ -#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index f609d1e2b..fbe02bffd 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -15,7 +15,7 @@ */ -#define VIA_VERSION "1.1.14" +#define VIA_VERSION "1.1.14a" #include <linux/config.h> @@ -76,8 +76,16 @@ #define VIA_COUNTER_LIMIT 100000 /* size of DMA buffers */ -#define VIA_DMA_BUFFERS 16 -#define VIA_DMA_BUF_SIZE PAGE_SIZE +#define VIA_MAX_BUFFER_DMA_PAGES 32 + +/* buffering default values in ms */ +#define VIA_DEFAULT_FRAG_TIME 20 +#define VIA_DEFAULT_BUFFER_TIME 500 + +#define VIA_MAX_FRAG_SIZE PAGE_SIZE +#define VIA_MIN_FRAG_SIZE 64 + +#define VIA_MIN_FRAG_NUMBER 2 #ifndef AC97_PCM_LR_ADC_RATE # define AC97_PCM_LR_ADC_RATE AC97_PCM_LR_DAC_RATE @@ -102,7 +110,6 @@ #define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00 #define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01 #define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02 -#define VIA_BASE0_PCM_OUT_BLOCK_COUNT 0x0C #define VIA_BASE0_PCM_IN_CHAN 0x10 /* input PCM from user */ #define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10 @@ -114,6 +121,7 @@ #define VIA_PCM_CONTROL 0x01 #define VIA_PCM_TYPE 0x02 #define VIA_PCM_TABLE_ADDR 0x04 +#define VIA_PCM_BLOCK_COUNT 0x0C /* XXX unused DMA channel for FM PCM data */ #define VIA_BASE0_FM_OUT_CHAN 0x20 @@ -223,14 +231,14 @@ enum via_channel_states { }; -struct via_sgd_data { +struct via_buffer_pgtbl { dma_addr_t handle; void *cpuaddr; }; struct via_channel { - atomic_t n_bufs; + atomic_t n_frags; atomic_t hw_ptr; wait_queue_head_t wait; @@ -246,11 +254,14 @@ struct via_channel { u8 pcm_fmt; /* VIA_PCM_FMT_xxx */ unsigned rate; /* sample rate */ + unsigned int frag_size; + unsigned int frag_number; volatile struct via_sgd_table *sgtable; dma_addr_t sgt_handle; - struct via_sgd_data sgbuf [VIA_DMA_BUFFERS]; + unsigned int page_number; + struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES]; long iobase; @@ -301,17 +312,16 @@ static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wa static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int via_dsp_open (struct inode *inode, struct file *file); static int via_dsp_release(struct inode *inode, struct file *file); -#ifdef VIA_SUPPORT_MMAP static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma); -#endif static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg); static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value); static u8 via_ac97_wait_idle (struct via_info *card); static void via_chan_free (struct via_info *card, struct via_channel *chan); -static void via_chan_clear (struct via_channel *chan); +static void via_chan_clear (struct via_info *card, struct via_channel *chan); static void via_chan_pcm_fmt (struct via_channel *chan, int reset); +static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan); #ifdef VIA_PROC_FS static int via_init_proc (void); @@ -569,25 +579,53 @@ static void via_chan_init_defaults (struct via_info *card, struct via_channel *c chan->pcm_fmt = VIA_PCM_FMT_MASK; chan->is_enabled = 1; - if (chan->is_record) - atomic_set (&chan->n_bufs, 0); - else - atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS); + chan->frag_number = 0; + chan->frag_size = 0; + atomic_set(&chan->n_frags, 0); atomic_set (&chan->hw_ptr, 0); } +/** + * via_chan_init - Initialize PCM channel + * @card: Private audio chip info + * @chan: Channel to be initialized + * + * Performs some of the preparations necessary to begin + * using a PCM channel. + * + * Currently the preparations consist in + * setting the + * PCM channel to a known state. + */ + + +static void via_chan_init (struct via_info *card, struct via_channel *chan) +{ + + DPRINTK ("ENTER\n"); + + /* bzero channel structure, and init members to defaults */ + via_chan_init_defaults (card, chan); + + /* stop any existing channel output */ + via_chan_clear (card, chan); + via_chan_status_clear (chan->iobase); + via_chan_pcm_fmt (chan, 1); + + DPRINTK ("EXIT\n"); +} /** - * via_chan_init - Initialize PCM channel + * via_chan_buffer_init - Initialize PCM channel buffer * @card: Private audio chip info * @chan: Channel to be initialized * - * Performs all the preparations necessary to begin + * Performs some of the preparations necessary to begin * using a PCM channel. * * Currently the preparations include allocating the - * scatter-gather DMA table and buffers, setting the - * PCM channel to a known state, and passing the + * scatter-gather DMA table and buffers, + * and passing the * address of the DMA table to the hardware. * * Note that special care is taken when passing the @@ -596,18 +634,21 @@ static void via_chan_init_defaults (struct via_info *card, struct via_channel *c * always "take" the address. */ -static int via_chan_init (struct via_info *card, struct via_channel *chan) +static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan) { + int page, offset; int i; DPRINTK ("ENTER\n"); - /* bzero channel structure, and init members to defaults */ - via_chan_init_defaults (card, chan); + if (chan->sgtable != NULL) { + DPRINTK ("EXIT\n"); + return 0; + } /* alloc DMA-able memory for scatter-gather table */ chan->sgtable = pci_alloc_consistent (card->pdev, - (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS), + (sizeof (struct via_sgd_table) * chan->frag_number), &chan->sgt_handle); if (!chan->sgtable) { printk (KERN_ERR PFX "DMA table alloc fail, aborting\n"); @@ -616,45 +657,54 @@ static int via_chan_init (struct via_info *card, struct via_channel *chan) } memset ((void*)chan->sgtable, 0, - (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS)); + (sizeof (struct via_sgd_table) * chan->frag_number)); /* alloc DMA-able memory for scatter-gather buffers */ - for (i = 0; i < VIA_DMA_BUFFERS; i++) { - chan->sgbuf[i].cpuaddr = - pci_alloc_consistent (card->pdev, VIA_DMA_BUF_SIZE, - &chan->sgbuf[i].handle); - if (!chan->sgbuf[i].cpuaddr) - goto err_out_nomem; + chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE + + (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0); + + for (i = 0; i < chan->page_number; i++) { + chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE, + &chan->pgtbl[i].handle); - if (i < (VIA_DMA_BUFFERS - 1)) - chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG); - else - chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL); - chan->sgtable[i].addr = cpu_to_le32 (chan->sgbuf[i].handle); + if (!chan->pgtbl[i].cpuaddr) { + chan->page_number = i; + goto err_out_nomem; + } #ifndef VIA_NDEBUG - memset (chan->sgbuf[i].cpuaddr, 0xBC, VIA_DMA_BUF_SIZE); + memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size); #endif #if 1 - DPRINTK ("dmabuf #%d (h=%lx, 32(h)=%lx, v2p=%lx, a=%p)\n", - i, (long)chan->sgbuf[i].handle, - (long)chan->sgtable[i].addr, - virt_to_phys(chan->sgbuf[i].cpuaddr), - chan->sgbuf[i].cpuaddr); + DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n", + i, (long)chan->pgtbl[i].handle, + virt_to_phys(chan->pgtbl[i].cpuaddr), + chan->pgtbl[i].cpuaddr); #endif - - assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0); } - /* stop any existing channel output */ - via_chan_clear (chan); - via_chan_status_clear (chan->iobase); - via_chan_pcm_fmt (chan, 1); + for (i = 0; i < chan->frag_number; i++) { + + page = i / (PAGE_SIZE / chan->frag_size); + offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size; + + chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG); + chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset); + +#if 1 + DPRINTK ("dmabuf #%d (32(h)=%lx)\n", + i, + (long)chan->sgtable[i].addr); +#endif + } + + /* overwrite the last buffer information */ + chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL); /* set location of DMA-able scatter-gather info table */ - DPRINTK("outl (0x%X, 0x%04lX)\n", + DPRINTK ("outl (0x%X, 0x%04lX)\n", cpu_to_le32 (chan->sgt_handle), chan->iobase + VIA_PCM_TABLE_ADDR); @@ -664,7 +714,7 @@ static int via_chan_init (struct via_info *card, struct via_channel *chan) udelay (20); via_ac97_wait_idle (card); - DPRINTK("inl (0x%lX) = %x\n", + DPRINTK ("inl (0x%lX) = %x\n", chan->iobase + VIA_PCM_TABLE_ADDR, inl(chan->iobase + VIA_PCM_TABLE_ADDR)); @@ -673,7 +723,7 @@ static int via_chan_init (struct via_info *card, struct via_channel *chan) err_out_nomem: printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n"); - via_chan_free (card, chan); + via_chan_buffer_free (card, chan); DPRINTK ("EXIT\n"); return -ENOMEM; } @@ -695,8 +745,6 @@ err_out_nomem: static void via_chan_free (struct via_info *card, struct via_channel *chan) { - int i; - DPRINTK ("ENTER\n"); synchronize_irq(); @@ -710,23 +758,33 @@ static void via_chan_free (struct via_info *card, struct via_channel *chan) spin_unlock_irq (&card->lock); + DPRINTK ("EXIT\n"); +} + +static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan) +{ + int i; + + DPRINTK ("ENTER\n"); + /* zero location of DMA-able scatter-gather info table */ via_ac97_wait_idle(card); outl (0, chan->iobase + VIA_PCM_TABLE_ADDR); - for (i = 0; i < VIA_DMA_BUFFERS; i++) - if (chan->sgbuf[i].cpuaddr) { - assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0); - pci_free_consistent (card->pdev, VIA_DMA_BUF_SIZE, - chan->sgbuf[i].cpuaddr, - chan->sgbuf[i].handle); - chan->sgbuf[i].cpuaddr = NULL; - chan->sgbuf[i].handle = 0; + for (i = 0; i < chan->page_number; i++) + if (chan->pgtbl[i].cpuaddr) { + pci_free_consistent (card->pdev, PAGE_SIZE, + chan->pgtbl[i].cpuaddr, + chan->pgtbl[i].handle); + chan->pgtbl[i].cpuaddr = NULL; + chan->pgtbl[i].handle = 0; } + chan->page_number = 0; + if (chan->sgtable) { pci_free_consistent (card->pdev, - (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS), + (sizeof (struct via_sgd_table) * chan->frag_number), (void*)chan->sgtable, chan->sgt_handle); chan->sgtable = NULL; } @@ -771,11 +829,11 @@ static void via_chan_pcm_fmt (struct via_channel *chan, int reset) if (!chan->is_record) chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT; - outb (chan->pcm_fmt, chan->iobase + 2); + outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE); DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n", chan->pcm_fmt, - inb (chan->iobase + 2)); + inb (chan->iobase + VIA_PCM_TYPE)); } @@ -787,10 +845,11 @@ static void via_chan_pcm_fmt (struct via_channel *chan, int reset) * all software pointers which track DMA operation. */ -static void via_chan_clear (struct via_channel *chan) +static void via_chan_clear (struct via_info *card, struct via_channel *chan) { DPRINTK ("ENTER\n"); via_chan_stop (chan->iobase); + via_chan_buffer_free(card, chan); chan->is_active = 0; chan->is_mapped = 0; chan->is_enabled = 1; @@ -798,10 +857,6 @@ static void via_chan_clear (struct via_channel *chan) chan->sw_ptr = 0; chan->n_irqs = 0; atomic_set (&chan->hw_ptr, 0); - if (chan->is_record) - atomic_set (&chan->n_bufs, 0); - else - atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS); DPRINTK ("EXIT\n"); } @@ -826,7 +881,7 @@ static int via_chan_set_speed (struct via_info *card, { DPRINTK ("ENTER, requested rate = %d\n", val); - via_chan_clear (chan); + via_chan_clear (card, chan); val = via_set_rate (&card->ac97, chan, val); @@ -858,7 +913,7 @@ static int via_chan_set_fmt (struct via_info *card, val == AFMT_S16_LE ? "AFMT_S16_LE" : "unknown"); - via_chan_clear (chan); + via_chan_clear (card, chan); assert (val != AFMT_QUERY); /* this case is handled elsewhere */ @@ -907,7 +962,7 @@ static int via_chan_set_stereo (struct via_info *card, { DPRINTK ("ENTER, channels = %d\n", val); - via_chan_clear (chan); + via_chan_clear (card, chan); switch (val) { @@ -934,6 +989,78 @@ static int via_chan_set_stereo (struct via_info *card, return val; } +static int via_chan_set_buffering (struct via_info *card, + struct via_channel *chan, int val) +{ + int shift; + + DPRINTK ("ENTER\n"); + + /* in both cases the buffer cannot be changed */ + if (chan->is_active || chan->is_mapped) { + DPRINTK ("EXIT\n"); + return -EINVAL; + } + + /* called outside SETFRAGMENT */ + /* set defaults or do nothing */ + if (val < 0) { + + if (chan->frag_size && chan->frag_number) + goto out; + + DPRINTK ("\n"); + + chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * + ((chan->pcm_fmt & VIA_PCM_FMT_STEREO) ? 2 : 1) * + ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1; + + shift = 0; + while (chan->frag_size) { + chan->frag_size >>= 1; + shift++; + } + chan->frag_size = 1 << shift; + + chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME); + + DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number); + } else { + chan->frag_size = 1 << (val & 0xFFFF); + chan->frag_number = (val >> 16) & 0xFFFF; + + DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number); + } + + /* quake3 wants frag_number to be a power of two */ + shift = 0; + while (chan->frag_number) { + chan->frag_number >>= 1; + shift++; + } + chan->frag_number = 1 << shift; + + if (chan->frag_size > VIA_MAX_FRAG_SIZE) + chan->frag_size = VIA_MAX_FRAG_SIZE; + else if (chan->frag_size < VIA_MIN_FRAG_SIZE) + chan->frag_size = VIA_MIN_FRAG_SIZE; + + if (chan->frag_number < VIA_MIN_FRAG_NUMBER) + chan->frag_number = VIA_MIN_FRAG_NUMBER; + + if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES) + chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size; + +out: + if (chan->is_record) + atomic_set (&chan->n_frags, 0); + else + atomic_set (&chan->n_frags, chan->frag_number); + + DPRINTK ("EXIT\n"); + + return 0; +} #ifdef VIA_CHAN_DUMP_BUFS /** @@ -948,7 +1075,7 @@ static void via_chan_dump_bufs (struct via_channel *chan) { int i; - for (i = 0; i < VIA_DMA_BUFFERS; i++) { + for (i = 0; i < chan->frag_number; i++) { DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n", i, chan->sgtable[i].addr, chan->sgtable[i].count & 0x00FFFFFF, @@ -975,15 +1102,15 @@ static void via_chan_flush_frag (struct via_channel *chan) assert (chan->slop_len > 0); - if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1)) + if (chan->sw_ptr == (chan->frag_number - 1)) chan->sw_ptr = 0; else chan->sw_ptr++; chan->slop_len = 0; - assert (atomic_read (&chan->n_bufs) > 0); - atomic_dec (&chan->n_bufs); + assert (atomic_read (&chan->n_frags) > 0); + atomic_dec (&chan->n_frags); DPRINTK ("EXIT\n"); } @@ -1003,7 +1130,7 @@ static inline void via_chan_maybe_start (struct via_channel *chan) if (!chan->is_active && chan->is_enabled) { chan->is_active = 1; sg_begin (chan); - DPRINTK("starting channel %s\n", chan->name); + DPRINTK ("starting channel %s\n", chan->name); } } @@ -1213,7 +1340,7 @@ static loff_t via_llseek(struct file *file, loff_t offset, int origin) { DPRINTK ("ENTER\n"); - DPRINTK("EXIT, returning -ESPIPE\n"); + DPRINTK ("EXIT, returning -ESPIPE\n"); return -ESPIPE; } @@ -1245,7 +1372,7 @@ static int __init via_ac97_reset (struct via_info *card) pci_read_config_byte (card->pdev, 0x43, &r43); pci_read_config_byte (card->pdev, 0x44, &r44); pci_read_config_byte (card->pdev, 0x48, &r48); - DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n", + DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n", r40,r41,r42,r43,r44,r48); spin_lock_irq (&card->lock); @@ -1334,7 +1461,7 @@ static int __init via_ac97_init (struct via_info *card) card->ac97.dev_mixer = register_sound_mixer (&via_mixer_fops, -1); if (card->ac97.dev_mixer < 0) { printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n"); - DPRINTK("EXIT, returning -EIO\n"); + DPRINTK ("EXIT, returning -EIO\n"); return -EIO; } @@ -1359,21 +1486,21 @@ static int __init via_ac97_init (struct via_info *card) err_out: unregister_sound_mixer (card->ac97.dev_mixer); - DPRINTK("EXIT, returning %d\n", rc); + DPRINTK ("EXIT, returning %d\n", rc); return rc; } static void via_ac97_cleanup (struct via_info *card) { - DPRINTK("ENTER\n"); + DPRINTK ("ENTER\n"); assert (card != NULL); assert (card->ac97.dev_mixer >= 0); unregister_sound_mixer (card->ac97.dev_mixer); - DPRINTK("EXIT\n"); + DPRINTK ("EXIT\n"); } @@ -1414,24 +1541,24 @@ static void via_intr_channel (struct via_channel *chan) /* sanity check: make sure our h/w ptr doesn't have a weird value */ assert (n >= 0); - assert (n < VIA_DMA_BUFFERS); + assert (n < chan->frag_number); /* reset SGD data structure in memory to reflect a full buffer, * and advance the h/w ptr, wrapping around to zero if needed */ - if (n == (VIA_DMA_BUFFERS - 1)) { - chan->sgtable[n].count = (VIA_DMA_BUF_SIZE | VIA_EOL); + if (n == (chan->frag_number - 1)) { + chan->sgtable[n].count = (chan->frag_size | VIA_EOL); atomic_set (&chan->hw_ptr, 0); } else { - chan->sgtable[n].count = (VIA_DMA_BUF_SIZE | VIA_FLAG); + chan->sgtable[n].count = (chan->frag_size | VIA_FLAG); atomic_inc (&chan->hw_ptr); } /* accounting crap for SNDCTL_DSP_GETxPTR */ chan->n_irqs++; - chan->bytes += VIA_DMA_BUF_SIZE; + chan->bytes += chan->frag_size; if (chan->bytes < 0) /* handle overflow of 31-bit value */ - chan->bytes = VIA_DMA_BUF_SIZE; + chan->bytes = chan->frag_size; /* wake up anyone listening to see when interrupts occur */ if (waitqueue_active (&chan->wait)) @@ -1445,25 +1572,25 @@ static void via_intr_channel (struct via_channel *chan) if (chan->is_mapped) return; - /* If we are recording, then n_bufs represents the number - * of buffers waiting to be handled by userspace. - * If we are playback, then n_bufs represents the number - * of buffers remaining to be filled by userspace. - * We increment here. If we reach max buffers (VIA_DMA_BUFFERS), + /* If we are recording, then n_frags represents the number + * of fragments waiting to be handled by userspace. + * If we are playback, then n_frags represents the number + * of fragments remaining to be filled by userspace. + * We increment here. If we reach max number of fragments, * this indicates an underrun/overrun. For this case under OSS, * we stop the record/playback process. */ - if (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS) - atomic_inc (&chan->n_bufs); - assert (atomic_read (&chan->n_bufs) <= VIA_DMA_BUFFERS); + if (atomic_read (&chan->n_frags) < chan->frag_number) + atomic_inc (&chan->n_frags); + assert (atomic_read (&chan->n_frags) <= chan->frag_number); - if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS) { + if (atomic_read (&chan->n_frags) == chan->frag_number) { chan->is_active = 0; via_chan_stop (chan->iobase); } - DPRINTK ("%s intr, channel n_bufs == %d\n", chan->name, - atomic_read (&chan->n_bufs)); + DPRINTK ("%s intr, channel n_frags == %d\n", chan->name, + atomic_read (&chan->n_frags)); } @@ -1618,9 +1745,7 @@ static struct file_operations via_dsp_fops = { poll: via_dsp_poll, llseek: via_llseek, ioctl: via_dsp_ioctl, -#ifdef VIA_SUPPORT_MMAP mmap: via_dsp_mmap, -#endif }; @@ -1668,7 +1793,6 @@ static void via_dsp_cleanup (struct via_info *card) } -#ifdef VIA_SUPPORT_MMAP static struct page * via_mm_nopage (struct vm_area_struct * vma, unsigned long address, int write_access) { @@ -1685,8 +1809,6 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, address, write_access); - assert (VIA_DMA_BUF_SIZE == PAGE_SIZE); - if (address > vma->vm_end) { DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n"); return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -1702,7 +1824,7 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, #ifndef VIA_NDEBUG { - unsigned long max_bufs = VIA_DMA_BUFFERS; + unsigned long max_bufs = chan->frag_number; if (rd && wr) max_bufs *= 2; /* via_dsp_mmap() should ensure this */ assert (pgoff < max_bufs); @@ -1711,17 +1833,17 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, /* if full-duplex (read+write) and we have two sets of bufs, * then the playback buffers come first, sez soundcard.c */ - if (pgoff >= VIA_DMA_BUFFERS) { - pgoff -= VIA_DMA_BUFFERS; + if (pgoff >= chan->page_number) { + pgoff -= chan->page_number; chan = &card->ch_in; } else if (!wr) chan = &card->ch_in; - assert ((((unsigned long)chan->sgbuf[pgoff].cpuaddr) % PAGE_SIZE) == 0); + assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0); - dmapage = virt_to_page (chan->sgbuf[pgoff].cpuaddr); + dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr); DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n", - dmapage, (unsigned long) chan->sgbuf[pgoff].cpuaddr); + dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr); get_page (dmapage); return dmapage; } @@ -1761,16 +1883,18 @@ static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_end - vma->vm_start, vma->vm_pgoff); - assert (VIA_DMA_BUF_SIZE == PAGE_SIZE); - max_size = 0; - if (file->f_mode & FMODE_READ) { + if (vma->vm_flags & VM_READ) { rd = 1; - max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE); + via_chan_set_buffering(card, &card->ch_in, -1); + via_chan_buffer_init (card, &card->ch_in); + max_size += card->ch_in.page_number << PAGE_SHIFT; } - if (file->f_mode & FMODE_WRITE) { + if (vma->vm_flags & VM_WRITE) { wr = 1; - max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE); + via_chan_set_buffering(card, &card->ch_out, -1); + via_chan_buffer_init (card, &card->ch_out); + max_size += card->ch_out.page_number << PAGE_SHIFT; } start = vma->vm_start; @@ -1802,10 +1926,9 @@ static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma) rc = 0; out: - DPRINTK("EXIT, returning %d\n", rc); + DPRINTK ("EXIT, returning %d\n", rc); return rc; } -#endif /* VIA_SUPPORT_MMAP */ static ssize_t via_dsp_do_read (struct via_info *card, @@ -1831,13 +1954,13 @@ handle_one_block: */ n = chan->sw_ptr; - /* n_bufs represents the number of buffers waiting + /* n_frags represents the number of fragments waiting * to be copied to userland. sleep until at least * one buffer has been read from the audio hardware. */ - tmp = atomic_read (&chan->n_bufs); + tmp = atomic_read (&chan->n_frags); assert (tmp >= 0); - assert (tmp <= VIA_DMA_BUFFERS); + assert (tmp <= chan->frag_number); while (tmp == 0) { if (nonblock || !chan->is_active) return -EAGAIN; @@ -1848,18 +1971,18 @@ handle_one_block: if (signal_pending (current)) return -ERESTARTSYS; - tmp = atomic_read (&chan->n_bufs); + tmp = atomic_read (&chan->n_frags); } /* Now that we have a buffer we can read from, send * as much as sample data possible to userspace. */ - while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) { - size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len; + while ((count > 0) && (chan->slop_len < chan->frag_size)) { + size_t slop_left = chan->frag_size - chan->slop_len; size = (count < slop_left) ? count : slop_left; if (copy_to_user (userbuf, - chan->sgbuf[n].cpuaddr + chan->slop_len, + chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + n % (PAGE_SIZE / chan->frag_size) + chan->slop_len, size)) return -EFAULT; @@ -1871,7 +1994,7 @@ handle_one_block: /* If we didn't copy the buffer completely to userspace, * stop now. */ - if (chan->slop_len < VIA_DMA_BUF_SIZE) + if (chan->slop_len < chan->frag_size) goto out; /* @@ -1882,20 +2005,20 @@ handle_one_block: /* advance channel software pointer to point to * the next buffer from which we will copy */ - if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1)) + if (chan->sw_ptr == (chan->frag_number - 1)) chan->sw_ptr = 0; else chan->sw_ptr++; /* mark one less buffer waiting to be processed */ - assert (atomic_read (&chan->n_bufs) > 0); - atomic_dec (&chan->n_bufs); + assert (atomic_read (&chan->n_frags) > 0); + atomic_dec (&chan->n_frags); /* we are at a block boundary, there is no fragment data */ chan->slop_len = 0; - DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n", - n, chan->sw_ptr, atomic_read (&chan->n_bufs)); + DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n", + n, chan->sw_ptr, atomic_read (&chan->n_frags)); DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", inb (card->baseaddr + 0x00), @@ -1941,12 +2064,18 @@ static ssize_t via_dsp_read(struct file *file, char *buffer, size_t count, loff_ goto out_up; } + via_chan_set_buffering(card, &card->ch_in, -1); + rc = via_chan_buffer_init (card, &card->ch_in); + + if (rc) + goto out_up; + rc = via_dsp_do_read (card, buffer, count, nonblock); out_up: up (&card->syscall_sem); out: - DPRINTK("EXIT, returning %ld\n",(long) rc); + DPRINTK ("EXIT, returning %ld\n",(long) rc); return rc; } @@ -1966,40 +2095,40 @@ handle_one_block: if (current->need_resched) schedule (); - /* grab current channel software pointer. In the case of - * playback, this is pointing to the next buffer that + /* grab current channel fragment pointer. In the case of + * playback, this is pointing to the next fragment that * should receive data from userland. */ n = chan->sw_ptr; - /* n_bufs represents the number of buffers remaining + /* n_frags represents the number of fragments remaining * to be filled by userspace. Sleep until - * at least one buffer is available for our use. + * at least one fragment is available for our use. */ - tmp = atomic_read (&chan->n_bufs); + tmp = atomic_read (&chan->n_frags); assert (tmp >= 0); - assert (tmp <= VIA_DMA_BUFFERS); + assert (tmp <= chan->frag_number); while (tmp == 0) { if (nonblock || !chan->is_enabled) return -EAGAIN; - DPRINTK ("Sleeping on block %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record); + DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record); interruptible_sleep_on (&chan->wait); if (signal_pending (current)) return -ERESTARTSYS; - tmp = atomic_read (&chan->n_bufs); + tmp = atomic_read (&chan->n_frags); } - /* Now that we have a buffer we can write to, fill it up + /* Now that we have at least one fragment we can write to, fill the buffer * as much as possible with data from userspace. */ - while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) { - size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len; + while ((count > 0) && (chan->slop_len < chan->frag_size)) { + size_t slop_left = chan->frag_size - chan->slop_len; size = (count < slop_left) ? count : slop_left; - if (copy_from_user (chan->sgbuf[n].cpuaddr + chan->slop_len, + if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len, userbuf, size)) return -EFAULT; @@ -2009,36 +2138,36 @@ handle_one_block: } /* If we didn't fill up the buffer with data, stop now. - * Put a 'stop' marker in the DMA table too, to tell the - * audio hardware to stop if it gets here. - */ - if (chan->slop_len < VIA_DMA_BUF_SIZE) { + * Put a 'stop' marker in the DMA table too, to tell the + * audio hardware to stop if it gets here. + */ + if (chan->slop_len < chan->frag_size) { sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP); goto out; } /* - * If we get to this point, we have filled a buffer with - * audio data, flush the buffer to audio hardware. - */ + * If we get to this point, we have filled a buffer with + * audio data, flush the buffer to audio hardware. + */ /* Record the true size for the audio hardware to notice */ - if (n == (VIA_DMA_BUFFERS - 1)) - sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL); - else - sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG); + if (n == (chan->frag_number - 1)) + sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL); + else + sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG); /* advance channel software pointer to point to * the next buffer we will fill with data */ - if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1)) + if (chan->sw_ptr == (chan->frag_number - 1)) chan->sw_ptr = 0; else chan->sw_ptr++; /* mark one less buffer as being available for userspace consumption */ - assert (atomic_read (&chan->n_bufs) > 0); - atomic_dec (&chan->n_bufs); + assert (atomic_read (&chan->n_frags) > 0); + atomic_dec (&chan->n_frags); /* we are at a block boundary, there is no fragment data */ chan->slop_len = 0; @@ -2046,8 +2175,8 @@ handle_one_block: /* if SGD has not yet been started, start it */ via_chan_maybe_start (chan); - DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n", - n, chan->sw_ptr, atomic_read (&chan->n_bufs)); + DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n", + n, chan->sw_ptr, atomic_read (&chan->n_frags)); DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", inb (card->baseaddr + 0x00), @@ -2093,12 +2222,18 @@ static ssize_t via_dsp_write(struct file *file, const char *buffer, size_t count goto out_up; } + via_chan_set_buffering(card, &card->ch_out, -1); + rc = via_chan_buffer_init (card, &card->ch_out); + + if (rc) + goto out_up; + rc = via_dsp_do_write (card, buffer, count, nonblock); out_up: up (&card->syscall_sem); out: - DPRINTK("EXIT, returning %ld\n",(long) rc); + DPRINTK ("EXIT, returning %ld\n",(long) rc); return rc; } @@ -2117,23 +2252,27 @@ static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wa rd = (file->f_mode & FMODE_READ); wr = (file->f_mode & FMODE_WRITE); - if (wr && (atomic_read (&card->ch_out.n_bufs) == 0)) { + if (wr && (atomic_read (&card->ch_out.n_frags) == 0)) { assert (card->ch_out.is_active); poll_wait(file, &card->ch_out.wait, wait); } if (rd) { /* XXX is it ok, spec-wise, to start DMA here? */ + if (!card->ch_in.is_active) { + via_chan_set_buffering(card, &card->ch_in, -1); + via_chan_buffer_init(card, &card->ch_in); + } via_chan_maybe_start (&card->ch_in); - if (atomic_read (&card->ch_in.n_bufs) == 0) + if (atomic_read (&card->ch_in.n_frags) == 0) poll_wait(file, &card->ch_in.wait, wait); } - if (wr && (atomic_read (&card->ch_out.n_bufs) > 0)) + if (wr && ((atomic_read (&card->ch_out.n_frags) > 0) || !card->ch_out.is_active)) mask |= POLLOUT | POLLWRNORM; - if (rd && (atomic_read (&card->ch_in.n_bufs) > 0)) + if (rd && (atomic_read (&card->ch_in.n_frags) > 0)) mask |= POLLIN | POLLRDNORM; - DPRINTK("EXIT, returning %u\n", mask); + DPRINTK ("EXIT, returning %u\n", mask); return mask; } @@ -2158,12 +2297,12 @@ static int via_dsp_drain_playback (struct via_info *card, if (chan->slop_len > 0) via_chan_flush_frag (chan); - if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS) + if (atomic_read (&chan->n_frags) == chan->frag_number) goto out; via_chan_maybe_start (chan); - while (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS) { + while (atomic_read (&chan->n_frags) < chan->frag_number) { if (nonblock) { DPRINTK ("EXIT, returning -EAGAIN\n"); return -EAGAIN; @@ -2178,7 +2317,7 @@ static int via_dsp_drain_playback (struct via_info *card, pci_read_config_byte (card->pdev, 0x43, &r43); pci_read_config_byte (card->pdev, 0x44, &r44); pci_read_config_byte (card->pdev, 0x48, &r48); - DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n", + DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n", r40,r41,r42,r43,r44,r48); DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", @@ -2195,7 +2334,7 @@ static int via_dsp_drain_playback (struct via_info *card, printk (KERN_ERR "sleeping but not active\n"); #endif - DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_bufs)); + DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags)); interruptible_sleep_on (&chan->wait); if (signal_pending (current)) { @@ -2213,7 +2352,7 @@ static int via_dsp_drain_playback (struct via_info *card, pci_read_config_byte (card->pdev, 0x43, &r43); pci_read_config_byte (card->pdev, 0x44, &r44); pci_read_config_byte (card->pdev, 0x48, &r48); - DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n", + DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n", r40,r41,r42,r43,r44,r48); DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", @@ -2225,7 +2364,7 @@ static int via_dsp_drain_playback (struct via_info *card, inl (card->baseaddr + 0x80), inl (card->baseaddr + 0x84)); - DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_bufs)); + DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags)); } #endif @@ -2252,21 +2391,23 @@ static int via_dsp_ioctl_space (struct via_info *card, { audio_buf_info info; - info.fragstotal = VIA_DMA_BUFFERS; - info.fragsize = VIA_DMA_BUF_SIZE; + via_chan_set_buffering(card, chan, -1); + + info.fragstotal = chan->frag_number; + info.fragsize = chan->frag_size; /* number of full fragments we can read/write without blocking */ - info.fragments = atomic_read (&chan->n_bufs); + info.fragments = atomic_read (&chan->n_frags); - if ((chan->slop_len > 0) && (info.fragments > 0)) + if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0)) info.fragments--; /* number of bytes that can be read or written immediately * without blocking. */ - info.bytes = (info.fragments * VIA_DMA_BUF_SIZE); - if (chan->slop_len > 0) - info.bytes += VIA_DMA_BUF_SIZE - chan->slop_len; + info.bytes = (info.fragments * chan->frag_size); + if (chan->slop_len % chan->frag_size > 0) + info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size); DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n", info.fragstotal, @@ -2305,8 +2446,8 @@ static int via_dsp_ioctl_ptr (struct via_info *card, if (chan->is_active) { unsigned long extra; - info.ptr = atomic_read (&chan->hw_ptr) * VIA_DMA_BUF_SIZE; - extra = VIA_DMA_BUF_SIZE - inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT); + info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size; + extra = chan->frag_size - inl (chan->iobase + VIA_PCM_BLOCK_COUNT); info.ptr += extra; info.bytes += extra; } else { @@ -2386,13 +2527,13 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, /* OSS API version. XXX unverified */ case OSS_GETVERSION: - DPRINTK("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n"); + DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n"); rc = put_user (SOUND_VERSION, (int *)arg); break; /* list of supported PCM data formats */ case SNDCTL_DSP_GETFMTS: - DPRINTK("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n"); + DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n"); rc = put_user (AFMT_U8 | AFMT_S16_LE, (int *)arg); break; @@ -2402,20 +2543,19 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = -EFAULT; break; } - DPRINTK("DSP_SETFMT, val==%d\n", val); + DPRINTK ("DSP_SETFMT, val==%d\n", val); if (val != AFMT_QUERY) { rc = 0; - if (rc == 0 && rd) + if (rd) rc = via_chan_set_fmt (card, &card->ch_in, val); - if (rc == 0 && wr) + + if (rc >= 0 && wr) rc = via_chan_set_fmt (card, &card->ch_out, val); - if (rc <= 0) { - if (rc == 0) - rc = -EINVAL; + if (rc < 0) break; - } + val = rc; } else { if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) || @@ -2424,7 +2564,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, else val = AFMT_U8; } - DPRINTK("SETFMT EXIT, returning %d\n", val); + DPRINTK ("SETFMT EXIT, returning %d\n", val); rc = put_user (val, (int *)arg); break; @@ -2434,18 +2574,19 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = -EFAULT; break; } - DPRINTK("DSP_CHANNELS, val==%d\n", val); + DPRINTK ("DSP_CHANNELS, val==%d\n", val); if (val != 0) { rc = 0; - if (rc == 0 && rd) + + if (rd) rc = via_chan_set_stereo (card, &card->ch_in, val); - if (rc == 0 && wr) + + if (rc >= 0 && wr) rc = via_chan_set_stereo (card, &card->ch_out, val); - if (rc <= 0) { - if (rc == 0) - rc = -EINVAL; + + if (rc < 0) break; - } + val = rc; } else { if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) || @@ -2454,7 +2595,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, else val = 1; } - DPRINTK("CHANNELS EXIT, returning %d\n", val); + DPRINTK ("CHANNELS EXIT, returning %d\n", val); rc = put_user (val, (int *)arg); break; @@ -2464,21 +2605,21 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = -EFAULT; break; } - DPRINTK("DSP_STEREO, val==%d\n", val); + DPRINTK ("DSP_STEREO, val==%d\n", val); rc = 0; - if (rc == 0 && rd) + if (rd) rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1); - if (rc == 0 && wr) + if (rc >= 0 && wr) rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1); - if (rc <= 0) { - if (rc == 0) - rc = -EINVAL; + if (rc < 0) break; - } - DPRINTK("STEREO EXIT, returning %d\n", val); - rc = 0; + + val = rc - 1; + + DPRINTK ("STEREO EXIT, returning %d\n", val); + rc = put_user(val, (int *) arg); break; /* query or set sampling rate */ @@ -2487,7 +2628,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = -EFAULT; break; } - DPRINTK("DSP_SPEED, val==%d\n", val); + DPRINTK ("DSP_SPEED, val==%d\n", val); if (val < 0) { rc = -EINVAL; break; @@ -2495,16 +2636,14 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, if (val > 0) { rc = 0; - if (rc == 0 && rd) + if (rd) rc = via_chan_set_speed (card, &card->ch_in, val); - if (rc == 0 && wr) + if (rc >= 0 && wr) rc = via_chan_set_speed (card, &card->ch_out, val); - if (rc <= 0) { - if (rc == 0) - rc = -EINVAL; + if (rc < 0) break; - } + val = rc; } else { if (rd) @@ -2514,7 +2653,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, else val = 0; } - DPRINTK("SPEED EXIT, returning %d\n", val); + DPRINTK ("SPEED EXIT, returning %d\n", val); rc = put_user (val, (int *)arg); break; @@ -2522,7 +2661,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, case SNDCTL_DSP_SYNC: DPRINTK ("DSP_SYNC\n"); if (wr) { - DPRINTK("SYNC EXIT (after calling via_dsp_drain_playback)\n"); + DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n"); rc = via_dsp_drain_playback (card, &card->ch_out, nonblock); } break; @@ -2531,12 +2670,19 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, case SNDCTL_DSP_RESET: DPRINTK ("DSP_RESET\n"); if (rd) { - via_chan_clear (&card->ch_in); + via_chan_clear (card, &card->ch_in); via_chan_pcm_fmt (&card->ch_in, 1); + card->ch_in.frag_number = 0; + card->ch_in.frag_size = 0; + atomic_set(&card->ch_in.n_frags, 0); } + if (wr) { - via_chan_clear (&card->ch_out); + via_chan_clear (card, &card->ch_out); via_chan_pcm_fmt (&card->ch_out, 1); + card->ch_out.frag_number = 0; + card->ch_out.frag_size = 0; + atomic_set(&card->ch_out.n_frags, 0); } rc = 0; @@ -2544,40 +2690,47 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ case SNDCTL_DSP_GETCAPS: - DPRINTK("DSP_GETCAPS\n"); + DPRINTK ("DSP_GETCAPS\n"); rc = put_user(VIA_DSP_CAP, (int *)arg); break; - /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ + /* obtain buffer fragment size */ case SNDCTL_DSP_GETBLKSIZE: - DPRINTK("DSP_GETBLKSIZE\n"); - rc = put_user(VIA_DMA_BUF_SIZE, (int *)arg); + DPRINTK ("DSP_GETBLKSIZE\n"); + + if (rd) { + via_chan_set_buffering(card, &card->ch_in, -1); + rc = put_user(card->ch_in.frag_size, (int *)arg); + } else if (wr) { + via_chan_set_buffering(card, &card->ch_out, -1); + rc = put_user(card->ch_out.frag_size, (int *)arg); + } break; /* obtain information about input buffering */ case SNDCTL_DSP_GETISPACE: - DPRINTK("DSP_GETISPACE\n"); + DPRINTK ("DSP_GETISPACE\n"); if (rd) rc = via_dsp_ioctl_space (card, &card->ch_in, (void*) arg); break; /* obtain information about output buffering */ case SNDCTL_DSP_GETOSPACE: - DPRINTK("DSP_GETOSPACE\n"); + DPRINTK ("DSP_GETOSPACE\n"); if (wr) rc = via_dsp_ioctl_space (card, &card->ch_out, (void*) arg); break; /* obtain information about input hardware pointer */ case SNDCTL_DSP_GETIPTR: - DPRINTK("DSP_GETIPTR\n"); + DPRINTK ("DSP_GETIPTR\n"); if (rd) rc = via_dsp_ioctl_ptr (card, &card->ch_in, (void*) arg); break; /* obtain information about output hardware pointer */ case SNDCTL_DSP_GETOPTR: - DPRINTK("DSP_GETOPTR\n"); + DPRINTK ("DSP_GETOPTR\n"); if (wr) rc = via_dsp_ioctl_ptr (card, &card->ch_out, (void*) arg); break; @@ -2585,25 +2738,29 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, /* return number of bytes remaining to be played by DMA engine */ case SNDCTL_DSP_GETODELAY: { - DPRINTK("DSP_GETODELAY\n"); + DPRINTK ("DSP_GETODELAY\n"); chan = &card->ch_out; if (!wr) break; - val = VIA_DMA_BUFFERS - atomic_read (&chan->n_bufs); + if (chan->is_active) { - if (val > 0) { - val *= VIA_DMA_BUF_SIZE; - val -= VIA_DMA_BUF_SIZE - - inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT); - } - val += chan->slop_len; + val = chan->frag_number - atomic_read (&chan->n_frags); - assert (val <= (VIA_DMA_BUF_SIZE * VIA_DMA_BUFFERS)); + if (val > 0) { + val *= chan->frag_size; + val -= chan->frag_size - + inl (chan->iobase + VIA_PCM_BLOCK_COUNT); + } + val += chan->slop_len % chan->frag_size; + } else + val = 0; - DPRINTK("GETODELAY EXIT, val = %d bytes\n", val); + assert (val <= (chan->frag_size * chan->frag_number)); + + DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val); rc = put_user (val, (int *)arg); break; } @@ -2617,7 +2774,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = -EFAULT; break; } - DPRINTK("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n", + DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n", rd, wr, card->ch_in.is_active, card->ch_out.is_active, card->ch_in.is_enabled, card->ch_out.is_enabled); @@ -2625,6 +2782,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, if (rd) rc = via_dsp_ioctl_trigger (&card->ch_in, val); + if (!rc && wr) rc = via_dsp_ioctl_trigger (&card->ch_out, val); @@ -2634,7 +2792,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, * with O_RDWR, this is mainly a no-op that always returns success. */ case SNDCTL_DSP_SETDUPLEX: - DPRINTK("DSP_SETDUPLEX\n"); + DPRINTK ("DSP_SETDUPLEX\n"); if (!rd || !wr) break; rc = 0; @@ -2646,7 +2804,13 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = -EFAULT; break; } - DPRINTK("DSP_SETFRAGMENT, val==%d\n", val); + DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val); + + if (rd) + rc = via_chan_set_buffering(card, &card->ch_in, val); + + if (wr) + rc = via_chan_set_buffering(card, &card->ch_out, val); DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n", val & 0xFFFF, @@ -2654,13 +2818,12 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, (val >> 16) & 0xFFFF, (val >> 16) & 0xFFFF); - /* just to shut up some programs */ rc = 0; break; /* inform device of an upcoming pause in input (or output). */ case SNDCTL_DSP_POST: - DPRINTK("DSP_POST\n"); + DPRINTK ("DSP_POST\n"); if (wr) { if (card->ch_out.slop_len > 0) via_chan_flush_frag (&card->ch_out); @@ -2678,15 +2841,14 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, } up (&card->syscall_sem); - DPRINTK("EXIT, returning %d\n", rc); + DPRINTK ("EXIT, returning %d\n", rc); return rc; } static int via_dsp_open (struct inode *inode, struct file *file) { - int rc, minor = MINOR(inode->i_rdev); - int got_read_chan = 0; + int minor = MINOR(inode->i_rdev); struct via_info *card; struct pci_dev *pdev; struct via_channel *chan; @@ -2733,17 +2895,13 @@ match: } file->private_data = card; - DPRINTK("file->f_mode == 0x%x\n", file->f_mode); + DPRINTK ("file->f_mode == 0x%x\n", file->f_mode); /* handle input from analog source */ if (file->f_mode & FMODE_READ) { chan = &card->ch_in; - rc = via_chan_init (card, chan); - if (rc) - goto err_out; - - got_read_chan = 1; + via_chan_init (card, chan); /* why is this forced to 16-bit stereo in all drivers? */ chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO; @@ -2756,30 +2914,28 @@ match: if (file->f_mode & FMODE_WRITE) { chan = &card->ch_out; - rc = via_chan_init (card, chan); - if (rc) - goto err_out_read_chan; + via_chan_init (card, chan); - if ((minor & 0xf) == SND_DEV_DSP16) { - chan->pcm_fmt |= VIA_PCM_FMT_16BIT; - via_set_rate (&card->ac97, chan, 44100); + if (file->f_mode & FMODE_READ) { + /* if in duplex mode make the recording and playback channels + have the same settings */ + chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO; + via_chan_pcm_fmt (chan, 0); + via_set_rate (&card->ac97, chan, 44100); } else { - via_set_rate (&card->ac97, chan, 8000); + if ((minor & 0xf) == SND_DEV_DSP16) { + chan->pcm_fmt = VIA_PCM_FMT_16BIT; + via_chan_pcm_fmt (chan, 0); + via_set_rate (&card->ac97, chan, 44100); + } else { + via_chan_pcm_fmt (chan, 0); + via_set_rate (&card->ac97, chan, 8000); + } } - - via_chan_pcm_fmt (chan, 0); } DPRINTK ("EXIT, returning 0\n"); return 0; - -err_out_read_chan: - if (got_read_chan) - via_chan_free (card, &card->ch_in); -err_out: - up (&card->open_sem); - DPRINTK("ERROR EXIT, returning %d\n", rc); - return rc; } @@ -2807,15 +2963,18 @@ static int via_dsp_release(struct inode *inode, struct file *file) printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc); via_chan_free (card, &card->ch_out); + via_chan_buffer_free(card, &card->ch_out); } - if (file->f_mode & FMODE_READ) + if (file->f_mode & FMODE_READ) { via_chan_free (card, &card->ch_in); + via_chan_buffer_free (card, &card->ch_in); + } up (&card->syscall_sem); up (&card->open_sem); - DPRINTK("EXIT, returning 0\n"); + DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -2934,9 +3093,9 @@ static int __init via_init_one (struct pci_dev *pdev, const struct pci_device_id tmp &= 0xF0; tmp |= pdev->irq; pci_write_config_byte (pdev, 0x3C, tmp); - DPRINTK("new 0x3c==0x%02x\n", tmp); + DPRINTK ("new 0x3c==0x%02x\n", tmp); } else { - DPRINTK("IRQ reg 0x3c==0x%02x, irq==%d\n", + DPRINTK ("IRQ reg 0x3c==0x%02x, irq==%d\n", tmp, tmp & 0x0F); } @@ -3036,12 +3195,12 @@ static int __init init_via82cxxx_audio(void) static void __exit cleanup_via82cxxx_audio(void) { - DPRINTK("ENTER\n"); + DPRINTK ("ENTER\n"); pci_unregister_driver (&via_driver); via_cleanup_proc (); - DPRINTK("EXIT\n"); + DPRINTK ("EXIT\n"); } @@ -3133,7 +3292,7 @@ static int via_info_read_proc (char *page, char **start, off_t off, ); - DPRINTK("EXIT, returning %d\n", len); + DPRINTK ("EXIT, returning %d\n", len); return len; #undef YN diff --git a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c index a8cdc58f2..9670951f8 100644 --- a/drivers/sound/ymfpci.c +++ b/drivers/sound/ymfpci.c @@ -24,19 +24,28 @@ * * TODO: * - Use P44Slot for 44.1 playback. - * - Capture and duplex * - 96KHz playback for DVD - use pitch of 2.0. * - uLaw for Sun apps. + * : Alan says firmly "no software format conversion in kernel". * - Retain DMA buffer on close, do not wait the end of frame. * - Cleanup - * ? merge ymf_pcm and state - * ? pcm interrupt no pointer * ? underused structure members * - Remove remaining P3 tags (debug messages). * - Resolve XXX tagged questions. * - Cannot play 5133Hz. + * - 2001/01/07 Consider if we can remove voice_lock, like so: + * : Allocate/deallocate voices in open/close under semafore. + * : We access voices in interrupt, that only for pcms that open. + * voice_lock around playback_prepare closes interrupts for insane duration. + * - Revisit the way voice_alloc is done - too confusing, overcomplicated. + * Should support various channel types, however. + * - Remove prog_dmabuf from read/write, leave it in open. + * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with + * native synthesizer through a playback slot. + * - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/ioport.h> @@ -50,19 +59,19 @@ #include <asm/dma.h> #include <asm/uaccess.h> +#ifdef CONFIG_SOUND_YMFPCI_LEGACY +# include "sound_config.h" +# include "mpu401.h" +#endif #include "ymfpci.h" -#define snd_magic_cast(t, p, err) ((t *)(p)) - -/* Channels, such as play and record. I do only play a.t.m. XXX */ -#define NR_HW_CH 1 - -static int ymf_playback_trigger(ymfpci_t *codec, ymfpci_pcm_t *ypcm, int cmd); -static int ymfpci_voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, - int pair, ymfpci_voice_t **rvoice); -static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice); -static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state); -static int ymf_state_alloc(ymfpci_t *unit, int nvirt); +static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd); +static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd); +static void ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice); +static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank); +static int ymf_playback_prepare(struct ymf_state *state); +static int ymf_capture_prepare(struct ymf_state *state); +static struct ymf_state *ymf_state_alloc(ymfpci_t *unit); static LIST_HEAD(ymf_devs); @@ -87,7 +96,7 @@ MODULE_DEVICE_TABLE(pci, ymf_id_tbl); /* * Mindlessly copied from cs46xx XXX */ -extern __inline__ unsigned ld2(unsigned int x) +static inline unsigned ld2(unsigned int x) { unsigned r = 0; @@ -281,18 +290,13 @@ static void ymf_pcm_update_shift(struct ymf_pcm_format *f) f->shift++; } -/* - * Whole OSS-style DMA machinery is taken from cs46xx. - */ - /* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */ #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) #define DMABUF_MINORDER 1 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */ -static int alloc_dmabuf(struct ymf_state *state) +static int alloc_dmabuf(struct ymf_dmabuf *dmabuf) { - struct ymf_dmabuf *dmabuf = &state->dmabuf; void *rawbuf = NULL; int order; struct page * map, * mapend; @@ -323,9 +327,8 @@ static int alloc_dmabuf(struct ymf_state *state) } /* free DMA buffer */ -static void dealloc_dmabuf(struct ymf_state *state) +static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf) { - struct ymf_dmabuf *dmabuf = &state->dmabuf; struct page *map, *mapend; if (dmabuf->rawbuf) { @@ -339,9 +342,9 @@ static void dealloc_dmabuf(struct ymf_state *state) dmabuf->mapped = dmabuf->ready = 0; } -static int prog_dmabuf(struct ymf_state *state, unsigned rec) +static int prog_dmabuf(struct ymf_state *state, int rec) { - struct ymf_dmabuf *dmabuf = &state->dmabuf; + struct ymf_dmabuf *dmabuf; int w_16; unsigned bytepersec; unsigned bufsize; @@ -350,6 +353,7 @@ static int prog_dmabuf(struct ymf_state *state, unsigned rec) int ret; w_16 = ymf_pcm_format_width(state->format.format) == 16; + dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf; spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->hwptr = dmabuf->swptr = 0; @@ -359,7 +363,7 @@ static int prog_dmabuf(struct ymf_state *state, unsigned rec) /* allocate DMA buffer if not allocated yet */ if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state))) + if ((ret = alloc_dmabuf(dmabuf))) return ret; bytepersec = state->format.rate << state->format.shift; @@ -383,7 +387,6 @@ static int prog_dmabuf(struct ymf_state *state, unsigned rec) dmabuf->numfrag = bufsize >> dmabuf->fragshift; } dmabuf->fragsize = 1 << dmabuf->fragshift; - dmabuf->fragsamples = dmabuf->fragsize >> state->format.shift; dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; /* @@ -414,15 +417,20 @@ static int prog_dmabuf(struct ymf_state *state, unsigned rec) * Now set up the ring */ - spin_lock_irqsave(&state->unit->reg_lock, flags); + /* XXX ret = rec? cap_pre(): pbk_pre(); */ + spin_lock_irqsave(&state->unit->voice_lock, flags); if (rec) { - /* ymf_rec_setup(state); */ + if ((ret = ymf_capture_prepare(state)) != 0) { + spin_unlock_irqrestore(&state->unit->voice_lock, flags); + return ret; + } } else { - if ((ret = ymf_playback_prepare(state->unit, state)) != 0) { + if ((ret = ymf_playback_prepare(state)) != 0) { + spin_unlock_irqrestore(&state->unit->voice_lock, flags); return ret; } } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + spin_unlock_irqrestore(&state->unit->voice_lock, flags); /* set the ready flag for the dma buffer (this comment is not stupid) */ dmabuf->ready = 1; @@ -439,9 +447,14 @@ static int prog_dmabuf(struct ymf_state *state, unsigned rec) static void ymf_start_dac(struct ymf_state *state) { - ymf_playback_trigger(state->unit, &state->ypcm, 1); + ymf_playback_trigger(state->unit, &state->wpcm, 1); } +// static void ymf_start_adc(struct ymf_state *state) +// { +// ymf_capture_trigger(state->unit, &state->rpcm, 1); +// } + /* * Wait until output is drained. * This does not kill the hardware for the sake of ioctls. @@ -449,14 +462,14 @@ static void ymf_start_dac(struct ymf_state *state) static void ymf_wait_dac(struct ymf_state *state) { struct ymf_unit *unit = state->unit; - ymfpci_pcm_t *ypcm = &state->ypcm; + struct ymf_pcm *ypcm = &state->wpcm; DECLARE_WAITQUEUE(waita, current); unsigned long flags; - add_wait_queue(&state->dmabuf.wait, &waita); + add_wait_queue(&ypcm->dmabuf.wait, &waita); spin_lock_irqsave(&unit->reg_lock, flags); - if (state->dmabuf.count != 0 && !state->ypcm.running) { + if (ypcm->dmabuf.count != 0 && !ypcm->running) { ymf_playback_trigger(unit, ypcm, 1); } @@ -479,7 +492,7 @@ static void ymf_wait_dac(struct ymf_state *state) spin_unlock_irqrestore(&unit->reg_lock, flags); set_current_state(TASK_RUNNING); - remove_wait_queue(&state->dmabuf.wait, &waita); + remove_wait_queue(&ypcm->dmabuf.wait, &waita); /* * This function may take up to 4 seconds to reach this point @@ -487,6 +500,17 @@ static void ymf_wait_dac(struct ymf_state *state) */ } +/* Can just stop, without wait. Or can we? */ +static void ymf_stop_adc(struct ymf_state *state) +{ + struct ymf_unit *unit = state->unit; + unsigned long flags; + + spin_lock_irqsave(&unit->reg_lock, flags); + ymf_capture_trigger(unit, &state->rpcm, 0); + spin_unlock_irqrestore(&unit->reg_lock, flags); +} + /* * Hardware start management */ @@ -523,12 +547,11 @@ static void ymfpci_hw_stop(ymfpci_t *codec) * Playback voice management */ -static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice) +static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[]) { ymfpci_voice_t *voice, *voice2; int idx; - - *rvoice = NULL; + for (idx = 0; idx < 64; idx += pair ? 2 : 1) { voice = &codec->voices[idx]; voice2 = pair ? &codec->voices[idx+1] : NULL; @@ -551,52 +574,29 @@ static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfp break; } ymfpci_hw_start(codec); - if (voice2) + rvoice[0] = voice; + if (voice2) { ymfpci_hw_start(codec); - *rvoice = voice; + rvoice[1] = voice2; + } return 0; } - return -ENOMEM; + return -EBUSY; /* Your audio channel is open by someone else. */ } -static int ymfpci_voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, - int pair, ymfpci_voice_t **rvoice) +static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice) { - unsigned long flags; - int result; - - spin_lock_irqsave(&codec->voice_lock, flags); - for (;;) { - result = voice_alloc(codec, type, pair, rvoice); - if (result == 0 || type != YMFPCI_PCM) - break; - /* TODO: synth/midi voice deallocation */ - break; - } - spin_unlock_irqrestore(&codec->voice_lock, flags); - return result; -} - -static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice) -{ - unsigned long flags; - - ymfpci_hw_stop(codec); - spin_lock_irqsave(&codec->voice_lock, flags); + ymfpci_hw_stop(unit); pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; pvoice->ypcm = NULL; - pvoice->interrupt = NULL; - spin_unlock_irqrestore(&codec->voice_lock, flags); - return 0; } /* - * PCM part */ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) { - ymfpci_pcm_t *ypcm; + struct ymf_pcm *ypcm; int redzone; int pos, delta, swptr; int played, distance; @@ -611,7 +611,7 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) ypcm->running = 0; // lock it return; } - dmabuf = &state->dmabuf; + dmabuf = &ypcm->dmabuf; spin_lock(&codec->reg_lock); if (ypcm->running) { /* P3 */ /** printk("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n", @@ -627,10 +627,9 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) pos = voice->bank[codec->active_bank].start; pos <<= state->format.shift; if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ - printk(KERN_ERR - "ymfpci%d: %d: runaway: hwptr %d dmasize %d\n", + printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n", codec->dev_audio, voice->number, - dmabuf->hwptr, dmabuf->dmasize); + dmabuf->hwptr, pos, dmabuf->dmasize); pos = 0; } if (pos < dmabuf->hwptr) { @@ -706,36 +705,66 @@ static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice) spin_unlock(&codec->reg_lock); } -#if HAVE_RECORD -static void ymfpci_pcm_capture_interrupt(snd_pcm_subchn_t *substream) +static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap) { - snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, ); - ymfpci_t *codec = ypcm->codec; - u32 pos, delta; - - spin_lock(&codec->reg_lock); + struct ymf_pcm *ypcm; + int redzone; + struct ymf_state *state; + struct ymf_dmabuf *dmabuf; + int pos, delta; + int cnt; + + if ((ypcm = cap->ypcm) == NULL) { + return; + } + if ((state = ypcm->state) == NULL) { + ypcm->running = 0; // lock it + return; + } + dmabuf = &ypcm->dmabuf; + spin_lock(&unit->reg_lock); if (ypcm->running) { - pos = codec->bank_capture[ypcm->capture_bank_number][codec->active_bank]->start << ypcm->shift_offset; - if (pos < ypcm->last_pos) // <-- dmabuf->hwptr - delta = pos + (ypcm->buffer_size - ypcm->last_pos); - else - delta = pos - ypcm->last_pos; - ypcm->frag_pos += delta; - ypcm->last_pos = pos; - while (ypcm->frag_pos >= ypcm->frag_size) { - ypcm->frag_pos -= ypcm->frag_size; - // printk("done - active_bank = 0x%x, start = 0x%x\n", codec->active_bank, voice->bank[codec->active_bank].start); - spin_unlock(&codec->reg_lock); - snd_pcm_transfer_done(substream); - spin_lock(&codec->reg_lock); + redzone = ymf_calc_lend(state->format.rate); + redzone <<= (state->format.shift + 1); + + pos = cap->bank[unit->active_bank].start; + // pos <<= state->format.shift; + if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ + printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n", + unit->dev_audio, ypcm->capture_bank_number, + dmabuf->hwptr, pos, dmabuf->dmasize); + pos = 0; + } + if (pos < dmabuf->hwptr) { + delta = dmabuf->dmasize - dmabuf->hwptr; + delta += pos; + } else { + delta = pos - dmabuf->hwptr; + } + dmabuf->hwptr = pos; + + cnt = dmabuf->count; + cnt += delta; + if (cnt + redzone > dmabuf->dmasize) { + /* Overflow - bump swptr */ + dmabuf->count = dmabuf->dmasize - redzone; + dmabuf->swptr = dmabuf->hwptr + redzone; + if (dmabuf->swptr >= dmabuf->dmasize) { + dmabuf->swptr -= dmabuf->dmasize; + } + } else { + dmabuf->count = cnt; + } + + dmabuf->total_bytes += delta; + if (dmabuf->count) { /* && is_sleeping XXX */ + wake_up(&dmabuf->wait); } } - spin_unlock(&codec->reg_lock); + spin_unlock(&unit->reg_lock); } -#endif -static int ymf_playback_trigger(ymfpci_t *codec, ymfpci_pcm_t *ypcm, int cmd) +static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd) { if (ypcm->voices[0] == NULL) { @@ -755,40 +784,29 @@ static int ymf_playback_trigger(ymfpci_t *codec, ymfpci_pcm_t *ypcm, int cmd) return 0; } -#if HAVE_RECORD -static int ymfpci_capture_trigger(void *private_data, - snd_pcm_subchn_t * substream, - int cmd) +static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd) { - unsigned long flags; - ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO); - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, substream->runtime->private_data, -ENXIO); - int result = 0; u32 tmp; - spin_lock_irqsave(&codec->reg_lock, flags); - if (cmd == SND_PCM_TRIGGER_GO) { + if (cmd != 0) { tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number); ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp); ypcm->running = 1; - } else if (cmd == SND_PCM_TRIGGER_STOP) { + } else { tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number); ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp); ypcm->running = 0; - } else { - result = -EINVAL; } - spin_unlock_irqrestore(&codec->reg_lock, flags); - return result; } -#endif -static int ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices) +static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices) { + struct ymf_unit *unit; int err; + unit = ypcm->state->unit; if (ypcm->voices[1] != NULL && voices < 2) { - ymfpci_voice_free(ypcm->codec, ypcm->voices[1]); + ymfpci_voice_free(unit, ypcm->voices[1]); ypcm->voices[1] = NULL; } if (voices == 1 && ypcm->voices[0] != NULL) @@ -797,18 +815,17 @@ static int ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices) return 0; /* already allocated */ if (voices > 1) { if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) { - ymfpci_voice_free(ypcm->codec, ypcm->voices[0]); + ymfpci_voice_free(unit, ypcm->voices[0]); ypcm->voices[0] = NULL; } - } - err = ymfpci_voice_alloc(ypcm->codec, YMFPCI_PCM, voices > 1, &ypcm->voices[0]); - if (err < 0) - return err; - ypcm->voices[0]->ypcm = ypcm; - ypcm->voices[0]->interrupt = ymf_pcm_interrupt; - if (voices > 1) { - ypcm->voices[1] = &ypcm->codec->voices[ypcm->voices[0]->number + 1]; + if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0) + return err; + ypcm->voices[0]->ypcm = ypcm; ypcm->voices[1]->ypcm = ypcm; + } else { + if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0) + return err; + ypcm->voices[0]->ypcm = ypcm; } return 0; } @@ -901,17 +918,32 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo, } /* - * XXX Use new cache coherent PCI DMA routines instead of virt_to_bus. + * XXX Capture channel allocation is entirely fake at the moment. + * We use only one channel and mark it busy as required. */ -static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state) +static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank) { - ymfpci_pcm_t *ypcm = &state->ypcm; + struct ymf_capture *cap; + int cbank; + + cbank = 1; /* Only ADC slot is used for now. */ + cap = &unit->capture[cbank]; + if (cap->use) + return -EBUSY; + cap->use = 1; + *pbank = cbank; + return 0; +} + +static int ymf_playback_prepare(struct ymf_state *state) +{ + struct ymf_pcm *ypcm = &state->wpcm; int err, nvoice; if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) { - /* Cannot be unless we leak voices in ymf_release! */ - printk(KERN_ERR "ymfpci%d: cannot allocate voice!\n", - codec->dev_audio); + /* Somebody started 32 mpg123's in parallel? */ + /* P3 */ printk("ymfpci%d: cannot allocate voice\n", + state->unit->dev_audio); return err; } @@ -919,101 +951,76 @@ static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state) ymf_pcm_init_voice(ypcm->voices[nvoice], state->format.voices == 2, state->format.rate, ymf_pcm_format_width(state->format.format) == 16, - virt_to_bus(state->dmabuf.rawbuf), state->dmabuf.dmasize, + virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize, ypcm->spdif); } return 0; } -#if 0 /* old */ -static int ymfpci_capture_prepare(void *private_data, - snd_pcm_subchn_t * substream) +static int ymf_capture_prepare(struct ymf_state *state) { - ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO); - snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO); + ymfpci_t *unit = state->unit; + struct ymf_pcm *ypcm = &state->rpcm; ymfpci_capture_bank_t * bank; - int nbank; + /* XXX This is confusing, gotta rename one of them banks... */ + int nbank; /* flip-flop bank */ + int cbank; /* input [super-]bank */ + struct ymf_capture *cap; u32 rate, format; - ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream); - ypcm->buffer_size = snd_pcm_lib_transfer_size(substream); - ypcm->frag_pos = 0; - ypcm->last_pos = 0; - ypcm->shift_offset = 0; - rate = ((48000 * 4096) / runtime->format.rate) - 1; + if (ypcm->capture_bank_number == -1) { + if (ymf_capture_alloc(unit, &cbank) != 0) + return -EBUSY; + + ypcm->capture_bank_number = cbank; + + cap = &unit->capture[cbank]; + cap->bank = unit->bank_capture[cbank][0]; + cap->ypcm = ypcm; + ymfpci_hw_start(unit); + } + + // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream); + // frag_size is replaced with nonfragged byte-aligned rolling buffer + rate = ((48000 * 4096) / state->format.rate) - 1; format = 0; - if (runtime->format.voices == 2) + if (state->format.voices == 2) format |= 2; - if (snd_pcm_format_width(runtime->format.format) == 8) + if (ymf_pcm_format_width(state->format.format) == 8) format |= 1; switch (ypcm->capture_bank_number) { case 0: - ymfpci_writel(codec, YDSXGR_RECFORMAT, format); - ymfpci_writel(codec, YDSXGR_RECSLOTSR, rate); + ymfpci_writel(unit, YDSXGR_RECFORMAT, format); + ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate); break; case 1: - ymfpci_writel(codec, YDSXGR_ADCFORMAT, format); - ymfpci_writel(codec, YDSXGR_ADCSLOTSR, rate); + ymfpci_writel(unit, YDSXGR_ADCFORMAT, format); + ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate); break; } for (nbank = 0; nbank < 2; nbank++) { - bank = codec->bank_capture[ypcm->capture_bank_number][nbank]; - bank->base = virt_to_bus(runtime->dma_area->buf); - bank->loop_end = ypcm->buffer_size; + bank = unit->bank_capture[ypcm->capture_bank_number][nbank]; + bank->base = virt_to_bus(ypcm->dmabuf.rawbuf); + // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift; + bank->loop_end = ypcm->dmabuf.dmasize; bank->start = 0; bank->num_of_loops = 0; } - if (runtime->digital.dig_valid) - /*runtime->digital.type == SND_PCM_DIG_AES_IEC958*/ - ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS, runtime->digital.dig_status[0] | - (runtime->digital.dig_status[1] << 8)); +#if 0 /* s/pdif */ + if (state->digital.dig_valid) + /*state->digital.type == SND_PCM_DIG_AES_IEC958*/ + ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS, + state->digital.dig_status[0] | (state->digital.dig_status[1] << 8)); +#endif return 0; } -static unsigned int ymfpci_playback_pointer(void *private_data, - snd_pcm_subchn_t * substream) -{ - ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO); - snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO); - ymfpci_voice_t *voice = ypcm->voices[0]; - unsigned long flags; - unsigned int result; - - spin_lock_irqsave(&codec->reg_lock, flags); - if (ypcm->running && voice) - result = voice->bank[codec->active_bank].start << ypcm->shift_offset; - else - result = 0; - spin_unlock_irqrestore(&codec->reg_lock, flags); - return result; -} - -static unsigned int ymfpci_capture_pointer(void *private_data, - snd_pcm_subchn_t * substream) -{ - ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO); - snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO); - unsigned long flags; - unsigned int result; - - spin_lock_irqsave(&codec->reg_lock, flags); - if (ypcm->running) - result = codec->bank_capture[ypcm->capture_bank_number][codec->active_bank]->start << ypcm->shift_offset; - else - result = 0; - spin_unlock_irqrestore(&codec->reg_lock, flags); - return result; -} -#endif /* old */ - void ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs) { ymfpci_t *codec = dev_id; u32 status, nvoice, mode; - ymfpci_voice_t *voice; + struct ymf_voice *voice; + struct ymf_capture *cap; status = ymfpci_readl(codec, YDSXGR_STATUS); if (status & 0x80000000) { @@ -1026,8 +1033,13 @@ void ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_lock(&codec->voice_lock); for (nvoice = 0; nvoice < 64; nvoice++) { voice = &codec->voices[nvoice]; - if (voice->interrupt) - voice->interrupt(codec, voice); + if (voice->use) + ymf_pcm_interrupt(codec, voice); + } + for (nvoice = 0; nvoice < 5; nvoice++) { + cap = &codec->capture[nvoice]; + if (cap->use) + ymf_cap_interrupt(codec, cap); } spin_unlock(&codec->voice_lock); } @@ -1039,22 +1051,32 @@ void ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } -static void ymf_pcm_free_substream(ymfpci_pcm_t *ypcm) +static void ymf_pcm_free_substream(struct ymf_pcm *ypcm) { - ymfpci_t *codec; + unsigned long flags; + struct ymf_unit *unit; + + unit = ypcm->state->unit; - if (ypcm) { - codec = ypcm->codec; + if (ypcm->type == PLAYBACK_VOICE) { + spin_lock_irqsave(&unit->voice_lock, flags); if (ypcm->voices[1]) - ymfpci_voice_free(codec, ypcm->voices[1]); + ymfpci_voice_free(unit, ypcm->voices[1]); if (ypcm->voices[0]) - ymfpci_voice_free(codec, ypcm->voices[0]); + ymfpci_voice_free(unit, ypcm->voices[0]); + spin_unlock_irqrestore(&unit->voice_lock, flags); + } else { + if (ypcm->capture_bank_number != -1) { + unit->capture[ypcm->capture_bank_number].use = 0; + ypcm->capture_bank_number = -1; + ymfpci_hw_stop(unit); + } } } -static int ymf_state_alloc(ymfpci_t *unit, int nvirt) +static struct ymf_state *ymf_state_alloc(ymfpci_t *unit) { - ymfpci_pcm_t *ypcm; + struct ymf_pcm *ypcm; struct ymf_state *state; if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) { @@ -1062,61 +1084,31 @@ static int ymf_state_alloc(ymfpci_t *unit, int nvirt) } memset(state, 0, sizeof(struct ymf_state)); - init_waitqueue_head(&state->dmabuf.wait); - - ypcm = &state->ypcm; + ypcm = &state->wpcm; ypcm->state = state; - ypcm->codec = unit; ypcm->type = PLAYBACK_VOICE; + ypcm->capture_bank_number = -1; + init_waitqueue_head(&ypcm->dmabuf.wait); + + ypcm = &state->rpcm; + ypcm->state = state; + ypcm->type = CAPTURE_AC97; + ypcm->capture_bank_number = -1; + init_waitqueue_head(&ypcm->dmabuf.wait); state->unit = unit; - state->virt = nvirt; state->format.format = AFMT_U8; state->format.rate = 8000; state->format.voices = 1; ymf_pcm_update_shift(&state->format); - unit->states[nvirt] = state; - return 0; + return state; out0: - return -ENOMEM; + return NULL; } -#if HAVE_RECORD - -static int ymfpci_capture_open(void *private_data, - snd_pcm_subchn_t * substream, - u32 capture_bank_number) -{ - ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO); - snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm; - int err; - - if ((err = snd_pcm_dma_alloc(substream, !capture_bank_number ? codec->dma2ptr : codec->dma3ptr, "YMFPCI - ADC")) < 0) - return err; - ypcm = snd_magic_kcalloc(ymfpci_pcm_t, 0, GFP_KERNEL); - if (ypcm == NULL) { - snd_pcm_dma_free(substream); - return -ENOMEM; - } - ypcm->codec = codec; - ypcm->type = capture_bank_number + CAPTURE_REC; - ypcm->substream = substream; - ypcm->capture_bank_number = capture_bank_number; - codec->capture_substream[capture_bank_number] = substream; - runtime->hw = &ymfpci_capture; - snd_pcm_set_mixer(substream, codec->mixer->device, codec->ac97->me_capture); - runtime->private_data = ypcm; - runtime->private_free = ymfpci_pcm_free_substream; - ymfpci_hw_start(codec); - return 0; -} - -#endif /* old */ - /* AES/IEC958 channel status bits */ #define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */ #define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */ @@ -1202,24 +1194,6 @@ static int ymfpci_capture_open(void *private_data, #define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */ #define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */ -#if HAVE_RECORD /* old */ - -static int ymfpci_capture_close(void *private_data, - snd_pcm_subchn_t * substream) -{ - ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO); - snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO); - - if (ypcm != NULL) { - codec->capture_substream[ypcm->capture_bank_number] = NULL; - ymfpci_hw_stop(codec); - } - snd_pcm_dma_free(substream); - return 0; -} -#endif - /* * User interface */ @@ -1229,21 +1203,21 @@ static loff_t ymf_llseek(struct file *file, loff_t offset, int origin) return -ESPIPE; } -/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to - the user's buffer. it is filled by the dma machine and drained by this loop. */ -static ssize_t ymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +/* + * in this loop, dmabuf.count signifies the amount of data that is + * waiting to be copied to the user's buffer. it is filled by the dma + * machine and drained by this loop. + */ +static ssize_t +ymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { -#if HAVE_RECORD - struct cs_state *state = (struct cs_state *)file->private_data; - struct dmabuf *dmabuf = &state->dmabuf; + struct ymf_state *state = (struct ymf_state *)file->private_data; + struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf; + DECLARE_WAITQUEUE(waita, current); ssize_t ret; unsigned long flags; - unsigned swptr; - int cnt; - -#ifdef DEBUG - printk("cs461x: cs_read called, count = %d\n", count); -#endif + unsigned int swptr; + int cnt; /* This many to go in this revolution */ if (ppos != &file->f_pos) return -ESPIPE; @@ -1255,19 +1229,14 @@ static ssize_t ymf_read(struct file *file, char *buffer, size_t count, loff_t *p return -EFAULT; ret = 0; + add_wait_queue(&dmabuf->wait, &waita); while (count > 0) { - spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->count > (signed) dmabuf->dmasize) { - /* buffer overrun, we are recovering from sleep_on_timeout, - resync hwptr and swptr, make process flush the buffer */ - dmabuf->count = dmabuf->dmasize; - dmabuf->swptr = dmabuf->hwptr; - } + spin_lock_irqsave(&state->unit->reg_lock, flags); swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count < cnt) cnt = dmabuf->count; - spin_unlock_irqrestore(&state->card->lock, flags); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (cnt > count) cnt = count; @@ -1275,14 +1244,18 @@ static ssize_t ymf_read(struct file *file, char *buffer, size_t count, loff_t *p unsigned long tmo; /* buffer is empty, start the dma machine and wait for data to be recorded */ - start_adc(state); + spin_lock_irqsave(&state->unit->reg_lock, flags); + if (!state->rpcm.running) { + ymf_capture_trigger(state->unit, &state->rpcm, 1); + } + spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + break; } /* This isnt strictly right for the 810 but it'll do */ - tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); - tmo >>= sample_shift[dmabuf->fmt]; + tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2); + tmo >>= state->format.shift; /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1290,50 +1263,56 @@ static ssize_t ymf_read(struct file *file, char *buffer, size_t count, loff_t *p is TOO LATE for the process to be scheduled to run (scheduler latency) which results in a (potential) buffer overrun. And worse, there is NOTHING we can do to prevent it. */ - if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { -#ifdef DEBUG - printk(KERN_ERR "cs461x: recording schedule timeout, " - "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, - dmabuf->hwptr, dmabuf->swptr); -#endif - /* a buffer overrun, we delay the recovery untill next time the - while loop begin and we REALLY have space to record */ + set_current_state(TASK_INTERRUPTIBLE); + tmo = schedule_timeout(tmo); + spin_lock_irqsave(&state->unit->reg_lock, flags); + if (tmo == 0 && dmabuf->count == 0) { + printk(KERN_ERR "ymfpci%d: recording schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + state->unit->dev_audio, + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); } + spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (signal_pending(current)) { ret = ret ? ret : -ERESTARTSYS; - return ret; + break; } continue; } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; - return ret; + break; } swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&state->card->lock, flags); + spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->swptr = swptr; dmabuf->count -= cnt; - spin_unlock_irqrestore(&state->card->lock, flags); + // spin_unlock_irqrestore(&state->unit->reg_lock, flags); count -= cnt; buffer += cnt; ret += cnt; - start_adc(state); + // spin_lock_irqsave(&state->unit->reg_lock, flags); + if (!state->rpcm.running) { + ymf_capture_trigger(state->unit, &state->rpcm, 1); + } + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } + set_current_state(TASK_RUNNING); + remove_wait_queue(&dmabuf->wait, &waita); + return ret; -#else - return -EINVAL; -#endif } -static ssize_t ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t +ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->dmabuf; + struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf; DECLARE_WAITQUEUE(waita, current); ssize_t ret; unsigned long flags; @@ -1375,7 +1354,7 @@ static ssize_t ymf_write(struct file *file, const char *buffer, size_t count, lo } if (dmabuf->count == 0) { swptr = dmabuf->hwptr; - if (state->ypcm.running) { + if (state->wpcm.running) { /* * Add uncertainty reserve. */ @@ -1410,8 +1389,8 @@ static ssize_t ymf_write(struct file *file, const char *buffer, size_t count, lo * wait for data to be played */ spin_lock_irqsave(&state->unit->reg_lock, flags); - if (!state->ypcm.running) { - ymf_playback_trigger(state->unit, &state->ypcm, 1); + if (!state->wpcm.running) { + ymf_playback_trigger(state->unit, &state->wpcm, 1); } spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (file->f_flags & O_NONBLOCK) { @@ -1448,8 +1427,8 @@ static ssize_t ymf_write(struct file *file, const char *buffer, size_t count, lo */ delay = state->format.rate / 20; /* 50ms */ delay <<= state->format.shift; - if (dmabuf->count >= delay && !state->ypcm.running) { - ymf_playback_trigger(state->unit, &state->ypcm, 1); + if (dmabuf->count >= delay && !state->wpcm.running) { + ymf_playback_trigger(state->unit, &state->wpcm, 1); } spin_unlock_irqrestore(&state->unit->reg_lock, flags); @@ -1469,19 +1448,23 @@ static ssize_t ymf_write(struct file *file, const char *buffer, size_t count, lo static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) { struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->dmabuf; + struct ymf_dmabuf *dmabuf; unsigned long flags; unsigned int mask = 0; - if (file->f_mode & (FMODE_WRITE | FMODE_READ)) - poll_wait(file, &dmabuf->wait, wait); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &state->wpcm.dmabuf.wait, wait); + // if (file->f_mode & FMODE_READ) + // poll_wait(file, &dmabuf->wait, wait); spin_lock_irqsave(&state->unit->reg_lock, flags); if (file->f_mode & FMODE_READ) { + dmabuf = &state->rpcm.dmabuf; if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { + dmabuf = &state->wpcm.dmabuf; if (dmabuf->mapped) { if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; @@ -1498,10 +1481,9 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) static int ymf_mmap(struct file *file, struct vm_area_struct *vma) { struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->dmabuf; + struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf; int ret; unsigned long size; - if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(state, 0)) != 0) @@ -1529,7 +1511,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct ymf_state *state = (struct ymf_state *)file->private_data; - struct ymf_dmabuf *dmabuf = &state->dmabuf; + struct ymf_dmabuf *dmabuf; unsigned long flags; audio_buf_info abinfo; count_info cinfo; @@ -1542,28 +1524,30 @@ static int ymf_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); + dmabuf = &state->wpcm.dmabuf; spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->swptr = dmabuf->hwptr; dmabuf->count = dmabuf->total_bytes = 0; spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#if HAVE_RECORD if (file->f_mode & FMODE_READ) { - stop_adc(state); - synchronize_irq(); + ymf_stop_adc(state); + dmabuf = &state->rpcm.dmabuf; + spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->swptr = dmabuf->hwptr; dmabuf->count = dmabuf->total_bytes = 0; + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#endif return 0; case SNDCTL_DSP_SYNC: if (file->f_mode & FMODE_WRITE) { + dmabuf = &state->wpcm.dmabuf; if (file->f_flags & O_NONBLOCK) { spin_lock_irqsave(&state->unit->reg_lock, flags); - if (dmabuf->count != 0 && !state->ypcm.running) { + if (dmabuf->count != 0 && !state->wpcm.running) { ymf_start_dac(state); } spin_unlock_irqrestore(&state->unit->reg_lock, flags); @@ -1571,6 +1555,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, ymf_wait_dac(state); } } + /* XXX What does this do for reading? dmabuf->count=0; ? */ return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */ @@ -1579,17 +1564,22 @@ static int ymf_ioctl(struct inode *inode, struct file *file, if (val >= 8000 && val <= 48000) { if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); + dmabuf = &state->wpcm.dmabuf; + spin_lock_irqsave(&state->unit->reg_lock, flags); + dmabuf->ready = 0; + state->format.rate = val; + ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#if HAVE_RECORD if (file->f_mode & FMODE_READ) { - stop_adc(state); + ymf_stop_adc(state); + dmabuf = &state->rpcm.dmabuf; + spin_lock_irqsave(&state->unit->reg_lock, flags); + dmabuf->ready = 0; + state->format.rate = val; + ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#endif - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.rate = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); } return put_user(state->format.rate, (int *)arg); @@ -1597,41 +1587,41 @@ static int ymf_ioctl(struct inode *inode, struct file *file, * OSS manual does not mention SNDCTL_DSP_STEREO at all. * All channels are mono and if you want stereo, you * play into two channels with SNDCTL_DSP_CHANNELS. - * However, mpg123 uses it. I wonder, why Michael Hipp uses it. + * However, mpg123 calls it. I wonder, why Michael Hipp used it. */ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); + dmabuf = &state->wpcm.dmabuf; spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; state->format.voices = val ? 2 : 1; ymf_pcm_update_shift(&state->format); spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#if HAVE_RECORD if (file->f_mode & FMODE_READ) { - /* stop_adc(state); */ + ymf_stop_adc(state); + dmabuf = &state->rpcm.dmabuf; + spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; - if(val) - dmabuf->fmt |= CS_FMT_STEREO; - else - dmabuf->fmt &= ~CS_FMT_STEREO; + state->format.voices = val ? 2 : 1; + ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#endif return 0; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(state, 0))) return val; - return put_user(dmabuf->fragsize, (int *)arg); + return put_user(state->wpcm.dmabuf.fragsize, (int *)arg); } if (file->f_mode & FMODE_READ) { if ((val = prog_dmabuf(state, 1))) return val; - return put_user(dmabuf->fragsize, (int *)arg); + return put_user(state->rpcm.dmabuf.fragsize, (int *)arg); } return -EINVAL; @@ -1644,17 +1634,22 @@ static int ymf_ioctl(struct inode *inode, struct file *file, if (val == AFMT_S16_LE || val == AFMT_U8) { if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); + dmabuf = &state->wpcm.dmabuf; + spin_lock_irqsave(&state->unit->reg_lock, flags); + dmabuf->ready = 0; + state->format.format = val; + ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#if HAVE_RECORD if (file->f_mode & FMODE_READ) { - stop_adc(state); + ymf_stop_adc(state); + dmabuf = &state->rpcm.dmabuf; + spin_lock_irqsave(&state->unit->reg_lock, flags); + dmabuf->ready = 0; + state->format.format = val; + ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } -#endif - spin_lock_irqsave(&state->unit->reg_lock, flags); - dmabuf->ready = 0; - state->format.format = val; - ymf_pcm_update_shift(&state->format); - spin_unlock_irqrestore(&state->unit->reg_lock, flags); } return put_user(state->format.format, (int *)arg); @@ -1667,20 +1662,24 @@ static int ymf_ioctl(struct inode *inode, struct file *file, ymf_wait_dac(state); if (val == 1 || val == 2) { spin_lock_irqsave(&state->unit->reg_lock, flags); + dmabuf = &state->wpcm.dmabuf; dmabuf->ready = 0; state->format.voices = val; ymf_pcm_update_shift(&state->format); spin_unlock_irqrestore(&state->unit->reg_lock, flags); } } -#if HAVE_RECORD if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&state->unit->reg_lock, flags); - stop_adc(state); - dmabuf->ready = 0; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + ymf_stop_adc(state); + if (val == 1 || val == 2) { + spin_lock_irqsave(&state->unit->reg_lock, flags); + dmabuf = &state->rpcm.dmabuf; + dmabuf->ready = 0; + state->format.voices = val; + ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); + } } -#endif } return put_user(state->format.voices, (int *)arg); @@ -1696,15 +1695,16 @@ static int ymf_ioctl(struct inode *inode, struct file *file, * The paragraph above is a clumsy way to say "flush ioctl". * This ioctl is used by mpg123. */ - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_POST\n"); */ spin_lock_irqsave(&state->unit->reg_lock, flags); - if (dmabuf->count != 0 && !state->ypcm.running) { + if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) { ymf_start_dac(state); } spin_unlock_irqrestore(&state->unit->reg_lock, flags); return 0; +#if 0 /* XXX Was dummy implementation anyways. Make sense of this. */ case SNDCTL_DSP_SUBDIVIDE: + dmabuf = &state->wpcm.dmabuf; if (dmabuf->subdivision) return -EINVAL; if (get_user(val, (int *)arg)) @@ -1713,6 +1713,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, return -EINVAL; dmabuf->subdivision = val; return 0; +#endif case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) @@ -1720,6 +1721,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, /* P3: these frags are for Doom. Amasingly, it sets [2,2**11]. */ /* P3 */ // printk("ymfpci: ioctl SNDCTL_DSP_SETFRAGMENT 0x%x\n", val); + dmabuf = &state->wpcm.dmabuf; dmabuf->ossfragshift = val & 0xffff; dmabuf->ossmaxfrags = (val >> 16) & 0xffff; switch (dmabuf->ossmaxfrags) { @@ -1736,10 +1738,10 @@ static int ymf_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + dmabuf = &state->wpcm.dmabuf; if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->unit->reg_lock, flags); - /* cs_update_ptr(state); */ /* XXX Always up to date? */ abinfo.fragsize = dmabuf->fragsize; abinfo.bytes = dmabuf->dmasize - dmabuf->count; abinfo.fragstotal = dmabuf->numfrag; @@ -1747,21 +1749,19 @@ static int ymf_ioctl(struct inode *inode, struct file *file, spin_unlock_irqrestore(&state->unit->reg_lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -#if HAVE_RECORD case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; + dmabuf = &state->rpcm.dmabuf; if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) return val; - spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(state); + spin_lock_irqsave(&state->unit->reg_lock, flags); abinfo.fragsize = dmabuf->fragsize; abinfo.bytes = dmabuf->count; abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; - spin_unlock_irqrestore(&state->card->lock, flags); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -#endif case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; @@ -1772,9 +1772,10 @@ static int ymf_ioctl(struct inode *inode, struct file *file, (int *)arg); */ return put_user(0, (int *)arg); -#if 0 /* old */ +#if 0 /* not implememnted, yet? */ case SNDCTL_DSP_GETTRIGGER: val = 0; + dmabuf = &state->wpcm.dmabuf; if (file->f_mode & FMODE_READ && dmabuf->enable) val |= PCM_ENABLE_INPUT; if (file->f_mode & FMODE_WRITE && dmabuf->enable) @@ -1785,6 +1786,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { + dmabuf = &state->rpcm.dmabuf; if (val & PCM_ENABLE_INPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; @@ -1793,6 +1795,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, stop_adc(state); } if (file->f_mode & FMODE_WRITE) { + dmabuf = &state->wpcm.dmabuf; if (val & PCM_ENABLE_OUTPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; @@ -1801,48 +1804,48 @@ static int ymf_ioctl(struct inode *inode, struct file *file, stop_dac(state); } return 0; - #endif -#if HAVE_RECORD case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; + dmabuf = &state->rpcm.dmabuf; spin_lock_irqsave(&state->unit->reg_lock, flags); - cs_update_ptr(state); cinfo.bytes = dmabuf->total_bytes; cinfo.blocks = dmabuf->count >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr; + /* XXX fishy - breaks invariant count=hwptr-swptr */ if (dmabuf->mapped) dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->unit->reg_lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -#endif + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + dmabuf = &state->wpcm.dmabuf; spin_lock_irqsave(&state->unit->reg_lock, flags); - /* cs_update_ptr(state); */ /* Always up to date */ cinfo.bytes = dmabuf->total_bytes; cinfo.blocks = dmabuf->count >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr; + /* XXX fishy - breaks invariant count=swptr-hwptr */ if (dmabuf->mapped) dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->unit->reg_lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */ return -EINVAL; -#if 0 /* old */ +#if 0 /* XXX implement when an app found that uses it. */ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&state->unit->reg_lock, flags); cs_update_ptr(state); + dmabuf = &state->wpcm.dmabuf; val = dmabuf->count; - spin_unlock_irqrestore(&state->card->lock, flags); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); return put_user(val, (int *)arg); #endif @@ -1850,7 +1853,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file, return put_user(state->format.rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: - return put_user(state->format.voices, (int *)arg); + return put_user(state->format.voices, (int *)arg); case SOUND_PCM_READ_BITS: return put_user(AFMT_S16_LE, (int *)arg); @@ -1873,28 +1876,25 @@ static int ymf_ioctl(struct inode *inode, struct file *file, return -ENOTTY; } +/* + * open(2) + * We use upper part of the minor to distinguish between soundcards. + * Channels are opened with a clone open. + */ static int ymf_open(struct inode *inode, struct file *file) { struct list_head *list; ymfpci_t *unit; int minor; struct ymf_state *state; - int nvirt; int err; - /* - * This is how we do it currently: only one channel is used - * in every board, so that we could use several boards in one machine. - * We waste 63 out of 64 playback slots, but so what. - * OSS model is constructed for devices with single playback channel. - */ minor = MINOR(inode->i_rdev); if ((minor & 0x0F) == 3) { /* /dev/dspN */ ; } else { return -ENXIO; } - nvirt = 0; /* Such is the partitioning of minor */ for (list = ymf_devs.next; list != &ymf_devs; list = list->next) { unit = list_entry(list, ymfpci_t, ymf_devs); @@ -1905,34 +1905,36 @@ static int ymf_open(struct inode *inode, struct file *file) return -ENODEV; down(&unit->open_sem); - if (unit->states[nvirt] != NULL) { - up(&unit->open_sem); - return -EBUSY; - } - if ((err = ymf_state_alloc(unit, nvirt)) != 0) { + if ((state = ymf_state_alloc(unit)) == NULL) { up(&unit->open_sem); - return err; + return -ENOMEM; } - state = unit->states[nvirt]; + list_add_tail(&state->chain, &unit->states); file->private_data = state; /* - * XXX This ymf_playback_prepare is totally unneeded here. - * The question is if we want to allow write to fail if - * prog_dmabuf fails... Say, no memory in DMA zone? + * ymf_read and ymf_write that we borrowed from cs46xx + * allocate buffers with prog_dmabuf(). We call prog_dmabuf + * here so that in case of DMA memory exhaustion open + * fails rather than write. + * + * XXX prog_dmabuf allocates voice. Should allocate explicitly, above. */ - if ((err = ymf_playback_prepare(unit, state)) != 0) { - /* XXX This recovery is ugly as hell. */ - - ymf_pcm_free_substream(&state->ypcm); - - unit->states[state->virt] = NULL; - kfree(state); - - up(&unit->open_sem); - return err; + if (file->f_mode & FMODE_WRITE) { + if (!state->wpcm.dmabuf.ready) { + if ((err = prog_dmabuf(state, 0)) != 0) { + goto out_nodma; + } + } + } + if (file->f_mode & FMODE_READ) { + if (!state->rpcm.dmabuf.ready) { + if ((err = prog_dmabuf(state, 1)) != 0) { + goto out_nodma; + } + } } #if 0 /* test if interrupts work */ @@ -1941,10 +1943,26 @@ static int ymf_open(struct inode *inode, struct file *file) (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN)); #endif up(&unit->open_sem); - /* XXX Is it correct to have MOD_INC_USE_COUNT outside of sem.? */ MOD_INC_USE_COUNT; return 0; + +out_nodma: + /* + * XXX Broken custom: "goto out_xxx" in other place is + * a nestable exception, but here it is not nestable due to semaphore. + * XXX Doubtful technique of self-describing objects.... + */ + dealloc_dmabuf(&state->wpcm.dmabuf); + dealloc_dmabuf(&state->rpcm.dmabuf); + ymf_pcm_free_substream(&state->wpcm); + ymf_pcm_free_substream(&state->rpcm); + + list_del(&state->chain); + kfree(state); + + up(&unit->open_sem); + return err; } static int ymf_release(struct inode *inode, struct file *file) @@ -1956,12 +1974,6 @@ static int ymf_release(struct inode *inode, struct file *file) ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0); #endif - if (state != codec->states[state->virt]) { - printk(KERN_ERR "ymfpci%d.%d: state mismatch\n", - state->unit->dev_audio, state->virt); - return -EIO; - } - down(&codec->open_sem); /* @@ -1969,10 +1981,14 @@ static int ymf_release(struct inode *inode, struct file *file) * Deallocate when unloading the driver and we can wait. */ ymf_wait_dac(state); - dealloc_dmabuf(state); - ymf_pcm_free_substream(&state->ypcm); - - codec->states[state->virt] = NULL; + ymf_stop_adc(state); /* fortunately, it's immediate */ + dealloc_dmabuf(&state->wpcm.dmabuf); + dealloc_dmabuf(&state->rpcm.dmabuf); + ymf_pcm_free_substream(&state->wpcm); + ymf_pcm_free_substream(&state->rpcm); + + list_del(&state->chain); + file->private_data = NULL; /* Can you tell I programmed Solaris */ kfree(state); up(&codec->open_sem); @@ -2045,6 +2061,83 @@ static /*const*/ struct file_operations ymf_mixer_fops = { * initialization routines */ +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + +static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev) +{ + int v; + int mpuio = -1, oplio = -1; + + switch (unit->iomidi) { + case 0x330: + mpuio = 0; + break; + case 0x300: + mpuio = 1; + break; + case 0x332: + mpuio = 2; + break; + case 0x334: + mpuio = 3; + break; + default: ; + } + + switch (unit->iosynth) { + case 0x388: + oplio = 0; + break; + case 0x398: + oplio = 1; + break; + case 0x3a0: + oplio = 2; + break; + case 0x3a8: + oplio = 3; + break; + default: ; + } + + if (mpuio >= 0 || oplio >= 0) { + v = 0x003e; + pci_write_config_word(pcidev, PCIR_LEGCTRL, v); + + switch (pcidev->device) { + case PCI_DEVICE_ID_YAMAHA_724: + case PCI_DEVICE_ID_YAMAHA_740: + case PCI_DEVICE_ID_YAMAHA_724F: + case PCI_DEVICE_ID_YAMAHA_740C: + v = 0x8800; + if (mpuio >= 0) { v |= mpuio<<4; } + if (oplio >= 0) { v |= oplio; } + pci_write_config_word(pcidev, PCIR_ELEGCTRL, v); + break; + + case PCI_DEVICE_ID_YAMAHA_744: + case PCI_DEVICE_ID_YAMAHA_754: + v = 0x8800; + pci_write_config_word(pcidev, PCIR_ELEGCTRL, v); + if (oplio >= 0) { + pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth); + } + if (mpuio >= 0) { + pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi); + } + break; + + default: + printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n", + pcidev->device); + return -EINVAL; + } + } + + return 0; +} +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ + static void ymfpci_aclink_reset(struct pci_dev * pci) { u8 cmd; @@ -2149,6 +2242,12 @@ static int ymfpci_memalloc(ymfpci_t *codec) ptr += 0x00ff; (long)ptr &= ~0x00ff; + /* + * Hardware requires only ptr[playback_ctrl_size] zeroed, + * but in our judgement it is a wrong kind of savings, so clear it all. + */ + memset(ptr, 0, size); + codec->bank_base_playback = ptr; codec->ctrl_playback = (u32 *)ptr; codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES; @@ -2213,7 +2312,7 @@ static void ymfpci_memfree(ymfpci_t *codec) kfree(codec->work_ptr); } -static int ymf_ac97_init(ymfpci_t *card, int num_ac97) +static int ymf_ac97_init(ymfpci_t *unit, int num_ac97) { struct ac97_codec *codec; u16 eid; @@ -2224,7 +2323,7 @@ static int ymf_ac97_init(ymfpci_t *card, int num_ac97) /* initialize some basic codec information, other fields will be filled in ac97_probe_codec */ - codec->private_data = card; + codec->private_data = unit; codec->id = num_ac97; codec->codec_read = ymfpci_codec_read; @@ -2241,14 +2340,14 @@ static int ymf_ac97_init(ymfpci_t *card, int num_ac97) goto out_kfree; } - card->ac97_features = eid; + unit->ac97_features = eid; if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) { printk(KERN_ERR "ymfpci: couldn't register mixer!\n"); goto out_kfree; } - card->ac97_codec[num_ac97] = codec; + unit->ac97_codec[num_ac97] = codec; return 0; out_kfree: @@ -2256,6 +2355,19 @@ static int ymf_ac97_init(ymfpci_t *card, int num_ac97) return -ENODEV; } +#ifdef CONFIG_SOUND_YMFPCI_LEGACY +# ifdef MODULE +static int mpu_io = 0; +static int synth_io = 0; +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(synth_io, "i"); +# else +static int mpu_io = 0x330; +static int synth_io = 0x388; +# endif +static int assigned; +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ + static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent) { u16 ctrl; @@ -2277,10 +2389,15 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi spin_lock_init(&codec->reg_lock); spin_lock_init(&codec->voice_lock); init_MUTEX(&codec->open_sem); + INIT_LIST_HEAD(&codec->states); codec->pci = pcidev; pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev); codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000); + if (codec->reg_area_virt == NULL) { + printk(KERN_ERR "ymfpci: unable to map registers\n"); + goto out_free; + } printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n", (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq); @@ -2289,6 +2406,16 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi if (ymfpci_codec_ready(codec, 0, 1) < 0) goto out_unmap; +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + if (assigned == 0) { + codec->iomidi = mpu_io; + codec->iosynth = synth_io; + if (ymfpci_setup_legacy(codec, pcidev) < 0) + goto out_unmap; + assigned = 1; + } +#endif + ymfpci_download_image(codec); udelay(100); /* seems we need some delay after downloading image.. */ @@ -2296,11 +2423,11 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi if (ymfpci_memalloc(codec) < 0) goto out_disable_dsp; - /* ymfpci_proc_init(card, codec); */ + /* ymfpci_proc_init(unit, codec); */ if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) { - printk(KERN_ERR "ymfpci%d: unable to request IRQ %d\n", - codec->dev_audio, pcidev->irq); + printk(KERN_ERR "ymfpci: unable to request IRQ %d\n", + pcidev->irq); goto out_memfree; } @@ -2317,6 +2444,23 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi if ((err = ymf_ac97_init(codec, 0)) != 0) goto out_unregister_sound_dsp; +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + codec->opl3_data.name = "ymfpci"; + codec->mpu_data.name = "ymfpci"; + + codec->opl3_data.io_base = codec->iosynth; + codec->opl3_data.irq = -1; + + codec->mpu_data.io_base = codec->iomidi; + codec->mpu_data.irq = -1; /* XXX Make it ours. */ + + if (codec->iomidi) { + if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) { + codec->iomidi = 0; /* XXX kludge */ + } + } +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ + /* put it into driver list */ list_add_tail(&codec->ymf_devs, &ymf_devs); pci_set_drvdata(pcidev, codec); @@ -2336,6 +2480,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi ymfpci_writel(codec, YDSXGR_STATUS, ~0); out_unmap: iounmap(codec->reg_area_virt); + out_free: kfree(codec); return -ENODEV; } @@ -2358,6 +2503,11 @@ static void __devexit ymf_remove_one(struct pci_dev *pcidev) ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL); ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); iounmap(codec->reg_area_virt); +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + if (codec->iomidi) { + unload_uart401(&codec->mpu_data); + } +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ kfree(codec); } diff --git a/drivers/sound/ymfpci.h b/drivers/sound/ymfpci.h index 6e1a8d5f3..bd2f4c2a3 100644 --- a/drivers/sound/ymfpci.h +++ b/drivers/sound/ymfpci.h @@ -21,6 +21,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ +#include <linux/config.h> /* * Direct registers @@ -131,7 +132,12 @@ #define YDSXG_AC97READCMD 0x8000 #define YDSXG_AC97WRITECMD 0x0000 +#define PCIR_LEGCTRL 0x40 +#define PCIR_ELEGCTRL 0x42 #define PCIR_DSXGCTRL 0x48 +#define PCIR_OPLADR 0x60 +#define PCIR_SBADR 0x62 +#define PCIR_MPUADR 0x64 #define YDSXG_DSPLENGTH 0x0080 #define YDSXG_CTRLLENGTH 0x3000 @@ -185,8 +191,8 @@ typedef struct stru_ymfpci_playback_bank { } ymfpci_playback_bank_t; typedef struct stru_ymfpci_capture_bank { - u32 base; /* 32-bit address */ - u32 loop_end; /* 32-bit offset */ + u32 base; /* 32-bit address (aligned at 4) */ + u32 loop_end; /* size in BYTES (aligned at 4) */ u32 start; /* 32-bit offset */ u32 num_of_loops; /* counter */ } ymfpci_capture_bank_t; @@ -198,8 +204,7 @@ typedef struct stru_ymfpci_effect_bank { u32 temp; } ymfpci_effect_bank_t; -typedef struct stru_ymfpci_voice ymfpci_voice_t; -typedef struct ymf_pcm ymfpci_pcm_t; +typedef struct ymf_voice ymfpci_voice_t; /* * Throughout the code Yaroslav names YMF unit pointer "codec" * even though it does not correspond to any codec. Must be historic. @@ -214,52 +219,35 @@ typedef enum { YMFPCI_MIDI } ymfpci_voice_type_t; -struct stru_ymfpci_voice { - ymfpci_t *codec; +struct ymf_voice { + // ymfpci_t *codec; int number; - int use: 1, - pcm: 1, - synth: 1, - midi: 1; + char use, pcm, synth, midi; // bool ymfpci_playback_bank_t *bank; - void (*interrupt)(ymfpci_t *codec, ymfpci_voice_t *voice); - ymfpci_pcm_t *ypcm; + struct ymf_pcm *ypcm; }; -typedef enum { - PLAYBACK_VOICE, - CAPTURE_REC, - CAPTURE_AC97, - EFFECT_DRY_LEFT, - EFFECT_DRY_RIGHT, - EFFECT_EFF1, - EFFECT_EFF2, - EFFECT_EFF3 -} ymfpci_pcm_type_t; - -struct ymf_pcm { - ymfpci_t *codec; - ymfpci_pcm_type_t type; - struct ymf_state *state; - ymfpci_voice_t *voices[2]; /* playback only */ - int running; // + - int spdif; +struct ymf_capture { + // struct ymf_unit *unit; + int use; + ymfpci_capture_bank_t *bank; + struct ymf_pcm *ypcm; }; struct ymf_unit { u8 rev; /* PCI revision */ void *reg_area_virt; - void *work_ptr; // + + void *work_ptr; unsigned int bank_size_playback; unsigned int bank_size_capture; unsigned int bank_size_effect; unsigned int work_size; - void *bank_base_playback; // + - void *bank_base_capture; // + - void *bank_base_effect; // + - void *work_base; // + + void *bank_base_playback; + void *bank_base_capture; + void *bank_base_effect; + void *work_base; u32 *ctrl_playback; ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2]; @@ -269,13 +257,20 @@ struct ymf_unit { int start_count; u32 active_bank; - ymfpci_voice_t voices[64]; + struct ymf_voice voices[64]; + struct ymf_capture capture[5]; struct ac97_codec *ac97_codec[NR_AC97]; u16 ac97_features; struct pci_dev *pci; +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + /* legacy hardware resources */ + unsigned int iosynth, iomidi; + struct address_info opl3_data, mpu_data; +#endif + spinlock_t reg_lock; spinlock_t voice_lock; @@ -284,14 +279,11 @@ struct ymf_unit { struct semaphore open_sem; struct list_head ymf_devs; - struct ymf_state *states[1]; // * - /* ypcm may be the same thing as state, but not for record, effects. */ + struct list_head states; /* List of states for this unit */ + /* For the moment we do not traverse list of states so it is + * entirely useless. Will be used (PM) or killed. XXX */ }; -/* - * "Software" or virtual channel, an instance of opened /dev/dsp. - */ - struct ymf_dmabuf { /* OSS buffer management stuff */ @@ -312,7 +304,6 @@ struct ymf_dmabuf { /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; /* Total rawbuf[] size */ - unsigned fragsamples; /* OSS stuff */ unsigned mapped:1; @@ -329,15 +320,40 @@ struct ymf_pcm_format { int shift; /* redundant, computed from the above */ }; -struct ymf_state { - struct ymf_unit *unit; /* backpointer */ +typedef enum { + PLAYBACK_VOICE, + CAPTURE_REC, + CAPTURE_AC97, + EFFECT_DRY_LEFT, + EFFECT_DRY_RIGHT, + EFFECT_EFF1, + EFFECT_EFF2, + EFFECT_EFF3 +} ymfpci_pcm_type_t; - /* virtual channel number */ - int virt; // * unused a.t.m. +/* This is variant record, but we hate unions. Little waste on pointers []. */ +struct ymf_pcm { + ymfpci_pcm_type_t type; + struct ymf_state *state; + + ymfpci_voice_t *voices[2]; + int capture_bank_number; + + struct ymf_dmabuf dmabuf; + int running; + int spdif; +}; - struct ymf_pcm ypcm; // * - struct ymf_dmabuf dmabuf; // * - struct ymf_pcm_format format; // * +/* + * "Software" or virtual channel, an instance of opened /dev/dsp. + * It may have two physical channels (pcms) for duplex operations. + */ + +struct ymf_state { + struct list_head chain; + struct ymf_unit *unit; /* backpointer */ + struct ymf_pcm rpcm, wpcm; + struct ymf_pcm_format format; }; #endif /* __YMFPCI_H */ diff --git a/drivers/usb/rio500.c b/drivers/usb/rio500.c index 6d7b9043d..29b926056 100644 --- a/drivers/usb/rio500.c +++ b/drivers/usb/rio500.c @@ -247,6 +247,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, return 0; err_out: + up(&(rio->lock)); return retval; } @@ -389,7 +390,7 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos) result, partial, this_read); return -EIO; } else { - unlock_kernel(); + up(&(rio->lock)); return (0); } diff --git a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in index 6d949bc0b..0032f6e15 100644 --- a/drivers/usb/serial/Config.in +++ b/drivers/usb/serial/Config.in @@ -22,6 +22,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W + bool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W fi dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index 1a07a03d5..3a3451e49 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -14,8 +14,14 @@ * based on a driver by Brad Keryan) * * See Documentation/usb/usb-serial.txt for more information on using this driver - * - * (12/29/2000) gkh + * + * (12/12/2000) gkh + * Removed MOD_INC and MOD_DEC from poll and disconnect functions, and + * moved them to the serial_open and serial_close functions. + * Also fixed bug with there not being a MOD_DEC for the generic driver + * (thanks to Gary Brubaker for finding this.) + * + * (11/29/2000) gkh * Small NULL pointer initialization cleanup which saves a bit of disk image * * (11/01/2000) Adam J. Richter @@ -471,6 +477,8 @@ static int serial_open (struct tty_struct *tty, struct file * filp) return -ENODEV; } + MOD_INC_USE_COUNT; + /* set up our port structure making the tty driver remember our port object, and us it */ portNumber = MINOR(tty->device) - serial->minor; port = &serial->port[portNumber]; @@ -508,6 +516,8 @@ static void serial_close(struct tty_struct *tty, struct file * filp) } else { generic_close(port, filp); } + + MOD_DEC_USE_COUNT; } @@ -721,12 +731,13 @@ static int generic_open (struct usb_serial_port *port, struct file *filp) if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; + MOD_INC_USE_COUNT; + dbg(__FUNCTION__ " - port %d", port->number); spin_lock_irqsave (&port->port_lock, flags); ++port->open_count; - MOD_INC_USE_COUNT; if (!port->active) { port->active = 1; @@ -776,6 +787,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp) } spin_unlock_irqrestore (&port->port_lock, flags); + MOD_DEC_USE_COUNT; } @@ -1069,7 +1081,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, } /* found all that we need */ - MOD_INC_USE_COUNT; info("%s converter detected", type->name); #ifdef CONFIG_USB_SERIAL_GENERIC @@ -1077,7 +1088,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, num_ports = num_bulk_out; if (num_ports == 0) { err("Generic device with no bulk out, not allowed."); - MOD_DEC_USE_COUNT; return NULL; } } else @@ -1087,7 +1097,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, serial = get_free_serial (num_ports, &minor); if (serial == NULL) { err("No more free serial devices"); - MOD_DEC_USE_COUNT; return NULL; } @@ -1233,7 +1242,6 @@ probe_error: /* free up any memory that we allocated */ kfree (serial); - MOD_DEC_USE_COUNT; return NULL; } @@ -1300,7 +1308,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) info("device disconnected"); } - MOD_DEC_USE_COUNT; } diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index e363916b9..d8a60a2a7 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -10,6 +10,10 @@ * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (12/12/2000) gkh + * Moved MOD_DEC to end of visor_close to be nicer, as the final write + * message can sleep. * * (11/12/2000) gkh * Fixed bug with data being dropped on the floor by forcing tty->low_latency @@ -214,7 +218,6 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) spin_lock_irqsave (&port->port_lock, flags); --port->open_count; - MOD_DEC_USE_COUNT; if (port->open_count <= 0) { transfer_buffer = kmalloc (0x12, GFP_KERNEL); @@ -237,6 +240,8 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ + + MOD_DEC_USE_COUNT; } diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index 5123f85f8..c5477dcaf 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Header File * - * $Id: debug.h,v 1.5 2000/09/04 02:12:47 groovyjava Exp $ + * $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 241f7d5f6..5c50b578c 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -248,7 +248,7 @@ static int bus_reset( Scsi_Cmnd *srb ) for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) { struct usb_interface *intf = &us->pusb_dev->actconfig->interface[i]; - const struct usb_device_id *id; + struct usb_device_id *id; /* if this is an unclaimed interface, skip it */ if (!intf->driver) { diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h new file mode 100644 index 000000000..d29307433 --- /dev/null +++ b/drivers/usb/storage/unusual_devs.h @@ -0,0 +1,232 @@ +/* Driver for USB Mass Storage compliant devices + * Ununsual Devices File + * + * $Id: unusual_devs.h,v 1.1 2000/12/05 05:38:31 mdharm Exp $ + * + * Current development and maintenance by: + * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Initial work by: + * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. + * + * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more + * information about this driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* IMPORTANT NOTE: This file must be included in another file which does + * the following thing for it to work: + * The macro UNUSUAL_DEV() must be defined before this file is included + */ +#include <linux/config.h> + +/* If you edit this file, please try to keep it sorted first by VendorID, + * then by ProductID. + */ + +UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, + "Mitsumi", + "CD-R/RW Drive", + US_SC_8020, US_PR_CBI, NULL, 0), + +UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, + "HP", + "CD-Writer+", + US_SC_8070, US_PR_CB, NULL, 0), + +#ifdef CONFIG_USB_STORAGE_HP8200e +UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, + "HP", + "CD-Writer+ 8200e", + US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), +#endif + +UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200, + "Matshita", + "LS-120", + US_SC_8020, US_PR_CB, NULL, 0), + +UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + +#ifdef CONFIG_USB_STORAGE_SDDR09 +UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999, + "Sandisk", + "ImageMate SDDR09", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP ), +#endif + +#ifdef CONFIG_USB_STORAGE_DPCM +UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, + "Microtech", + "CameraMate (DPCM_USB)", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP ), +#endif + +UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0200, + "Shuttle", + "eUSB MMC Adapter", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN), + +UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200, + "Sony", + "Hifd", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN), + +UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200, + "Shuttle", + "eUSB ATA/ATAPI Adapter", + US_SC_8020, US_PR_CB, NULL, 0), + +UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200, + "Shuttle", + "eUSB CompactFlash Adapter", + US_SC_8020, US_PR_CB, NULL, 0), + +UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + +UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + +UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200, + "Shuttle", + "CD-RW Device", + US_SC_8020, US_PR_CB, NULL, 0), + +UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0210, + "Sony", + "DSC-S30/S70/505V/F505", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), + +UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100, + "Sony", + "Memorystick MSAC-US1", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP ), + +UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN), + +UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CBI, NULL, + US_FL_SINGLE_LUN), + +UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, + "LaCie", + "USB Hard Disk", + US_SC_RBC, US_PR_CB, NULL, 0 ), + +UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0100, + "In-System", + "USB/IDE Bridge (ATAPI ONLY!)", + US_SC_8070, US_PR_BULK, NULL, 0 ), + +UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, + "TEAC", + "Floppy Drive", + US_SC_UFI, US_PR_CB, NULL, 0 ), + +#ifdef CONFIG_USB_STORAGE_SDDR09 +UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, + "Olympus", + "Camedia MAUSB-2", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP ), +#endif + +UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, + "Hagiwara", + "FlashGate SmartMedia", + US_SC_SCSI, US_PR_BULK, NULL, 0 ), + +UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100, + "Hagiwara", + "Flashgate", + US_SC_SCSI, US_PR_BULK, NULL, 0 ), + +UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, + "Sandisk", + "ImageMate SDDR-05a", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP), + +UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, + "Sandisk", + "ImageMate SDDR-12", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN ), + +#ifdef CONFIG_USB_STORAGE_SDDR09 +UNUSUAL_DEV( 0x0781, 0x0200, 0x0100, 0x0100, + "Sandisk", + "ImageMate SDDR-09", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP ), +#endif + +UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, + "Sandisk", + "ImageMate SDDR-31", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_IGNORE_SER), + +UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-DB25", + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + +#ifdef CONFIG_USB_STORAGE_FREECOM +UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, + "Freecom", + "USB-IDE", + US_SC_QIC, US_PR_FREECOM, freecom_init, 0), +#endif + +UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-HD50", + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_FL_SCM_MULT_TARG ), + +#ifdef CONFIG_USB_STORAGE_DPCM +UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, + "Microtech", + "CameraMate (DPCM_USB)", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP ), +#endif + diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 6c254c701..1e0f40f50 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.57 2000/11/21 02:56:41 mdharm Exp $ + * $Id: usb.c,v 1.61 2001/01/13 00:10:59 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -11,6 +11,9 @@ * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) * + * usb_device_id support by Adam J. Richter (adam@yggdrasil.com): + * (c) 2000 Yggdrasil Computing, Inc. + * * This driver is based on the 'USB Mass Storage Class' document. This * describes in detail the protocol used to communicate with such * devices. Clearly, the designers had SCSI and ATAPI commands in @@ -95,11 +98,133 @@ struct semaphore us_list_semaphore; static void * storage_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id); + static void storage_disconnect(struct usb_device *dev, void *ptr); + +/* The entries in this table, except for final ones here + * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, + * line for line with the entries of us_unsuaul_dev_list[]. + * For now, we duplicate idVendor and idProduct in us_unsual_dev_list, + * just to avoid alignment bugs. + */ + +#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ + vendorName, productName,useProtocol, useTransport, \ + initFunction, flags) \ +{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) } + +static struct usb_device_id storage_usb_ids [] = { + +# include "unusual_devs.h" +#undef UNUSUAL_DEV + /* Control/Bulk transport for all SubClass values */ + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) }, + + /* Control/Bulk/Interrupt transport for all SubClass values */ + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) }, + + /* Bulk-only transport for all SubClass values */ + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) }, + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, + + /* Terminating entry */ + { } +}; + +MODULE_DEVICE_TABLE (usb, storage_usb_ids); + +/* This is the list of devices we recognize, along with their flag data */ + +/* The vendor name should be kept at eight characters or less, and + * the product name should be kept at 16 characters or less. If a device + * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names + * normally generated by a device thorugh the INQUIRY response will be + * taken from this list, and this is the reason for the above size + * restriction. However, if the flag is not present, then you + * are free to use as many characters as you like. + */ + +#undef UNUSUAL_DEV +#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ + vendor_name, product_name, use_protocol, use_transport, \ + init_function, Flags) \ +{ \ + vendorName: vendor_name, \ + productName: product_name, \ + useProtocol: use_protocol, \ + useTransport: use_transport, \ + initFunction : init_function, \ + flags: Flags, \ +} + +static struct us_unusual_dev us_unusual_dev_list[] = { +# include "unusual_devs.h" +# undef UNUSUAL_DEV + /* Control/Bulk transport for all SubClass values */ + { useProtocol: US_SC_RBC, + useTransport: US_PR_CB}, + { useProtocol: US_SC_8020, + useTransport: US_PR_CB}, + { useProtocol: US_SC_QIC, + useTransport: US_PR_CB}, + { useProtocol: US_SC_UFI, + useTransport: US_PR_CB}, + { useProtocol: US_SC_8070, + useTransport: US_PR_CB}, + { useProtocol: US_SC_SCSI, + useTransport: US_PR_CB}, + + /* Control/Bulk/Interrupt transport for all SubClass values */ + { useProtocol: US_SC_RBC, + useTransport: US_PR_CBI}, + { useProtocol: US_SC_8020, + useTransport: US_PR_CBI}, + { useProtocol: US_SC_QIC, + useTransport: US_PR_CBI}, + { useProtocol: US_SC_UFI, + useTransport: US_PR_CBI}, + { useProtocol: US_SC_8070, + useTransport: US_PR_CBI}, + { useProtocol: US_SC_SCSI, + useTransport: US_PR_CBI}, + + /* Bulk-only transport for all SubClass values */ + { useProtocol: US_SC_RBC, + useTransport: US_PR_BULK}, + { useProtocol: US_SC_8020, + useTransport: US_PR_BULK}, + { useProtocol: US_SC_QIC, + useTransport: US_PR_BULK}, + { useProtocol: US_SC_UFI, + useTransport: US_PR_BULK}, + { useProtocol: US_SC_8070, + useTransport: US_PR_BULK}, + { useProtocol: US_SC_SCSI, + useTransport: US_PR_BULK}, + + /* Terminating entry */ + { 0 } +}; + struct usb_driver usb_storage_driver = { name: "usb-storage", probe: storage_probe, disconnect: storage_disconnect, + id_table: storage_usb_ids, }; /* @@ -325,246 +450,6 @@ static int usb_stor_control_thread(void * __us) return 0; } -/* This is the list of devices we recognize, along with their flag data */ - -/* The vendor name should be kept at eight characters or less, and - * the product name should be kept at 16 characters or less. If a device - * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names - * normally generated by a device thorugh the INQUIRY response will be - * taken from this list, and this is the reason for the above size - * restriction. However, if the flag is not present, then you - * are free to use as many characters as you like. - */ -static struct us_unusual_dev us_unusual_dev_list[] = { - - { 0x03ee, 0x0000, 0x0000, 0x0245, - "Mitsumi", - "CD-R/RW Drive", - US_SC_8020, US_PR_CBI, NULL, 0}, - - { 0x03f0, 0x0107, 0x0200, 0x0200, - "HP", - "CD-Writer+", - US_SC_8070, US_PR_CB, NULL, 0}, - -#ifdef CONFIG_USB_STORAGE_HP8200e - { 0x03f0, 0x0207, 0x0001, 0x0001, - "HP", - "CD-Writer+ 8200e", - US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0}, -#endif - - { 0x04e6, 0x0001, 0x0200, 0x0200, - "Matshita", - "LS-120", - US_SC_8020, US_PR_CB, NULL, 0}, - - { 0x04e6, 0x0002, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG }, - -#ifdef CONFIG_USB_STORAGE_SDDR09 - { 0x04e6, 0x0003, 0x0000, 0x9999, - "Sandisk", - "ImageMate SDDR09", - US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP }, -#endif - -#ifdef CONFIG_USB_STORAGE_DPCM - { 0x0436, 0x0005, 0x0100, 0x0100, - "Microtech", - "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP }, -#endif - - { 0x04e6, 0x0006, 0x0100, 0x0200, - "Shuttle", - "eUSB MMC Adapter", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, - - { 0x04e6, 0x0007, 0x0100, 0x0200, - "Sony", - "Hifd", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, - - { 0x04e6, 0x0009, 0x0200, 0x0200, - "Shuttle", - "eUSB ATA/ATAPI Adapter", - US_SC_8020, US_PR_CB, NULL, 0}, - - { 0x04e6, 0x000a, 0x0200, 0x0200, - "Shuttle", - "eUSB CompactFlash Adapter", - US_SC_8020, US_PR_CB, NULL, 0}, - - { 0x04e6, 0x000B, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG }, - - { 0x04e6, 0x000C, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG }, - - { 0x04e6, 0x0101, 0x0200, 0x0200, - "Shuttle", - "CD-RW Device", - US_SC_8020, US_PR_CB, NULL, 0}, - - { 0x054c, 0x0010, 0x0106, 0x0210, - "Sony", - "DSC-S30/S70/505V/F505", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, - - { 0x054c, 0x002d, 0x0100, 0x0100, - "Sony", - "Memorystick MSAC-US1", - US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP }, - - { 0x057b, 0x0000, 0x0000, 0x0299, - "Y-E Data", - "Flashbuster-U", - US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, - - { 0x057b, 0x0000, 0x0300, 0x9999, - "Y-E Data", - "Flashbuster-U", - US_SC_UFI, US_PR_CBI, NULL, - US_FL_SINGLE_LUN}, - - { 0x059f, 0xa601, 0x0200, 0x0200, - "LaCie", - "USB Hard Disk", - US_SC_RBC, US_PR_CB, NULL, 0 }, - - { 0x05ab, 0x0031, 0x0100, 0x0100, - "In-System", - "USB/IDE Bridge (ATAPI ONLY!)", - US_SC_8070, US_PR_BULK, NULL, 0 }, - - { 0x0644, 0x0000, 0x0100, 0x0100, - "TEAC", - "Floppy Drive", - US_SC_UFI, US_PR_CB, NULL, 0 }, - -#ifdef CONFIG_USB_STORAGE_SDDR09 - { 0x066b, 0x0105, 0x0100, 0x0100, - "Olympus", - "Camedia MAUSB-2", - US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP }, -#endif - - { 0x0693, 0x0002, 0x0100, 0x0100, - "Hagiwara", - "FlashGate SmartMedia", - US_SC_SCSI, US_PR_BULK, NULL, 0 }, - - { 0x0693, 0x0005, 0x0100, 0x0100, - "Hagiwara", - "Flashgate", - US_SC_SCSI, US_PR_BULK, NULL, 0 }, - - { 0x0781, 0x0001, 0x0200, 0x0200, - "Sandisk", - "ImageMate SDDR-05a", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP}, - - { 0x0781, 0x0100, 0x0100, 0x0100, - "Sandisk", - "ImageMate SDDR-12", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN }, - -#ifdef CONFIG_USB_STORAGE_SDDR09 - { 0x0781, 0x0200, 0x0100, 0x0208, - "Sandisk", - "ImageMate SDDR-09", - US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP }, -#endif - - { 0x0781, 0x0002, 0x0009, 0x0009, - "Sandisk", - "ImageMate SDDR-31", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_IGNORE_SER}, - - { 0x07af, 0x0004, 0x0100, 0x0100, - "Microtech", - "USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG }, - -#ifdef CONFIG_USB_STORAGE_FREECOM - { 0x07ab, 0xfc01, 0x0000, 0x9999, - "Freecom", - "USB-IDE", - US_SC_QIC, US_PR_FREECOM, freecom_init, 0}, -#endif - - { 0x07af, 0x0005, 0x0100, 0x0100, - "Microtech", - "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG }, - -#ifdef CONFIG_USB_STORAGE_DPCM - { 0x07af, 0x0006, 0x0100, 0x0100, - "Microtech", - "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP }, -#endif - { 0 } -}; - -/* Search our ususual device list, based on vendor/product combinations - * to see if we can support this device. Returns a pointer to a structure - * defining how we should support this device, or NULL if it's not in the - * list - */ -static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, - u16 bcdDevice) -{ - struct us_unusual_dev* ptr; - - US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n", - idVendor, idProduct, bcdDevice); - - ptr = us_unusual_dev_list; - while ((ptr->idVendor != 0x0000) && - !((ptr->idVendor == idVendor) && - (ptr->idProduct == idProduct) && - (ptr->bcdDeviceMin <= bcdDevice) && - (ptr->bcdDeviceMax >= bcdDevice))) - ptr++; - - /* if the search ended because we hit the end record, we failed */ - if (ptr->idVendor == 0x0000) { - US_DEBUGP("-- did not find a matching device\n"); - return NULL; - } - - /* otherwise, we found one! */ - US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName, - ptr->productName); - return ptr; -} - /* Set up the IRQ pipe and handler * Note that this function assumes that all the data in the us_data * strucuture is current. This includes the ep_int field, which gives us @@ -620,6 +505,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { int i; + const int id_index = id - storage_usb_ids; char mf[USB_STOR_STRING_LEN]; /* manufacturer */ char prod[USB_STOR_STRING_LEN]; /* product */ char serial[USB_STOR_STRING_LEN]; /* serial number */ @@ -640,47 +526,48 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, u8 subclass = 0; u8 protocol = 0; - /* the altsettting 0 on the interface we're probing */ - struct usb_interface_descriptor *altsetting = - &(dev->actconfig->interface[ifnum].altsetting[0]); + /* the altsettting on the interface we're probing that matched our + * usb_match_id table + */ + struct usb_interface *intf = dev->actconfig->interface; + struct usb_interface_descriptor *altsetting = + intf[ifnum].altsetting + intf[ifnum].act_altsetting; + US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting); /* clear the temporary strings */ memset(mf, 0, sizeof(mf)); memset(prod, 0, sizeof(prod)); memset(serial, 0, sizeof(serial)); - /* search for this device in our unusual device list */ - unusual_dev = us_find_dev(dev->descriptor.idVendor, - dev->descriptor.idProduct, - dev->descriptor.bcdDevice); - /* * Can we support this device, either because we know about it * from our unusual device list, or because it advertises that it's * compliant to the specification? + * + * id_index is calculated in the declaration to be the index number + * of the match from the usb_device_id table, so we can find the + * corresponding entry in the private table. */ - if (!unusual_dev && - !(dev->descriptor.bDeviceClass == 0 && - altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE && - altsetting->bInterfaceSubClass >= US_SC_MIN && - altsetting->bInterfaceSubClass <= US_SC_MAX)) { - /* if it's not a mass storage, we go no further */ + US_DEBUGP("id_index calculated to be: %d\n", id_index); + US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])); + if (id_index < + sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) { + unusual_dev = &us_unusual_dev_list[id_index]; + if (unusual_dev->vendorName) + US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); + if (unusual_dev->productName) + US_DEBUGP("Product: %s\n", unusual_dev->productName); + } else + /* no, we can't support it */ return NULL; - } /* At this point, we know we've got a live one */ US_DEBUGP("USB Mass Storage device detected\n"); /* Determine subclass and protocol, or copy from the interface */ - if (unusual_dev) { - subclass = unusual_dev->useProtocol; - protocol = unusual_dev->useTransport; - flags = unusual_dev->flags; - } else { - subclass = altsetting->bInterfaceSubClass; - protocol = altsetting->bInterfaceProtocol; - flags = 0; - } + subclass = unusual_dev->useProtocol; + protocol = unusual_dev->useTransport; + flags = unusual_dev->flags; /* * Find the endpoints we need @@ -728,7 +615,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, /* Do some basic sanity checks, and bail if we find a problem */ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { - US_DEBUGP("Sanity check failed. Rejecting device.\n"); + US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); return NULL; } @@ -861,7 +748,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, strncpy(ss->product, prod, USB_STOR_STRING_LEN); strncpy(ss->serial, serial, USB_STOR_STRING_LEN); if (strlen(ss->vendor) == 0) { - if (unusual_dev) + if (unusual_dev->vendorName) strncpy(ss->vendor, unusual_dev->vendorName, USB_STOR_STRING_LEN); else @@ -869,7 +756,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, USB_STOR_STRING_LEN); } if (strlen(ss->product) == 0) { - if (unusual_dev) + if (unusual_dev->productName) strncpy(ss->product, unusual_dev->productName, USB_STOR_STRING_LEN); else @@ -1118,6 +1005,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) int __init usb_stor_init(void) { + printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); + /* initialize internal global data elements */ us_list = NULL; init_MUTEX(&us_list_semaphore); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index e0dac568d..9c8076c8d 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.11 2000/11/13 22:38:55 mdharm Exp $ + * $Id: usb.h,v 1.12 2000/12/05 03:33:49 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -84,13 +84,6 @@ struct us_data; */ struct us_unusual_dev { - /* we search the list based on these parameters */ - __u16 idVendor; - __u16 idProduct; - __u16 bcdDeviceMin; - __u16 bcdDeviceMax; - - /* the list specifies these parameters */ const char* vendorName; const char* productName; __u8 useProtocol; diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c index f9fa0d213..4d5b66386 100644 --- a/drivers/video/sbusfb.c +++ b/drivers/video/sbusfb.c @@ -678,7 +678,7 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, int end, count, index; struct fbcmap *cmap; - if (!fb->loadcmap) + if (!fb->loadcmap || !fb->color_map) return -EINVAL; i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap)); if (i) return i; @@ -1110,6 +1110,8 @@ sizechange: } if (!p) { + if (fb->color_map) + kfree(fb->color_map); kfree(fb); return; } @@ -1147,6 +1149,8 @@ sizechange: sbusfb_set_var(var, -1, &fb->info); if (register_framebuffer(&fb->info) < 0) { + if (fb->color_map) + kfree(fb->color_map); kfree(fb); return; } diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 8833cbeac..b494e25c6 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -461,7 +461,7 @@ static u_long get_line_length(int xres_virtual, int bpp) { u_long length; - length = (xres_virtual+bpp-1)/bpp; + length = xres_virtual*bpp; length = (length+31)&-32; length >>= 3; return(length); |